1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.app.procstats;
18 
19 import android.util.DebugUtils;
20 
21 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
22 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
23 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_SAMPLE_COUNT;
24 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MINIMUM;
25 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_AVERAGE;
26 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MAXIMUM;
27 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MINIMUM;
28 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_AVERAGE;
29 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MAXIMUM;
30 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MINIMUM;
31 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_AVERAGE;
32 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MAXIMUM;
33 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MINIMUM;
34 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_AVERAGE;
35 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MAXIMUM;
36 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MINIMUM;
37 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_AVERAGE;
38 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MAXIMUM;
39 import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_COUNT;
40 
41 import java.io.PrintWriter;
42 
43 
44 /**
45  * Class to accumulate system mem usage data.
46  */
47 public class SysMemUsageTable extends SparseMappingTable.Table {
48     /**
49      * Construct the SysMemUsageTable with 'tableData' as backing store
50      * for the longs data.
51      */
SysMemUsageTable(SparseMappingTable tableData)52     public SysMemUsageTable(SparseMappingTable tableData) {
53         super(tableData);
54     }
55 
56     /**
57      * Merge the stats given into our own values.
58      *
59      * @param that  SysMemUsageTable to copy from.
60      */
mergeStats(SysMemUsageTable that)61     public void mergeStats(SysMemUsageTable that) {
62         final int N = that.getKeyCount();
63         for (int i=0; i<N; i++) {
64             final int key = that.getKeyAt(i);
65 
66             final int state = SparseMappingTable.getIdFromKey(key);
67             final long[] addData = that.getArrayForKey(key);
68             final int addOff = SparseMappingTable.getIndexFromKey(key);
69 
70             mergeStats(state, addData, addOff);
71         }
72     }
73 
74     /**
75      * Merge the stats given into our own values.
76      *
77      * @param state     The state
78      * @param addData   The data array to copy
79      * @param addOff    The index in addOff to start copying from
80      */
mergeStats(int state, long[] addData, int addOff)81     public void mergeStats(int state, long[] addData, int addOff) {
82         final int key = getOrAddKey((byte)state, SYS_MEM_USAGE_COUNT);
83 
84         final long[] dstData = getArrayForKey(key);
85         final int dstOff = SparseMappingTable.getIndexFromKey(key);
86 
87         SysMemUsageTable.mergeSysMemUsage(dstData, dstOff, addData, addOff);
88     }
89 
90     /**
91      * Return a long[] containing the merge of all of the usage in this table.
92      */
getTotalMemUsage()93     public long[] getTotalMemUsage() {
94         long[] total = new long[SYS_MEM_USAGE_COUNT];
95         final int N = getKeyCount();
96         for (int i=0; i<N; i++) {
97             final int key = getKeyAt(i);
98 
99             final long[] addData = getArrayForKey(key);
100             final int addOff = SparseMappingTable.getIndexFromKey(key);
101 
102             SysMemUsageTable.mergeSysMemUsage(total, 0, addData, addOff);
103         }
104         return total;
105     }
106 
107     /**
108      * Merge the stats from one raw long[] into another.
109      *
110      * @param dstData The destination array
111      * @param dstOff  The index in the destination array to start from
112      * @param addData The source array
113      * @param addOff  The index in the source array to start from
114      */
mergeSysMemUsage(long[] dstData, int dstOff, long[] addData, int addOff)115     public static void mergeSysMemUsage(long[] dstData, int dstOff,
116             long[] addData, int addOff) {
117         final long dstCount = dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT];
118         final long addCount = addData[addOff+SYS_MEM_USAGE_SAMPLE_COUNT];
119         if (dstCount == 0) {
120             dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = addCount;
121             for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i++) {
122                 dstData[dstOff+i] = addData[addOff+i];
123             }
124         } else if (addCount > 0) {
125             dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = dstCount + addCount;
126             for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i+=3) {
127                 if (dstData[dstOff+i] > addData[addOff+i]) {
128                     dstData[dstOff+i] = addData[addOff+i];
129                 }
130                 dstData[dstOff+i+1] = (long)(
131                         ((dstData[dstOff+i+1]*(double)dstCount)
132                                 + (addData[addOff+i+1]*(double)addCount))
133                                 / (dstCount+addCount) );
134                 if (dstData[dstOff+i+2] < addData[addOff+i+2]) {
135                     dstData[dstOff+i+2] = addData[addOff+i+2];
136                 }
137             }
138         }
139     }
140 
141 
dump(PrintWriter pw, String prefix, int[] screenStates, int[] memStates)142     public void dump(PrintWriter pw, String prefix, int[] screenStates, int[] memStates) {
143         int printedScreen = -1;
144         for (int is=0; is<screenStates.length; is++) {
145             int printedMem = -1;
146             for (int im=0; im<memStates.length; im++) {
147                 final int iscreen = screenStates[is];
148                 final int imem = memStates[im];
149                 final int bucket = ((iscreen + imem) * STATE_COUNT);
150                 long count = getValueForId((byte)bucket, SYS_MEM_USAGE_SAMPLE_COUNT);
151                 if (count > 0) {
152                     pw.print(prefix);
153                     if (screenStates.length > 1) {
154                         DumpUtils.printScreenLabel(pw, printedScreen != iscreen
155                                 ? iscreen : STATE_NOTHING);
156                         printedScreen = iscreen;
157                     }
158                     if (memStates.length > 1) {
159                         DumpUtils.printMemLabel(pw,
160                                 printedMem != imem ? imem : STATE_NOTHING, '\0');
161                         printedMem = imem;
162                     }
163                     pw.print(": ");
164                     pw.print(count);
165                     pw.println(" samples:");
166                     dumpCategory(pw, prefix, "  Cached", bucket, SYS_MEM_USAGE_CACHED_MINIMUM);
167                     dumpCategory(pw, prefix, "  Free", bucket, SYS_MEM_USAGE_FREE_MINIMUM);
168                     dumpCategory(pw, prefix, "  ZRam", bucket, SYS_MEM_USAGE_ZRAM_MINIMUM);
169                     dumpCategory(pw, prefix, "  Kernel", bucket, SYS_MEM_USAGE_KERNEL_MINIMUM);
170                     dumpCategory(pw, prefix, "  Native", bucket, SYS_MEM_USAGE_NATIVE_MINIMUM);
171                 }
172             }
173         }
174     }
175 
dumpCategory(PrintWriter pw, String prefix, String label, int bucket, int index)176     private void dumpCategory(PrintWriter pw, String prefix, String label, int bucket, int index) {
177         pw.print(prefix); pw.print(label);
178         pw.print(": ");
179         DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index) * 1024);
180         pw.print(" min, ");
181         DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index + 1) * 1024);
182         pw.print(" avg, ");
183         DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index+2) * 1024);
184         pw.println(" max");
185     }
186 
187 }
188 
189 
190