mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
With mimalloc 3.3.2's release build, free(NULL) before the allocator's constructor dereferenced a page map that does not exist yet. glibc 2.44's newlocale() does exactly that during libstdc++ start-up, so every Linux binary died with SIGSEGV before main (reported with a reproduction in #2562). Upstream fixed it in b2226c19 (mimalloc #1341), first released in v3.4.4; v3.5.3, upstream's latest published release, contains it. Vendored from microsoft/mimalloc tag v3.5.3 (tag object deac3dcf, commit d4881d338125e1cb7c47ba4cfb398d6f7c0c8d45): LICENSE, include/ and src/, written blob by blob from a bare clone. Before the local patches were reapplied, the staged LICENSE blob and include/ and src/ trees had the tag's exact object ids (50 files; src/arena-meta.c is gone upstream). Afterwards the only differences are two documented hunks: - src/prim/unix/prim.c: macOS always recommits on decommit, carried from63fb7b3d(the phys_footprint fix). - src/prim/osx/alloc-override-zone.c: one comment reworded, because scripts/security-vendored.sh rejects the upstream "fork()" spelling even inside a comment. No code change. The reproducible-banner patch (no __DATE__/__TIME__) is dropped: upstream removed the build clock in v3.4.5 (mimalloc #1355). The two Makefile comments that pointed at that patch now say so. The production object is built with -DMI_PROFILE=0: mimalloc 3.5.2+ compiles its allocation-sampling profiler in by default, with a sample countdown on the allocation path, and the product never uses it. vendored/mimalloc/PATCHES.md records the pin, a re-verification recipe, the check that pins each patch and the refresh procedure; THIRD_PARTY.md points at it, the SBOM version is 3.5.3 and scripts/vendored-checksums.txt is regenerated (mimalloc lines only; security-vendored.sh passes). Measured on Apple M5 Pro (macOS 26.6), full indexes, 2 interleaved reps, mainfceb25d8(3.3.2) -> this change: TypeScript peak phys_footprint 1.07/1.01 -> 1.04/1.04 GB, peak RSS 1.87/1.84 -> 1.85/1.86 GB, wall 30.6/29.1 -> 29.3/30.0 s; django footprint 0.41/0.41 -> 0.38/0.39 GB, RSS 0.59/0.59 -> 0.58/0.60 GB, wall 6.5/6.2 -> 6.5/6.5 s. The graphs are identical: full node and edge hashes, node and edge census, no dangling edges (django 68022 nodes / 322464 edges, TypeScript 306239 / 835984). The same tree without the recommit patch peaks at 2.09/2.04 GB footprint on TypeScript, so63fb7b3dstill does its job. Linux arm64 (glibc 2.39, gcc 13.3): both trees build without warnings; django peak RSS 0.67/0.68 GB on main, 0.69/0.68 GB with this change. Co-authored-by: Felix Rath <felixm.rath@gmail.com> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
80 lines
4.0 KiB
C
80 lines
4.0 KiB
C
/* ----------------------------------------------------------------------------
|
|
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 <stdbool.h> // bool
|
|
#include <stdint.h> // 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, const 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, const 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, const mi_heap_t* heap);
|
|
|
|
// 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)
|
|
// ... 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
|
|
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);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // MIMALLOC_PROFILE_H
|