| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/android/jank_metric_uma_recorder.h" |
| |
| #include <cstdint> |
| |
| #include "base/android/jni_android.h" |
| #include "base/android/jni_array.h" |
| #include "base/android/jni_string.h" |
| #include "base/base_jni_headers/JankMetricUMARecorder_jni.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/strings/strcat.h" |
| #include "base/time/time.h" |
| #include "base/trace_event/base_tracing.h" |
| #include "base/tracing_buildflags.h" |
| |
| namespace base { |
| namespace android { |
| |
| namespace { |
| |
| void AddFrameToTrace(int64_t timestamp_ns, int64_t durations_ns) { |
| #if BUILDFLAG(ENABLE_BASE_TRACING) |
| if (timestamp_ns < 0) |
| return; |
| auto t = perfetto::Track(static_cast<uint64_t>(timestamp_ns)); |
| TRACE_EVENT_BEGIN( |
| "ui", "AndroidFrameVsync", t, [&](perfetto::EventContext ctx) { |
| ctx.event()->set_timestamp_absolute_us(timestamp_ns / 1000); |
| }); |
| TRACE_EVENT_END("ui", t, [&](perfetto::EventContext ctx) { |
| ctx.event()->set_timestamp_absolute_us((timestamp_ns + durations_ns) / |
| 1000); |
| }); |
| #endif // BUILDFLAG(ENABLE_BASE_TRACING) |
| } |
| |
| } // namespace |
| |
| // This function is called from Java with JNI, it's declared in |
| // base/base_jni_headers/JankMetricUMARecorder_jni.h which is an autogenerated |
| // header. The actual implementation is in RecordJankMetrics for simpler |
| // testing. |
| void JNI_JankMetricUMARecorder_RecordJankMetrics( |
| JNIEnv* env, |
| const base::android::JavaParamRef<jstring>& java_scenario_name, |
| const base::android::JavaParamRef<jlongArray>& java_timestamps_ns, |
| const base::android::JavaParamRef<jlongArray>& java_durations_ns, |
| const base::android::JavaParamRef<jlongArray>& java_jank_bursts_ns, |
| jint java_missed_frames) { |
| RecordJankMetrics(env, java_scenario_name, java_timestamps_ns, |
| java_durations_ns, java_jank_bursts_ns, java_missed_frames); |
| } |
| |
| void RecordJankMetrics( |
| JNIEnv* env, |
| const base::android::JavaParamRef<jstring>& java_scenario_name, |
| const base::android::JavaParamRef<jlongArray>& java_timestamps_ns, |
| const base::android::JavaParamRef<jlongArray>& java_durations_ns, |
| const base::android::JavaParamRef<jlongArray>& java_jank_bursts_ns, |
| jint java_missed_frames) { |
| std::string scenario_name = ConvertJavaStringToUTF8(env, java_scenario_name); |
| std::vector<int64_t> timestamps_ns; |
| std::vector<int64_t> durations_ns; |
| std::vector<int64_t> jank_bursts_ns; |
| |
| JavaLongArrayToInt64Vector(env, java_timestamps_ns, ×tamps_ns); |
| JavaLongArrayToInt64Vector(env, java_durations_ns, &durations_ns); |
| JavaLongArrayToInt64Vector(env, java_jank_bursts_ns, &jank_bursts_ns); |
| |
| std::string frame_duration_histogram_name = |
| base::StrCat({"Android.Jank.FrameDuration.", scenario_name}); |
| std::string jank_burst_histogram_name = |
| base::StrCat({"Android.Jank.JankBursts.", scenario_name}); |
| std::string missed_frames_histogram_name = |
| base::StrCat({"Android.Jank.MissedFrames.", scenario_name}); |
| |
| for (size_t i = 0; i < timestamps_ns.size(); ++i) { |
| AddFrameToTrace(timestamps_ns[i], durations_ns[i]); |
| } |
| |
| for (const int64_t frame_duration_ns : durations_ns) { |
| base::UmaHistogramTimes(frame_duration_histogram_name, |
| base::Nanoseconds(frame_duration_ns)); |
| } |
| |
| for (const int64_t jank_burst_duration_ns : jank_bursts_ns) { |
| base::UmaHistogramTimes(jank_burst_histogram_name, |
| base::Nanoseconds(jank_burst_duration_ns)); |
| } |
| |
| base::UmaHistogramCounts1000(missed_frames_histogram_name, |
| java_missed_frames); |
| } |
| |
| } // namespace android |
| } // namespace base |