blob: 8d591dff4085246e24e9c5af7753a763980fbae2 [file] [log] [blame]
Girish1f002cf2023-02-17 00:36:29 +00001/*
2**
3** Copyright 2023, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "ResourceManagerMetrics"
20#include <utils/Log.h>
21#include <mediautils/ProcessInfo.h>
22
23#include <stats_media_metrics.h>
24
25#include "UidObserver.h"
26#include "ResourceManagerMetrics.h"
27
28#include <cmath>
29#include <sstream>
30
31namespace android {
32
33using stats::media_metrics::stats_write;
34using stats::media_metrics::MEDIA_CODEC_STARTED;
35using stats::media_metrics::MEDIA_CODEC_STOPPED;
36// Disabling this for now.
37#ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
38using stats::media_metrics::MEDIA_CODEC_CONCURRENT_USAGE_REPORTED;
39#endif
40using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED;
41using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
42using stats::media_metrics::\
43 MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
44using stats::media_metrics::\
45 MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
46
47inline const char* getCodecType(MediaResourceSubType codecType) {
48 switch (codecType) {
49 case MediaResourceSubType::kAudioCodec: return "Audio";
50 case MediaResourceSubType::kVideoCodec: return "Video";
51 case MediaResourceSubType::kImageCodec: return "Image";
52 case MediaResourceSubType::kUnspecifiedSubType:
53 default:
54 return "Unspecified";
55 }
56 return "Unspecified";
57}
58
59static CodecBucket getCodecBucket(bool isHardware,
60 bool isEncoder,
61 MediaResourceSubType codecType) {
62 if (isHardware) {
63 switch (codecType) {
64 case MediaResourceSubType::kAudioCodec:
65 if (isEncoder) return HwAudioEncoder;
66 return HwAudioDecoder;
67 case MediaResourceSubType::kVideoCodec:
68 if (isEncoder) return HwVideoEncoder;
69 return HwVideoDecoder;
70 case MediaResourceSubType::kImageCodec:
71 if (isEncoder) return HwImageEncoder;
72 return HwImageDecoder;
73 case MediaResourceSubType::kUnspecifiedSubType:
74 default:
75 return CodecBucketUnspecified;
76 }
77 } else {
78 switch (codecType) {
79 case MediaResourceSubType::kAudioCodec:
80 if (isEncoder) return SwAudioEncoder;
81 return SwAudioDecoder;
82 case MediaResourceSubType::kVideoCodec:
83 if (isEncoder) return SwVideoEncoder;
84 return SwVideoDecoder;
85 case MediaResourceSubType::kImageCodec:
86 if (isEncoder) return SwImageEncoder;
87 return SwImageDecoder;
88 case MediaResourceSubType::kUnspecifiedSubType:
89 default:
90 return CodecBucketUnspecified;
91 }
92 }
93
94 return CodecBucketUnspecified;
95}
96
97static bool getLogMessage(int hwCount, int swCount, std::stringstream& logMsg) {
98 bool update = false;
99 logMsg.clear();
100
101 if (hwCount > 0) {
102 logMsg << " HW: " << hwCount;
103 update = true;
104 }
105 if (swCount > 0) {
106 logMsg << " SW: " << swCount;
107 update = true;
108 }
109
110 if (update) {
111 logMsg << " ] ";
112 }
113 return update;
114}
115
116ResourceManagerMetrics::ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo) {
117 // Create a process termination watcher, with 5seconds of polling frequency.
118 mUidObserver = sp<UidObserver>::make(processInfo,
119 [this] (int32_t pid, uid_t uid) {
120 onProcessTerminated(pid, uid);
121 });
122 mUidObserver->start();
123}
124
125ResourceManagerMetrics::~ResourceManagerMetrics() {
126 mUidObserver->stop();
127}
128
129void ResourceManagerMetrics::addPid(int pid, uid_t uid) {
130 if (uid != 0) {
131 std::scoped_lock lock(mLock);
132 mUidObserver->add(pid, uid);
133 }
134}
135
136void ResourceManagerMetrics::notifyClientCreated(const ClientInfoParcel& clientInfo) {
137 std::scoped_lock lock(mLock);
138 // Update the resource instance count.
139 std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientInfo.name);
140 if (found == mConcurrentResourceCountMap.end()) {
141 mConcurrentResourceCountMap[clientInfo.name] = 1;
142 } else {
143 found->second++;
144 }
145}
146
147void ResourceManagerMetrics::notifyClientReleased(const ClientInfoParcel& clientInfo) {
148 bool stopCalled = true;
Girishc9637682023-03-23 23:33:32 +0000149 ClientConfigParcel clientConfig;
Girish1f002cf2023-02-17 00:36:29 +0000150 {
151 std::scoped_lock lock(mLock);
Girishc9637682023-03-23 23:33:32 +0000152 ClientConfigMap::iterator found = mClientConfigMap.find(clientInfo.id);
Girish1f002cf2023-02-17 00:36:29 +0000153 if (found != mClientConfigMap.end()) {
154 // Release is called without Stop!
155 stopCalled = false;
Girishc9637682023-03-23 23:33:32 +0000156 clientConfig = found->second;
157 // Update the timestamp for stopping the codec.
158 clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
Girish1f002cf2023-02-17 00:36:29 +0000159 }
160 }
161 if (!stopCalled) {
162 // call Stop to update the metrics.
Girishc9637682023-03-23 23:33:32 +0000163 notifyClientStopped(clientConfig);
Girish1f002cf2023-02-17 00:36:29 +0000164 }
165 {
166 std::scoped_lock lock(mLock);
167 // Update the resource instance count also.
168 std::map<std::string, int>::iterator found =
169 mConcurrentResourceCountMap.find(clientInfo.name);
170 if (found != mConcurrentResourceCountMap.end()) {
171 if (found->second > 0) {
172 found->second--;
173 }
174 }
175 }
176}
177
178void ResourceManagerMetrics::notifyClientStarted(const ClientConfigParcel& clientConfig) {
179 std::scoped_lock lock(mLock);
180 int pid = clientConfig.clientInfo.pid;
181 // We need to observer this process.
182 mUidObserver->add(pid, clientConfig.clientInfo.uid);
183
184 // Update the client config for thic client.
185 mClientConfigMap[clientConfig.clientInfo.id] = clientConfig;
186
187 // Update the concurrent codec count for this process.
188 CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
189 clientConfig.isEncoder,
190 clientConfig.codecType);
191 increaseConcurrentCodecs(pid, codecBucket);
192
193 if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
194 clientConfig.codecType == MediaResourceSubType::kImageCodec) {
195 // Update the pixel count for this process
196 increasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
197 }
198
199 // System concurrent codec usage
200 int systemConcurrentCodecCount = mConcurrentCodecsMap[codecBucket];
201 // Process/Application concurrent codec usage for this type of codec
202 int appConcurrentCodecCount = mProcessConcurrentCodecsMap[pid].mCurrent[codecBucket];
203 // Process/Application's current pixel count.
204 long pixelCount = 0;
205 std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
206 if (it != mProcessPixelsMap.end()) {
207 pixelCount = it->second.mCurrent;
208 }
209
210 int result = stats_write(
211 MEDIA_CODEC_STARTED,
212 clientConfig.clientInfo.uid,
213 clientConfig.id,
214 clientConfig.clientInfo.name.c_str(),
215 static_cast<int32_t>(clientConfig.codecType),
216 clientConfig.isEncoder,
217 clientConfig.isHardware,
218 clientConfig.width, clientConfig.height,
219 systemConcurrentCodecCount,
220 appConcurrentCodecCount,
221 pixelCount);
222
223 ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: "
224 "Process[pid(%d): uid(%d)] "
225 "Codec: [%s: %ju] is %s %s %s "
226 "Timestamp: %jd "
227 "Resolution: %d x %d "
228 "ConcurrentCodec[%d]={System: %d App: %d} "
229 "result: %d",
230 __func__,
231 pid, clientConfig.clientInfo.uid,
232 clientConfig.clientInfo.name.c_str(),
233 clientConfig.id,
234 clientConfig.isHardware? "hardware" : "software",
235 getCodecType(clientConfig.codecType),
236 clientConfig.isEncoder? "encoder" : "decoder",
237 clientConfig.timeStamp,
238 clientConfig.width, clientConfig.height,
239 codecBucket, systemConcurrentCodecCount, appConcurrentCodecCount,
240 result);
241}
242
243void ResourceManagerMetrics::notifyClientStopped(const ClientConfigParcel& clientConfig) {
244 std::scoped_lock lock(mLock);
245 int pid = clientConfig.clientInfo.pid;
246 // Update the concurrent codec count for this process.
247 CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
248 clientConfig.isEncoder,
249 clientConfig.codecType);
250 decreaseConcurrentCodecs(pid, codecBucket);
251
252 if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
253 clientConfig.codecType == MediaResourceSubType::kImageCodec) {
254 // Update the pixel count for this process
255 decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
256 }
257
258 // System concurrent codec usage
259 int systemConcurrentCodecCount = mConcurrentCodecsMap[codecBucket];
260 // Process/Application concurrent codec usage for this type of codec
261 int appConcurrentCodecCount = 0;
262 std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
263 if (found != mProcessConcurrentCodecsMap.end()) {
264 appConcurrentCodecCount = found->second.mCurrent[codecBucket];
265 }
266 // Process/Application's current pixel count.
267 long pixelCount = 0;
268 std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
269 if (it != mProcessPixelsMap.end()) {
270 pixelCount = it->second.mCurrent;
271 }
272
273 // calculate the usageTime as:
274 // MediaCodecStopped.clientConfig.timeStamp -
275 // MediaCodecStarted.clientConfig.timeStamp
276 int64_t usageTime = 0;
277 ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
278 if (entry != mClientConfigMap.end()) {
279 usageTime = clientConfig.timeStamp - entry->second.timeStamp;
280 // And we can erase this config now.
281 mClientConfigMap.erase(entry);
282 } else {
283 ALOGW("%s: Start Config is missing!", __func__);
284 }
285
286 int result = stats_write(
287 MEDIA_CODEC_STOPPED,
288 clientConfig.clientInfo.uid,
289 clientConfig.id,
290 clientConfig.clientInfo.name.c_str(),
291 static_cast<int32_t>(clientConfig.codecType),
292 clientConfig.isEncoder,
293 clientConfig.isHardware,
294 clientConfig.width, clientConfig.height,
295 systemConcurrentCodecCount,
296 appConcurrentCodecCount,
297 pixelCount,
298 usageTime);
299 ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: "
300 "Process[pid(%d): uid(%d)] "
301 "Codec: [%s: %ju] is %s %s %s "
302 "Timestamp: %jd Usage time: %jd "
303 "Resolution: %d x %d "
304 "ConcurrentCodec[%d]={System: %d App: %d} "
305 "result: %d",
306 __func__,
307 pid, clientConfig.clientInfo.uid,
308 clientConfig.clientInfo.name.c_str(),
309 clientConfig.id,
310 clientConfig.isHardware? "hardware" : "software",
311 getCodecType(clientConfig.codecType),
312 clientConfig.isEncoder? "encoder" : "decoder",
313 clientConfig.timeStamp, usageTime,
314 clientConfig.width, clientConfig.height,
315 codecBucket, systemConcurrentCodecCount, appConcurrentCodecCount,
316 result);
317}
318
319void ResourceManagerMetrics::onProcessTerminated(int32_t pid, uid_t uid) {
320 std::scoped_lock lock(mLock);
321 // post MediaCodecConcurrentUsageReported for this terminated pid.
322 pushConcurrentUsageReport(pid, uid);
323}
324
325void ResourceManagerMetrics::pushConcurrentUsageReport(int32_t pid, uid_t uid) {
326 // Process/Application peak concurrent codec usage
327 std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
328 if (found == mProcessConcurrentCodecsMap.end()) {
329 ALOGI("%s: No MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom Entry for: "
330 "Application[pid(%d): uid(%d)]", __func__, pid, uid);
331 return;
332 }
333 const ConcurrentCodecsMap& codecsMap = found->second.mPeak;
334 int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder];
335 int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder];
336 int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder];
337 int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder];
338 int peakHwImageEncoderCount = codecsMap[HwImageEncoder];
339 int peakHwImageDecoderCount = codecsMap[HwImageDecoder];
340 int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder];
341 int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder];
342 int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder];
343 int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder];
344 int peakSwImageEncoderCount = codecsMap[SwImageEncoder];
345 int peakSwImageDecoderCount = codecsMap[SwImageDecoder];
346
347 long peakPixels = 0;
348 std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
349 if (it == mProcessPixelsMap.end()) {
350 ALOGI("%s: No Video Codec Entry for Application[pid(%d): uid(%d)]",
351 __func__, pid, uid);
352 } else {
353 peakPixels = it->second.mPeak;
354 }
355 std::string peakPixelsLog("Peak Pixels: " + std::to_string(peakPixels));
356
357 std::stringstream peakCodecLog;
358 peakCodecLog << "Peak { ";
359 std::stringstream logMsg;
360 if (getLogMessage(peakHwAudioEncoderCount, peakSwAudioEncoderCount, logMsg)) {
361 peakCodecLog << "AudioEnc[" << logMsg.str();
362 }
363 if (getLogMessage(peakHwAudioDecoderCount, peakSwAudioDecoderCount, logMsg)) {
364 peakCodecLog << "AudioDec[" << logMsg.str();
365 }
366 if (getLogMessage(peakHwVideoEncoderCount, peakSwVideoEncoderCount, logMsg)) {
367 peakCodecLog << "VideoEnc[" << logMsg.str();
368 }
369 if (getLogMessage(peakHwVideoDecoderCount, peakSwVideoDecoderCount, logMsg)) {
370 peakCodecLog << "VideoDec[" << logMsg.str();
371 }
372 if (getLogMessage(peakHwImageEncoderCount, peakSwImageEncoderCount, logMsg)) {
373 peakCodecLog << "ImageEnc[" << logMsg.str();
374 }
375 if (getLogMessage(peakHwImageDecoderCount, peakSwImageDecoderCount, logMsg)) {
376 peakCodecLog << "ImageDec[" << logMsg.str();
377 }
378 peakCodecLog << "}";
379
380#ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
381 int result = stats_write(
382 MEDIA_CODEC_CONCURRENT_USAGE_REPORTED,
383 uid,
384 peakHwVideoDecoderCount,
385 peakHwVideoEncoderCount,
386 peakSwVideoDecoderCount,
387 peakSwVideoEncoderCount,
388 peakHwAudioDecoderCount,
389 peakHwAudioEncoderCount,
390 peakSwAudioDecoderCount,
391 peakSwAudioEncoderCount,
392 peakHwImageDecoderCount,
393 peakHwImageEncoderCount,
394 peakSwImageDecoderCount,
395 peakSwImageEncoderCount,
396 peakPixels);
397 ALOGI("%s: Pushed MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom: "
398 "Process[pid(%d): uid(%d)] %s %s result: %d",
399 __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str(), result);
400#else
401 ALOGI("%s: Concurrent Codec Usage Report for the Process[pid(%d): uid(%d)] is %s %s",
402 __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str());
403#endif
404}
405
406void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
407 const std::vector<int>& priorities,
408 const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
409 const PidUidVector& idList, bool reclaimed) {
410 // Construct the metrics for codec reclaim as a pushed atom.
411 // 1. Information about the requester.
412 // - UID and the priority (oom score)
413 int32_t callingPid = clientInfo.pid;
414 int32_t requesterUid = clientInfo.uid;
415 std::string clientName = clientInfo.name;
416 int requesterPriority = priorities[0];
417
418 // 2. Information about the codec.
419 // - Name of the codec requested
420 // - Number of concurrent codecs running.
421 int32_t noOfConcurrentCodecs = 0;
422 std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientName);
423 if (found != mConcurrentResourceCountMap.end()) {
424 noOfConcurrentCodecs = found->second;
425 }
426
427 // 3. Information about the Reclaim:
428 // - Status of reclaim request
429 // - How many codecs are reclaimed
430 // - For each codecs reclaimed, information of the process that it belonged to:
431 // - UID and the Priority (oom score)
432 int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
433 if (!reclaimed) {
434 if (clients.size() == 0) {
435 // No clients to reclaim from
436 reclaimStatus =
437 MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
438 } else {
439 // Couldn't reclaim resources from the clients
440 reclaimStatus =
441 MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
442 }
443 }
444 int32_t noOfCodecsReclaimed = clients.size();
445 int32_t targetIndex = 1;
446 for (PidUidVector::const_reference id : idList) {
447 int32_t targetUid = id.second;
448 int targetPriority = priorities[targetIndex];
449 // Post the pushed atom
450 int result = stats_write(
451 MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
452 requesterUid,
453 requesterPriority,
454 clientName.c_str(),
455 noOfConcurrentCodecs,
456 reclaimStatus,
457 noOfCodecsReclaimed,
458 targetIndex,
459 targetUid,
460 targetPriority);
461 ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
462 "Requester[pid(%d): uid(%d): priority(%d)] "
463 "Codec: [%s] "
464 "No of concurrent codecs: %d "
465 "Reclaim Status: %d "
466 "No of codecs reclaimed: %d "
467 "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d",
468 __func__, callingPid, requesterUid, requesterPriority,
469 clientName.c_str(), noOfConcurrentCodecs,
470 reclaimStatus, noOfCodecsReclaimed,
471 targetIndex, id.first, targetUid, targetPriority, result);
472 targetIndex++;
473 }
474}
475
476void ResourceManagerMetrics::increaseConcurrentCodecs(int32_t pid,
477 CodecBucket codecBucket) {
478 // Increase the codec usage across the system.
479 mConcurrentCodecsMap[codecBucket]++;
480
481 // Now update the codec usage for this (pid) process.
482 std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
483 if (found == mProcessConcurrentCodecsMap.end()) {
484 ConcurrentCodecs codecs;
485 codecs.mCurrent[codecBucket] = 1;
486 codecs.mPeak[codecBucket] = 1;
487 mProcessConcurrentCodecsMap.emplace(pid, codecs);
488 } else {
489 found->second.mCurrent[codecBucket]++;
490 // Check if it's the peak count for this slot.
491 if (found->second.mPeak[codecBucket] < found->second.mCurrent[codecBucket]) {
492 found->second.mPeak[codecBucket] = found->second.mCurrent[codecBucket];
493 }
494 }
495}
496
497void ResourceManagerMetrics::decreaseConcurrentCodecs(int32_t pid,
498 CodecBucket codecBucket) {
499 // Decrease the codec usage across the system.
500 if (mConcurrentCodecsMap[codecBucket] > 0) {
501 mConcurrentCodecsMap[codecBucket]--;
502 }
503
504 // Now update the codec usage for this (pid) process.
505 std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
506 if (found != mProcessConcurrentCodecsMap.end()) {
507 if (found->second.mCurrent[codecBucket] > 0) {
508 found->second.mCurrent[codecBucket]--;
509 }
510 }
511}
512
513void ResourceManagerMetrics::increasePixelCount(int32_t pid, long pixels) {
514 // Now update the current pixel usage for this (pid) process.
515 std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
516 if (found == mProcessPixelsMap.end()) {
517 PixelCount pixelCount {pixels, pixels};
518 mProcessPixelsMap.emplace(pid, pixelCount);
519 } else {
520 if (__builtin_add_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
521 ALOGI("Pixel Count overflow");
522 return;
523 }
524 // Check if it's the peak count for this slot.
525 if (found->second.mPeak < found->second.mCurrent) {
526 found->second.mPeak = found->second.mCurrent;
527 }
528 }
529}
530
531void ResourceManagerMetrics::decreasePixelCount(int32_t pid, long pixels) {
532 // Now update the current pixel usage for this (pid) process.
533 std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
534 if (found != mProcessPixelsMap.end()) {
535 if (found->second.mCurrent < pixels) {
536 found->second.mCurrent = 0;
537 } else {
538 if (__builtin_sub_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
539 ALOGI("Pixel Count overflow");
540 return;
541 }
542 }
543 }
544}
545
546long ResourceManagerMetrics::getPeakConcurrentPixelCount(int pid) const {
547 std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
548 if (found != mProcessPixelsMap.end()) {
549 return found->second.mPeak;
550 }
551
552 return 0;
553}
554
555long ResourceManagerMetrics::getCurrentConcurrentPixelCount(int pid) const {
556 std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
557 if (found != mProcessPixelsMap.end()) {
558 return found->second.mCurrent;
559 }
560
561 return 0;
562}
563
564} // namespace android