• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 package dev.perfetto.sdk;
18 
19 import dalvik.annotation.optimization.CriticalNative;
20 import dalvik.annotation.optimization.FastNative;
21 
22 import java.util.concurrent.atomic.AtomicInteger;
23 
24 /**
25  * Writes trace events to the perfetto trace buffer. These trace events can be
26  * collected and visualized using the Perfetto UI.
27  *
28  * <p>This tracing mechanism is independent of the method tracing mechanism
29  * offered by {@link Debug#startMethodTracing} or {@link Trace}.
30  *
31  * @hide
32  */
33 public final class PerfettoTrace {
34     private static final String TAG = "PerfettoTrace";
35 
36     // Keep in sync with C++
37     private static final int PERFETTO_TE_TYPE_SLICE_BEGIN = 1;
38     private static final int PERFETTO_TE_TYPE_SLICE_END = 2;
39     private static final int PERFETTO_TE_TYPE_INSTANT = 3;
40     private static final int PERFETTO_TE_TYPE_COUNTER = 4;
41 
42     static class NativeAllocationRegistry {
createMalloced( ClassLoader classLoader, long freeFunction)43         public static NativeAllocationRegistry createMalloced(
44                 ClassLoader classLoader, long freeFunction) {
45             // do nothing
46             return new NativeAllocationRegistry();
47         }
registerNativeAllocation(Object obj, long ptr)48         public void registerNativeAllocation(Object obj, long ptr) {
49             // do nothing
50         }
51     }
52 
53     /**
54      * For fetching the next flow event id in a process.
55      */
56     private static final AtomicInteger sFlowEventId = new AtomicInteger();
57 
58     /**
59      * Perfetto category a trace event belongs to.
60      * Registering a category is not sufficient to capture events within the category, it must
61      * also be enabled in the trace config.
62      */
63     public static final class Category implements PerfettoTrackEventExtra.PerfettoPointer {
64         private static final NativeAllocationRegistry sRegistry =
65                 NativeAllocationRegistry.createMalloced(
66                         Category.class.getClassLoader(), native_delete());
67 
68         private final long mPtr;
69         private final long mExtraPtr;
70         private final String mName;
71         private final String mTag;
72         private final String mSeverity;
73         private boolean mIsRegistered;
74 
75         /**
76          * Category ctor.
77          *
78          * @param name The category name.
79          */
Category(String name)80         public Category(String name) {
81             this(name, "", "");
82         }
83 
84         /**
85          * Category ctor.
86          *
87          * @param name The category name.
88          * @param tag An atrace tag name that this category maps to.
89          */
Category(String name, String tag)90         public Category(String name, String tag) {
91             this(name, tag, "");
92         }
93 
94         /**
95          * Category ctor.
96          *
97          * @param name The category name.
98          * @param tag An atrace tag name that this category maps to.
99          * @param severity A Log style severity string for the category.
100          */
Category(String name, String tag, String severity)101         public Category(String name, String tag, String severity) {
102             mName = name;
103             mTag = tag;
104             mSeverity = severity;
105             mPtr = native_init(name, tag, severity);
106             mExtraPtr = native_get_extra_ptr(mPtr);
107         }
108 
109         @FastNative
native_init(String name, String tag, String severity)110         private static native long native_init(String name, String tag, String severity);
111         @CriticalNative
native_delete()112         private static native long native_delete();
113         @CriticalNative
native_register(long ptr)114         private static native void native_register(long ptr);
115         @CriticalNative
native_unregister(long ptr)116         private static native void native_unregister(long ptr);
117         @CriticalNative
native_is_enabled(long ptr)118         private static native boolean native_is_enabled(long ptr);
119         @CriticalNative
native_get_extra_ptr(long ptr)120         private static native long native_get_extra_ptr(long ptr);
121 
122         /**
123          * Register the category.
124          */
register()125         public Category register() {
126             native_register(mPtr);
127             mIsRegistered = true;
128             return this;
129         }
130 
131         /**
132          * Unregister the category.
133          */
unregister()134         public Category unregister() {
135             native_unregister(mPtr);
136             mIsRegistered = false;
137             return this;
138         }
139 
140         /**
141          * Whether the category is enabled or not.
142          */
isEnabled()143         public boolean isEnabled() {
144             return native_is_enabled(mPtr);
145         }
146 
147         /**
148          * Whether the category is registered or not.
149          */
isRegistered()150         public boolean isRegistered() {
151             return mIsRegistered;
152         }
153 
154         /**
155          * Returns the native pointer for the category.
156          */
157         @Override
getPtr()158         public long getPtr() {
159             return mExtraPtr;
160         }
161     }
162 
163     /**
164      * Manages a perfetto tracing session.
165      * Constructing this object with a config automatically starts a tracing session. Each session
166      * must be closed after use and then the resulting trace bytes can be read.
167      *
168      * The session could be in process or system wide, depending on {@code isBackendInProcess}.
169      * This functionality is intended for testing.
170      */
171     public static final class Session {
172         private final long mPtr;
173 
174         /**
175          * Session ctor.
176          */
Session(boolean isBackendInProcess, byte[] config)177         public Session(boolean isBackendInProcess, byte[] config) {
178             mPtr = native_start_session(isBackendInProcess, config);
179         }
180 
181         /**
182          * Closes the session and returns the trace.
183          */
close()184         public byte[] close() {
185             return native_stop_session(mPtr);
186         }
187     }
188 
189     @CriticalNative
native_get_process_track_uuid()190     private static native long native_get_process_track_uuid();
191     @CriticalNative
native_get_thread_track_uuid(long tid)192     private static native long native_get_thread_track_uuid(long tid);
193 
194     @FastNative
native_activate_trigger(String name, int ttlMs)195     private static native void native_activate_trigger(String name, int ttlMs);
196     @FastNative
native_register(boolean isBackendInProcess)197     private static native void native_register(boolean isBackendInProcess);
198 
native_start_session(boolean isBackendInProcess, byte[] config)199     private static native long native_start_session(boolean isBackendInProcess, byte[] config);
native_stop_session(long ptr)200     private static native byte[] native_stop_session(long ptr);
201 
202     /**
203      * Writes a trace message to indicate a given section of code was invoked.
204      *
205      * @param category The perfetto category.
206      * @param eventName The event name to appear in the trace.
207      */
instant(Category category, String eventName)208     public static PerfettoTrackEventExtra.Builder instant(Category category, String eventName) {
209         return PerfettoTrackEventExtra.builder(category.isEnabled())
210             .init(PERFETTO_TE_TYPE_INSTANT, category)
211             .setEventName(eventName);
212     }
213 
214     /**
215      * Writes a trace message to indicate the start of a given section of code.
216      *
217      * @param category The perfetto category.
218      * @param eventName The event name to appear in the trace.
219      */
begin(Category category, String eventName)220     public static PerfettoTrackEventExtra.Builder begin(Category category, String eventName) {
221         return PerfettoTrackEventExtra.builder(category.isEnabled())
222             .init(PERFETTO_TE_TYPE_SLICE_BEGIN, category)
223             .setEventName(eventName);
224     }
225 
226     /**
227      * Writes a trace message to indicate the end of a given section of code.
228      *
229      * @param category The perfetto category.
230      */
end(Category category)231     public static PerfettoTrackEventExtra.Builder end(Category category) {
232         return PerfettoTrackEventExtra.builder(category.isEnabled())
233             .init(PERFETTO_TE_TYPE_SLICE_END, category);
234     }
235 
236     /**
237      * Writes a trace message to indicate the value of a given section of code.
238      *
239      * @param category The perfetto category.
240      * @param value The value of the counter.
241      */
counter(Category category, long value)242     public static PerfettoTrackEventExtra.Builder counter(Category category, long value) {
243         return PerfettoTrackEventExtra.builder(category.isEnabled())
244             .init(PERFETTO_TE_TYPE_COUNTER, category)
245             .setCounter(value);
246     }
247 
248     /**
249      * Writes a trace message to indicate the value of a given section of code.
250      *
251      * @param category The perfetto category.
252      * @param value The value of the counter.
253      * @param trackName The trackName for the event.
254      */
counter( Category category, long value, String trackName)255     public static PerfettoTrackEventExtra.Builder counter(
256             Category category, long value, String trackName) {
257         return counter(category, value).usingProcessCounterTrack(trackName);
258     }
259 
260     /**
261      * Writes a trace message to indicate the value of a given section of code.
262      *
263      * @param category The perfetto category.
264      * @param value The value of the counter.
265      */
counter(Category category, double value)266     public static PerfettoTrackEventExtra.Builder counter(Category category, double value) {
267         return PerfettoTrackEventExtra.builder(category.isEnabled())
268             .init(PERFETTO_TE_TYPE_COUNTER, category)
269             .setCounter(value);
270     }
271 
272     /**
273      * Writes a trace message to indicate the value of a given section of code.
274      *
275      * @param category The perfetto category.
276      * @param value The value of the counter.
277      * @param trackName The trackName for the event.
278      */
counter( Category category, double value, String trackName)279     public static PerfettoTrackEventExtra.Builder counter(
280             Category category, double value, String trackName) {
281         return counter(category, value).usingProcessCounterTrack(trackName);
282     }
283 
284     /**
285      * Returns the next flow id to be used.
286      */
getFlowId()287     public static int getFlowId() {
288         return sFlowEventId.incrementAndGet();
289     }
290 
291     /**
292      * Returns the global track uuid that can be used as a parent track uuid.
293      */
getGlobalTrackUuid()294     public static long getGlobalTrackUuid() {
295         return 0;
296     }
297 
298     /**
299      * Returns the process track uuid that can be used as a parent track uuid.
300      */
getProcessTrackUuid()301     public static long getProcessTrackUuid() {
302         return native_get_process_track_uuid();
303     }
304 
305     /**
306      * Given a thread tid, returns the thread track uuid that can be used as a parent track uuid.
307      */
getThreadTrackUuid(long tid)308     public static long getThreadTrackUuid(long tid) {
309         return native_get_thread_track_uuid(tid);
310     }
311 
312     /**
313      * Activates a trigger by name {@code triggerName} with expiry in {@code ttlMs}.
314      */
activateTrigger(String triggerName, int ttlMs)315     public static void activateTrigger(String triggerName, int ttlMs) {
316         native_activate_trigger(triggerName, ttlMs);
317     }
318 
319     /**
320      * Registers the process with Perfetto.
321      */
register(boolean isBackendInProcess)322     public static void register(boolean isBackendInProcess) {
323         native_register(isBackendInProcess);
324     }
325 }
326