package com.android.internal.os; import android.os.StrictMode; import android.text.TextUtils; import android.util.LongSparseLongArray; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /** * Reads DDR time spent at various frequencies and stores the data. Supports diff comparison with * other KernelMemoryBandwidthStats objects. The sysfs file has the format: * * freq time_in_bucket ... time_in_bucket * ... * freq time_in_bucket ... time_in_bucket * * where time is measured in nanoseconds. */ public class KernelMemoryBandwidthStats { private static final String TAG = "KernelMemoryBandwidthStats"; private static final String mSysfsFile = "/sys/kernel/memory_state_time/show_stat"; private static final boolean DEBUG = false; protected final LongSparseLongArray mBandwidthEntries = new LongSparseLongArray(); private boolean mStatsDoNotExist = false; public void updateStats() { if (mStatsDoNotExist) { // Skip reading. return; } StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads(); try (BufferedReader reader = new BufferedReader(new FileReader(mSysfsFile))) { parseStats(reader); } catch (FileNotFoundException e) { Slog.w(TAG, "No kernel memory bandwidth stats available"); mBandwidthEntries.clear(); mStatsDoNotExist = true; } catch (IOException e) { Slog.e(TAG, "Failed to read memory bandwidth: " + e.getMessage()); mBandwidthEntries.clear(); } finally { StrictMode.setThreadPolicy(policy); } } @VisibleForTesting public void parseStats(BufferedReader reader) throws IOException { String line; TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); mBandwidthEntries.clear(); while ((line = reader.readLine()) != null) { splitter.setString(line); splitter.next(); int bandwidth = 0; int index; do { if ((index = mBandwidthEntries.indexOfKey(bandwidth)) >= 0) { mBandwidthEntries.put(bandwidth, mBandwidthEntries.valueAt(index) + Long.parseLong(splitter.next()) / 1000000); } else { mBandwidthEntries.put(bandwidth, Long.parseLong(splitter.next()) / 1000000); } if (DEBUG) { Slog.d(TAG, String.format("bandwidth: %s time: %s", bandwidth, mBandwidthEntries.get(bandwidth))); } bandwidth++; } while(splitter.hasNext()); } } public LongSparseLongArray getBandwidthEntries() { return mBandwidthEntries; } }