Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/mimalloc/include/mimalloc-stats.h
14369 views
1
/* ----------------------------------------------------------------------------
2
Copyright (c) 2024-2025, Microsoft Research, Daan Leijen
3
This is free software; you can redistribute it and/or modify it under the
4
terms of the MIT license. A copy of the license can be found in the file
5
"LICENSE" at the root of this distribution.
6
-----------------------------------------------------------------------------*/
7
#pragma once
8
#ifndef MIMALLOC_STATS_H
9
#define MIMALLOC_STATS_H
10
11
#include <mimalloc.h>
12
#include <stdint.h>
13
14
#define MI_STAT_VERSION 5 // increased on every backward incompatible change
15
16
// alignment for atomic fields
17
#if defined(_MSC_VER)
18
#define mi_decl_align(a) __declspec(align(a))
19
#elif defined(__GNUC__)
20
#define mi_decl_align(a) __attribute__((aligned(a)))
21
#elif __cplusplus >= 201103L
22
#define mi_decl_align(a) alignas(a)
23
#else
24
#define mi_decl_align(a)
25
#endif
26
27
28
// count allocation over time
29
typedef struct mi_stat_count_s {
30
int64_t total; // total allocated
31
int64_t peak; // peak allocation
32
int64_t current; // current allocation
33
} mi_stat_count_t;
34
35
// counters only increase
36
typedef struct mi_stat_counter_s {
37
int64_t total; // total count
38
} mi_stat_counter_t;
39
40
#define MI_STAT_FIELDS() \
41
MI_STAT_COUNT(pages) /* count of mimalloc pages */ \
42
MI_STAT_COUNT(reserved) /* reserved memory bytes */ \
43
MI_STAT_COUNT(committed) /* committed bytes */ \
44
MI_STAT_COUNTER(reset) /* reset bytes */ \
45
MI_STAT_COUNTER(purged) /* purged bytes */ \
46
MI_STAT_COUNT(page_committed) /* committed memory inside pages */ \
47
MI_STAT_COUNT(pages_abandoned) /* abandoned pages count */ \
48
MI_STAT_COUNT(threads) /* number of threads */ \
49
MI_STAT_COUNT(malloc_normal) /* allocated bytes <= MI_LARGE_OBJ_SIZE_MAX */ \
50
MI_STAT_COUNT(malloc_huge) /* allocated bytes in huge pages */ \
51
MI_STAT_COUNT(malloc_requested) /* malloc requested bytes */ \
52
\
53
MI_STAT_COUNTER(mmap_calls) \
54
MI_STAT_COUNTER(commit_calls) \
55
MI_STAT_COUNTER(reset_calls) \
56
MI_STAT_COUNTER(purge_calls) \
57
MI_STAT_COUNTER(arena_count) /* number of memory arena's */ \
58
MI_STAT_COUNTER(malloc_normal_count) /* number of blocks <= MI_LARGE_OBJ_SIZE_MAX */ \
59
MI_STAT_COUNTER(malloc_huge_count) /* number of huge bloks */ \
60
MI_STAT_COUNTER(malloc_guarded_count) /* number of allocations with guard pages */ \
61
\
62
/* internal statistics */ \
63
MI_STAT_COUNTER(arena_rollback_count) \
64
MI_STAT_COUNTER(arena_purges) \
65
MI_STAT_COUNTER(pages_extended) /* number of page extensions */ \
66
MI_STAT_COUNTER(pages_retire) /* number of pages that are retired */ \
67
MI_STAT_COUNTER(page_searches) /* total pages searched for a fresh page */ \
68
MI_STAT_COUNTER(page_searches_count) /* searched count for a fresh page */ \
69
/* only on v1 and v2 */ \
70
MI_STAT_COUNT(segments) \
71
MI_STAT_COUNT(segments_abandoned) \
72
MI_STAT_COUNT(segments_cache) \
73
MI_STAT_COUNT(_segments_reserved) \
74
/* only on v3 */ \
75
MI_STAT_COUNT(heaps) \
76
MI_STAT_COUNT(theaps) \
77
MI_STAT_COUNTER(pages_reclaim_on_alloc) \
78
MI_STAT_COUNTER(pages_reclaim_on_free) \
79
MI_STAT_COUNTER(pages_reabandon_full) \
80
MI_STAT_COUNTER(pages_unabandon_busy_wait) \
81
MI_STAT_COUNTER(heaps_delete_wait)
82
83
// Size bins for chunks
84
typedef enum mi_chunkbin_e {
85
MI_CBIN_SMALL, // slice_count == 1
86
MI_CBIN_OTHER, // slice_count: any other from the other bins, and 1 <= slice_count <= MI_BCHUNK_BITS
87
MI_CBIN_MEDIUM, // slice_count == 8
88
MI_CBIN_LARGE, // slice_count == MI_SIZE_BITS (only used if MI_ENABLE_LARGE_PAGES is 1)
89
MI_CBIN_HUGE, // slice_count > MI_BCHUNK_BITS
90
MI_CBIN_NONE, // no bin assigned yet (the chunk is completely free)
91
MI_CBIN_COUNT
92
} mi_chunkbin_t;
93
94
95
// Define the statistics structure
96
#define MI_BIN_HUGE (73U) // see types.h
97
#define MI_STAT_COUNT(stat) mi_stat_count_t stat;
98
#define MI_STAT_COUNTER(stat) mi_stat_counter_t stat;
99
100
typedef struct mi_stats_s
101
{
102
size_t size; // size of the mi_stats_t structure
103
size_t version;
104
105
mi_decl_align(8) MI_STAT_FIELDS()
106
107
// future extension
108
mi_stat_count_t _stat_reserved[4];
109
mi_stat_counter_t _stat_counter_reserved[4];
110
111
// size segregated statistics
112
mi_stat_count_t malloc_bins[MI_BIN_HUGE+1]; // allocation per size bin
113
mi_stat_count_t page_bins[MI_BIN_HUGE+1]; // pages allocated per size bin
114
mi_stat_count_t chunk_bins[MI_CBIN_COUNT]; // chunks per page sizes
115
} mi_stats_t;
116
117
#undef MI_STAT_COUNT
118
#undef MI_STAT_COUNTER
119
120
// helper
121
#if __cplusplus
122
#define MI_STATS_ZERO_INIT { } /* empty initializer to prevent running the constructor (with msvc) */
123
#else
124
#define MI_STATS_ZERO_INIT { 0 } /* C zero initialize */
125
#endif
126
127
#define mi_stats_t_decl(name) mi_stats_t name = MI_STATS_ZERO_INIT; name.size = sizeof(mi_stats_t); name.version = MI_STAT_VERSION;
128
129
// Exported definitions
130
#ifdef __cplusplus
131
extern "C" {
132
#endif
133
134
// stats from a heap
135
mi_decl_export bool mi_heap_stats_get(mi_heap_t* heap, mi_stats_t* stats) mi_attr_noexcept;
136
mi_decl_export char* mi_heap_stats_get_json(mi_heap_t* heap, size_t buf_size, char* buf) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL
137
mi_decl_export void mi_heap_stats_print_out(mi_heap_t* heap, mi_output_fun* out, void* arg) mi_attr_noexcept;
138
139
// stats from a subprocess and its heaps aggregated
140
mi_decl_export bool mi_subproc_stats_get(mi_subproc_id_t subproc_id, mi_stats_t* stats) mi_attr_noexcept;
141
mi_decl_export char* mi_subproc_stats_get_json(mi_subproc_id_t subproc_id, size_t buf_size, char* buf) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL
142
mi_decl_export void mi_subproc_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun* out, void* arg) mi_attr_noexcept;
143
// print subprocess and all its heap stats segregated
144
mi_decl_export void mi_subproc_heap_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun* out, void* arg) mi_attr_noexcept;
145
146
// stats aggregated for the current subprocess and all its heaps.
147
mi_decl_export bool mi_stats_get(mi_stats_t* stats) mi_attr_noexcept;
148
mi_decl_export char* mi_stats_get_json(size_t buf_size, char* buf) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL
149
mi_decl_export void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept;
150
151
// add the stats of the heap to the subprocess and clear the heap stats
152
mi_decl_export void mi_heap_stats_merge_to_subproc(mi_heap_t* heap);
153
154
// stats from the subprocess without aggregating its heaps
155
mi_decl_export bool mi_subproc_stats_get_exclusive(mi_subproc_id_t subproc_id, mi_stats_t* stats) mi_attr_noexcept;
156
157
mi_decl_export char* mi_stats_as_json(mi_stats_t* stats, size_t buf_size, char* buf) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL
158
mi_decl_export size_t mi_stats_get_bin_size(size_t bin) mi_attr_noexcept;
159
160
#ifdef __cplusplus
161
}
162
#endif
163
164
#endif // MIMALLOC_STATS_H
165
166