// // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // Heap.cc -- // // Author : Thierry Delisle // Created On : Thu May 3 16:16:10 2018 // Last Modified By : Peter A. Buhr // Last Modified On : Fri May 4 17:27:31 2018 // Update Count : 28 // #include #include #include #include #include #include namespace Stats { namespace Heap { #if defined( NO_HEAP_STATISTICS ) void newPass( const char * const ) {} void print() {} #else struct StatBlock { const char * name = nullptr; ///< Name of this pass size_t mallocs = 0; ///< Allocations in this pass size_t frees = 0; ///< Frees in this pass size_t n_allocs = 0; ///< Current number of live allocations size_t peak_allocs = 0; ///< Peak number of live allocations this pass }; StatBlock passes[100] = {{ "Pre-Parse", 0, 0, 0, 0 }}; const size_t passes_size = sizeof(passes) / sizeof(passes[0]); size_t passes_cnt = 1; void newPass( const char * const name ) { passes[passes_cnt].name = name; passes[passes_cnt].mallocs = 0; passes[passes_cnt].frees = 0; passes[passes_cnt].n_allocs = passes[passes_cnt].peak_allocs = passes[passes_cnt-1].n_allocs; passes_cnt++; assertf(passes_cnt < passes_size, "Too many passes for Stats::Heap, increase the size of the array in Heap.cc"); } void print(size_t value, size_t total) { std::cerr << std::setw(12) << value; std::cerr << "(" << std::setw(3); std::cerr << (value == 0 ? 0 : value * 100 / total); std::cerr << "%) | "; } void print(const StatBlock& stat, size_t nc, size_t total_mallocs, size_t total_frees, size_t overall_peak) { std::cerr << std::setw(nc) << stat.name; std::cerr << " | "; print(stat.mallocs, total_mallocs); print(stat.frees, total_frees ); print(stat.peak_allocs, overall_peak ); std::cerr << "\n"; } void print(char c, size_t nc) { for(size_t i = 0; i < nc; i++) { std::cerr << c; } std::cerr << '\n'; } void print() { size_t nc = 0; size_t total_mallocs = 0; size_t total_frees = 0; size_t overall_peak = 0; for(size_t i = 0; i < passes_cnt; i++) { nc = std::max(nc, std::strlen(passes[i].name)); total_mallocs += passes[i].mallocs; total_frees += passes[i].frees; overall_peak = std::max(overall_peak, passes[i].peak_allocs); } size_t nct = nc + 65; const char * const title = "Heap Usage Statistic"; print('=', nct); for(size_t i = 0; i < (nct - std::strlen(title)) / 2; i++) std::cerr << ' '; std::cerr << title << std::endl; print('-', nct); std::cerr << std::setw(nc) << "Pass"; std::cerr << " | Malloc Count | Free Count | Peak Allocs |" << std::endl; print('-', nct); for(size_t i = 0; i < passes_cnt; i++) { print(passes[i], nc, total_mallocs, total_frees, overall_peak); } print('-', nct); print({"Sum", total_mallocs, total_frees, 0, overall_peak}, nc, total_mallocs, total_frees, overall_peak); } #include #include #include #include #include #include extern "C" { #include #include } //============================================================================================= // Interposing helpers //============================================================================================= typedef void (* generic_fptr_t)(void); generic_fptr_t interpose_symbol( const char * symbol, const char * version ) { const char * error; static void * library; if ( ! library ) { # if defined( RTLD_NEXT ) library = RTLD_NEXT; # else // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ library = dlopen( "libc.so.6", RTLD_LAZY ); error = dlerror(); if ( error ) { std::cerr << "interpose_symbol : failed to open libc, " << error << std::endl; abort(); } # endif // RTLD_NEXT } // if generic_fptr_t fptr; # if defined( _GNU_SOURCE ) if ( version ) { fptr = (generic_fptr_t)dlvsym( library, symbol, version ); } else { fptr = (generic_fptr_t)dlsym( library, symbol ); } # else fptr = (generic_fptr_t)dlsym( library, symbol ); # endif // _GNU_SOURCE error = dlerror(); if ( error ) { std::cerr << "interpose_symbol : internal error, " << error << std::endl; abort(); } return fptr; } extern "C" { void * malloc( size_t size ) __attribute__((malloc)); void * malloc( size_t size ) { static auto __malloc = reinterpret_cast(interpose_symbol( "malloc", nullptr )); if( passes_cnt > 0 ) { passes[passes_cnt - 1].mallocs++; passes[passes_cnt - 1].n_allocs++; passes[passes_cnt - 1].peak_allocs = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); } return __malloc( size ); } void free( void * ptr ) { static auto __free = reinterpret_cast(interpose_symbol( "free", nullptr )); if( passes_cnt > 0 ) { passes[passes_cnt - 1].frees++; passes[passes_cnt - 1].n_allocs--; } return __free( ptr ); } void * calloc( size_t nelem, size_t size ) { static auto __calloc = reinterpret_cast(interpose_symbol( "calloc", nullptr )); if( passes_cnt > 0 ) { passes[passes_cnt - 1].mallocs++; passes[passes_cnt - 1].n_allocs++; passes[passes_cnt - 1].peak_allocs = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); } return __calloc( nelem, size ); } void * realloc( void * ptr, size_t size ) { static auto __realloc = reinterpret_cast(interpose_symbol( "realloc", nullptr )); void * s = __realloc( ptr, size ); if ( s != ptr && passes_cnt > 0 ) { // did realloc get new storage ? passes[passes_cnt - 1].mallocs++; passes[passes_cnt - 1].frees++; } // if return s; } } #endif } }