User Guide

  • 2020
  • 05/04/2020
  • Public Content
Contents

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:
  • Create
    wrapper
    functions for your routines, and put the
    __itt_heap_*_begin
    and
    __itt_heap_*_end
    calls in these functions.
  • Allocate a unique domain for each pair of
    allocate
    /
    free
    functions when calling
    __itt_heap_function_create
    . This allows the
    Intel Inspector
    to verify a matching
    free
    function is called for every
    allocate
    function call.
  • Annotate the beginning and end of every
    allocate
    function and
    free
    function.
  • Call all function pairs from the same stack frame, otherwise the
    Intel Inspector
    assumes an exception occurred and the allocation attempt failed.
  • Do not call an
    end
    function without first calling the matching
    begin
    function.

Using Memory Allocation APIs in Your Code

Use This
To Do This
typedef void* __itt_heap_function; __itt_heap_function __itt_heap_function_create( const __itt_char*
name
, const __itt_char*
domain
);
Declare a handle type to match
begin
and
end
calls and
domains.
  • name
    = Name of the function you want to annotate.
  • domain
    = String identifying a matching set of functions. For example, if there are three functions that all work with
    my_struct
    , such as
    alloc_my_structs
    ,
    free_my_structs
    , and
    realloc_my_structs
    , pass the same domain to all three
    __itt_heap_function_create()
    calls.
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
.
void __itt_heap_allocate_begin( __itt_heap_function
h
, size_t
size
, int
initialized
); void __itt_heap_allocate_end( __itt_heap_function
h
, void**
addr
, size_t
size
, int
initialized
);
Identify allocation functions.
  • h
    = Handle returned when this function's name was passed to
    __itt_heap_function_create()
    .
  • size
    = Size in bytes of the requested memory region.
  • initialized
    = Flag indicating if the memory region will be initialized by this routine.
  • addr
    = Pointer to the address of the memory region this function has allocated, or 0 if the allocation failed.
void __itt_heap_free_begin( __itt_heap_function
h
, void*
addr
); void __itt_heap_free_end( __itt_heap_function
h
, void*
addr
);
Identify deallocation functions.
  • h
    = Handle returned when this function's name was passed to
    __itt_heap_function_create()
    .
  • addr
    = Pointer to the address of the memory region this function is deallocating.
void __itt_heap_reallocate_begin( __itt_heap_function
h
, void*
addr
, size_t
new_size
, int
initialized
); void __itt_heap_reallocate_end( __itt_heap_function
h
, void*
addr
, void**
new_addr
, size_t
new_size
, int
initialized
);
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.
  • h
    = Handle returned when this function's name was passed to
    __itt_heap_function_create()
    .
  • addr
    = Pointer to the address of the memory region this function is reallocating. If
    addr
    is NULL, the
    Intel Inspector
    treats this as if it is an allocation.
  • new_addr
    = Pointer to a pointer to hold the address of the reallocated memory region.
  • size
    = Size in bytes of the requested memory region. If
    new_size
    is 0, the
    Intel Inspector
    treats this as if it is a deallocation.
void __itt_heap_internal_access_begin( void ); void __itt_heap_internal_access_end( void );
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
void __itt_heap_record_memory_growth_begin( void ); void __itt_heap_record_memory_growth_end( void );
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
void __itt_heap_reset_detection( unsigned int mask);
subroutine itt_heap_reset_detection(mask) integer, intent(in), value:: mask end subroutine itt_heap_reset_detection
Reset the starting point for on-demand leak detection and/or memory growth reporting.
For C/C++, the mask is:
  • __itt_heap_leaks
    to reset the leak detection starting point
  • __itt_heap_growth
    to reset the memory growth starting point.
For Fortran, the mask is:
  • itt_heap_leaks
    to reset the leak detection starting point
  • itt_heap_growth
    to reset the memory growth starting point.
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.
void __itt_heap_record(unsigned int mask);
subroutine itt_heap_record(mask) integer, intent(in), value:: mask end subroutine itt_heap_record
Record current data about memory leaks and/or memory growth for inclusion in the result.
For C/C++, the mask is:
  • __itt_heap_leaks
    to detect and record information about memory leaks
  • __itt_heap_growth
    to detect and record information about memory growth
For Fortran, the mask is:
  • itt_heap_leaks
    to detect and record information about memory leaks
  • itt_heap_growth
    to detect and record information about memory growth
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 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> 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); }

Product and Performance Information

1

Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804