brintos

brintos / llvm-project-archived public Read only

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