| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_PROFILING_ALLOCATION_EVENT_H_ |
| #define CHROME_PROFILING_ALLOCATION_EVENT_H_ |
| |
| #include <functional> |
| #include <map> |
| #include <unordered_set> |
| |
| #include "chrome/common/profiling/memlog_stream.h" |
| #include "chrome/profiling/address.h" |
| #include "chrome/profiling/backtrace_storage.h" |
| |
| namespace profiling { |
| |
| // This class is copyable and assignable. |
| // |
| // AllocationEvents can be uniquely identified by their address. Caveat: This is |
| // true at any given point in time, since each address can only be used in a |
| // single allocation. However, it's possible that comparing different points in |
| // time, there are different AllocationEvents with the same address. |
| class AllocationEvent { |
| public: |
| // There must be a reference to this kept in the BacktraceStorage object on |
| // behalf of this class. |
| AllocationEvent(AllocatorType allocator, |
| Address addr, |
| size_t sz, |
| const Backtrace* bt, |
| int context_id); |
| |
| // This partial initializer creates an allocation of empty size for |
| // searching purposes. |
| explicit AllocationEvent(Address addr); |
| |
| AllocatorType allocator() const { return allocator_; } |
| |
| Address address() const { return address_; } |
| size_t size() const { return size_; } |
| |
| // The backtrace for this allocation. There must be a reference to this kept |
| // in the BacktraceStorage object on behalf of this class. |
| const Backtrace* backtrace() const { return backtrace_; } |
| |
| // ID into context map, 0 means no context. |
| int context_id() const { return context_id_; } |
| |
| struct HashByAddress { |
| size_t operator()(const AllocationEvent& event) const { |
| std::hash<profiling::Address> hasher; |
| return hasher(event.address()); |
| } |
| }; |
| |
| struct EqualityByAddress { |
| bool operator()(const AllocationEvent& lhs, |
| const AllocationEvent& rhs) const { |
| return lhs.address().value == rhs.address().value; |
| } |
| }; |
| |
| // Implements < for AllocationEvent using everything but the address. |
| struct MetadataPartialLess { |
| bool operator()(const AllocationEvent& lhs, |
| const AllocationEvent& rhs) const { |
| // Note that we're using pointer compiarisons on the backtrace objects |
| // since they're atoms and the actual ordering is not important. |
| return std::tie(lhs.size_, lhs.backtrace_, lhs.context_id_, |
| lhs.allocator_) < std::tie(rhs.size_, rhs.backtrace_, |
| rhs.context_id_, |
| rhs.allocator_); |
| } |
| }; |
| |
| private: |
| AllocatorType allocator_ = AllocatorType::kMalloc; |
| Address address_; |
| size_t size_ = 0; |
| const Backtrace* backtrace_ = nullptr; |
| int context_id_ = 0; |
| }; |
| |
| // Unique set based on addresses of allocations. |
| using AllocationEventSet = |
| std::unordered_set<AllocationEvent, |
| AllocationEvent::HashByAddress, |
| AllocationEvent::EqualityByAddress>; |
| |
| // Maps allocation metadata to allocation counts of that type. In this case, |
| // the address of the AllocationEvent is unused. |
| using AllocationCountMap = |
| std::map<AllocationEvent, int, AllocationEvent::MetadataPartialLess>; |
| |
| // Aggregates the allocation events to a count map. The address of the |
| // allocation event in the returned map will be the address of the first item |
| // in the set with that metadata. |
| AllocationCountMap AllocationEventSetToCountMap(const AllocationEventSet& set); |
| |
| } // namespace profiling |
| |
| #endif // CHROME_PROFILING_ALLOCATION_EVENT_H_ |