/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.annotation.Nullable; /** * CPU tracking using eBPF. * * The tracking state and data about available frequencies are cached to avoid JNI calls and * creating temporary arrays. The data is stored in a format that is convenient for metrics * computation. * * Synchronization is not needed because the underlying native library can be invoked concurrently * and getters are idempotent. */ public final class KernelCpuBpfTracking { private static boolean sTracking = false; /** Cached mapping from frequency index to frequency in kHz. */ private static long[] sFreqs = null; /** Cached mapping from frequency index to CPU cluster / policy. */ private static int[] sFreqsClusters = null; private KernelCpuBpfTracking() { } /** Returns whether CPU tracking using eBPF is supported. */ public static native boolean isSupported(); /** Starts CPU tracking using eBPF. */ public static boolean startTracking() { if (!sTracking) { sTracking = startTrackingInternal(); } return sTracking; } private static native boolean startTrackingInternal(); /** Returns frequencies in kHz on which CPU is tracked. Empty if not supported. */ public static long[] getFreqs() { if (sFreqs == null) { long[] freqs = getFreqsInternal(); if (freqs == null) { return new long[0]; } sFreqs = freqs; } return sFreqs; } @Nullable static native long[] getFreqsInternal(); /** * Returns the cluster (policy) number for each frequency on which CPU is tracked. Empty if * not supported. */ public static int[] getFreqsClusters() { if (sFreqsClusters == null) { int[] freqsClusters = getFreqsClustersInternal(); if (freqsClusters == null) { return new int[0]; } sFreqsClusters = freqsClusters; } return sFreqsClusters; } @Nullable private static native int[] getFreqsClustersInternal(); /** Returns the number of clusters (policies). */ public static int getClusters() { int[] freqClusters = getFreqsClusters(); return freqClusters.length > 0 ? freqClusters[freqClusters.length - 1] + 1 : 0; } }