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
17package com.android.internal.app.procstats;
18
19import android.util.DebugUtils;
20
21import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
22import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
23import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_SAMPLE_COUNT;
24import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MINIMUM;
25import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_AVERAGE;
26import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MAXIMUM;
27import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MINIMUM;
28import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_AVERAGE;
29import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MAXIMUM;
30import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MINIMUM;
31import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_AVERAGE;
32import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MAXIMUM;
33import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MINIMUM;
34import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_AVERAGE;
35import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MAXIMUM;
36import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MINIMUM;
37import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_AVERAGE;
38import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MAXIMUM;
39import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_COUNT;
40
41import java.io.PrintWriter;
42
43
44/**
45 * Class to accumulate system mem usage data.
46 */
47public class SysMemUsageTable extends SparseMappingTable.Table {
48    /**
49     * Construct the SysMemUsageTable with 'tableData' as backing store
50     * for the longs data.
51     */
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     */
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     */
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     */
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     */
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
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
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