1package com.android.internal.os;
2
3import android.os.StrictMode;
4import android.os.SystemClock;
5import android.text.TextUtils;
6import android.util.LongSparseLongArray;
7import android.util.Slog;
8
9import com.android.internal.annotations.VisibleForTesting;
10
11import java.io.BufferedReader;
12import java.io.FileNotFoundException;
13import java.io.FileReader;
14import java.io.IOException;
15
16/**
17 * Reads DDR time spent at various frequencies and stores the data.  Supports diff comparison with
18 * other KernelMemoryBandwidthStats objects. The sysfs file has the format:
19 *
20 * freq time_in_bucket ... time_in_bucket
21 *      ...
22 * freq time_in_bucket ... time_in_bucket
23 *
24 * where time is measured in nanoseconds.
25 */
26public class KernelMemoryBandwidthStats {
27    private static final String TAG = "KernelMemoryBandwidthStats";
28
29    private static final String mSysfsFile = "/sys/kernel/memory_state_time/show_stat";
30    private static final boolean DEBUG = false;
31
32    protected final LongSparseLongArray mBandwidthEntries = new LongSparseLongArray();
33    private boolean mStatsDoNotExist = false;
34
35    public void updateStats() {
36        if (mStatsDoNotExist) {
37            // Skip reading.
38            return;
39        }
40
41        final long startTime = SystemClock.uptimeMillis();
42
43        StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
44        try (BufferedReader reader = new BufferedReader(new FileReader(mSysfsFile))) {
45            parseStats(reader);
46        } catch (FileNotFoundException e) {
47            Slog.w(TAG, "No kernel memory bandwidth stats available");
48            mBandwidthEntries.clear();
49            mStatsDoNotExist = true;
50        } catch (IOException e) {
51            Slog.e(TAG, "Failed to read memory bandwidth: " + e.getMessage());
52            mBandwidthEntries.clear();
53        } finally {
54            StrictMode.setThreadPolicy(policy);
55        }
56
57        final long readTime = SystemClock.uptimeMillis() - startTime;
58        if (DEBUG || readTime > 100) {
59            Slog.w(TAG, "Reading memory bandwidth file took " + readTime + "ms");
60        }
61    }
62
63    @VisibleForTesting
64    public void parseStats(BufferedReader reader) throws IOException {
65        String line;
66        TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
67        mBandwidthEntries.clear();
68        while ((line = reader.readLine()) != null) {
69            splitter.setString(line);
70            splitter.next();
71            int bandwidth = 0;
72            int index;
73            do {
74                if ((index = mBandwidthEntries.indexOfKey(bandwidth)) >= 0) {
75                    mBandwidthEntries.put(bandwidth, mBandwidthEntries.valueAt(index)
76                            + Long.parseLong(splitter.next()) / 1000000);
77                } else {
78                    mBandwidthEntries.put(bandwidth, Long.parseLong(splitter.next()) / 1000000);
79                }
80                if (DEBUG) {
81                    Slog.d(TAG, String.format("bandwidth: %s time: %s", bandwidth,
82                            mBandwidthEntries.get(bandwidth)));
83                }
84                bandwidth++;
85            } while(splitter.hasNext());
86        }
87    }
88
89    public LongSparseLongArray getBandwidthEntries() {
90        return mBandwidthEntries;
91    }
92}
93