| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // API to report allocations to heapprofd. This allows users to see the |
| // callstacks causing these allocations in heap profiles. |
| // |
| // In the context of this API, a "heap" is memory associated with an allocator. |
| // An example of an allocator is the malloc-family of libc functions (malloc / |
| // calloc / posix_memalign). |
| // |
| // A very simple custom allocator would look like this: |
| // |
| // void* my_malloc(size_t size) { |
| // void* ptr = [code to somehow allocate get size bytes]; |
| // return ptr; |
| // } |
| // |
| // void my_free(void* ptr) { |
| // [code to somehow free ptr] |
| // } |
| // |
| // To find out where in a program these two functions get called, we instrument |
| // the allocator using this API: |
| // |
| // static uint32_t g_heap_id = |
| // AHeapProfile_registerHeap(AHeapInfo_create("invalid.example")); |
| // |
| // void* my_malloc(size_t size) { |
| // void* ptr = [code to somehow allocate get size bytes]; |
| // AHeapProfile_reportAllocation(g_heap_id, static_cast<uintptr_t>(ptr), |
| // size); |
| // return ptr; |
| // } |
| // |
| // void my_free(void* ptr) { |
| // AHeapProfile_reportFree(g_heap_id, static_cast<uintptr_t>(ptr)); |
| // [code to somehow free ptr] |
| // } |
| // |
| // This will allow users to get a flamegraph of the callstacks calling into |
| // these functions. |
| // |
| // See https://perfetto.dev/docs/data-sources/native-heap-profiler for more |
| // information on heapprofd in general. |
| |
| #ifndef SRC_PROFILING_MEMORY_INCLUDE_PERFETTO_HEAP_PROFILE_H_ |
| #define SRC_PROFILING_MEMORY_INCLUDE_PERFETTO_HEAP_PROFILE_H_ |
| |
| #include <inttypes.h> |
| #include <stdlib.h> |
| |
| #pragma GCC diagnostic push |
| |
| #if defined(__clang__) |
| #pragma GCC diagnostic ignored "-Wnullability-extension" |
| #else |
| #define _Nullable |
| #define _Nonnull |
| #endif |
| |
| // Maximum size of heap name, including NUL-byte. |
| #define HEAPPROFD_HEAP_NAME_SZ 64 |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| typedef struct AHeapInfo AHeapInfo; |
| typedef struct AHeapProfileEnableCallbackInfo AHeapProfileEnableCallbackInfo; |
| typedef struct AHeapProfileDisableCallbackInfo AHeapProfileDisableCallbackInfo; |
| |
| // Get sampling interval (in bytes) of the profiling session that was started. |
| uint64_t AHeapProfileEnableCallbackInfo_getSamplingInterval( |
| const AHeapProfileEnableCallbackInfo* _Nonnull session_info); |
| |
| // Create new AHeapInfo, a struct describing a heap. |
| // |
| // Takes name of the heap, up to 64 bytes including null terminator. To |
| // guarantee uniqueness, this should include the caller's domain name, |
| // e.g. "dev.perfetto.largeobjects". |
| // |
| // On error, returns NULL. |
| // Errors are: |
| // * Empty or too long (larger than 64 bytes including null terminator) |
| // heap_name. |
| // * Too many heaps have been registered in this process already. |
| // |
| // Must eventually be passed to AHeapProfile_registerHeap. |
| AHeapInfo* _Nullable AHeapInfo_create(const char* _Nonnull heap_name); |
| |
| // Set enabled callback in AHeapInfo. |
| // |
| // If info is NULL, do nothing. |
| // |
| // After this AHeapInfo is registered via AHeapProfile_registerHeap, |
| // this callback is called when profiling of the heap is requested. |
| AHeapInfo* _Nullable AHeapInfo_setEnabledCallback( |
| AHeapInfo* _Nullable info, |
| void (*_Nonnull callback)( |
| void* _Nullable, |
| const AHeapProfileEnableCallbackInfo* _Nonnull session_info), |
| void* _Nullable data); |
| |
| // Set disabled callback in AHeapInfo. |
| // |
| // If info is NULL, do nothing. |
| // |
| // After this AHeapInfo is registered via AHeapProfile_registerHeap, |
| // this callback is called when profiling of the heap ends. |
| AHeapInfo* _Nullable AHeapInfo_setDisabledCallback( |
| AHeapInfo* _Nullable info, |
| void (*_Nonnull callback)( |
| void* _Nullable, |
| const AHeapProfileDisableCallbackInfo* _Nonnull session_info), |
| void* _Nullable data); |
| |
| // Register heap described in AHeapInfo. |
| // |
| // If info is NULL, return a no-op heap_id. |
| // |
| // The returned heap_id can be used in AHeapProfile_reportAllocation and |
| // AHeapProfile_reportFree. |
| // |
| // Takes ownership of |info|. |
| uint32_t AHeapProfile_registerHeap(AHeapInfo* _Nullable info); |
| |
| // Reports an allocation of |size| on the given |heap_id|. |
| // |
| // The |alloc_id| needs to be a unique identifier for the allocation, and can |
| // can be used in AHeapProfile_reportFree to report the allocation has been |
| // freed. |
| // |
| // If a profiling session is active, this function decides whether the reported |
| // allocation should be sampled. If the allocation is sampled, it will be |
| // associated to the current callstack in the profile. |
| // |
| // Returns whether the allocation was sampled. |
| bool AHeapProfile_reportAllocation(uint32_t heap_id, |
| uint64_t alloc_id, |
| uint64_t size); |
| |
| // Reports a sample of |size| on the given |heap_id|. |
| // |
| // If a profiling session is active, this function associates the sample with |
| // the current callstack in the profile. |
| // |
| // Returns whether the profiling session was active. |
| // |
| // THIS IS GENERALLY NOT WHAT YOU WANT. THIS IS ONLY NEEDED IF YOU NEED TO |
| // DO THE SAMPLING YOURSELF FOR PERFORMANCE REASONS. |
| // USE AHeapProfile_reportAllocation TO REPORT AN ALLOCATION AND LET |
| // HEAPPROFD DO THE SAMPLING. |
| // |
| // TODO(fmayer): Make this unavailable to non-Mainline. |
| bool AHeapProfile_reportSample(uint32_t heap_id, |
| uint64_t alloc_id, |
| uint64_t size); |
| |
| // Report allocation was freed on the given heap. |
| // |
| // If |alloc_id| was sampled in a previous call to |
| // AHeapProfile_reportAllocation, this allocation is marked as freed in the |
| // profile. |
| // |
| // It is allowed to call with an |alloc_id| that was either not sampled or never |
| // passed to AHeapProfile_reportAllocation, in which case the call will not |
| // change the output. |
| void AHeapProfile_reportFree(uint32_t heap_id, uint64_t alloc_id); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #pragma GCC diagnostic pop |
| |
| #endif // SRC_PROFILING_MEMORY_INCLUDE_PERFETTO_HEAP_PROFILE_H_ |