Index: base/android/java/src/org/chromium/base/metrics/RecordHistogram.java |
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java |
index 0ceddcd3ace2a255fce60b8687af2973fa9338ee..56a5803c5c50b64e658f6a68d03fa24891f47438 100644 |
--- a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java |
+++ b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java |
@@ -7,11 +7,18 @@ package org.chromium.base.metrics; |
import org.chromium.base.VisibleForTesting; |
import org.chromium.base.annotations.JNINamespace; |
+import java.util.Collections; |
+import java.util.HashMap; |
+import java.util.Map; |
import java.util.concurrent.TimeUnit; |
/** |
- * Java API for recording UMA histograms. Internally, the histogram will be cached by |
- * System.identityHashCode(name). |
+ * Java API for recording UMA histograms. |
+ * |
+ * Internally, histograms objects are cached on the Java side by their pointer |
+ * values (converted to long). This is safe to do because C++ Histogram objects |
+ * are never freed. Caching them on the Java side prevents needing to do costly |
+ * Java String to C++ string conversions on the C++ side during lookup. |
* |
* Note: the JNI calls are relatively costly - avoid calling these methods in performance-critical |
* code. |
@@ -19,6 +26,8 @@ import java.util.concurrent.TimeUnit; |
@JNINamespace("base::android") |
public class RecordHistogram { |
private static boolean sIsDisabledForTests = false; |
+ private static Map<String, Long> sCache = |
+ Collections.synchronizedMap(new HashMap<String, Long>()); |
/** |
* Tests may not have native initialized, so they may need to disable metrics. |
@@ -28,6 +37,15 @@ public class RecordHistogram { |
sIsDisabledForTests = true; |
} |
+ private static long getCachedHistogramKey(String name) { |
+ Long key = sCache.get(name); |
+ // Note: If key is null, we don't have it cached. In that case, pass 0 |
+ // to the native code, which gets converted to a null histogram pointer |
+ // which will cause the native code to look up the object on the native |
+ // side. |
+ return (key == null ? 0 : key); |
+ } |
+ |
/** |
* Records a sample in a boolean UMA histogram of the given name. Boolean histogram has two |
* buckets, corresponding to success (true) and failure (false). This is the Java equivalent of |
@@ -37,7 +55,9 @@ public class RecordHistogram { |
*/ |
public static void recordBooleanHistogram(String name, boolean sample) { |
if (sIsDisabledForTests) return; |
- nativeRecordBooleanHistogram(name, System.identityHashCode(name), sample); |
+ long key = getCachedHistogramKey(name); |
+ long result = nativeRecordBooleanHistogram(name, key, sample); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -51,7 +71,9 @@ public class RecordHistogram { |
*/ |
public static void recordEnumeratedHistogram(String name, int sample, int boundary) { |
if (sIsDisabledForTests) return; |
- nativeRecordEnumeratedHistogram(name, System.identityHashCode(name), sample, boundary); |
+ long key = getCachedHistogramKey(name); |
+ long result = nativeRecordEnumeratedHistogram(name, key, sample, boundary); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -96,8 +118,9 @@ public class RecordHistogram { |
public static void recordCustomCountHistogram( |
String name, int sample, int min, int max, int numBuckets) { |
if (sIsDisabledForTests) return; |
- nativeRecordCustomCountHistogram( |
- name, System.identityHashCode(name), sample, min, max, numBuckets); |
+ long key = getCachedHistogramKey(name); |
+ long result = nativeRecordCustomCountHistogram(name, key, sample, min, max, numBuckets); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -112,8 +135,9 @@ public class RecordHistogram { |
public static void recordLinearCountHistogram( |
String name, int sample, int min, int max, int numBuckets) { |
if (sIsDisabledForTests) return; |
- nativeRecordLinearCountHistogram( |
- name, System.identityHashCode(name), sample, min, max, numBuckets); |
+ long key = getCachedHistogramKey(name); |
+ long result = nativeRecordLinearCountHistogram(name, key, sample, min, max, numBuckets); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -124,7 +148,9 @@ public class RecordHistogram { |
*/ |
public static void recordPercentageHistogram(String name, int sample) { |
if (sIsDisabledForTests) return; |
- nativeRecordEnumeratedHistogram(name, System.identityHashCode(name), sample, 101); |
+ long key = getCachedHistogramKey(name); |
+ long result = nativeRecordEnumeratedHistogram(name, key, sample, 101); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -135,7 +161,9 @@ public class RecordHistogram { |
*/ |
public static void recordSparseSlowlyHistogram(String name, int sample) { |
if (sIsDisabledForTests) return; |
- nativeRecordSparseHistogram(name, System.identityHashCode(name), sample); |
+ long key = getCachedHistogramKey(name); |
+ long result = nativeRecordSparseHistogram(name, key, sample); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -201,12 +229,14 @@ public class RecordHistogram { |
private static void recordCustomTimesHistogramMilliseconds( |
String name, long duration, long min, long max, int numBuckets) { |
if (sIsDisabledForTests) return; |
+ long key = getCachedHistogramKey(name); |
// Note: Duration, min and max are clamped to int here because that's what's expected by |
// the native histograms API. Callers of these functions still pass longs because that's |
// the types returned by TimeUnit and System.currentTimeMillis() APIs, from which these |
// values come. |
- nativeRecordCustomTimesHistogramMilliseconds(name, System.identityHashCode(name), |
- clampToInt(duration), clampToInt(min), clampToInt(max), numBuckets); |
+ long result = nativeRecordCustomTimesHistogramMilliseconds( |
+ name, key, clampToInt(duration), clampToInt(min), clampToInt(max), numBuckets); |
+ if (result != key) sCache.put(name, result); |
} |
/** |
@@ -227,17 +257,17 @@ public class RecordHistogram { |
nativeInitialize(); |
} |
- private static native void nativeRecordCustomTimesHistogramMilliseconds( |
- String name, int key, int duration, int min, int max, int numBuckets); |
+ private static native long nativeRecordCustomTimesHistogramMilliseconds( |
+ String name, long key, int duration, int min, int max, int numBuckets); |
- private static native void nativeRecordBooleanHistogram(String name, int key, boolean sample); |
- private static native void nativeRecordEnumeratedHistogram( |
- String name, int key, int sample, int boundary); |
- private static native void nativeRecordCustomCountHistogram( |
- String name, int key, int sample, int min, int max, int numBuckets); |
- private static native void nativeRecordLinearCountHistogram( |
- String name, int key, int sample, int min, int max, int numBuckets); |
- private static native void nativeRecordSparseHistogram(String name, int key, int sample); |
+ private static native long nativeRecordBooleanHistogram(String name, long key, boolean sample); |
+ private static native long nativeRecordEnumeratedHistogram( |
+ String name, long key, int sample, int boundary); |
+ private static native long nativeRecordCustomCountHistogram( |
+ String name, long key, int sample, int min, int max, int numBuckets); |
+ private static native long nativeRecordLinearCountHistogram( |
+ String name, long key, int sample, int min, int max, int numBuckets); |
+ private static native long nativeRecordSparseHistogram(String name, long key, int sample); |
private static native int nativeGetHistogramValueCountForTesting(String name, int sample); |
private static native void nativeInitialize(); |