|
| 1 | +// |
| 2 | +// Created by ahueck on 30.12.20. |
| 3 | +// |
| 4 | + |
| 5 | +#ifndef TYPEART_ACCESSCOUNTPRINTER_H |
| 6 | +#define TYPEART_ACCESSCOUNTPRINTER_H |
| 7 | + |
| 8 | +#include "AccessCounter.h" |
| 9 | +#include "support/Logger.h" |
| 10 | +#include "support/Table.h" |
| 11 | + |
| 12 | +#include <map> |
| 13 | +#include <set> |
| 14 | +#include <sstream> |
| 15 | +#include <string> |
| 16 | +#include <string_view> |
| 17 | +#include <unordered_map> |
| 18 | +#include <unordered_set> |
| 19 | + |
| 20 | +namespace typeart::softcounter { |
| 21 | +namespace memory { |
| 22 | +struct MemOverhead { |
| 23 | + static constexpr auto pointerMapSize = sizeof(RuntimeT::PointerMap); // Map overhead |
| 24 | + static constexpr auto perNodeSizeMap = |
| 25 | + sizeof(std::remove_pointer<std::map<MemAddr, PointerInfo>::iterator::_Link_type>::type) + |
| 26 | + sizeof(RuntimeT::MapEntry); // not applicable to btree |
| 27 | + static constexpr auto stackVectorSize = sizeof(RuntimeT::Stack); // Stack overhead |
| 28 | + static constexpr auto perNodeSizeStack = sizeof(RuntimeT::StackEntry); // Stack allocs |
| 29 | + double stack{0}; |
| 30 | + double map{0}; |
| 31 | +}; |
| 32 | +inline MemOverhead estimate(Counter stack_max, Counter heap_max, Counter global_max, const double scale = 1024.0) { |
| 33 | + MemOverhead mem; |
| 34 | + mem.stack = double(MemOverhead::stackVectorSize + |
| 35 | + MemOverhead::perNodeSizeStack * std::max<size_t>(RuntimeT::StackReserve, stack_max)) / |
| 36 | + scale; |
| 37 | + mem.map = |
| 38 | + double(MemOverhead::pointerMapSize + MemOverhead::perNodeSizeMap * (stack_max + heap_max + global_max)) / scale; |
| 39 | + return mem; |
| 40 | +} |
| 41 | +} // namespace memory |
| 42 | + |
| 43 | +template <typename Recorder> |
| 44 | +void serialise(const Recorder& r, llvm::raw_ostream& buf) { |
| 45 | + if constexpr (std::is_same_v<Recorder, NoneRecorder>) { |
| 46 | + return; |
| 47 | + } else { |
| 48 | + const auto memory_use = memory::estimate(r.getMaxStackAllocs(), r.getMaxHeapAllocs(), r.getGlobalAllocs()); |
| 49 | + |
| 50 | + Table t("Alloc Stats from softcounters"); |
| 51 | + t.wrap_length = true; |
| 52 | + t.put(Row::make("Total heap", r.getHeapAllocs(), r.getHeapArray())); |
| 53 | + t.put(Row::make("Total stack", r.getStackAllocs(), r.getStackArray())); |
| 54 | + t.put(Row::make("Total global", r.getGlobalAllocs(), r.getGlobalArray())); |
| 55 | + t.put(Row::make("Max. Heap Allocs", r.getMaxHeapAllocs())); |
| 56 | + t.put(Row::make("Max. Stack Allocs", r.getMaxStackAllocs())); |
| 57 | + t.put(Row::make("Addresses checked", r.getAddrChecked())); |
| 58 | + t.put(Row::make("Distinct Addresses checked", r.getSeen().size())); |
| 59 | + t.put(Row::make("Addresses re-used", r.getAddrReuses())); |
| 60 | + t.put(Row::make("Addresses missed", r.getAddrMissing())); |
| 61 | + t.put(Row::make("Distinct Addresses missed", r.getMissing().size())); |
| 62 | + t.put(Row::make("Total free heap", r.getHeapAllocsFree(), r.getHeapArrayFree())); |
| 63 | + t.put(Row::make("Total free stack", r.getStackAllocsFree(), r.getStackArrayFree())); |
| 64 | + t.put(Row::make("Null/Zero/NullZero Addr", r.getNullAlloc(), r.getZeroAlloc(), r.getNullAndZeroAlloc())); |
| 65 | + t.put(Row::make("User-def. types", r.getNumUDefTypes())); |
| 66 | + t.put(Row::make("Estimated memory use (KiB)", size_t(std::round(memory_use.map + memory_use.stack)))); |
| 67 | + t.put(Row::make("Bytes per node map/stack", memory::MemOverhead::perNodeSizeMap, |
| 68 | + memory::MemOverhead::perNodeSizeStack)); |
| 69 | + |
| 70 | + t.print(buf); |
| 71 | + |
| 72 | + std::set<int> type_id_set; |
| 73 | + const auto fill_set = [&type_id_set](const auto& map) { |
| 74 | + for (const auto& [key, val] : map) { |
| 75 | + type_id_set.insert(key); |
| 76 | + } |
| 77 | + }; |
| 78 | + fill_set(r.getHeapAlloc()); |
| 79 | + fill_set(r.getGlobalAlloc()); |
| 80 | + fill_set(r.getStackAlloc()); |
| 81 | + fill_set(r.getHeapFree()); |
| 82 | + fill_set(r.getStackFree()); |
| 83 | + |
| 84 | + const auto count = [](const auto& map, auto id) { |
| 85 | + auto it = map.find(id); |
| 86 | + if (it != map.end()) { |
| 87 | + return it->second; |
| 88 | + } |
| 89 | + return 0ll; |
| 90 | + }; |
| 91 | + |
| 92 | + Table type_table("Allocation type detail (heap, stack, global)"); |
| 93 | + type_table.table_header = '#'; |
| 94 | + for (auto type_id : type_id_set) { |
| 95 | + type_table.put(Row::make(std::to_string(type_id), count(r.getHeapAlloc(), type_id), |
| 96 | + count(r.getStackAlloc(), type_id), count(r.getGlobalAlloc(), type_id), |
| 97 | + typeart_get_type_name(type_id))); |
| 98 | + } |
| 99 | + |
| 100 | + type_table.print(buf); |
| 101 | + |
| 102 | + Table type_table_free("Free allocation type detail (heap, stack)"); |
| 103 | + type_table_free.table_header = '#'; |
| 104 | + for (auto type_id : type_id_set) { |
| 105 | + type_table_free.put(Row::make(std::to_string(type_id), count(r.getHeapFree(), type_id), |
| 106 | + count(r.getStackFree(), type_id), typeart_get_type_name(type_id))); |
| 107 | + } |
| 108 | + |
| 109 | + type_table_free.print(buf); |
| 110 | + } |
| 111 | +} |
| 112 | +} // namespace typeart::softcounter |
| 113 | + |
| 114 | +#endif // TYPEART_ACCESSCOUNTPRINTER_H |
0 commit comments