Home | History | Annotate | Line # | Download | only in asan
      1  1.1  kamil //===-- asan_stats.cc -----------------------------------------------------===//
      2  1.1  kamil //
      3  1.1  kamil //                     The LLVM Compiler Infrastructure
      4  1.1  kamil //
      5  1.1  kamil // This file is distributed under the University of Illinois Open Source
      6  1.1  kamil // License. See LICENSE.TXT for details.
      7  1.1  kamil //
      8  1.1  kamil //===----------------------------------------------------------------------===//
      9  1.1  kamil //
     10  1.1  kamil // This file is a part of AddressSanitizer, an address sanity checker.
     11  1.1  kamil //
     12  1.1  kamil // Code related to statistics collected by AddressSanitizer.
     13  1.1  kamil //===----------------------------------------------------------------------===//
     14  1.1  kamil #include "asan_interceptors.h"
     15  1.1  kamil #include "asan_internal.h"
     16  1.1  kamil #include "asan_stats.h"
     17  1.1  kamil #include "asan_thread.h"
     18  1.1  kamil #include "sanitizer_common/sanitizer_allocator_interface.h"
     19  1.1  kamil #include "sanitizer_common/sanitizer_mutex.h"
     20  1.1  kamil #include "sanitizer_common/sanitizer_stackdepot.h"
     21  1.1  kamil 
     22  1.1  kamil namespace __asan {
     23  1.1  kamil 
     24  1.1  kamil AsanStats::AsanStats() {
     25  1.1  kamil   Clear();
     26  1.1  kamil }
     27  1.1  kamil 
     28  1.1  kamil void AsanStats::Clear() {
     29  1.1  kamil   CHECK(REAL(memset));
     30  1.1  kamil   REAL(memset)(this, 0, sizeof(AsanStats));
     31  1.1  kamil }
     32  1.1  kamil 
     33  1.1  kamil static void PrintMallocStatsArray(const char *prefix,
     34  1.1  kamil                                   uptr (&array)[kNumberOfSizeClasses]) {
     35  1.1  kamil   Printf("%s", prefix);
     36  1.1  kamil   for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
     37  1.1  kamil     if (!array[i]) continue;
     38  1.1  kamil     Printf("%zu:%zu; ", i, array[i]);
     39  1.1  kamil   }
     40  1.1  kamil   Printf("\n");
     41  1.1  kamil }
     42  1.1  kamil 
     43  1.1  kamil void AsanStats::Print() {
     44  1.1  kamil   Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
     45  1.1  kamil              malloced>>20, malloced_redzones>>20, mallocs);
     46  1.1  kamil   Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
     47  1.1  kamil   Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
     48  1.1  kamil   Printf("Stats: %zuM really freed by %zu calls\n",
     49  1.1  kamil              really_freed>>20, real_frees);
     50  1.1  kamil   Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n",
     51  1.1  kamil              (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20,
     52  1.1  kamil              mmaps, munmaps);
     53  1.1  kamil 
     54  1.1  kamil   PrintMallocStatsArray("  mallocs by size class: ", malloced_by_size);
     55  1.1  kamil   Printf("Stats: malloc large: %zu\n", malloc_large);
     56  1.1  kamil }
     57  1.1  kamil 
     58  1.1  kamil void AsanStats::MergeFrom(const AsanStats *stats) {
     59  1.1  kamil   uptr *dst_ptr = reinterpret_cast<uptr*>(this);
     60  1.1  kamil   const uptr *src_ptr = reinterpret_cast<const uptr*>(stats);
     61  1.1  kamil   uptr num_fields = sizeof(*this) / sizeof(uptr);
     62  1.1  kamil   for (uptr i = 0; i < num_fields; i++)
     63  1.1  kamil     dst_ptr[i] += src_ptr[i];
     64  1.1  kamil }
     65  1.1  kamil 
     66  1.1  kamil static BlockingMutex print_lock(LINKER_INITIALIZED);
     67  1.1  kamil 
     68  1.1  kamil static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
     69  1.1  kamil static AsanStats dead_threads_stats(LINKER_INITIALIZED);
     70  1.1  kamil static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED);
     71  1.1  kamil // Required for malloc_zone_statistics() on OS X. This can't be stored in
     72  1.1  kamil // per-thread AsanStats.
     73  1.1  kamil static uptr max_malloced_memory;
     74  1.1  kamil 
     75  1.1  kamil static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) {
     76  1.1  kamil   AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg);
     77  1.1  kamil   AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
     78  1.1  kamil   if (AsanThread *t = tctx->thread)
     79  1.1  kamil     accumulated_stats->MergeFrom(&t->stats());
     80  1.1  kamil }
     81  1.1  kamil 
     82  1.1  kamil static void GetAccumulatedStats(AsanStats *stats) {
     83  1.1  kamil   stats->Clear();
     84  1.1  kamil   {
     85  1.1  kamil     ThreadRegistryLock l(&asanThreadRegistry());
     86  1.1  kamil     asanThreadRegistry()
     87  1.1  kamil         .RunCallbackForEachThreadLocked(MergeThreadStats, stats);
     88  1.1  kamil   }
     89  1.1  kamil   stats->MergeFrom(&unknown_thread_stats);
     90  1.1  kamil   {
     91  1.1  kamil     BlockingMutexLock lock(&dead_threads_stats_lock);
     92  1.1  kamil     stats->MergeFrom(&dead_threads_stats);
     93  1.1  kamil   }
     94  1.1  kamil   // This is not very accurate: we may miss allocation peaks that happen
     95  1.1  kamil   // between two updates of accumulated_stats_. For more accurate bookkeeping
     96  1.1  kamil   // the maximum should be updated on every malloc(), which is unacceptable.
     97  1.1  kamil   if (max_malloced_memory < stats->malloced) {
     98  1.1  kamil     max_malloced_memory = stats->malloced;
     99  1.1  kamil   }
    100  1.1  kamil }
    101  1.1  kamil 
    102  1.1  kamil void FlushToDeadThreadStats(AsanStats *stats) {
    103  1.1  kamil   BlockingMutexLock lock(&dead_threads_stats_lock);
    104  1.1  kamil   dead_threads_stats.MergeFrom(stats);
    105  1.1  kamil   stats->Clear();
    106  1.1  kamil }
    107  1.1  kamil 
    108  1.1  kamil void FillMallocStatistics(AsanMallocStats *malloc_stats) {
    109  1.1  kamil   AsanStats stats;
    110  1.1  kamil   GetAccumulatedStats(&stats);
    111  1.1  kamil   malloc_stats->blocks_in_use = stats.mallocs;
    112  1.1  kamil   malloc_stats->size_in_use = stats.malloced;
    113  1.1  kamil   malloc_stats->max_size_in_use = max_malloced_memory;
    114  1.1  kamil   malloc_stats->size_allocated = stats.mmaped;
    115  1.1  kamil }
    116  1.1  kamil 
    117  1.1  kamil AsanStats &GetCurrentThreadStats() {
    118  1.1  kamil   AsanThread *t = GetCurrentThread();
    119  1.1  kamil   return (t) ? t->stats() : unknown_thread_stats;
    120  1.1  kamil }
    121  1.1  kamil 
    122  1.1  kamil static void PrintAccumulatedStats() {
    123  1.1  kamil   AsanStats stats;
    124  1.1  kamil   GetAccumulatedStats(&stats);
    125  1.1  kamil   // Use lock to keep reports from mixing up.
    126  1.1  kamil   BlockingMutexLock lock(&print_lock);
    127  1.1  kamil   stats.Print();
    128  1.1  kamil   StackDepotStats *stack_depot_stats = StackDepotGetStats();
    129  1.1  kamil   Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
    130  1.1  kamil          stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
    131  1.1  kamil   PrintInternalAllocatorStats();
    132  1.1  kamil }
    133  1.1  kamil 
    134  1.1  kamil }  // namespace __asan
    135  1.1  kamil 
    136  1.1  kamil // ---------------------- Interface ---------------- {{{1
    137  1.1  kamil using namespace __asan;  // NOLINT
    138  1.1  kamil 
    139  1.1  kamil uptr __sanitizer_get_current_allocated_bytes() {
    140  1.1  kamil   AsanStats stats;
    141  1.1  kamil   GetAccumulatedStats(&stats);
    142  1.1  kamil   uptr malloced = stats.malloced;
    143  1.1  kamil   uptr freed = stats.freed;
    144  1.1  kamil   // Return sane value if malloced < freed due to racy
    145  1.1  kamil   // way we update accumulated stats.
    146  1.1  kamil   return (malloced > freed) ? malloced - freed : 1;
    147  1.1  kamil }
    148  1.1  kamil 
    149  1.1  kamil uptr __sanitizer_get_heap_size() {
    150  1.1  kamil   AsanStats stats;
    151  1.1  kamil   GetAccumulatedStats(&stats);
    152  1.1  kamil   return stats.mmaped - stats.munmaped;
    153  1.1  kamil }
    154  1.1  kamil 
    155  1.1  kamil uptr __sanitizer_get_free_bytes() {
    156  1.1  kamil   AsanStats stats;
    157  1.1  kamil   GetAccumulatedStats(&stats);
    158  1.1  kamil   uptr total_free = stats.mmaped
    159  1.1  kamil                   - stats.munmaped
    160  1.1  kamil                   + stats.really_freed;
    161  1.1  kamil   uptr total_used = stats.malloced
    162  1.1  kamil                   + stats.malloced_redzones;
    163  1.1  kamil   // Return sane value if total_free < total_used due to racy
    164  1.1  kamil   // way we update accumulated stats.
    165  1.1  kamil   return (total_free > total_used) ? total_free - total_used : 1;
    166  1.1  kamil }
    167  1.1  kamil 
    168  1.1  kamil uptr __sanitizer_get_unmapped_bytes() {
    169  1.1  kamil   return 0;
    170  1.1  kamil }
    171  1.1  kamil 
    172  1.1  kamil void __asan_print_accumulated_stats() {
    173  1.1  kamil   PrintAccumulatedStats();
    174  1.1  kamil }
    175