1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/memory_pressure/memory_pressure_stats_collector.h"
7 #include "base/metrics/histogram.h"
8 #include "base/time/tick_clock.h"
10 namespace memory_pressure
{
14 using MemoryPressureLevel
= MemoryPressureListener::MemoryPressureLevel
;
16 // Converts a memory pressure level to an UMA enumeration value.
17 MemoryPressureLevelUMA
MemoryPressureLevelToUmaEnumValue(
18 MemoryPressureLevel level
) {
20 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
:
21 return UMA_MEMORY_PRESSURE_LEVEL_NONE
;
22 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
:
23 return UMA_MEMORY_PRESSURE_LEVEL_MODERATE
;
24 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL
:
25 return UMA_MEMORY_PRESSURE_LEVEL_CRITICAL
;
28 return UMA_MEMORY_PRESSURE_LEVEL_NONE
;
31 // Converts an UMA enumeration value to a memory pressure level.
32 MemoryPressureLevel
MemoryPressureLevelFromUmaEnumValue(
33 MemoryPressureLevelUMA level
) {
35 case UMA_MEMORY_PRESSURE_LEVEL_NONE
:
36 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
;
37 case UMA_MEMORY_PRESSURE_LEVEL_MODERATE
:
38 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
;
39 case UMA_MEMORY_PRESSURE_LEVEL_CRITICAL
:
40 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL
;
41 case UMA_MEMORY_PRESSURE_LEVEL_COUNT
:
46 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
;
49 // Converts a pressure state change to an UMA enumeration value.
50 MemoryPressureLevelChangeUMA
MemoryPressureLevelChangeToUmaEnumValue(
51 MemoryPressureLevel old_level
,
52 MemoryPressureLevel new_level
) {
54 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
: {
55 if (new_level
== MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
)
56 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_MODERATE
;
57 if (new_level
== MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL
)
58 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_CRITICAL
;
59 break; // Should never happen; handled by the NOTREACHED below.
61 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
: {
62 if (new_level
== MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
)
63 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_MODERATE_TO_NONE
;
64 if (new_level
== MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL
)
65 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_MODERATE_TO_CRITICAL
;
66 break; // Should never happen; handled by the NOTREACHED below.
68 case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL
: {
69 if (new_level
== MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
)
70 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_CRITICAL_TO_MODERATE
;
71 if (new_level
== MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
)
72 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_CRITICAL_TO_MODERATE
;
73 break; // Should never happen; handled by the NOTREACHED below.
77 return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_MODERATE
;
82 MemoryPressureStatsCollector::MemoryPressureStatsCollector(
83 base::TickClock
* tick_clock
)
84 : tick_clock_(tick_clock
),
85 last_pressure_level_(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE
) {
88 void MemoryPressureStatsCollector::UpdateStatistics(
89 MemoryPressureLevel current_pressure_level
) {
90 base::TimeTicks now
= tick_clock_
->NowTicks();
92 // Special case: first call to the collector. Observations have just started
93 // so there's nothing to report.
94 if (last_update_time_
.is_null()) {
95 last_pressure_level_
= current_pressure_level
;
96 last_update_time_
= now
;
100 // If the pressure level has transitioned then report this.
101 if (last_pressure_level_
!= current_pressure_level
)
102 ReportLevelChange(last_pressure_level_
, current_pressure_level
);
104 // Increment the appropriate cumulative bucket.
105 int index
= MemoryPressureLevelToUmaEnumValue(current_pressure_level
);
106 unreported_cumulative_time_
[index
] += now
- last_update_time_
;
108 // Update last pressure related state.
109 last_pressure_level_
= current_pressure_level
;
110 last_update_time_
= now
;
112 // Make reports about the amount of time spent cumulatively at each level.
113 for (size_t i
= 0; i
< arraysize(unreported_cumulative_time_
); ++i
) {
114 // Report the largest number of whole seconds possible at this moment and
115 // carry around the rest for a future report.
116 if (unreported_cumulative_time_
[i
].is_zero())
118 int64_t seconds
= unreported_cumulative_time_
[i
].InSeconds();
121 unreported_cumulative_time_
[i
] -= base::TimeDelta::FromSeconds(seconds
);
123 ReportCumulativeTime(MemoryPressureLevelFromUmaEnumValue(
124 static_cast<MemoryPressureLevelUMA
>(i
)),
125 static_cast<int>(seconds
));
130 void MemoryPressureStatsCollector::ReportCumulativeTime(
131 MemoryPressureLevel pressure_level
,
133 // Use the more primitive STATIC_HISTOGRAM_POINTER_BLOCK macro because the
134 // simple UMA_HISTOGRAM macros don't expose 'AddCount' functionality.
135 STATIC_HISTOGRAM_POINTER_BLOCK(
136 "Memory.PressureLevel",
137 AddCount(MemoryPressureLevelToUmaEnumValue(pressure_level
), seconds
),
138 base::LinearHistogram::FactoryGet(
139 "Memory.PressureLevel", 1, UMA_MEMORY_PRESSURE_LEVEL_COUNT
,
140 UMA_MEMORY_PRESSURE_LEVEL_COUNT
+ 1,
141 base::HistogramBase::kUmaTargetedHistogramFlag
));
145 void MemoryPressureStatsCollector::ReportLevelChange(
146 MemoryPressureLevel old_pressure_level
,
147 MemoryPressureLevel new_pressure_level
) {
148 UMA_HISTOGRAM_ENUMERATION("Memory.PressureLevelChange",
149 MemoryPressureLevelChangeToUmaEnumValue(
150 old_pressure_level
, new_pressure_level
),
151 UMA_MEMORY_PRESSURE_LEVEL_CHANGE_COUNT
);
154 } // namespace memory_pressure