APIs for Custom Memory Allocation
Intel Inspector
provides a set of APIs to help it identify the semantics of your
malloc
-like heap management functions. Annotating your code with these APIs reduces the number of false positives the
Intel Inspector
reports when analyzing your code.
Usage Tips
Follow these guidelines when using the memory allocation APIs:
- Createwrapperfunctions for your routines, and put the__itt_heap_*_beginand__itt_heap_*_endcalls in these functions.
- Allocate a unique domain for each pair ofallocate/freefunctions when calling__itt_heap_function_create. This allows theIntel Inspectorto verify a matchingfreefunction is called for everyallocatefunction call.
- Annotate the beginning and end of everyallocatefunction andfreefunction.
- Call all function pairs from the same stack frame, otherwise theIntel Inspectorassumes an exception occurred and the allocation attempt failed.
- Do not call anendfunction without first calling the matchingbeginfunction.
Using Memory Allocation APIs in Your Code
Use This
| To Do This
|
---|---|
| Declare a handle type to match
begin and
end calls and
domains.
Parameters of type
__itt_char follow the Windows* OS unicode convention. If UNICODE is defined when compiling on a Windows* OS,
__itt_char is
wchar_t ; otherwise it is
char .
|
| Identify allocation functions.
|
| Identify deallocation functions.
|
| Identify reallocation functions.
Note that
itt_heap_reallocate_end() must be called after the attempt even if no memory is returned.
Intel Inspector assumes C-runtime
realloc semantics.
|
| Identify functions related to private heap management, such as queries for remaining heap size and validation of heap state.
This function tells the
Intel Inspector that this memory access is intentional and should not be flagged.
Call
__itt_heap_internal_access_begin() before accessing the underlying heap management internals and
__itt_heap_internal_access_end() after the access is finished
|
| Produce reports of memory growth that occurs between calls to
__itt_heap_record_memory_growth_begin()
and
__itt_heap_record_memory_growth_end()
The report identifies any memory allocated but not freed between the two calls. Any memory allocated but not freed prior to the first call to
__itt_heap_record_memory_growth_begin() is not reported. Any memory allocated but not freed after the final call to__itt_heap_record_memory_growth_end() is reported when collection is complete.
|
Usage Example: Heap Allocation
#include <ittnotify.h> void* user_defined_malloc(size_t size); void user_defined_free(void *p); void* user_defined_realloc(void *p, size_t s); __itt_heap_function my_allocator; __itt_heap_function my_reallocator; __itt_heap_function my_freer; void* my_malloc(size_t s) { void* p; __itt_heap_allocate_begin(my_allocator, s, 0); p = user_defined_malloc(s); __itt_heap_allocate_end(my_allocator, &p, s, 0); return p; } void my_free(void *p) { __itt_heap_free_begin (my_freer, p); user_defined_free(p); __itt_heap_free_end (my_freer, p); } void* my_realloc(void *p, size_t s) { void *np; __itt_heap_reallocate_begin (my_reallocator, p, s, 0); np = user_defined_realloc(p, s); __itt_heap_reallocate_end(my_reallocator, p, &np, s, 0); return(np); } // Make sure to call this init routine before any calls to // user defined allocators. void init_itt_calls() { my_allocator = __itt_heap_function_create("my_malloc", "mydomain"); my_reallocator = __itt_heap_function_create("my_realloc", "mydomain"); my_freer = __itt_heap_function_create("my_free", "mydomain"); } void test_size_of_held_memory(void *p) { size_t s=0; // This will tell Intel Inspector that this memory access // is intentional, and should not be flagged. __itt_heap_internal_access_begin(); #ifdef TARGET_WINDOWS s = _msize(p); #endif __itt_heap_internal_access_end(); } // Now use my_alloc, my_free, my_realloc in place of the user defined // functions.
Usage Example: Heap Growth
#include <ittnotify.h> void ProcessTransaction(TransactionContext x) { ... char* m = (char*) malloc(128); // Memory leak Inspector will report ... return; } // In this example, a leak report will be generated for each transaction in // the for loop. void WaitForTransactions() { ... for (;;) { __itt_heap_record_memory_growth_begin(); TransactionContext x = WaitForTransaction(); // Transaction end-point ProcessTransaction(x); __itt_heap_record_memory_growth_end(); } }
Memory Allocation APIs for On-demand Memory Leak Detection and Memory Growth Detection
These APIs support on-demand memory leak detection and memory growth detection features in the GUI, and analogous memory leak reporting and growth detection capabilities in the CLI.
Mask values can be added or OR’ed together to reset both values with a single call.
Use This in C/C++ Code
| Use This in Fortran Code
| To Do This
|
---|---|---|
|
| Reset the starting point for on-demand leak detection and/or memory growth reporting.
For C/C++, the mask is:
For Fortran, the mask is:
If
__itt_heap_record() is called without a prior call to
__itt_heap_reset_detection() , the program’s start is used for the starting point.
|
|
| Record current data about memory leaks and/or memory growth for inclusion in the result.
For C/C++, the mask is:
For Fortran, the mask is:
If you are using the GUI for collection, this data is displayed immediately. If you are using the CLI for collection, the data is available after the result is finalized.
|
__itt_heap_record_memory_growth_begin()
and
__itt_heap_record_memory_growth_end()
are aliases for __itt_heap_reset_detection
(__itt_heap_growth
) and __itt_heap_record
(__itt_heap_growth
), respectively.
Usage Example: On-demand Leak Reporting (C++)
In this example, the goal is to measure the memory leaked by the functions
pipeline_stage1()
, and
pipeline_stage2()
. We also want to examine the memory growth exhibited by the function pipeline_stage2()
. Strictly speaking, the call to
__itt_heap_record()
after
pipeline_stage1()
finishes is not necessary, because any leaks that occur in pipeline stage 1 area also reported by the call to __itt_heap_record()
that follows
pipeline_stage2()
. This example also demonstrates finer-grained leak and growth detection than that available via the CLI and GUI.
#include <ittnotify.h> void ProcessPipeline() { __itt_heap_reset_detection(__itt_heap_leaks); // Start measuring memory leaks here pipeline_stage1(); // Run pipeline stage 1 __itt_heap_record(__itt_heap_leaks); // Report leaks in stage 1 // Now process stage 2 of the pipeline – measure growth and leaks there. // We reset the growth starting point for stage 2. // There’s no need to reset the leak start point, since it follows stage 1. __itt_heap_reset_detection(__itt_heap_growth); // Reset growth starting point for stage 2 pipeline_stage2(); __itt_heap_record(__itt_heap_leaks|__itt_heap_growth);// Report leaks and growth }
Usage Example: On-demand Leak Detection (Fortran)
In this example, the goal is to measure the memory leaked by the functions
pipeline_stage1()
, and
pipeline_stage2()
. We also want to examine the memory growth exhibited by the function pipeline_stage2()
. Strictly speaking, the call to
itt_heap_record()
after
pipeline_stage1()
finishes is not necessary, because any leaks that occur in pipeline stage 1 are also reported by the call toitt_heap_record()
that follows
pipeline_stage2()
. This example also demonstrates finer-grained leak and growth detection than that available via the CLI and GUI.
#include <ittnotify.h> subroutine process_pipeline() ! Start looking for leaks starting with pipeline stage 1. call itt_heap_reset_detection(itt_heap_leaks); pipeline_stage1(); call itt_heap_record(itt_heap_leaks); ! Now process stage 2 of the pipeline – measure growth and leaks there. ! We reset the growth starting point for stage 2. ! There’s no need to reset the leak start point, since it follows stage 1. call itt_heap_reset_baseline(itt_heap_growth); pipeline_stage2(); call itt_heap_record(itt_heap_leaks+itt_heap_growth); }