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