mem_usage.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_BASE_MEM_USAGE_H_
  5. #define CARBON_TOOLCHAIN_BASE_MEM_USAGE_H_
  6. #include <cstdint>
  7. #include "common/map.h"
  8. #include "common/set.h"
  9. #include "llvm/ADT/STLFunctionalExtras.h"
  10. #include "llvm/ADT/SmallVector.h"
  11. #include "llvm/ADT/StringRef.h"
  12. #include "llvm/Support/FormatVariadic.h"
  13. #include "toolchain/base/yaml.h"
  14. namespace Carbon {
  15. // Helps track memory usage for a compile.
  16. //
  17. // Users will mix `Add` and `Collect` calls, using `ConcatLabel` to label
  18. // allocation sources. Typically we'll collect stats for growable, potentially
  19. // large data types (such as `SmallVector`), ignoring small fixed-size members
  20. // (such as pointers or `int32_t`).
  21. //
  22. // For example:
  23. //
  24. // auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  25. // -> void {
  26. // // Explicit tracking.
  27. // mem_usage.Add(MemUsage::ConcatLabel(label, "data_"), data_.used_bytes(),
  28. // data_.reserved_bytes());
  29. // // Common library types like `Map` and `llvm::SmallVector` have
  30. // // type-specific support.
  31. // mem_usage.Add(MemUsage::Concat(label, "array_"), array_);
  32. // // Implementing `CollectMemUsage` allows use with the same interface.
  33. // mem_usage.Collect(MemUsage::Concat(label, "obj_"), obj_);
  34. // }
  35. class MemUsage {
  36. public:
  37. // Adds tracking for used and reserved bytes, paired with the given label.
  38. auto Add(std::string label, int64_t used_bytes, int64_t reserved_bytes)
  39. -> void {
  40. mem_usage_.push_back({.label = std::move(label),
  41. .used_bytes = used_bytes,
  42. .reserved_bytes = reserved_bytes});
  43. }
  44. // Adds memory usage for a `llvm::BumpPtrAllocator`.
  45. auto Collect(std::string label, const llvm::BumpPtrAllocator& allocator)
  46. -> void {
  47. Add(std::move(label), allocator.getBytesAllocated(),
  48. allocator.getTotalMemory());
  49. }
  50. // Adds memory usage for a `Map`.
  51. template <typename KeyT, typename ValueT, ssize_t SmallSize,
  52. typename KeyContextT>
  53. auto Collect(std::string label,
  54. const Map<KeyT, ValueT, SmallSize, KeyContextT>& map,
  55. KeyContextT key_context = KeyContextT()) -> void {
  56. // These don't track used bytes, so we set the same value for used and
  57. // reserved bytes.
  58. auto bytes = map.ComputeMetrics(key_context).storage_bytes;
  59. Add(std::move(label), bytes, bytes);
  60. }
  61. // Adds memory usage for a `Set`.
  62. template <typename KeyT, ssize_t SmallSize, typename KeyContextT>
  63. auto Collect(std::string label, const Set<KeyT, SmallSize, KeyContextT>& set,
  64. KeyContextT key_context = KeyContextT()) -> void {
  65. // These don't track used bytes, so we set the same value for used and
  66. // reserved bytes.
  67. auto bytes = set.ComputeMetrics(key_context).storage_bytes;
  68. Add(std::move(label), bytes, bytes);
  69. }
  70. // Adds memory usage of an array's data. This ignores the possible overhead of
  71. // a SmallVector's in-place storage; if it's used, it's going to be tiny
  72. // relative to scaling memory costs.
  73. //
  74. // This uses SmallVector in order to get proper inference for T, which
  75. // ArrayRef misses.
  76. template <typename T>
  77. auto Collect(std::string label, const llvm::SmallVectorImpl<T>& array)
  78. -> void {
  79. Add(std::move(label), array.size_in_bytes(), array.capacity_in_bytes());
  80. }
  81. // Adds memory usage for an object that provides `CollectMemUsage`.
  82. //
  83. // The expected signature of `CollectMemUsage` is above, in MemUsage class
  84. // comments.
  85. template <typename T>
  86. requires requires(MemUsage& mem_usage, llvm::StringRef label,
  87. const T& arg) {
  88. { arg.CollectMemUsage(mem_usage, label) };
  89. }
  90. auto Collect(std::string label, const T& arg) -> void {
  91. arg.CollectMemUsage(*this, label);
  92. }
  93. // Constructs a label for memory usage, handling the `.` concatenation.
  94. // We don't expect much depth in labels per-call.
  95. static auto ConcatLabel(llvm::StringRef label, llvm::StringRef child_label)
  96. -> std::string {
  97. return llvm::formatv("{0}.{1}", label, child_label);
  98. }
  99. static auto ConcatLabel(llvm::StringRef label, llvm::StringRef child_label1,
  100. llvm::StringRef child_label2) -> std::string {
  101. return llvm::formatv("{0}.{1}.{2}", label, child_label1, child_label2);
  102. }
  103. auto OutputYaml(llvm::StringRef filename) const -> Yaml::OutputMapping {
  104. // Explicitly copy the filename.
  105. return Yaml::OutputMapping([&, filename](Yaml::OutputMapping::Map map) {
  106. map.Add("filename", filename);
  107. int64_t total_used = 0;
  108. int64_t total_reserved = 0;
  109. for (const auto& entry : mem_usage_) {
  110. total_used += entry.used_bytes;
  111. total_reserved += entry.reserved_bytes;
  112. map.Add(entry.label,
  113. Yaml::OutputMapping([&](Yaml::OutputMapping::Map byte_map) {
  114. byte_map.Add("used_bytes", entry.used_bytes);
  115. byte_map.Add("reserved_bytes", entry.reserved_bytes);
  116. }));
  117. }
  118. map.Add("Total",
  119. Yaml::OutputMapping([&](Yaml::OutputMapping::Map byte_map) {
  120. byte_map.Add("used_bytes", total_used);
  121. byte_map.Add("reserved_bytes", total_reserved);
  122. }));
  123. });
  124. }
  125. private:
  126. // Memory usage for a specific label.
  127. struct Entry {
  128. std::string label;
  129. int64_t used_bytes;
  130. int64_t reserved_bytes;
  131. };
  132. // The accumulated data on memory usage.
  133. llvm::SmallVector<Entry> mem_usage_;
  134. };
  135. } // namespace Carbon
  136. #endif // CARBON_TOOLCHAIN_BASE_MEM_USAGE_H_