asan_stats.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
1765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//===-- asan_stats.cc -----------------------------------------------------===//
2765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//
3765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//                     The LLVM Compiler Infrastructure
4765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//
5765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// This file is distributed under the University of Illinois Open Source
6765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// License. See LICENSE.TXT for details.
7765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//
8765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//===----------------------------------------------------------------------===//
9765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//
10765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// This file is a part of AddressSanitizer, an address sanity checker.
11765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//
12765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// Code related to statistics collected by AddressSanitizer.
13765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye//===----------------------------------------------------------------------===//
14765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_interceptors.h"
15765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_internal.h"
16765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_stats.h"
17765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "asan_thread.h"
18765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "sanitizer_common/sanitizer_allocator_interface.h"
19765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "sanitizer_common/sanitizer_mutex.h"
20765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye#include "sanitizer_common/sanitizer_stackdepot.h"
21765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
22765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyenamespace __asan {
23765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
24765e52e2d30d0754625b8c7af6c36e93612f15beTor NorbyeAsanStats::AsanStats() {
25765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Clear();
26765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
27765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
28765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyevoid AsanStats::Clear() {
29765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  CHECK(REAL(memset));
30765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  REAL(memset)(this, 0, sizeof(AsanStats));
31765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
32765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
33765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic void PrintMallocStatsArray(const char *prefix,
34765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                                  uptr (&array)[kNumberOfSizeClasses]) {
35765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("%s", prefix);
36765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
37765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!array[i]) continue;
38765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Printf("%zu:%zu; ", i, array[i]);
39765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
40765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("\n");
41765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
42765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
43765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyevoid AsanStats::Print() {
44765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
45765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye             malloced>>20, malloced_redzones>>20, mallocs);
46765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
47765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
48765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("Stats: %zuM really freed by %zu calls\n",
49765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye             really_freed>>20, real_frees);
50765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n",
51765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye             (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20,
52765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye             mmaps, munmaps);
53765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
54765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  PrintMallocStatsArray("  mmaps   by size class: ", mmaped_by_size);
55765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  PrintMallocStatsArray("  mallocs by size class: ", malloced_by_size);
56765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  PrintMallocStatsArray("  frees   by size class: ", freed_by_size);
57765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  PrintMallocStatsArray("  rfrees  by size class: ", really_freed_by_size);
58765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  Printf("Stats: malloc large: %zu small slow: %zu\n",
59765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye             malloc_large, malloc_small_slow);
60765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
61765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
62765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyevoid AsanStats::MergeFrom(const AsanStats *stats) {
63765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  uptr *dst_ptr = reinterpret_cast<uptr*>(this);
64765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  const uptr *src_ptr = reinterpret_cast<const uptr*>(stats);
65765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  uptr num_fields = sizeof(*this) / sizeof(uptr);
66765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  for (uptr i = 0; i < num_fields; i++)
67765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    dst_ptr[i] += src_ptr[i];
68765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}
69765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
70765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic BlockingMutex print_lock(LINKER_INITIALIZED);
71765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
72765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic AsanStats unknown_thread_stats(LINKER_INITIALIZED);
73765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic AsanStats dead_threads_stats(LINKER_INITIALIZED);
74765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED);
75765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// Required for malloc_zone_statistics() on OS X. This can't be stored in
76765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye// per-thread AsanStats.
77765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic uptr max_malloced_memory;
78765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
79765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyestatic void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) {
80765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg);
81  AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
82  if (AsanThread *t = tctx->thread)
83    accumulated_stats->MergeFrom(&t->stats());
84}
85
86static void GetAccumulatedStats(AsanStats *stats) {
87  stats->Clear();
88  {
89    ThreadRegistryLock l(&asanThreadRegistry());
90    asanThreadRegistry()
91        .RunCallbackForEachThreadLocked(MergeThreadStats, stats);
92  }
93  stats->MergeFrom(&unknown_thread_stats);
94  {
95    BlockingMutexLock lock(&dead_threads_stats_lock);
96    stats->MergeFrom(&dead_threads_stats);
97  }
98  // This is not very accurate: we may miss allocation peaks that happen
99  // between two updates of accumulated_stats_. For more accurate bookkeeping
100  // the maximum should be updated on every malloc(), which is unacceptable.
101  if (max_malloced_memory < stats->malloced) {
102    max_malloced_memory = stats->malloced;
103  }
104}
105
106void FlushToDeadThreadStats(AsanStats *stats) {
107  BlockingMutexLock lock(&dead_threads_stats_lock);
108  dead_threads_stats.MergeFrom(stats);
109  stats->Clear();
110}
111
112void FillMallocStatistics(AsanMallocStats *malloc_stats) {
113  AsanStats stats;
114  GetAccumulatedStats(&stats);
115  malloc_stats->blocks_in_use = stats.mallocs;
116  malloc_stats->size_in_use = stats.malloced;
117  malloc_stats->max_size_in_use = max_malloced_memory;
118  malloc_stats->size_allocated = stats.mmaped;
119}
120
121AsanStats &GetCurrentThreadStats() {
122  AsanThread *t = GetCurrentThread();
123  return (t) ? t->stats() : unknown_thread_stats;
124}
125
126static void PrintAccumulatedStats() {
127  AsanStats stats;
128  GetAccumulatedStats(&stats);
129  // Use lock to keep reports from mixing up.
130  BlockingMutexLock lock(&print_lock);
131  stats.Print();
132  StackDepotStats *stack_depot_stats = StackDepotGetStats();
133  Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
134         stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
135  PrintInternalAllocatorStats();
136}
137
138}  // namespace __asan
139
140// ---------------------- Interface ---------------- {{{1
141using namespace __asan;  // NOLINT
142
143uptr __sanitizer_get_current_allocated_bytes() {
144  AsanStats stats;
145  GetAccumulatedStats(&stats);
146  uptr malloced = stats.malloced;
147  uptr freed = stats.freed;
148  // Return sane value if malloced < freed due to racy
149  // way we update accumulated stats.
150  return (malloced > freed) ? malloced - freed : 1;
151}
152uptr __asan_get_current_allocated_bytes() {
153  return __sanitizer_get_current_allocated_bytes();
154}
155
156uptr __sanitizer_get_heap_size() {
157  AsanStats stats;
158  GetAccumulatedStats(&stats);
159  return stats.mmaped - stats.munmaped;
160}
161uptr __asan_get_heap_size() {
162  return __sanitizer_get_heap_size();
163}
164
165uptr __sanitizer_get_free_bytes() {
166  AsanStats stats;
167  GetAccumulatedStats(&stats);
168  uptr total_free = stats.mmaped
169                  - stats.munmaped
170                  + stats.really_freed
171                  + stats.really_freed_redzones;
172  uptr total_used = stats.malloced
173                  + stats.malloced_redzones;
174  // Return sane value if total_free < total_used due to racy
175  // way we update accumulated stats.
176  return (total_free > total_used) ? total_free - total_used : 1;
177}
178uptr __asan_get_free_bytes() {
179  return __sanitizer_get_free_bytes();
180}
181
182uptr __sanitizer_get_unmapped_bytes() {
183  return 0;
184}
185uptr __asan_get_unmapped_bytes() {
186  return __sanitizer_get_unmapped_bytes();
187}
188
189void __asan_print_accumulated_stats() {
190  PrintAccumulatedStats();
191}
192