Skip to content
Draft

Mimallocv3 #159718

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/license.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ mimalloc

MIT License::

Copyright (c) 2018-2021 Microsoft Corporation, Daan Leijen
Copyright (c) 2018-2025 Microsoft Corporation, Daan Leijen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
66 changes: 66 additions & 0 deletions Include/internal/mimalloc/mimalloc-new-delete.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* ----------------------------------------------------------------------------
Copyright (c) 2018-2020 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_NEW_DELETE_H
#define MIMALLOC_NEW_DELETE_H

// ----------------------------------------------------------------------------
// This header provides convenient overrides for the new and
// delete operations in C++.
//
// This header should be included in only one source file!
//
// On Windows, or when linking dynamically with mimalloc, these
// can be more performant than the standard new-delete operations.
// See <https://en.cppreference.com/w/cpp/memory/new/operator_new>
// ---------------------------------------------------------------------------
#if defined(__cplusplus)
#include <new>
#include <mimalloc.h>

#if defined(_MSC_VER) && defined(_Ret_notnull_) && defined(_Post_writable_byte_size_)
// stay consistent with VCRT definitions
#define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict _Ret_notnull_ _Post_writable_byte_size_(n)
#define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(n)
#else
#define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict
#define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict
#endif

void operator delete(void* p) noexcept { mi_free(p); };
void operator delete[](void* p) noexcept { mi_free(p); };

void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); }
void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); }

mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); }

mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }
mi_decl_new_nothrow(n) void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }

#if (__cplusplus >= 201402L || _MSC_VER >= 1916)
void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); };
void operator delete[](void* p, std::size_t n) noexcept { mi_free_size(p,n); };
#endif

#if (__cplusplus > 201402L && defined(__cpp_aligned_new))
void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); };
void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); };
void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }

void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); }
void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); }
void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
#endif
#endif

#endif // MIMALLOC_NEW_DELETE_H
68 changes: 68 additions & 0 deletions Include/internal/mimalloc/mimalloc-override.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* ----------------------------------------------------------------------------
Copyright (c) 2018-2020 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_OVERRIDE_H
#define MIMALLOC_OVERRIDE_H

/* ----------------------------------------------------------------------------
This header can be used to statically redirect malloc/free and new/delete
to the mimalloc variants. This can be useful if one can include this file on
each source file in a project (but be careful when using external code to
not accidentally mix pointers from different allocators).
-----------------------------------------------------------------------------*/

#include <mimalloc.h>

// Standard C allocation
#define malloc(n) mi_malloc(n)
#define calloc(c,n) mi_calloc(c,n)
#define realloc(p,n) mi_realloc(p,n)
#define free(p) mi_free(p)

#define strdup(s) mi_strdup(s)
#define strndup(s,n) mi_strndup(s,n)
#define realpath(f,n) mi_realpath(f,n)

// Microsoft extensions
#define _expand(p,n) mi_expand(p,n)
#define _msize(p) mi_usable_size(p)
#define _recalloc(p,c,n) mi_recalloc(p,c,n)

#define _strdup(s) mi_strdup(s)
#define _strndup(s,n) mi_strndup(s,n)
#define _wcsdup(s) mi_wcsdup(s)
#define _mbsdup(s) mi_mbsdup(s)
#define _dupenv_s(buf,n,nm) mi_dupenv_s(buf,n,nm)
#define _wdupenv_s(buf,n,nm) mi_wdupenv_s(buf,n,nm)

// Various Posix and Unix variants
#define reallocf(p,n) mi_reallocf(p,n)
#define malloc_size(p) mi_usable_size(p)
#define malloc_usable_size(p) mi_usable_size(p)
#define malloc_good_size(n) mi_malloc_good_size(n)
#define cfree(p) mi_free(p)

#define valloc(n) mi_valloc(n)
#define pvalloc(n) mi_pvalloc(n)
#define reallocarray(p,c,n) mi_reallocarray(p,c,n)
#define reallocarr(ptrp,c,n) mi_reallocarr(ptrp,c,n)
#define memalign(a,n) mi_memalign(a,n)
#define aligned_alloc(a,n) mi_aligned_alloc(a,n)
#define posix_memalign(p,a,n) mi_posix_memalign(p,a,n)
#define _posix_memalign(p,a,n) mi_posix_memalign(p,a,n)

// Microsoft aligned variants
#define _aligned_malloc(n,a) mi_malloc_aligned(n,a)
#define _aligned_realloc(p,n,a) mi_realloc_aligned(p,n,a)
#define _aligned_recalloc(p,c,n,a) mi_aligned_recalloc(p,c,n,a)
#define _aligned_msize(p,a,o) mi_usable_size(p)
#define _aligned_free(p) mi_free(p)
#define _aligned_offset_malloc(n,a,o) mi_malloc_aligned_at(n,a,o)
#define _aligned_offset_realloc(p,n,a,o) mi_realloc_aligned_at(p,n,a,o)
#define _aligned_offset_recalloc(p,c,n,a,o) mi_recalloc_aligned_at(p,c,n,a,o)

#endif // MIMALLOC_OVERRIDE_H
97 changes: 97 additions & 0 deletions Include/internal/mimalloc/mimalloc-profile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* ----------------------------------------------------------------------------
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, 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
Loading