1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.os; 18 19 import android.annotation.Nullable; 20 21 /** 22 * CPU tracking using eBPF. 23 * 24 * The tracking state and data about available frequencies are cached to avoid JNI calls and 25 * creating temporary arrays. The data is stored in a format that is convenient for metrics 26 * computation. 27 * 28 * Synchronization is not needed because the underlying native library can be invoked concurrently 29 * and getters are idempotent. 30 */ 31 public final class KernelCpuBpfTracking { 32 private static boolean sTracking = false; 33 34 /** Cached mapping from frequency index to frequency in kHz. */ 35 private static long[] sFreqs = null; 36 37 /** Cached mapping from frequency index to CPU cluster / policy. */ 38 private static int[] sFreqsClusters = null; 39 KernelCpuBpfTracking()40 private KernelCpuBpfTracking() { 41 } 42 43 /** Returns whether CPU tracking using eBPF is supported. */ isSupported()44 public static native boolean isSupported(); 45 46 /** Starts CPU tracking using eBPF. */ startTracking()47 public static boolean startTracking() { 48 if (!sTracking) { 49 sTracking = startTrackingInternal(); 50 } 51 return sTracking; 52 } 53 startTrackingInternal()54 private static native boolean startTrackingInternal(); 55 56 /** Returns frequencies in kHz on which CPU is tracked. Empty if not supported. */ getFreqs()57 public static long[] getFreqs() { 58 if (sFreqs == null) { 59 long[] freqs = getFreqsInternal(); 60 if (freqs == null) { 61 return new long[0]; 62 } 63 sFreqs = freqs; 64 } 65 return sFreqs; 66 } 67 68 @Nullable getFreqsInternal()69 static native long[] getFreqsInternal(); 70 71 /** 72 * Returns the cluster (policy) number for each frequency on which CPU is tracked. Empty if 73 * not supported. 74 */ getFreqsClusters()75 public static int[] getFreqsClusters() { 76 if (sFreqsClusters == null) { 77 int[] freqsClusters = getFreqsClustersInternal(); 78 if (freqsClusters == null) { 79 return new int[0]; 80 } 81 sFreqsClusters = freqsClusters; 82 } 83 return sFreqsClusters; 84 } 85 86 @Nullable getFreqsClustersInternal()87 private static native int[] getFreqsClustersInternal(); 88 89 /** Returns the number of clusters (policies). */ getClusters()90 public static int getClusters() { 91 int[] freqClusters = getFreqsClusters(); 92 return freqClusters.length > 0 ? freqClusters[freqClusters.length - 1] + 1 : 0; 93 } 94 } 95