integrate ETW windows event tracing into mimalloc as another track tool

This commit is contained in:
Daan Leijen 2023-03-16 20:08:43 -07:00
parent 072316bd33
commit 1a99efc671
10 changed files with 80 additions and 28 deletions

View file

@ -12,6 +12,7 @@ option(MI_XMALLOC "Enable abort() call on memory allocation failure by
option(MI_SHOW_ERRORS "Show error and warning messages by default (only enabled by default in DEBUG mode)" OFF) option(MI_SHOW_ERRORS "Show error and warning messages by default (only enabled by default in DEBUG mode)" OFF)
option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhead)" OFF) option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhead)" OFF)
option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF) option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF)
option(MI_TRACK_ETW "Compile with Windows event tracing (ETW) support (adds a small overhead)" OFF)
option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF) option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF)
option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_SEE_ASM "Generate assembly files" OFF)
option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON)
@ -165,6 +166,21 @@ if(MI_TRACK_ASAN)
endif() endif()
endif() endif()
if(MI_TRACK_ETW)
if NOT WIN32
set(MI_TRACK_ETW OFF)
message(WARNING "Can only enable ETW support on Windows (MI_TRACK_ETW=OFF)")
endif()
if (MI_TRACK_VALGRIND OR MI_TRACK_ASAN)
set(MI_TRACK_ETW OFF)
message(WARNING "Cannot enable ETW support with also Valgrind or ASAN support enabled (MI_TRACK_ETW=OFF)")
endif()
if(MI_TRACK_ETW)
message(STATUS "Compile with Windows event tracing support (MI_TRACK_ETW=ON)")
list(APPEND mi_defines MI_TRACK_ETW=1)
endif()
endif()
if(MI_SEE_ASM) if(MI_SEE_ASM)
message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)") message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)")
list(APPEND mi_cflags -save-temps) list(APPEND mi_cflags -save-temps)

View file

@ -1,4 +0,0 @@
#pragma once
#include <windows.h>
#include "mimalloc-etw-gen.h"

View file

@ -27,10 +27,12 @@ Optional:
#define mi_track_align(p,alignedp,offset,size) #define mi_track_align(p,alignedp,offset,size)
#define mi_track_resize(p,oldsize,newsize) #define mi_track_resize(p,oldsize,newsize)
#define mi_track_init()
The `mi_track_align` is called right after a `mi_track_malloc` for aligned pointers in a block. The `mi_track_align` is called right after a `mi_track_malloc` for aligned pointers in a block.
The corresponding `mi_track_free` still uses the block start pointer and original size (corresponding to the `mi_track_malloc`). The corresponding `mi_track_free` still uses the block start pointer and original size (corresponding to the `mi_track_malloc`).
The `mi_track_resize` is currently unused but could be called on reallocations within a block. The `mi_track_resize` is currently unused but could be called on reallocations within a block.
`mi_track_init` is called at program start.
The following macros are for tools like asan and valgrind to track whether memory is The following macros are for tools like asan and valgrind to track whether memory is
defined, undefined, or not accessible at all: defined, undefined, or not accessible at all:
@ -42,6 +44,7 @@ defined, undefined, or not accessible at all:
-------------------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------------------------------*/
#if MI_TRACK_VALGRIND #if MI_TRACK_VALGRIND
// valgrind tool
#define MI_TRACK_ENABLED 1 #define MI_TRACK_ENABLED 1
#define MI_TRACK_HEAP_DESTROY 1 // track free of individual blocks on heap_destroy #define MI_TRACK_HEAP_DESTROY 1 // track free of individual blocks on heap_destroy
@ -58,6 +61,7 @@ defined, undefined, or not accessible at all:
#define mi_track_mem_noaccess(p,size) VALGRIND_MAKE_MEM_NOACCESS(p,size) #define mi_track_mem_noaccess(p,size) VALGRIND_MAKE_MEM_NOACCESS(p,size)
#elif MI_TRACK_ASAN #elif MI_TRACK_ASAN
// address sanitizer
#define MI_TRACK_ENABLED 1 #define MI_TRACK_ENABLED 1
#define MI_TRACK_HEAP_DESTROY 0 #define MI_TRACK_HEAP_DESTROY 0
@ -71,19 +75,23 @@ defined, undefined, or not accessible at all:
#define mi_track_mem_undefined(p,size) ASAN_UNPOISON_MEMORY_REGION(p,size) #define mi_track_mem_undefined(p,size) ASAN_UNPOISON_MEMORY_REGION(p,size)
#define mi_track_mem_noaccess(p,size) ASAN_POISON_MEMORY_REGION(p,size) #define mi_track_mem_noaccess(p,size) ASAN_POISON_MEMORY_REGION(p,size)
#elif MI_ETW #elif MI_TRACK_ETW
// windows event tracing
#define MI_TRACK_ENABLED 1 #define MI_TRACK_ENABLED 1
#define MI_TRACK_HEAP_DESTROY 0
#define MI_TRACK_TOOL "ETW" #define MI_TRACK_TOOL "ETW"
#include "mimalloc-etw.h" #define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "../src/prim/windows/etw.h"
#define mi_track_malloc_size(p,reqsize,size,zero) EventWriteETW_MI_ALLOC((UINT64)p, size) #define mi_track_init() EventRegistermicrosoft_windows_mimalloc();
#define mi_track_free_size(p,size) EventWriteETW_MI_FREE((UINT64)p, size) #define mi_track_malloc_size(p,reqsize,size,zero) EventWriteETW_MI_ALLOC((UINT64)(p), size)
#define mi_track_mem_defined(p,size) #define mi_track_free_size(p,size) EventWriteETW_MI_FREE((UINT64)(p), size)
#define mi_track_mem_undefined(p,size)
#define mi_track_mem_noaccess(p,size)
#else #else
// no tracking
#define MI_TRACK_ENABLED 0 #define MI_TRACK_ENABLED 0
#define MI_TRACK_HEAP_DESTROY 0 #define MI_TRACK_HEAP_DESTROY 0
@ -91,11 +99,6 @@ defined, undefined, or not accessible at all:
#define mi_track_malloc_size(p,reqsize,size,zero) #define mi_track_malloc_size(p,reqsize,size,zero)
#define mi_track_free_size(p,_size) #define mi_track_free_size(p,_size)
#define mi_track_align(p,alignedp,offset,size)
#define mi_track_resize(p,oldsize,newsize)
#define mi_track_mem_defined(p,size)
#define mi_track_mem_undefined(p,size)
#define mi_track_mem_noaccess(p,size)
#endif #endif
@ -110,6 +113,23 @@ defined, undefined, or not accessible at all:
#define mi_track_align(p,alignedp,offset,size) mi_track_mem_noaccess(p,offset) #define mi_track_align(p,alignedp,offset,size) mi_track_mem_noaccess(p,offset)
#endif #endif
#ifndef mi_track_init
#define mi_track_init()
#endif
#ifndef mi_track_mem_defined
#define mi_track_mem_defined(p,size)
#endif
#ifndef mi_track_mem_undefined
#define mi_track_mem_undefined(p,size)
#endif
#ifndef mi_track_mem_noaccess
#define mi_track_mem_noaccess(p,size)
#endif
#if MI_PADDING #if MI_PADDING
#define mi_track_malloc(p,reqsize,zero) \ #define mi_track_malloc(p,reqsize,zero) \
if ((p)!=NULL) { \ if ((p)!=NULL) { \

View file

@ -32,8 +32,7 @@ terms of the MIT license. A copy of the license can be found in the file
// Define MI_TRACK_<tool> to enable tracking support // Define MI_TRACK_<tool> to enable tracking support
// #define MI_TRACK_VALGRIND 1 // #define MI_TRACK_VALGRIND 1
// #define MI_TRACK_ASAN 1 // #define MI_TRACK_ASAN 1
// Define MI_ETW to enable ETW provider #define MI_TRACK_ETW 1
#define MI_ETW 1
// Define MI_STAT as 1 to maintain statistics; set it to 2 to have detailed statistics (but costs some performance). // Define MI_STAT as 1 to maintain statistics; set it to 2 to have detailed statistics (but costs some performance).
// #define MI_STAT 1 // #define MI_STAT 1
@ -62,7 +61,7 @@ terms of the MIT license. A copy of the license can be found in the file
// Reserve extra padding at the end of each block to be more resilient against heap block overflows. // Reserve extra padding at the end of each block to be more resilient against heap block overflows.
// The padding can detect buffer overflow on free. // The padding can detect buffer overflow on free.
#if !defined(MI_PADDING) && (MI_SECURE>=3 || MI_DEBUG>=1 || MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_ETW) #if !defined(MI_PADDING) && (MI_SECURE>=3 || MI_DEBUG>=1 || (MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_TRACK_ETW))
#define MI_PADDING 1 #define MI_PADDING 1
#endif #endif

View file

@ -534,6 +534,7 @@ void mi_process_init(void) mi_attr_noexcept {
#endif #endif
mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL) mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL)
mi_track_init();
if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) {
size_t pages = mi_option_get_clamp(mi_option_reserve_huge_os_pages, 0, 128*1024); size_t pages = mi_option_get_clamp(mi_option_reserve_huge_os_pages, 0, 128*1024);
@ -550,10 +551,6 @@ void mi_process_init(void) mi_attr_noexcept {
mi_reserve_os_memory((size_t)ksize*MI_KiB, true, true); mi_reserve_os_memory((size_t)ksize*MI_KiB, true, true);
} }
} }
#ifdef MI_ETW
EventRegistermicrosoft_windows_mimalloc();
#endif
} }
// Called when the process is done (through `at_exit`) // Called when the process is done (through `at_exit`)

View file

@ -1,6 +1,8 @@
## Portability Primitives
This is the portability layer where all primitives needed from the OS are defined. This is the portability layer where all primitives needed from the OS are defined.
- `prim.h`: API definition - `prim.h`: API definition
- `prim.c`: Selects one of `prim-unix.c`, `prim-wasi.c`, or `prim-windows.c` depending on the host platform. - `prim.c`: Selects one of `unix/prim.c`, `wasi/prim.c`, or `windows/prim.c` depending on the host platform.
Note: still work in progress, there may be other places in the sources that still depend on OS ifdef's. Note: still work in progress, there may still be places in the sources that still depend on OS ifdef's.

View file

@ -29,7 +29,12 @@
</SystemCollectorId> </SystemCollectorId>
<EventCollectorId Value="Mimalloc_Collector"> <EventCollectorId Value="Mimalloc_Collector">
<EventProviders> <EventProviders>
<EventProviderId Value="MimallocEventProvider" /> <EventProviderId Value="MimallocEventProvider" >
<Keywords>
<Keyword Value="100"/>
<Keyword Value="101"/>
</Keywords>
</EventProviderId>
</EventProviders> </EventProviders>
</EventCollectorId> </EventCollectorId>
</Collectors> </Collectors>

View file

@ -0,0 +1,17 @@
## Primitives:
- `prim.c` contains Windows primitives for OS allocation.
## Event Tracing for Windows (ETW)
- `etw.h` is generated from `etw.man` which contains the manifest for mimalloc events.
(100 is an allocation, 101 is for a free)
- `mimalloc.wprp` is a profile for the Windows Performance Recorder (WPR).
In an admin prompt, you can use:
```
> wpr -start src\prim\windows\mimalloc.wprp -filemode
> <my mimalloc program>
> wpr -stop test.etl
```
and then open `test.etl` in the Windows Performance Analyzer (WPA).