13a2260598ab8e45f1f1db9a05057532da279a541James Carrpackage com.android.internal.os;
23a2260598ab8e45f1f1db9a05057532da279a541James Carr
33a2260598ab8e45f1f1db9a05057532da279a541James Carrimport android.os.StrictMode;
43d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasaniimport android.os.SystemClock;
53a2260598ab8e45f1f1db9a05057532da279a541James Carrimport android.text.TextUtils;
63a2260598ab8e45f1f1db9a05057532da279a541James Carrimport android.util.LongSparseLongArray;
73a2260598ab8e45f1f1db9a05057532da279a541James Carrimport android.util.Slog;
83a2260598ab8e45f1f1db9a05057532da279a541James Carr
93a2260598ab8e45f1f1db9a05057532da279a541James Carrimport com.android.internal.annotations.VisibleForTesting;
103a2260598ab8e45f1f1db9a05057532da279a541James Carr
113a2260598ab8e45f1f1db9a05057532da279a541James Carrimport java.io.BufferedReader;
1261d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinskiimport java.io.FileNotFoundException;
133a2260598ab8e45f1f1db9a05057532da279a541James Carrimport java.io.FileReader;
143a2260598ab8e45f1f1db9a05057532da279a541James Carrimport java.io.IOException;
153a2260598ab8e45f1f1db9a05057532da279a541James Carr
163a2260598ab8e45f1f1db9a05057532da279a541James Carr/**
173a2260598ab8e45f1f1db9a05057532da279a541James Carr * Reads DDR time spent at various frequencies and stores the data.  Supports diff comparison with
183a2260598ab8e45f1f1db9a05057532da279a541James Carr * other KernelMemoryBandwidthStats objects. The sysfs file has the format:
193a2260598ab8e45f1f1db9a05057532da279a541James Carr *
203a2260598ab8e45f1f1db9a05057532da279a541James Carr * freq time_in_bucket ... time_in_bucket
213a2260598ab8e45f1f1db9a05057532da279a541James Carr *      ...
223a2260598ab8e45f1f1db9a05057532da279a541James Carr * freq time_in_bucket ... time_in_bucket
233a2260598ab8e45f1f1db9a05057532da279a541James Carr *
243a2260598ab8e45f1f1db9a05057532da279a541James Carr * where time is measured in nanoseconds.
253a2260598ab8e45f1f1db9a05057532da279a541James Carr */
263a2260598ab8e45f1f1db9a05057532da279a541James Carrpublic class KernelMemoryBandwidthStats {
273a2260598ab8e45f1f1db9a05057532da279a541James Carr    private static final String TAG = "KernelMemoryBandwidthStats";
283a2260598ab8e45f1f1db9a05057532da279a541James Carr
293a2260598ab8e45f1f1db9a05057532da279a541James Carr    private static final String mSysfsFile = "/sys/kernel/memory_state_time/show_stat";
303a2260598ab8e45f1f1db9a05057532da279a541James Carr    private static final boolean DEBUG = false;
313a2260598ab8e45f1f1db9a05057532da279a541James Carr
3261d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski    protected final LongSparseLongArray mBandwidthEntries = new LongSparseLongArray();
3361d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski    private boolean mStatsDoNotExist = false;
3461d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski
353a2260598ab8e45f1f1db9a05057532da279a541James Carr    public void updateStats() {
3661d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski        if (mStatsDoNotExist) {
3761d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski            // Skip reading.
3861d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski            return;
3961d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski        }
4061d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski
413d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani        final long startTime = SystemClock.uptimeMillis();
423d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani
433a2260598ab8e45f1f1db9a05057532da279a541James Carr        StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
443a2260598ab8e45f1f1db9a05057532da279a541James Carr        try (BufferedReader reader = new BufferedReader(new FileReader(mSysfsFile))) {
453a2260598ab8e45f1f1db9a05057532da279a541James Carr            parseStats(reader);
4661d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski        } catch (FileNotFoundException e) {
4761d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski            Slog.w(TAG, "No kernel memory bandwidth stats available");
4861d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski            mBandwidthEntries.clear();
4961d2d372336c7e2527a06f0673a74e9b0a93ec43Adam Lesinski            mStatsDoNotExist = true;
503a2260598ab8e45f1f1db9a05057532da279a541James Carr        } catch (IOException e) {
513a2260598ab8e45f1f1db9a05057532da279a541James Carr            Slog.e(TAG, "Failed to read memory bandwidth: " + e.getMessage());
523a2260598ab8e45f1f1db9a05057532da279a541James Carr            mBandwidthEntries.clear();
533a2260598ab8e45f1f1db9a05057532da279a541James Carr        } finally {
543a2260598ab8e45f1f1db9a05057532da279a541James Carr            StrictMode.setThreadPolicy(policy);
553a2260598ab8e45f1f1db9a05057532da279a541James Carr        }
563d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani
573d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani        final long readTime = SystemClock.uptimeMillis() - startTime;
583d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani        if (DEBUG || readTime > 100) {
593d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani            Slog.w(TAG, "Reading memory bandwidth file took " + readTime + "ms");
603d5d9aefc13c95b94cfe42fe41f57c40c5f13483Amith Yamasani        }
613a2260598ab8e45f1f1db9a05057532da279a541James Carr    }
623a2260598ab8e45f1f1db9a05057532da279a541James Carr
633a2260598ab8e45f1f1db9a05057532da279a541James Carr    @VisibleForTesting
643a2260598ab8e45f1f1db9a05057532da279a541James Carr    public void parseStats(BufferedReader reader) throws IOException {
653a2260598ab8e45f1f1db9a05057532da279a541James Carr        String line;
663a2260598ab8e45f1f1db9a05057532da279a541James Carr        TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
673a2260598ab8e45f1f1db9a05057532da279a541James Carr        mBandwidthEntries.clear();
683a2260598ab8e45f1f1db9a05057532da279a541James Carr        while ((line = reader.readLine()) != null) {
693a2260598ab8e45f1f1db9a05057532da279a541James Carr            splitter.setString(line);
703a2260598ab8e45f1f1db9a05057532da279a541James Carr            splitter.next();
713a2260598ab8e45f1f1db9a05057532da279a541James Carr            int bandwidth = 0;
723a2260598ab8e45f1f1db9a05057532da279a541James Carr            int index;
733a2260598ab8e45f1f1db9a05057532da279a541James Carr            do {
743a2260598ab8e45f1f1db9a05057532da279a541James Carr                if ((index = mBandwidthEntries.indexOfKey(bandwidth)) >= 0) {
753a2260598ab8e45f1f1db9a05057532da279a541James Carr                    mBandwidthEntries.put(bandwidth, mBandwidthEntries.valueAt(index)
763a2260598ab8e45f1f1db9a05057532da279a541James Carr                            + Long.parseLong(splitter.next()) / 1000000);
773a2260598ab8e45f1f1db9a05057532da279a541James Carr                } else {
783a2260598ab8e45f1f1db9a05057532da279a541James Carr                    mBandwidthEntries.put(bandwidth, Long.parseLong(splitter.next()) / 1000000);
793a2260598ab8e45f1f1db9a05057532da279a541James Carr                }
803a2260598ab8e45f1f1db9a05057532da279a541James Carr                if (DEBUG) {
813a2260598ab8e45f1f1db9a05057532da279a541James Carr                    Slog.d(TAG, String.format("bandwidth: %s time: %s", bandwidth,
823a2260598ab8e45f1f1db9a05057532da279a541James Carr                            mBandwidthEntries.get(bandwidth)));
833a2260598ab8e45f1f1db9a05057532da279a541James Carr                }
843a2260598ab8e45f1f1db9a05057532da279a541James Carr                bandwidth++;
853a2260598ab8e45f1f1db9a05057532da279a541James Carr            } while(splitter.hasNext());
863a2260598ab8e45f1f1db9a05057532da279a541James Carr        }
873a2260598ab8e45f1f1db9a05057532da279a541James Carr    }
883a2260598ab8e45f1f1db9a05057532da279a541James Carr
893a2260598ab8e45f1f1db9a05057532da279a541James Carr    public LongSparseLongArray getBandwidthEntries() {
903a2260598ab8e45f1f1db9a05057532da279a541James Carr        return mBandwidthEntries;
913a2260598ab8e45f1f1db9a05057532da279a541James Carr    }
923a2260598ab8e45f1f1db9a05057532da279a541James Carr}
93