xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_stats.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
2368d75effSDimitry Andric AsanStats::AsanStats() {
2468d75effSDimitry Andric   Clear();
2568d75effSDimitry Andric }
2668d75effSDimitry Andric 
2768d75effSDimitry Andric void AsanStats::Clear() {
2868d75effSDimitry Andric   CHECK(REAL(memset));
2968d75effSDimitry Andric   REAL(memset)(this, 0, sizeof(AsanStats));
3068d75effSDimitry Andric }
3168d75effSDimitry Andric 
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 
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 
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 
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 
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 
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 
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 
11668d75effSDimitry Andric AsanStats &GetCurrentThreadStats() {
11768d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
11868d75effSDimitry Andric   return (t) ? t->stats() : unknown_thread_stats;
11968d75effSDimitry Andric }
12068d75effSDimitry Andric 
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 
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 
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 
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 
16768d75effSDimitry Andric uptr __sanitizer_get_unmapped_bytes() {
16868d75effSDimitry Andric   return 0;
16968d75effSDimitry Andric }
17068d75effSDimitry Andric 
17168d75effSDimitry Andric void __asan_print_accumulated_stats() {
17268d75effSDimitry Andric   PrintAccumulatedStats();
17368d75effSDimitry Andric }
174