// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // This is a framework to measure the memory overhead of different containers. // Under the hood, it works by logging allocations and frees using an allocator // hook. // // Since the free callback does not report a size, and the allocator hooks run // in the middle of allocation, the logger simply takes the simplest approach // and logs out the raw data, relying on analyze_containers_memory_usage.py to // turn the raw output into useful numbers. // // The output of consists of m (number of different key/value combinations being // tested) x n (number of different map types being tested) sections: // // <key type 1> -> <value type 1> // ===== <map type 1> ===== // iteration 0 // alloc <address 1> size <size 1> // iteration 1 // alloc <address 2> size <size 2> // free <address 1> // iteration 2 // alloc <address 3> size <size 3> // free <address 2> // ... // ... // ... // ===== <map type n> // iteration 0 // alloc <address 1000> size <size 1000> // iteration 1 // alloc <address 1001> size <size 1001> // free <address 1000> // iteration 2 // alloc <address 1002> size <size 1002> // free <address 1001> // ... // ... // ... // <key type m> -> <value type m> // ===== <map type 1> ===== // ... // ... // ===== <map type n> ===== // // Alternate output strategies are possible, but most of them are worse/more // complex, and do not eliminate the postprocessing step. #include <array> #include <atomic> #include <charconv> #include <limits> #include <map> #include <optional> #include <string> #include <unordered_map> #include <utility> #include "base/allocator/dispatcher/dispatcher.h" #include "base/allocator/dispatcher/notification_data.h" #include "base/containers/flat_map.h" #include "base/logging.h" #include "base/strings/safe_sprintf.h" #include "base/unguessable_token.h" #include "base/values.h" #include "third_party/abseil-cpp/absl/container/btree_map.h" #include "third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "third_party/abseil-cpp/absl/container/node_hash_map.h" namespace { std::atomic<bool> log_allocs_and_frees; struct AllocationLogger { … }; class ScopedLogAllocAndFree { … }; // Measures the memory usage for a container with type `Container` from 0 to // 6857 elements, using `inserter` to insert a single element at a time. // `inserter` should be a functor that takes a `Container& container` as its // first parameter and a `size_t current_index` as its second parameter. // // Note that `inserter` can't use `base::FunctionRef` since the inserter is // passed through several layers before actually being instantiated below in // this function. template <typename Container, typename Inserter> void MeasureOneContainer(const Inserter& inserter) { … } // Measures the memory usage for all the container types under test. `inserter` // is used to insert a single element at a time into the tested container. template <typename K, typename V, typename Inserter> void Measure(const Inserter& inserter) { … } } // namespace int main() { … }