blob: 3e4e1201a58d7089e9ca1ce34f23af0b5aef6ce0 [file] [log] [blame]
ppidde405ee62015-01-22 01:12:511// Copyright 2014 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.
4
avib30f2402015-12-24 03:43:285#include <stdint.h>
6
jdduke825e3242015-01-27 00:13:547#include <map>
asvitkine0f5bc5e2016-04-05 22:43:308#include <string>
jdduke825e3242015-01-27 00:13:549
ppidde405ee62015-01-22 01:12:5110#include "base/android/jni_android.h"
11#include "base/android/jni_string.h"
jdduke825e3242015-01-27 00:13:5412#include "base/lazy_instance.h"
avib30f2402015-12-24 03:43:2813#include "base/macros.h"
ppidde405ee62015-01-22 01:12:5114#include "base/metrics/histogram.h"
pkotwicz5aab4432015-04-03 08:01:0215#include "base/metrics/sparse_histogram.h"
ppidde405ee62015-01-22 01:12:5116#include "base/metrics/statistics_recorder.h"
asvitkinebb7cf5992016-02-12 00:21:0317#include "base/strings/stringprintf.h"
jdduke825e3242015-01-27 00:13:5418#include "base/synchronization/lock.h"
cjhopmandcb2b412015-02-12 01:43:3219#include "base/time/time.h"
ppidde405ee62015-01-22 01:12:5120#include "jni/RecordHistogram_jni.h"
21
22namespace base {
23namespace android {
jdduke825e3242015-01-27 00:13:5424namespace {
25
26// Simple thread-safe wrapper for caching histograms. This avoids
27// relatively expensive JNI string translation for each recording.
28class HistogramCache {
29 public:
30 HistogramCache() {}
31
asvitkinebb7cf5992016-02-12 00:21:0332 std::string HistogramConstructionParamsToString(HistogramBase* histogram) {
33 std::string params_str = histogram->histogram_name();
34 switch (histogram->GetHistogramType()) {
35 case HISTOGRAM:
36 case LINEAR_HISTOGRAM:
37 case BOOLEAN_HISTOGRAM:
38 case CUSTOM_HISTOGRAM: {
39 Histogram* hist = static_cast<Histogram*>(histogram);
40 params_str += StringPrintf("/%d/%d/%d", hist->declared_min(),
41 hist->declared_max(), hist->bucket_count());
42 break;
43 }
44 case SPARSE_HISTOGRAM:
Gayane Petrosyan5745ac62018-03-23 01:45:2445 case DUMMY_HISTOGRAM:
asvitkinebb7cf5992016-02-12 00:21:0346 break;
47 }
48 return params_str;
49 }
50
Daniel Bratell7aacf952017-11-21 17:51:2551 void JNI_RecordHistogram_CheckHistogramArgs(JNIEnv* env,
52 jstring j_histogram_name,
53 int32_t expected_min,
54 int32_t expected_max,
55 uint32_t expected_bucket_count,
56 HistogramBase* histogram) {
romax0e110862017-02-07 19:54:0057 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
58 bool valid_arguments = Histogram::InspectConstructionArguments(
59 histogram_name, &expected_min, &expected_max, &expected_bucket_count);
60 DCHECK(valid_arguments);
asvitkinebb7cf5992016-02-12 00:21:0361 DCHECK(histogram->HasConstructionArguments(expected_min, expected_max,
62 expected_bucket_count))
romax0e110862017-02-07 19:54:0063 << histogram_name << "/" << expected_min << "/" << expected_max << "/"
64 << expected_bucket_count << " vs. "
asvitkinebb7cf5992016-02-12 00:21:0365 << HistogramConstructionParamsToString(histogram);
66 }
67
Daniel Bratell7aacf952017-11-21 17:51:2568 HistogramBase* JNI_RecordHistogram_BooleanHistogram(JNIEnv* env,
69 jstring j_histogram_name,
70 jlong j_histogram_key) {
jdduke825e3242015-01-27 00:13:5471 DCHECK(j_histogram_name);
asvitkine0f5bc5e2016-04-05 22:43:3072 HistogramBase* histogram = HistogramFromKey(j_histogram_key);
jdduke825e3242015-01-27 00:13:5473 if (histogram)
74 return histogram;
75
76 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
77 histogram = BooleanHistogram::FactoryGet(
78 histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
asvitkine0f5bc5e2016-04-05 22:43:3079 return histogram;
jdduke825e3242015-01-27 00:13:5480 }
81
Daniel Bratell7aacf952017-11-21 17:51:2582 HistogramBase* JNI_RecordHistogram_EnumeratedHistogram(
83 JNIEnv* env,
84 jstring j_histogram_name,
85 jlong j_histogram_key,
86 jint j_boundary) {
jdduke825e3242015-01-27 00:13:5487 DCHECK(j_histogram_name);
asvitkine0f5bc5e2016-04-05 22:43:3088 HistogramBase* histogram = HistogramFromKey(j_histogram_key);
asvitkinebb7cf5992016-02-12 00:21:0389 int32_t boundary = static_cast<int32_t>(j_boundary);
cjhopmandcb2b412015-02-12 01:43:3290 if (histogram) {
Daniel Bratell7aacf952017-11-21 17:51:2591 JNI_RecordHistogram_CheckHistogramArgs(env, j_histogram_name, 1, boundary,
92 boundary + 1, histogram);
jdduke825e3242015-01-27 00:13:5493 return histogram;
cjhopmandcb2b412015-02-12 01:43:3294 }
jdduke825e3242015-01-27 00:13:5495
96 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
jdduke825e3242015-01-27 00:13:5497 histogram =
98 LinearHistogram::FactoryGet(histogram_name, 1, boundary, boundary + 1,
99 HistogramBase::kUmaTargetedHistogramFlag);
asvitkine0f5bc5e2016-04-05 22:43:30100 return histogram;
jdduke825e3242015-01-27 00:13:54101 }
102
Daniel Bratell7aacf952017-11-21 17:51:25103 HistogramBase* JNI_RecordHistogram_CustomCountHistogram(
104 JNIEnv* env,
105 jstring j_histogram_name,
106 jlong j_histogram_key,
107 jint j_min,
108 jint j_max,
109 jint j_num_buckets) {
hartmanng39be88c72015-03-12 22:13:50110 DCHECK(j_histogram_name);
asvitkinebb7cf5992016-02-12 00:21:03111 int32_t min = static_cast<int32_t>(j_min);
112 int32_t max = static_cast<int32_t>(j_max);
113 int32_t num_buckets = static_cast<int32_t>(j_num_buckets);
asvitkine0f5bc5e2016-04-05 22:43:30114 HistogramBase* histogram = HistogramFromKey(j_histogram_key);
hartmanng39be88c72015-03-12 22:13:50115 if (histogram) {
Daniel Bratell7aacf952017-11-21 17:51:25116 JNI_RecordHistogram_CheckHistogramArgs(env, j_histogram_name, min, max,
117 num_buckets, histogram);
hartmanng39be88c72015-03-12 22:13:50118 return histogram;
119 }
120
sebsgd96ddb12016-10-28 21:10:56121 DCHECK_GE(min, 1) << "The min expected sample must be >= 1";
122
hartmanng39be88c72015-03-12 22:13:50123 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
pkotwicz5aab4432015-04-03 08:01:02124 histogram =
125 Histogram::FactoryGet(histogram_name, min, max, num_buckets,
126 HistogramBase::kUmaTargetedHistogramFlag);
asvitkine0f5bc5e2016-04-05 22:43:30127 return histogram;
pkotwicz5aab4432015-04-03 08:01:02128 }
129
Daniel Bratell7aacf952017-11-21 17:51:25130 HistogramBase* JNI_RecordHistogram_LinearCountHistogram(
131 JNIEnv* env,
132 jstring j_histogram_name,
133 jlong j_histogram_key,
134 jint j_min,
135 jint j_max,
136 jint j_num_buckets) {
khushalsagar0e93d6cb2015-08-31 17:33:42137 DCHECK(j_histogram_name);
asvitkinebb7cf5992016-02-12 00:21:03138 int32_t min = static_cast<int32_t>(j_min);
139 int32_t max = static_cast<int32_t>(j_max);
140 int32_t num_buckets = static_cast<int32_t>(j_num_buckets);
asvitkine0f5bc5e2016-04-05 22:43:30141 HistogramBase* histogram = HistogramFromKey(j_histogram_key);
khushalsagar0e93d6cb2015-08-31 17:33:42142 if (histogram) {
Daniel Bratell7aacf952017-11-21 17:51:25143 JNI_RecordHistogram_CheckHistogramArgs(env, j_histogram_name, min, max,
144 num_buckets, histogram);
khushalsagar0e93d6cb2015-08-31 17:33:42145 return histogram;
146 }
147
148 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
149 histogram =
150 LinearHistogram::FactoryGet(histogram_name, min, max, num_buckets,
151 HistogramBase::kUmaTargetedHistogramFlag);
asvitkine0f5bc5e2016-04-05 22:43:30152 return histogram;
khushalsagar0e93d6cb2015-08-31 17:33:42153 }
154
Daniel Bratell7aacf952017-11-21 17:51:25155 HistogramBase* JNI_RecordHistogram_SparseHistogram(JNIEnv* env,
156 jstring j_histogram_name,
157 jlong j_histogram_key) {
pkotwicz5aab4432015-04-03 08:01:02158 DCHECK(j_histogram_name);
asvitkine0f5bc5e2016-04-05 22:43:30159 HistogramBase* histogram = HistogramFromKey(j_histogram_key);
pkotwicz5aab4432015-04-03 08:01:02160 if (histogram)
161 return histogram;
162
163 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
164 histogram = SparseHistogram::FactoryGet(
165 histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
asvitkine0f5bc5e2016-04-05 22:43:30166 return histogram;
hartmanng39be88c72015-03-12 22:13:50167 }
168
Daniel Bratell7aacf952017-11-21 17:51:25169 HistogramBase* JNI_RecordHistogram_CustomTimesHistogram(
170 JNIEnv* env,
171 jstring j_histogram_name,
172 jlong j_histogram_key,
173 jint j_min,
174 jint j_max,
175 jint j_bucket_count) {
cjhopmandcb2b412015-02-12 01:43:32176 DCHECK(j_histogram_name);
asvitkine0f5bc5e2016-04-05 22:43:30177 HistogramBase* histogram = HistogramFromKey(j_histogram_key);
asvitkinebb7cf5992016-02-12 00:21:03178 int32_t min = static_cast<int32_t>(j_min);
179 int32_t max = static_cast<int32_t>(j_max);
180 int32_t bucket_count = static_cast<int32_t>(j_bucket_count);
cjhopmandcb2b412015-02-12 01:43:32181 if (histogram) {
Daniel Bratell7aacf952017-11-21 17:51:25182 JNI_RecordHistogram_CheckHistogramArgs(env, j_histogram_name, min, max,
183 bucket_count, histogram);
cjhopmandcb2b412015-02-12 01:43:32184 return histogram;
185 }
186
187 std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
188 // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
189 // is just a convenience for constructing the underlying Histogram with
190 // TimeDelta arguments.
191 histogram = Histogram::FactoryGet(histogram_name, min, max, bucket_count,
192 HistogramBase::kUmaTargetedHistogramFlag);
jdduke825e3242015-01-27 00:13:54193 return histogram;
194 }
195
asvitkine0f5bc5e2016-04-05 22:43:30196 private:
197 // Convert a jlong |histogram_key| from Java to a HistogramBase* via a cast.
198 // The Java side caches these in a map (see RecordHistogram.java), which is
199 // safe to do since C++ Histogram objects are never freed.
200 static HistogramBase* HistogramFromKey(jlong j_histogram_key) {
201 return reinterpret_cast<HistogramBase*>(j_histogram_key);
202 }
jdduke825e3242015-01-27 00:13:54203
204 DISALLOW_COPY_AND_ASSIGN(HistogramCache);
205};
206
asvitkinebb7cf5992016-02-12 00:21:03207LazyInstance<HistogramCache>::Leaky g_histograms;
jdduke825e3242015-01-27 00:13:54208
209} // namespace
ppidde405ee62015-01-22 01:12:51210
Daniel Bratell7aacf952017-11-21 17:51:25211jlong JNI_RecordHistogram_RecordBooleanHistogram(
212 JNIEnv* env,
Daniel Bratell7aacf952017-11-21 17:51:25213 const JavaParamRef<jstring>& j_histogram_name,
214 jlong j_histogram_key,
215 jboolean j_sample) {
asvitkine0f5bc5e2016-04-05 22:43:30216 bool sample = static_cast<bool>(j_sample);
Daniel Bratell7aacf952017-11-21 17:51:25217 HistogramBase* histogram =
218 g_histograms.Get().JNI_RecordHistogram_BooleanHistogram(
219 env, j_histogram_name, j_histogram_key);
asvitkine0f5bc5e2016-04-05 22:43:30220 histogram->AddBoolean(sample);
221 return reinterpret_cast<jlong>(histogram);
222}
223
Daniel Bratell7aacf952017-11-21 17:51:25224jlong JNI_RecordHistogram_RecordEnumeratedHistogram(
225 JNIEnv* env,
Daniel Bratell7aacf952017-11-21 17:51:25226 const JavaParamRef<jstring>& j_histogram_name,
227 jlong j_histogram_key,
228 jint j_sample,
229 jint j_boundary) {
asvitkine0f5bc5e2016-04-05 22:43:30230 int sample = static_cast<int>(j_sample);
231
Daniel Bratell7aacf952017-11-21 17:51:25232 HistogramBase* histogram =
233 g_histograms.Get().JNI_RecordHistogram_EnumeratedHistogram(
234 env, j_histogram_name, j_histogram_key, j_boundary);
asvitkine0f5bc5e2016-04-05 22:43:30235 histogram->Add(sample);
236 return reinterpret_cast<jlong>(histogram);
237}
238
Daniel Bratell7aacf952017-11-21 17:51:25239jlong JNI_RecordHistogram_RecordCustomCountHistogram(
240 JNIEnv* env,
Daniel Bratell7aacf952017-11-21 17:51:25241 const JavaParamRef<jstring>& j_histogram_name,
242 jlong j_histogram_key,
243 jint j_sample,
244 jint j_min,
245 jint j_max,
246 jint j_num_buckets) {
asvitkine0f5bc5e2016-04-05 22:43:30247 int sample = static_cast<int>(j_sample);
248
Daniel Bratell7aacf952017-11-21 17:51:25249 HistogramBase* histogram =
250 g_histograms.Get().JNI_RecordHistogram_CustomCountHistogram(
251 env, j_histogram_name, j_histogram_key, j_min, j_max, j_num_buckets);
asvitkine0f5bc5e2016-04-05 22:43:30252 histogram->Add(sample);
253 return reinterpret_cast<jlong>(histogram);
254}
255
Daniel Bratell7aacf952017-11-21 17:51:25256jlong JNI_RecordHistogram_RecordLinearCountHistogram(
257 JNIEnv* env,
Daniel Bratell7aacf952017-11-21 17:51:25258 const JavaParamRef<jstring>& j_histogram_name,
259 jlong j_histogram_key,
260 jint j_sample,
261 jint j_min,
262 jint j_max,
263 jint j_num_buckets) {
asvitkine0f5bc5e2016-04-05 22:43:30264 int sample = static_cast<int>(j_sample);
265
Daniel Bratell7aacf952017-11-21 17:51:25266 HistogramBase* histogram =
267 g_histograms.Get().JNI_RecordHistogram_LinearCountHistogram(
268 env, j_histogram_name, j_histogram_key, j_min, j_max, j_num_buckets);
asvitkine0f5bc5e2016-04-05 22:43:30269 histogram->Add(sample);
270 return reinterpret_cast<jlong>(histogram);
271}
272
Daniel Bratell7aacf952017-11-21 17:51:25273jlong JNI_RecordHistogram_RecordSparseHistogram(
274 JNIEnv* env,
Daniel Bratell7aacf952017-11-21 17:51:25275 const JavaParamRef<jstring>& j_histogram_name,
276 jlong j_histogram_key,
277 jint j_sample) {
ppidde405ee62015-01-22 01:12:51278 int sample = static_cast<int>(j_sample);
Daniel Bratell7aacf952017-11-21 17:51:25279 HistogramBase* histogram =
280 g_histograms.Get().JNI_RecordHistogram_SparseHistogram(
281 env, j_histogram_name, j_histogram_key);
asvitkine0f5bc5e2016-04-05 22:43:30282 histogram->Add(sample);
283 return reinterpret_cast<jlong>(histogram);
ppidde405ee62015-01-22 01:12:51284}
285
Daniel Bratell7aacf952017-11-21 17:51:25286jlong JNI_RecordHistogram_RecordCustomTimesHistogramMilliseconds(
torne89cc5d92015-09-04 11:16:35287 JNIEnv* env,
torne89cc5d92015-09-04 11:16:35288 const JavaParamRef<jstring>& j_histogram_name,
asvitkine0f5bc5e2016-04-05 22:43:30289 jlong j_histogram_key,
asvitkinebb7cf5992016-02-12 00:21:03290 jint j_duration,
291 jint j_min,
292 jint j_max,
torne89cc5d92015-09-04 11:16:35293 jint j_num_buckets) {
Daniel Bratell7aacf952017-11-21 17:51:25294 HistogramBase* histogram =
295 g_histograms.Get().JNI_RecordHistogram_CustomTimesHistogram(
296 env, j_histogram_name, j_histogram_key, j_min, j_max, j_num_buckets);
asvitkine0f5bc5e2016-04-05 22:43:30297 histogram->AddTime(
298 TimeDelta::FromMilliseconds(static_cast<int64_t>(j_duration)));
299 return reinterpret_cast<jlong>(histogram);
cjhopmandcb2b412015-02-12 01:43:32300}
301
ppidde405ee62015-01-22 01:12:51302// This backs a Java test util for testing histograms -
303// MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
304// currently can't have test-specific native code packaged in test-specific Java
305// targets - see http://crbug.com/415945.
Daniel Bratell7aacf952017-11-21 17:51:25306jint JNI_RecordHistogram_GetHistogramValueCountForTesting(
torne89cc5d92015-09-04 11:16:35307 JNIEnv* env,
torne89cc5d92015-09-04 11:16:35308 const JavaParamRef<jstring>& histogram_name,
309 jint sample) {
ppidde405ee62015-01-22 01:12:51310 HistogramBase* histogram = StatisticsRecorder::FindHistogram(
311 android::ConvertJavaStringToUTF8(env, histogram_name));
312 if (histogram == nullptr) {
313 // No samples have been recorded for this histogram (yet?).
314 return 0;
315 }
316
dcheng093de9b2016-04-04 21:25:51317 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
ppidde405ee62015-01-22 01:12:51318 return samples->GetCount(static_cast<int>(sample));
319}
320
Daniel Bratell7aacf952017-11-21 17:51:25321jint JNI_RecordHistogram_GetHistogramTotalCountForTesting(
pkotwicz5c9311ed2017-06-29 21:08:55322 JNIEnv* env,
pkotwicz5c9311ed2017-06-29 21:08:55323 const JavaParamRef<jstring>& histogram_name) {
324 HistogramBase* histogram = StatisticsRecorder::FindHistogram(
325 android::ConvertJavaStringToUTF8(env, histogram_name));
326 if (histogram == nullptr) {
327 // No samples have been recorded for this histogram.
328 return 0;
329 }
330
331 return histogram->SnapshotSamples()->TotalCount();
332}
333
ppidde405ee62015-01-22 01:12:51334} // namespace android
335} // namespace base