File indexing completed on 2024-04-28 05:41:20
0001 /* 0002 SPDX-FileCopyrightText: 2015-2017 Milian Wolff <mail@milianw.de> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #ifndef POINTERMAP_H 0008 #define POINTERMAP_H 0009 0010 #include <algorithm> 0011 #include <iostream> 0012 #include <limits> 0013 #include <vector> 0014 0015 #include <tsl/robin_map.h> 0016 #include <tsl/robin_set.h> 0017 0018 #include <boost/functional/hash.hpp> 0019 0020 #include "indices.h" 0021 0022 /** 0023 * Information for a single call to an allocation function for big allocations. 0024 */ 0025 struct IndexedAllocationInfo 0026 { 0027 uint64_t size; 0028 TraceIndex traceIndex; 0029 AllocationInfoIndex allocationIndex; 0030 bool operator==(const IndexedAllocationInfo& rhs) const 0031 { 0032 return rhs.traceIndex == traceIndex && rhs.size == size; 0033 // allocationInfoIndex not compared to allow to look it up 0034 } 0035 }; 0036 0037 namespace std { 0038 template <> 0039 struct hash<IndexedAllocationInfo> 0040 { 0041 size_t operator()(const IndexedAllocationInfo& info) const 0042 { 0043 std::size_t seed = 0; 0044 boost::hash_combine(seed, info.size); 0045 boost::hash_combine(seed, info.traceIndex.index); 0046 // allocationInfoIndex not hashed to allow to look it up 0047 return seed; 0048 } 0049 }; 0050 } 0051 0052 struct AllocationInfoSet 0053 { 0054 AllocationInfoSet() 0055 { 0056 set.reserve(625000); 0057 } 0058 0059 bool add(uint64_t size, TraceIndex traceIndex, AllocationInfoIndex* allocationIndex) 0060 { 0061 allocationIndex->index = set.size(); 0062 IndexedAllocationInfo info = {size, traceIndex, *allocationIndex}; 0063 auto it = set.find(info); 0064 if (it != set.end()) { 0065 *allocationIndex = it->allocationIndex; 0066 return false; 0067 } else { 0068 set.insert(it, info); 0069 return true; 0070 } 0071 } 0072 tsl::robin_set<IndexedAllocationInfo> set; 0073 }; 0074 0075 /** 0076 * A low-memory-overhead map of 64bit pointer addresses to 32bit allocation 0077 * indices. 0078 * 0079 * We leverage the fact that pointers are allocated in pages, i.e. close to each 0080 * other. We split the 64bit address into a common large part and an individual 0081 * 16bit small part by dividing the address by some number (PageSize below) and 0082 * keeping the result as the big part and the residue as the small part. 0083 * 0084 * The big part of the address is used for a hash map to lookup the Indices 0085 * structure where we aggregate common pointers in two memory-efficient vectors, 0086 * one for the 16bit small pointer pairs, and one for the 32bit allocation 0087 * indices. 0088 */ 0089 class PointerMap 0090 { 0091 struct SplitPointer 0092 { 0093 enum 0094 { 0095 PageSize = std::numeric_limits<uint16_t>::max() / 4 0096 }; 0097 SplitPointer(uint64_t ptr) 0098 : big(ptr / PageSize) 0099 , small(ptr % PageSize) 0100 { 0101 } 0102 uint64_t big; 0103 uint16_t small; 0104 }; 0105 0106 public: 0107 PointerMap() 0108 { 0109 map.reserve(1024); 0110 } 0111 0112 void addPointer(const uint64_t ptr, const AllocationInfoIndex allocationIndex) 0113 { 0114 const SplitPointer pointer(ptr); 0115 0116 auto mapIt = map.find(pointer.big); 0117 if (mapIt == map.end()) { 0118 mapIt = map.insert(mapIt, std::make_pair(pointer.big, Indices())); 0119 } 0120 auto& indices = mapIt.value(); 0121 auto pageIt = std::lower_bound(indices.smallPtrParts.begin(), indices.smallPtrParts.end(), pointer.small); 0122 auto allocationIt = indices.allocationIndices.begin() + distance(indices.smallPtrParts.begin(), pageIt); 0123 if (pageIt == indices.smallPtrParts.end() || *pageIt != pointer.small) { 0124 indices.smallPtrParts.insert(pageIt, pointer.small); 0125 indices.allocationIndices.insert(allocationIt, allocationIndex); 0126 } else { 0127 *allocationIt = allocationIndex; 0128 } 0129 } 0130 0131 std::pair<AllocationInfoIndex, bool> takePointer(const uint64_t ptr) 0132 { 0133 const SplitPointer pointer(ptr); 0134 0135 auto mapIt = map.find(pointer.big); 0136 if (mapIt == map.end()) { 0137 return {{}, false}; 0138 } 0139 auto& indices = mapIt.value(); 0140 auto pageIt = std::lower_bound(indices.smallPtrParts.begin(), indices.smallPtrParts.end(), pointer.small); 0141 if (pageIt == indices.smallPtrParts.end() || *pageIt != pointer.small) { 0142 return {{}, false}; 0143 } 0144 auto allocationIt = indices.allocationIndices.begin() + distance(indices.smallPtrParts.begin(), pageIt); 0145 auto index = *allocationIt; 0146 indices.allocationIndices.erase(allocationIt); 0147 indices.smallPtrParts.erase(pageIt); 0148 if (indices.allocationIndices.empty()) { 0149 map.erase(mapIt); 0150 } 0151 return {index, true}; 0152 } 0153 0154 private: 0155 struct Indices 0156 { 0157 std::vector<uint16_t> smallPtrParts; 0158 std::vector<AllocationInfoIndex> allocationIndices; 0159 }; 0160 tsl::robin_map<uint64_t, Indices> map; 0161 }; 0162 0163 #endif // POINTERMAP_H