1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <jni.h>
18 #include <asm/unistd.h>
19 #include <memory>
20 #include <android/log.h>
21 #include "Profiler.h"
22 #include <iostream>
23 #include <sys/syscall.h>
24
25 #pragma clang diagnostic push
26 #pragma ide diagnostic ignored "UnusedParameter"
27
28 const int32_t CountersLongCount = sizeof(utils::Profiler::Counters) / sizeof(uint64_t);
29
30 static_assert(
31 CountersLongCount == 19,
32 "Expected Counters to have consistent length, "
33 "may need to update Kotlin LongArray definition"
34 );
35
perf_event_open(perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)36 static int perf_event_open(perf_event_attr *hw_event, pid_t pid,
37 int cpu, int group_fd, unsigned long flags) {
38 return (int) syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
39 }
40
41 #pragma clang diagnostic pop
42 extern "C"
43 JNIEXPORT jstring JNICALL
Java_androidx_benchmark_CpuCounterJni_checkPerfEventSupport(JNIEnv * env,jobject thiz)44 Java_androidx_benchmark_CpuCounterJni_checkPerfEventSupport(
45 JNIEnv *env,
46 jobject thiz
47 ) {
48
49 // perf event group creation code copied from Profiler.cpp to allow us to
50 // return an error string on failure instead of killing process
51 perf_event_attr pe{};
52 pe.type = PERF_TYPE_HARDWARE;
53 pe.size = sizeof(perf_event_attr);
54 pe.config = PERF_COUNT_HW_INSTRUCTIONS;
55 pe.disabled = 1;
56 pe.exclude_kernel = 1;
57 pe.exclude_hv = 1;
58 pe.read_format = PERF_FORMAT_GROUP |
59 PERF_FORMAT_ID |
60 PERF_FORMAT_TOTAL_TIME_ENABLED |
61 PERF_FORMAT_TOTAL_TIME_RUNNING;
62 int fd = perf_event_open(&pe, 0, -1, -1, 0);
63 // TODO: implement checkPerfEventSupport()
64 if (fd == -1) {
65 char output[256];
66 sprintf(&output[0], "perf_event_open failed: [%d]%s", errno, strerror(errno));
67 return (jstring) env->NewStringUTF(&output[0]);
68 } else {
69 close(fd);
70 return (jstring) nullptr;
71 }
72 }
73
74 extern "C"
75 JNIEXPORT jlong JNICALL
Java_androidx_benchmark_CpuCounterJni_newProfiler(JNIEnv * env,jobject thiz)76 Java_androidx_benchmark_CpuCounterJni_newProfiler(
77 JNIEnv *env,
78 jobject thiz
79 ) {
80 auto *pProfiler = new utils::Profiler();
81 return (long) pProfiler;
82 }
83
84 extern "C"
85 JNIEXPORT void JNICALL
Java_androidx_benchmark_CpuCounterJni_freeProfiler(JNIEnv * env,jobject thiz,jlong profiler_ptr)86 Java_androidx_benchmark_CpuCounterJni_freeProfiler(
87 JNIEnv *env,
88 jobject thiz,
89 jlong profiler_ptr
90 ) {
91 auto *pProfiler = (utils::Profiler *) profiler_ptr;
92 delete pProfiler;
93 }
94 extern "C"
95 JNIEXPORT jint JNICALL
Java_androidx_benchmark_CpuCounterJni_resetEvents(JNIEnv * env,jobject thiz,jlong profiler_ptr,jint event_mask)96 Java_androidx_benchmark_CpuCounterJni_resetEvents(
97 JNIEnv *env,
98 jobject thiz,
99 jlong profiler_ptr,
100 jint event_mask
101 ) {
102 auto *pProfiler = (utils::Profiler *) profiler_ptr;
103 return (jint) pProfiler->resetEvents(event_mask);
104 }
105 extern "C"
106 JNIEXPORT void JNICALL
Java_androidx_benchmark_CpuCounterJni_reset(JNIEnv * env,jobject thiz,jlong profiler_ptr)107 Java_androidx_benchmark_CpuCounterJni_reset(
108 JNIEnv *env,
109 jobject thiz,
110 jlong profiler_ptr
111 ) {
112 auto *pProfiler = (utils::Profiler *) profiler_ptr;
113 pProfiler->reset();
114 }
115 extern "C"
116 JNIEXPORT void JNICALL
Java_androidx_benchmark_CpuCounterJni_start(JNIEnv * env,jobject thiz,jlong profiler_ptr)117 Java_androidx_benchmark_CpuCounterJni_start(
118 JNIEnv *env,
119 jobject thiz,
120 jlong profiler_ptr
121 ) {
122 auto *pProfiler = (utils::Profiler *) profiler_ptr;
123 pProfiler->start();
124 }
125 extern "C"
126 JNIEXPORT void JNICALL
Java_androidx_benchmark_CpuCounterJni_stop(JNIEnv * env,jobject thiz,jlong profiler_ptr)127 Java_androidx_benchmark_CpuCounterJni_stop(
128 JNIEnv *env,
129 jobject thiz,
130 jlong profiler_ptr
131 ) {
132 auto *pProfiler = (utils::Profiler *) profiler_ptr;
133 pProfiler->stop();
134 }
135 extern "C"
136 JNIEXPORT void JNICALL
Java_androidx_benchmark_CpuCounterJni_read(JNIEnv * env,jobject thiz,jlong profiler_ptr,jlongArray out_data)137 Java_androidx_benchmark_CpuCounterJni_read(
138 JNIEnv *env,
139 jobject thiz,
140 jlong profiler_ptr,
141 jlongArray out_data
142 ) {
143 auto *pProfiler = (utils::Profiler *) profiler_ptr;
144 utils::Profiler::Counters counters = pProfiler->readCounters();
145 jsize longCount = sizeof(utils::Profiler::Counters) / sizeof(uint64_t);
146 env->SetLongArrayRegion(out_data, 0, longCount, reinterpret_cast<jlong *>(&counters));
147 }