168d75effSDimitry Andric //===-- asan_stats.cpp ----------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Code related to statistics collected by AddressSanitizer.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric #include "asan_interceptors.h"
1468d75effSDimitry Andric #include "asan_internal.h"
1568d75effSDimitry Andric #include "asan_stats.h"
1668d75effSDimitry Andric #include "asan_thread.h"
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_interface.h"
1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_mutex.h"
1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
2068d75effSDimitry Andric
2168d75effSDimitry Andric namespace __asan {
2268d75effSDimitry Andric
AsanStats()2368d75effSDimitry Andric AsanStats::AsanStats() {
2468d75effSDimitry Andric Clear();
2568d75effSDimitry Andric }
2668d75effSDimitry Andric
Clear()2768d75effSDimitry Andric void AsanStats::Clear() {
2868d75effSDimitry Andric CHECK(REAL(memset));
2968d75effSDimitry Andric REAL(memset)(this, 0, sizeof(AsanStats));
3068d75effSDimitry Andric }
3168d75effSDimitry Andric
PrintMallocStatsArray(const char * prefix,uptr (& array)[kNumberOfSizeClasses])3268d75effSDimitry Andric static void PrintMallocStatsArray(const char *prefix,
3368d75effSDimitry Andric uptr (&array)[kNumberOfSizeClasses]) {
3468d75effSDimitry Andric Printf("%s", prefix);
3568d75effSDimitry Andric for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
3668d75effSDimitry Andric if (!array[i]) continue;
3768d75effSDimitry Andric Printf("%zu:%zu; ", i, array[i]);
3868d75effSDimitry Andric }
3968d75effSDimitry Andric Printf("\n");
4068d75effSDimitry Andric }
4168d75effSDimitry Andric
Print()4268d75effSDimitry Andric void AsanStats::Print() {
4368d75effSDimitry Andric Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
4468d75effSDimitry Andric malloced>>20, malloced_redzones>>20, mallocs);
4568d75effSDimitry Andric Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
4668d75effSDimitry Andric Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
4768d75effSDimitry Andric Printf("Stats: %zuM really freed by %zu calls\n",
4868d75effSDimitry Andric really_freed>>20, real_frees);
4968d75effSDimitry Andric Printf("Stats: %zuM (%zuM-%zuM) mmaped; %zu maps, %zu unmaps\n",
5068d75effSDimitry Andric (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20,
5168d75effSDimitry Andric mmaps, munmaps);
5268d75effSDimitry Andric
5368d75effSDimitry Andric PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
5468d75effSDimitry Andric Printf("Stats: malloc large: %zu\n", malloc_large);
5568d75effSDimitry Andric }
5668d75effSDimitry Andric
MergeFrom(const AsanStats * stats)5768d75effSDimitry Andric void AsanStats::MergeFrom(const AsanStats *stats) {
5868d75effSDimitry Andric uptr *dst_ptr = reinterpret_cast<uptr*>(this);
5968d75effSDimitry Andric const uptr *src_ptr = reinterpret_cast<const uptr*>(stats);
6068d75effSDimitry Andric uptr num_fields = sizeof(*this) / sizeof(uptr);
6168d75effSDimitry Andric for (uptr i = 0; i < num_fields; i++)
6268d75effSDimitry Andric dst_ptr[i] += src_ptr[i];
6368d75effSDimitry Andric }
6468d75effSDimitry Andric
65349cc55cSDimitry Andric static Mutex print_lock;
6668d75effSDimitry Andric
6768d75effSDimitry Andric static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
6868d75effSDimitry Andric static AsanStats dead_threads_stats(LINKER_INITIALIZED);
69349cc55cSDimitry Andric static Mutex dead_threads_stats_lock;
7068d75effSDimitry Andric // Required for malloc_zone_statistics() on OS X. This can't be stored in
7168d75effSDimitry Andric // per-thread AsanStats.
7268d75effSDimitry Andric static uptr max_malloced_memory;
7368d75effSDimitry Andric
MergeThreadStats(ThreadContextBase * tctx_base,void * arg)7468d75effSDimitry Andric static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) {
7568d75effSDimitry Andric AsanStats *accumulated_stats = reinterpret_cast<AsanStats*>(arg);
7668d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
7768d75effSDimitry Andric if (AsanThread *t = tctx->thread)
7868d75effSDimitry Andric accumulated_stats->MergeFrom(&t->stats());
7968d75effSDimitry Andric }
8068d75effSDimitry Andric
GetAccumulatedStats(AsanStats * stats)8168d75effSDimitry Andric static void GetAccumulatedStats(AsanStats *stats) {
8268d75effSDimitry Andric stats->Clear();
8368d75effSDimitry Andric {
8468d75effSDimitry Andric ThreadRegistryLock l(&asanThreadRegistry());
8568d75effSDimitry Andric asanThreadRegistry()
8668d75effSDimitry Andric .RunCallbackForEachThreadLocked(MergeThreadStats, stats);
8768d75effSDimitry Andric }
8868d75effSDimitry Andric stats->MergeFrom(&unknown_thread_stats);
8968d75effSDimitry Andric {
90349cc55cSDimitry Andric Lock lock(&dead_threads_stats_lock);
9168d75effSDimitry Andric stats->MergeFrom(&dead_threads_stats);
9268d75effSDimitry Andric }
9368d75effSDimitry Andric // This is not very accurate: we may miss allocation peaks that happen
9468d75effSDimitry Andric // between two updates of accumulated_stats_. For more accurate bookkeeping
9568d75effSDimitry Andric // the maximum should be updated on every malloc(), which is unacceptable.
9668d75effSDimitry Andric if (max_malloced_memory < stats->malloced) {
9768d75effSDimitry Andric max_malloced_memory = stats->malloced;
9868d75effSDimitry Andric }
9968d75effSDimitry Andric }
10068d75effSDimitry Andric
FlushToDeadThreadStats(AsanStats * stats)10168d75effSDimitry Andric void FlushToDeadThreadStats(AsanStats *stats) {
102349cc55cSDimitry Andric Lock lock(&dead_threads_stats_lock);
10368d75effSDimitry Andric dead_threads_stats.MergeFrom(stats);
10468d75effSDimitry Andric stats->Clear();
10568d75effSDimitry Andric }
10668d75effSDimitry Andric
FillMallocStatistics(AsanMallocStats * malloc_stats)10768d75effSDimitry Andric void FillMallocStatistics(AsanMallocStats *malloc_stats) {
10868d75effSDimitry Andric AsanStats stats;
10968d75effSDimitry Andric GetAccumulatedStats(&stats);
11068d75effSDimitry Andric malloc_stats->blocks_in_use = stats.mallocs;
11168d75effSDimitry Andric malloc_stats->size_in_use = stats.malloced;
11268d75effSDimitry Andric malloc_stats->max_size_in_use = max_malloced_memory;
11368d75effSDimitry Andric malloc_stats->size_allocated = stats.mmaped;
11468d75effSDimitry Andric }
11568d75effSDimitry Andric
GetCurrentThreadStats()11668d75effSDimitry Andric AsanStats &GetCurrentThreadStats() {
11768d75effSDimitry Andric AsanThread *t = GetCurrentThread();
11868d75effSDimitry Andric return (t) ? t->stats() : unknown_thread_stats;
11968d75effSDimitry Andric }
12068d75effSDimitry Andric
PrintAccumulatedStats()12168d75effSDimitry Andric static void PrintAccumulatedStats() {
12268d75effSDimitry Andric AsanStats stats;
12368d75effSDimitry Andric GetAccumulatedStats(&stats);
12468d75effSDimitry Andric // Use lock to keep reports from mixing up.
125349cc55cSDimitry Andric Lock lock(&print_lock);
12668d75effSDimitry Andric stats.Print();
127349cc55cSDimitry Andric StackDepotStats stack_depot_stats = StackDepotGetStats();
12868d75effSDimitry Andric Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
129349cc55cSDimitry Andric stack_depot_stats.n_uniq_ids, stack_depot_stats.allocated >> 20);
13068d75effSDimitry Andric PrintInternalAllocatorStats();
13168d75effSDimitry Andric }
13268d75effSDimitry Andric
13368d75effSDimitry Andric } // namespace __asan
13468d75effSDimitry Andric
13568d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1
13668d75effSDimitry Andric using namespace __asan;
13768d75effSDimitry Andric
__sanitizer_get_current_allocated_bytes()13868d75effSDimitry Andric uptr __sanitizer_get_current_allocated_bytes() {
13968d75effSDimitry Andric AsanStats stats;
14068d75effSDimitry Andric GetAccumulatedStats(&stats);
14168d75effSDimitry Andric uptr malloced = stats.malloced;
14268d75effSDimitry Andric uptr freed = stats.freed;
14368d75effSDimitry Andric // Return sane value if malloced < freed due to racy
14468d75effSDimitry Andric // way we update accumulated stats.
145*5f757f3fSDimitry Andric return (malloced > freed) ? malloced - freed : 0;
14668d75effSDimitry Andric }
14768d75effSDimitry Andric
__sanitizer_get_heap_size()14868d75effSDimitry Andric uptr __sanitizer_get_heap_size() {
14968d75effSDimitry Andric AsanStats stats;
15068d75effSDimitry Andric GetAccumulatedStats(&stats);
15168d75effSDimitry Andric return stats.mmaped - stats.munmaped;
15268d75effSDimitry Andric }
15368d75effSDimitry Andric
__sanitizer_get_free_bytes()15468d75effSDimitry Andric uptr __sanitizer_get_free_bytes() {
15568d75effSDimitry Andric AsanStats stats;
15668d75effSDimitry Andric GetAccumulatedStats(&stats);
15768d75effSDimitry Andric uptr total_free = stats.mmaped
15868d75effSDimitry Andric - stats.munmaped
15968d75effSDimitry Andric + stats.really_freed;
16068d75effSDimitry Andric uptr total_used = stats.malloced
16168d75effSDimitry Andric + stats.malloced_redzones;
16268d75effSDimitry Andric // Return sane value if total_free < total_used due to racy
16368d75effSDimitry Andric // way we update accumulated stats.
164*5f757f3fSDimitry Andric return (total_free > total_used) ? total_free - total_used : 0;
16568d75effSDimitry Andric }
16668d75effSDimitry Andric
__sanitizer_get_unmapped_bytes()16768d75effSDimitry Andric uptr __sanitizer_get_unmapped_bytes() {
16868d75effSDimitry Andric return 0;
16968d75effSDimitry Andric }
17068d75effSDimitry Andric
__asan_print_accumulated_stats()17168d75effSDimitry Andric void __asan_print_accumulated_stats() {
17268d75effSDimitry Andric PrintAccumulatedStats();
17368d75effSDimitry Andric }
174