1 /*
2  * Copyright (C) 2020 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 // API to report allocations to heapprofd. This allows users to see the
18 // callstacks causing these allocations in heap profiles.
19 //
20 // In the context of this API, a "heap" is memory associated with an allocator.
21 // An example of an allocator is the malloc-family of libc functions (malloc /
22 // calloc / posix_memalign).
23 //
24 // A very simple custom allocator would look like this:
25 //
26 // void* my_malloc(size_t size) {
27 //   void* ptr = [code to somehow allocate get size bytes];
28 //   return ptr;
29 // }
30 //
31 // void my_free(void* ptr) {
32 //   [code to somehow free ptr]
33 // }
34 //
35 // To find out where in a program these two functions get called, we instrument
36 // the allocator using this API:
37 //
38 // static uint32_t g_heap_id =
39 //   AHeapProfile_registerHeap(AHeapInfo_create("invalid.example"));
40 //
41 // void* my_malloc(size_t size) {
42 //   void* ptr = [code to somehow allocate get size bytes];
43 //   AHeapProfile_reportAllocation(g_heap_id, static_cast<uintptr_t>(ptr),
44 //                                 size);
45 //   return ptr;
46 // }
47 //
48 // void my_free(void* ptr) {
49 //   AHeapProfile_reportFree(g_heap_id, static_cast<uintptr_t>(ptr));
50 //   [code to somehow free ptr]
51 // }
52 //
53 // This will allow users to get a flamegraph of the callstacks calling into
54 // these functions.
55 //
56 // See https://perfetto.dev/docs/data-sources/native-heap-profiler for more
57 // information on heapprofd in general.
58 
59 #ifndef SRC_PROFILING_MEMORY_INCLUDE_PERFETTO_HEAP_PROFILE_H_
60 #define SRC_PROFILING_MEMORY_INCLUDE_PERFETTO_HEAP_PROFILE_H_
61 
62 #include <stdlib.h>
63 
64 #include <cinttypes>
65 
66 #pragma GCC diagnostic push
67 
68 #if defined(__clang__)
69 #pragma GCC diagnostic ignored "-Wnullability-extension"
70 #else
71 #define _Nullable
72 #define _Nonnull
73 #endif
74 
75 // Maximum size of heap name, including NUL-byte.
76 #define HEAPPROFD_HEAP_NAME_SZ 64
77 
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
81 
82 typedef struct AHeapInfo AHeapInfo;
83 typedef struct AHeapProfileEnableCallbackInfo AHeapProfileEnableCallbackInfo;
84 typedef struct AHeapProfileDisableCallbackInfo AHeapProfileDisableCallbackInfo;
85 
86 typedef void (*_Nonnull AHeapInfo_EnableCallback)(
87     void* _Nullable data,
88     const AHeapProfileEnableCallbackInfo* _Nonnull session_info);
89 
90 typedef void (*_Nonnull AHeapInfo_DisableCallback)(
91     void* _Nullable data,
92     const AHeapProfileDisableCallbackInfo* _Nonnull session_info);
93 
94 // Get sampling interval (in bytes) of the profiling session that was started.
95 uint64_t AHeapProfileEnableCallbackInfo_getSamplingInterval(
96     const AHeapProfileEnableCallbackInfo* _Nonnull session_info);
97 
98 // Create new AHeapInfo, a struct describing a heap.
99 //
100 // Takes name of the heap, up to 64 bytes including null terminator. To
101 // guarantee uniqueness, this should include the caller's domain name,
102 // e.g. "dev.perfetto.largeobjects".
103 //
104 // On error, returns NULL.
105 // Errors are:
106 //  * Empty or too long (larger than 64 bytes including null terminator)
107 //    heap_name.
108 //  * Too many heaps have been registered in this process already.
109 //
110 // Must eventually be passed to AHeapProfile_registerHeap.
111 AHeapInfo* _Nullable AHeapInfo_create(const char* _Nonnull heap_name);
112 
113 // Set enabled callback in AHeapInfo.
114 //
115 // If info is NULL, do nothing.
116 //
117 // After this AHeapInfo is registered via AHeapProfile_registerHeap,
118 // this callback is called when profiling of the heap is requested.
119 AHeapInfo* _Nullable AHeapInfo_setEnabledCallback(
120     AHeapInfo* _Nullable info,
121     AHeapInfo_EnableCallback callback,
122     void* _Nullable data);
123 
124 // Set disabled callback in AHeapInfo.
125 //
126 // If info is NULL, do nothing.
127 //
128 // After this AHeapInfo is registered via AHeapProfile_registerHeap,
129 // this callback is called when profiling of the heap ends.
130 AHeapInfo* _Nullable AHeapInfo_setDisabledCallback(
131     AHeapInfo* _Nullable info,
132     AHeapInfo_DisableCallback callback,
133     void* _Nullable data);
134 
135 // Register heap described in AHeapInfo.
136 //
137 // If info is NULL, return a no-op heap_id.
138 //
139 // The returned heap_id can be used in AHeapProfile_reportAllocation and
140 // AHeapProfile_reportFree.
141 //
142 // Takes ownership of |info|.
143 uint32_t AHeapProfile_registerHeap(AHeapInfo* _Nullable info);
144 
145 // Reports an allocation of |size| on the given |heap_id|.
146 //
147 // The |alloc_id| needs to be a unique identifier for the allocation, and can
148 // can be used in AHeapProfile_reportFree to report the allocation has been
149 // freed.
150 //
151 // If a profiling session is active, this function decides whether the reported
152 // allocation should be sampled. If the allocation is sampled, it will be
153 // associated to the current callstack in the profile.
154 //
155 // Returns whether the allocation was sampled.
156 bool AHeapProfile_reportAllocation(uint32_t heap_id,
157                                    uint64_t alloc_id,
158                                    uint64_t size);
159 
160 // Reports a sample of |size| on the given |heap_id|.
161 //
162 // If a profiling session is active, this function associates the sample with
163 // the current callstack in the profile.
164 //
165 // Returns whether the profiling session was active.
166 //
167 // THIS IS GENERALLY NOT WHAT YOU WANT. THIS IS ONLY NEEDED IF YOU NEED TO
168 // DO THE SAMPLING YOURSELF FOR PERFORMANCE REASONS.
169 // USE AHeapProfile_reportAllocation TO REPORT AN ALLOCATION AND LET
170 // HEAPPROFD DO THE SAMPLING.
171 //
172 // TODO(fmayer): Make this unavailable to non-Mainline.
173 bool AHeapProfile_reportSample(uint32_t heap_id,
174                                uint64_t alloc_id,
175                                uint64_t size);
176 
177 // Report allocation was freed on the given heap.
178 //
179 // If |alloc_id| was sampled in a previous call to
180 // AHeapProfile_reportAllocation, this allocation is marked as freed in the
181 // profile.
182 //
183 // It is allowed to call with an |alloc_id| that was either not sampled or never
184 // passed to AHeapProfile_reportAllocation, in which case the call will not
185 // change the output.
186 void AHeapProfile_reportFree(uint32_t heap_id, uint64_t alloc_id);
187 
188 #ifdef __cplusplus
189 }
190 #endif
191 
192 #pragma GCC diagnostic pop
193 
194 #endif  // SRC_PROFILING_MEMORY_INCLUDE_PERFETTO_HEAP_PROFILE_H_
195