/* ---------------------------------------------------------------------------- Copyright (c) 2024-2026, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #pragma once #ifndef MIMALLOC_PROFILE_H #define MIMALLOC_PROFILE_H #include "mimalloc.h" #include // bool #include // uint64_t //--------------------------------------------------------------------------- // Initial support for profiling hooks; still experimental //--------------------------------------------------------------------------- #define MI_PROFILE_SAMPLE_DATA_MAX_SIZE (1024) // User defined profiler; see `test_profile.c` for an example. typedef struct mi_profiler_s mi_profiler_t; // Profiler data is stored together with each sampled allocation (unless the `on_free` field in the profiler is NULL.) typedef struct mi_profiler_sample_data_s { size_t user_data_size; // size of the user_data (should be the `mi_profiler_t.sample_data_size`) void* user_data[1]; // default, but can be less or more (up to 1KiB), depending on `sample_data_size` } mi_profiler_sample_data_t; // Profiling callback invoked on each sampled allocation. // If `profiler_data!=NULL` (i.e. when `on_free` is not NULL), then `profiler_data->requested_size == requested_size`. typedef size_t (mi_cdecl mi_profiler_on_alloc_fun)(mi_profiler_t* profiler, mi_profiler_sample_data_t* profiler_data, void* ptr, size_t requested_size, size_t bytes_sample_rate, uint64_t bytes_since_last_sample, mi_heap_t* heap); // Profiling callback invoked on each sampled in-place re-allocation. typedef size_t (mi_cdecl mi_profiler_on_realloc_inplace_fun)(mi_profiler_t* profiler, mi_profiler_sample_data_t* profiler_data, void* ptr, size_t old_size, mi_heap_t* heap); // Profiling callback invoked on a previously sampled allocation. typedef void (mi_cdecl mi_profiler_on_free_fun)(mi_profiler_t* profiler, mi_profiler_sample_data_t* profiler_data, void* ptr, mi_heap_t* heap); // Profiling callback invoked on mi_profiler_snapshot() typedef void (mi_cdecl mi_profiler_on_snapshot_fun)(mi_profiler_t* profiler); // A profiler // All fields are considered immutable such that they can be copied and accessed concurrently. All fields can be NULL/0. struct mi_profiler_s { void* reserved; // opaque; reserved by mimalloc size_t sample_data_size; // size of required profiler data for each sampled allocation (or zero for no data) size_t initial_sample_rate;// initial sample rate in bytes (set to at least 1 or higher) (can be adjusted by `on_alloc`) mi_profiler_on_alloc_fun* on_alloc; // called on a sampled allocation (may be called concurrently) mi_profiler_on_free_fun* on_free; // called on when previous sampled allocation is freed (may be called concurrently) mi_profiler_on_realloc_inplace_fun* on_realloc_inplace; // (as yet unused) called on in-place reallocation of a previous sampled allocation (may be called concurrently) mi_profiler_on_snapshot_fun* on_snapshot; // called on mi_profiler_snapshot() (only one thread at a time) // ... more user fields allowed }; // Exported definitions #ifdef __cplusplus extern "C" { #endif // attach a profiler to a particular heap only. mi_decl_export bool mi_heap_profile(mi_heap_t* heap, mi_profiler_t* profiler); // disable profiling for a particular heap; useful for a heap that the profiler uses itself for metadata. mi_decl_export void mi_heap_profile_disable(mi_heap_t* heap); // attach a profiler to any (current and future) heaps in a sub-process (unless those heaps disabled profiling) mi_decl_export bool mi_subproc_profile(mi_subproc_id_t subproc_id, mi_profiler_t* profiler); // attach a profiler to any heaps in the main sub-process (use NULL to detach) mi_decl_export bool mi_profile(mi_profiler_t* profiler); // start sampling mi_decl_export bool mi_profiler_start(mi_profiler_t* profiler); // end sampling mi_decl_export bool mi_profiler_stop(mi_profiler_t* profiler); // snapshot the current profile (may be called concurrently but only one thread will actually call the snapshot callback) mi_decl_export void mi_profiler_snapshot(mi_profiler_t* profiler); // builtin pprof compatible profiler // the builtin profiler can also be activated using environment variables (see [`pprof.c`](/src/profile/pprof.c)) // `base_file_name` selects the text snapshot format if it ends in `.heap` or `.text` (the extension is // stripped); any other extension, or none, uses the default (protobuf) snapshot format. // `alloc_interval_size`, if >0, automatically snapshots every that many allocated bytes. // `inuse_interval_size`, if >0, automatically snapshots every time the in-use bytes grow by that many bytes. // `time_interval_secs`, if >0, automatically snapshots every that many seconds (checked from allocation events). mi_decl_export mi_profiler_t* mi_pprof_profiler_new(size_t initial_threshold, const char* base_file_name, size_t alloc_interval_size, size_t inuse_interval_size, size_t time_interval_secs); mi_decl_export void mi_pprof_profiler_delete(mi_profiler_t* profiler); #ifdef __cplusplus } #endif #endif // MIMALLOC_PROFILE_H