blob: 826bb9b1f71818b72e7811779d5c6bee6bbdacf6 [file] [log] [blame]
// 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, &timestamps_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