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 static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE;
20 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM;
21 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
22 import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
23 import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
24 import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
25 import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
26 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
27 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
28 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
29 import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
30 
31 import android.service.procstats.ProcessStatsStateProto;
32 import android.util.proto.ProtoOutputStream;
33 import android.util.proto.ProtoUtils;
34 
35 /**
36  * Class to accumulate PSS data.
37  */
38 public class PssTable extends SparseMappingTable.Table {
39     /**
40      * Construct the PssTable with 'tableData' as backing store
41      * for the longs data.
42      */
PssTable(SparseMappingTable tableData)43     public PssTable(SparseMappingTable tableData) {
44         super(tableData);
45     }
46 
47     /**
48      * Merge the the values from the other table into this one.
49      */
mergeStats(PssTable that)50     public void mergeStats(PssTable that) {
51         final int N = that.getKeyCount();
52         for (int i=0; i<N; i++) {
53             final int thatKey = that.getKeyAt(i);
54             final int state = SparseMappingTable.getIdFromKey(thatKey);
55 
56             final int key = getOrAddKey((byte)state, PSS_COUNT);
57             final long[] stats = getArrayForKey(key);
58             final int statsIndex = SparseMappingTable.getIndexFromKey(key);
59 
60             final long[] thatStats = that.getArrayForKey(thatKey);
61             final int thatStatsIndex = SparseMappingTable.getIndexFromKey(thatKey);
62 
63             mergeStats(stats, statsIndex, thatStats, thatStatsIndex);
64         }
65     }
66 
67     /**
68      * Merge the supplied PSS data in.  The new min pss will be the minimum of the existing
69      * one and the new one, the average will now incorporate the new average, etc.
70      */
mergeStats(int state, int inCount, long minPss, long avgPss, long maxPss, long minUss, long avgUss, long maxUss, long minRss, long avgRss, long maxRss)71     public void mergeStats(int state, int inCount, long minPss, long avgPss, long maxPss,
72             long minUss, long avgUss, long maxUss, long minRss, long avgRss, long maxRss) {
73         final int key = getOrAddKey((byte)state, PSS_COUNT);
74         final long[] stats = getArrayForKey(key);
75         final int statsIndex = SparseMappingTable.getIndexFromKey(key);
76         mergeStats(stats, statsIndex, inCount, minPss, avgPss, maxPss, minUss, avgUss, maxUss,
77                 minRss, avgRss, maxRss);
78     }
79 
mergeStats(final long[] stats, final int statsIndex, final long[] thatStats, int thatStatsIndex)80     public static void mergeStats(final long[] stats, final int statsIndex,
81             final long[] thatStats, int thatStatsIndex) {
82         mergeStats(stats, statsIndex, (int)thatStats[thatStatsIndex + PSS_SAMPLE_COUNT],
83                 thatStats[thatStatsIndex + PSS_MINIMUM],
84                 thatStats[thatStatsIndex + PSS_AVERAGE],
85                 thatStats[thatStatsIndex + PSS_MAXIMUM],
86                 thatStats[thatStatsIndex + PSS_USS_MINIMUM],
87                 thatStats[thatStatsIndex + PSS_USS_AVERAGE],
88                 thatStats[thatStatsIndex + PSS_USS_MAXIMUM],
89                 thatStats[thatStatsIndex + PSS_RSS_MINIMUM],
90                 thatStats[thatStatsIndex + PSS_RSS_AVERAGE],
91                 thatStats[thatStatsIndex + PSS_RSS_MAXIMUM]);
92     }
93 
mergeStats(final long[] stats, final int statsIndex, final int inCount, final long minPss, final long avgPss, final long maxPss, final long minUss, final long avgUss, final long maxUss, final long minRss, final long avgRss, final long maxRss)94     public static void mergeStats(final long[] stats, final int statsIndex, final int inCount,
95             final long minPss, final long avgPss, final long maxPss,
96             final long minUss, final long avgUss, final long maxUss,
97             final long minRss, final long avgRss, final long maxRss) {
98         final long count = stats[statsIndex + PSS_SAMPLE_COUNT];
99         if (count == 0) {
100             stats[statsIndex + PSS_SAMPLE_COUNT] = inCount;
101             stats[statsIndex + PSS_MINIMUM] = minPss;
102             stats[statsIndex + PSS_AVERAGE] = avgPss;
103             stats[statsIndex + PSS_MAXIMUM] = maxPss;
104             stats[statsIndex + PSS_USS_MINIMUM] = minUss;
105             stats[statsIndex + PSS_USS_AVERAGE] = avgUss;
106             stats[statsIndex + PSS_USS_MAXIMUM] = maxUss;
107             stats[statsIndex + PSS_RSS_MINIMUM] = minRss;
108             stats[statsIndex + PSS_RSS_AVERAGE] = avgRss;
109             stats[statsIndex + PSS_RSS_MAXIMUM] = maxRss;
110         } else {
111             stats[statsIndex + PSS_SAMPLE_COUNT] = count + inCount;
112 
113             if (stats[statsIndex + PSS_MINIMUM] > minPss) {
114                 stats[statsIndex + PSS_MINIMUM] = minPss;
115             }
116 
117             stats[statsIndex + PSS_AVERAGE] = (long)(((stats[statsIndex + PSS_AVERAGE]
118                     * (double)count) + (avgPss * (double)inCount)) / (count + inCount));
119 
120             if (stats[statsIndex + PSS_MAXIMUM] < maxPss) {
121                 stats[statsIndex + PSS_MAXIMUM] = maxPss;
122             }
123 
124             if (stats[statsIndex + PSS_USS_MINIMUM] > minUss) {
125                 stats[statsIndex + PSS_USS_MINIMUM] = minUss;
126             }
127 
128             stats[statsIndex + PSS_USS_AVERAGE] = (long)(((stats[statsIndex + PSS_USS_AVERAGE]
129                     * (double)count) + (avgUss * (double)inCount)) / (count + inCount));
130 
131             if (stats[statsIndex + PSS_USS_MAXIMUM] < maxUss) {
132                 stats[statsIndex + PSS_USS_MAXIMUM] = maxUss;
133             }
134 
135             if (stats[statsIndex + PSS_RSS_MINIMUM] > minRss) {
136                 stats[statsIndex + PSS_RSS_MINIMUM] = minRss;
137             }
138 
139             stats[statsIndex + PSS_RSS_AVERAGE] = (long)(((stats[statsIndex + PSS_RSS_AVERAGE]
140                     * (double)count) + (avgRss * (double)inCount)) / (count + inCount));
141 
142             if (stats[statsIndex + PSS_RSS_MAXIMUM] < maxRss) {
143                 stats[statsIndex + PSS_RSS_MAXIMUM] = maxRss;
144             }
145         }
146     }
147 
writeStatsToProtoForKey(ProtoOutputStream proto, int key)148     public void writeStatsToProtoForKey(ProtoOutputStream proto, int key) {
149         final long[] stats = getArrayForKey(key);
150         final int statsIndex = SparseMappingTable.getIndexFromKey(key);
151         writeStatsToProto(proto, stats, statsIndex);
152     }
153 
writeStatsToProto(ProtoOutputStream proto, final long[] stats, final int statsIndex)154     public static void writeStatsToProto(ProtoOutputStream proto, final long[] stats,
155             final int statsIndex) {
156         proto.write(ProcessStatsStateProto.SAMPLE_SIZE, stats[statsIndex + PSS_SAMPLE_COUNT]);
157         ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.PSS,
158                 stats[statsIndex + PSS_MINIMUM],
159                 stats[statsIndex + PSS_AVERAGE],
160                 stats[statsIndex + PSS_MAXIMUM]);
161         ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.USS,
162                 stats[statsIndex + PSS_USS_MINIMUM],
163                 stats[statsIndex + PSS_USS_AVERAGE],
164                 stats[statsIndex + PSS_USS_MAXIMUM]);
165         ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.RSS,
166                 stats[statsIndex + PSS_RSS_MINIMUM],
167                 stats[statsIndex + PSS_RSS_AVERAGE],
168                 stats[statsIndex + PSS_RSS_MAXIMUM]);
169     }
170 }
171