1e5f5895bda30f374b0b51412fd4d837fa59aed66Alexey Samsonov//===-- asan_stats.cc -----------------------------------------------------===// 21e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// 31e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// The LLVM Compiler Infrastructure 41e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// 51e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is distributed under the University of Illinois Open Source 61e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// License. See LICENSE.TXT for details. 71e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// 81e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===// 91e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// 101e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is a part of AddressSanitizer, an address sanity checker. 111e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// 121e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// Code related to statistics collected by AddressSanitizer. 131e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===// 141e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_interceptors.h" 151e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_internal.h" 161e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_stats.h" 17def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov#include "asan_thread.h" 18c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov#include "sanitizer_common/sanitizer_mutex.h" 199e3bd38388a7c182db57f6e3fc0943e6d12f012eKostya Serebryany#include "sanitizer_common/sanitizer_stackdepot.h" 201e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 211e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanynamespace __asan { 221e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 231e172b4bdec57329bf904f063a29f99cddf2d85fKostya SerebryanyAsanStats::AsanStats() { 24a27bdf70ca24202dce21cf7c1a387aeaa400d889Kostya Serebryany CHECK(REAL(memset)); 2509672caefb5694f1981a1712fdefa44840a95e67Alexey Samsonov REAL(memset)(this, 0, sizeof(AsanStats)); 261e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 271e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 281e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanystatic void PrintMallocStatsArray(const char *prefix, 293f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany uptr (&array)[kNumberOfSizeClasses]) { 30283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("%s", prefix); 313f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany for (uptr i = 0; i < kNumberOfSizeClasses; i++) { 321e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany if (!array[i]) continue; 33283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("%zu:%zu; ", i, array[i]); 341e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany } 35283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("\n"); 361e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 371e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 381e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanyvoid AsanStats::Print() { 39283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n", 40e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov malloced>>20, malloced_redzones>>20, mallocs); 41283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs); 42283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees); 43283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("Stats: %zuM really freed by %zu calls\n", 44e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov really_freed>>20, real_frees); 45e11c5c5a8cd6e448ddf3c69f783eb655cf4aab01Kostya Serebryany Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n", 46e11c5c5a8cd6e448ddf3c69f783eb655cf4aab01Kostya Serebryany (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20, 47e11c5c5a8cd6e448ddf3c69f783eb655cf4aab01Kostya Serebryany mmaps, munmaps); 481e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 491e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size); 501e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size); 511e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany PrintMallocStatsArray(" frees by size class: ", freed_by_size); 521e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size); 53283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany Printf("Stats: malloc large: %zu small slow: %zu\n", 54e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov malloc_large, malloc_small_slow); 551e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 561e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 57f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukovstatic BlockingMutex print_lock(LINKER_INITIALIZED); 5875f74616d227a158539a5cc23ea8282142623159Kostya Serebryany 591e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanystatic void PrintAccumulatedStats() { 6084f5bacaf1021b9fb6fc2cf48abe5d4d416422efAlexey Samsonov AsanStats stats; 61c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov GetAccumulatedStats(&stats); 621e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany // Use lock to keep reports from mixing up. 63f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov BlockingMutexLock lock(&print_lock); 641e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany stats.Print(); 659e3bd38388a7c182db57f6e3fc0943e6d12f012eKostya Serebryany StackDepotStats *stack_depot_stats = StackDepotGetStats(); 669e3bd38388a7c182db57f6e3fc0943e6d12f012eKostya Serebryany Printf("Stats: StackDepot: %zd ids; %zdM mapped\n", 679e3bd38388a7c182db57f6e3fc0943e6d12f012eKostya Serebryany stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20); 684b48f4563ca25d8915155acc5837e195cf0e5c57Kostya Serebryany PrintInternalAllocatorStats(); 691e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 701e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 71c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovstatic AsanStats unknown_thread_stats(LINKER_INITIALIZED); 72c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovstatic AsanStats accumulated_stats(LINKER_INITIALIZED); 73c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov// Required for malloc_zone_statistics() on OS X. This can't be stored in 74c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov// per-thread AsanStats. 75c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovstatic uptr max_malloced_memory; 76c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovstatic BlockingMutex acc_stats_lock(LINKER_INITIALIZED); 77c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 78def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonovstatic void FlushToAccumulatedStatsUnlocked(AsanStats *stats) { 79c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov acc_stats_lock.CheckLocked(); 80c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr *dst = (uptr*)&accumulated_stats; 81c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr *src = (uptr*)stats; 82c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr num_fields = sizeof(*stats) / sizeof(uptr); 83c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov for (uptr i = 0; i < num_fields; i++) { 84c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov dst[i] += src[i]; 85c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov src[i] = 0; 86c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov } 87c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov} 88c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 89def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonovstatic void FlushThreadStats(ThreadContextBase *tctx_base, void *arg) { 90def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base); 91def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov if (AsanThread *t = tctx->thread) 92def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov FlushToAccumulatedStatsUnlocked(&t->stats()); 93def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov} 94def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov 95c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovstatic void UpdateAccumulatedStatsUnlocked() { 96c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov acc_stats_lock.CheckLocked(); 97def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov { 98def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov ThreadRegistryLock l(&asanThreadRegistry()); 99def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov asanThreadRegistry().RunCallbackForEachThreadLocked(FlushThreadStats, 0); 100def1be9b7ef4091ce465c0fbfb26cdb52128ade8Alexey Samsonov } 101c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov FlushToAccumulatedStatsUnlocked(&unknown_thread_stats); 102c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // This is not very accurate: we may miss allocation peaks that happen 103c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // between two updates of accumulated_stats_. For more accurate bookkeeping 104c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // the maximum should be updated on every malloc(), which is unacceptable. 105c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov if (max_malloced_memory < accumulated_stats.malloced) { 106c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov max_malloced_memory = accumulated_stats.malloced; 107c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov } 108c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov} 109c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 110c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovvoid FlushToAccumulatedStats(AsanStats *stats) { 111c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov BlockingMutexLock lock(&acc_stats_lock); 112c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov FlushToAccumulatedStatsUnlocked(stats); 113c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov} 114c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 115c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovvoid GetAccumulatedStats(AsanStats *stats) { 116c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov BlockingMutexLock lock(&acc_stats_lock); 117c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov UpdateAccumulatedStatsUnlocked(); 118c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov internal_memcpy(stats, &accumulated_stats, sizeof(accumulated_stats)); 119c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov} 120c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 121c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonovvoid FillMallocStatistics(AsanMallocStats *malloc_stats) { 122c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov BlockingMutexLock lock(&acc_stats_lock); 123c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov UpdateAccumulatedStatsUnlocked(); 124c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov malloc_stats->blocks_in_use = accumulated_stats.mallocs; 125c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov malloc_stats->size_in_use = accumulated_stats.malloced; 126c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov malloc_stats->max_size_in_use = max_malloced_memory; 127c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov malloc_stats->size_allocated = accumulated_stats.mmaped; 128c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov} 129c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 130c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey SamsonovAsanStats &GetCurrentThreadStats() { 131c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov AsanThread *t = GetCurrentThread(); 132c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov return (t) ? t->stats() : unknown_thread_stats; 133c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov} 134c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov 1351e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} // namespace __asan 1361e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 1371e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// ---------------------- Interface ---------------- {{{1 1381e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanyusing namespace __asan; // NOLINT 1391e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 1409aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanyuptr __asan_get_current_allocated_bytes() { 141c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov BlockingMutexLock lock(&acc_stats_lock); 142c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov UpdateAccumulatedStatsUnlocked(); 143c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr malloced = accumulated_stats.malloced; 144c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr freed = accumulated_stats.freed; 145c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // Return sane value if malloced < freed due to racy 146c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // way we update accumulated stats. 147c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov return (malloced > freed) ? malloced - freed : 1; 1481e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 1491e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 1509aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanyuptr __asan_get_heap_size() { 151c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov BlockingMutexLock lock(&acc_stats_lock); 152c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov UpdateAccumulatedStatsUnlocked(); 153c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov return accumulated_stats.mmaped - accumulated_stats.munmaped; 1541e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 1551e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 1569aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanyuptr __asan_get_free_bytes() { 157c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov BlockingMutexLock lock(&acc_stats_lock); 158c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov UpdateAccumulatedStatsUnlocked(); 159c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr total_free = accumulated_stats.mmaped 160c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov - accumulated_stats.munmaped 161c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov + accumulated_stats.really_freed 162c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov + accumulated_stats.really_freed_redzones; 163c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov uptr total_used = accumulated_stats.malloced 164c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov + accumulated_stats.malloced_redzones; 165c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // Return sane value if total_free < total_used due to racy 166c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov // way we update accumulated stats. 167c25e62b0cdbca855e7611583b0ff7013c31db21dAlexey Samsonov return (total_free > total_used) ? total_free - total_used : 1; 1681e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 1691e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 1709aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanyuptr __asan_get_unmapped_bytes() { 1711e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany return 0; 1721e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 1731e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany 1741e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanyvoid __asan_print_accumulated_stats() { 1751e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany PrintAccumulatedStats(); 1761e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany} 177