1 package com.android.internal.os;
2 
3 import android.os.StrictMode;
4 import android.os.SystemClock;
5 import android.text.TextUtils;
6 import android.util.LongSparseLongArray;
7 import android.util.Slog;
8 
9 import com.android.internal.annotations.VisibleForTesting;
10 
11 import java.io.BufferedReader;
12 import java.io.FileNotFoundException;
13 import java.io.FileReader;
14 import 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  */
26 public 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 
updateStats()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
parseStats(BufferedReader reader)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 
getBandwidthEntries()89     public LongSparseLongArray getBandwidthEntries() {
90         return mBandwidthEntries;
91     }
92 }
93