1*6dbdd20aSAndroid Build Coastguard Worker /* 2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker * 4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker * 8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker * 10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker */ 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Worker #ifndef SRC_SHARED_LIB_INTERN_MAP_H_ 18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_SHARED_LIB_INTERN_MAP_H_ 19*6dbdd20aSAndroid Build Coastguard Worker 20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/flat_hash_map.h" 21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/public/fnv1a.h" 22*6dbdd20aSAndroid Build Coastguard Worker 23*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto { 24*6dbdd20aSAndroid Build Coastguard Worker 25*6dbdd20aSAndroid Build Coastguard Worker // Assigns and maintains the mapping between "interned" data and iids (small 26*6dbdd20aSAndroid Build Coastguard Worker // integers that can be used to refer to the same data without repeating it) 27*6dbdd20aSAndroid Build Coastguard Worker // for different types. 28*6dbdd20aSAndroid Build Coastguard Worker class InternMap { 29*6dbdd20aSAndroid Build Coastguard Worker public: 30*6dbdd20aSAndroid Build Coastguard Worker // Zero will never be assigned as a valid iid: it is used as the return value 31*6dbdd20aSAndroid Build Coastguard Worker // of Find() to signal failure. 32*6dbdd20aSAndroid Build Coastguard Worker using Iid = uint64_t; 33*6dbdd20aSAndroid Build Coastguard Worker 34*6dbdd20aSAndroid Build Coastguard Worker InternMap(); 35*6dbdd20aSAndroid Build Coastguard Worker ~InternMap(); 36*6dbdd20aSAndroid Build Coastguard Worker 37*6dbdd20aSAndroid Build Coastguard Worker // Given a value (identified by the memory buffer starting at `value`, 38*6dbdd20aSAndroid Build Coastguard Worker // `value_size` bytes long) of a specific `type`, finds if there was an 39*6dbdd20aSAndroid Build Coastguard Worker // existing iid associated with it, or assigns a new iid to it. Assigned iids 40*6dbdd20aSAndroid Build Coastguard Worker // are unique for a specific type, but are reused across different types. 41*6dbdd20aSAndroid Build Coastguard Worker struct FindOrAssignRes { 42*6dbdd20aSAndroid Build Coastguard Worker // Iid associated with the passed value. 43*6dbdd20aSAndroid Build Coastguard Worker Iid iid; 44*6dbdd20aSAndroid Build Coastguard Worker // Whether the iid was newly assigned in this call (i.e. true if the value 45*6dbdd20aSAndroid Build Coastguard Worker // was not seen before). 46*6dbdd20aSAndroid Build Coastguard Worker bool newly_assigned; 47*6dbdd20aSAndroid Build Coastguard Worker }; 48*6dbdd20aSAndroid Build Coastguard Worker FindOrAssignRes FindOrAssign(int32_t type, 49*6dbdd20aSAndroid Build Coastguard Worker const void* value, 50*6dbdd20aSAndroid Build Coastguard Worker size_t value_size); 51*6dbdd20aSAndroid Build Coastguard Worker 52*6dbdd20aSAndroid Build Coastguard Worker private: 53*6dbdd20aSAndroid Build Coastguard Worker // Stores a value of a specific type. If the value is small, it is stored 54*6dbdd20aSAndroid Build Coastguard Worker // inline, otherwise it is stored in an external buffer. The Key can own the 55*6dbdd20aSAndroid Build Coastguard Worker // external buffer (when the key is stored in the map) or not (when the key is 56*6dbdd20aSAndroid Build Coastguard Worker // just used for lookup). 57*6dbdd20aSAndroid Build Coastguard Worker class Key { 58*6dbdd20aSAndroid Build Coastguard Worker public: NonOwning(int32_t type,const void * value,size_t value_size)59*6dbdd20aSAndroid Build Coastguard Worker static Key NonOwning(int32_t type, const void* value, size_t value_size) { 60*6dbdd20aSAndroid Build Coastguard Worker Key key; 61*6dbdd20aSAndroid Build Coastguard Worker key.type_ = type; 62*6dbdd20aSAndroid Build Coastguard Worker key.val_type_ = ValueStorage::kNonOwnedPtr; 63*6dbdd20aSAndroid Build Coastguard Worker key.ptr_ = value; 64*6dbdd20aSAndroid Build Coastguard Worker key.value_size_ = value_size; 65*6dbdd20aSAndroid Build Coastguard Worker return key; 66*6dbdd20aSAndroid Build Coastguard Worker } Owning(int32_t type,const void * value,size_t value_size)67*6dbdd20aSAndroid Build Coastguard Worker static Key Owning(int32_t type, const void* value, size_t value_size) { 68*6dbdd20aSAndroid Build Coastguard Worker Key key; 69*6dbdd20aSAndroid Build Coastguard Worker key.type_ = type; 70*6dbdd20aSAndroid Build Coastguard Worker key.value_size_ = value_size; 71*6dbdd20aSAndroid Build Coastguard Worker if (value_size < sizeof(value_buf_)) { 72*6dbdd20aSAndroid Build Coastguard Worker key.val_type_ = ValueStorage::kInline; 73*6dbdd20aSAndroid Build Coastguard Worker memcpy(key.value_buf_, value, value_size); 74*6dbdd20aSAndroid Build Coastguard Worker } else { 75*6dbdd20aSAndroid Build Coastguard Worker key.val_type_ = ValueStorage::kOwnedPtr; 76*6dbdd20aSAndroid Build Coastguard Worker char* newvalue = new char[value_size]; 77*6dbdd20aSAndroid Build Coastguard Worker memcpy(newvalue, value, value_size); 78*6dbdd20aSAndroid Build Coastguard Worker key.owned_ptr_ = newvalue; 79*6dbdd20aSAndroid Build Coastguard Worker } 80*6dbdd20aSAndroid Build Coastguard Worker return key; 81*6dbdd20aSAndroid Build Coastguard Worker } ~Key()82*6dbdd20aSAndroid Build Coastguard Worker ~Key() { 83*6dbdd20aSAndroid Build Coastguard Worker if (val_type_ == ValueStorage::kOwnedPtr) { 84*6dbdd20aSAndroid Build Coastguard Worker delete[] owned_ptr_; 85*6dbdd20aSAndroid Build Coastguard Worker } 86*6dbdd20aSAndroid Build Coastguard Worker } 87*6dbdd20aSAndroid Build Coastguard Worker Key(const Key&) = delete; Key(Key && other)88*6dbdd20aSAndroid Build Coastguard Worker Key(Key&& other) noexcept { 89*6dbdd20aSAndroid Build Coastguard Worker type_ = other.type_; 90*6dbdd20aSAndroid Build Coastguard Worker value_size_ = other.value_size_; 91*6dbdd20aSAndroid Build Coastguard Worker switch (other.val_type_) { 92*6dbdd20aSAndroid Build Coastguard Worker case ValueStorage::kNonOwnedPtr: 93*6dbdd20aSAndroid Build Coastguard Worker val_type_ = ValueStorage::kNonOwnedPtr; 94*6dbdd20aSAndroid Build Coastguard Worker ptr_ = other.ptr_; 95*6dbdd20aSAndroid Build Coastguard Worker return; 96*6dbdd20aSAndroid Build Coastguard Worker case ValueStorage::kOwnedPtr: 97*6dbdd20aSAndroid Build Coastguard Worker val_type_ = ValueStorage::kOwnedPtr; 98*6dbdd20aSAndroid Build Coastguard Worker owned_ptr_ = other.owned_ptr_; 99*6dbdd20aSAndroid Build Coastguard Worker other.val_type_ = ValueStorage::kInline; 100*6dbdd20aSAndroid Build Coastguard Worker other.value_size_ = 0; 101*6dbdd20aSAndroid Build Coastguard Worker return; 102*6dbdd20aSAndroid Build Coastguard Worker case ValueStorage::kInline: 103*6dbdd20aSAndroid Build Coastguard Worker val_type_ = ValueStorage::kInline; 104*6dbdd20aSAndroid Build Coastguard Worker memcpy(value_buf_, other.value_buf_, value_size_); 105*6dbdd20aSAndroid Build Coastguard Worker return; 106*6dbdd20aSAndroid Build Coastguard Worker } 107*6dbdd20aSAndroid Build Coastguard Worker } 108*6dbdd20aSAndroid Build Coastguard Worker bool operator==(const Key& other) const { 109*6dbdd20aSAndroid Build Coastguard Worker if (type_ != other.type_) { 110*6dbdd20aSAndroid Build Coastguard Worker return false; 111*6dbdd20aSAndroid Build Coastguard Worker } 112*6dbdd20aSAndroid Build Coastguard Worker if (value_size_ != other.value_size_) { 113*6dbdd20aSAndroid Build Coastguard Worker return false; 114*6dbdd20aSAndroid Build Coastguard Worker } 115*6dbdd20aSAndroid Build Coastguard Worker return memcmp(value(), other.value(), value_size_) == 0; 116*6dbdd20aSAndroid Build Coastguard Worker } value()117*6dbdd20aSAndroid Build Coastguard Worker const void* value() const { 118*6dbdd20aSAndroid Build Coastguard Worker switch (val_type_) { 119*6dbdd20aSAndroid Build Coastguard Worker case ValueStorage::kNonOwnedPtr: 120*6dbdd20aSAndroid Build Coastguard Worker return ptr_; 121*6dbdd20aSAndroid Build Coastguard Worker case ValueStorage::kOwnedPtr: 122*6dbdd20aSAndroid Build Coastguard Worker return owned_ptr_; 123*6dbdd20aSAndroid Build Coastguard Worker case ValueStorage::kInline: 124*6dbdd20aSAndroid Build Coastguard Worker break; 125*6dbdd20aSAndroid Build Coastguard Worker } 126*6dbdd20aSAndroid Build Coastguard Worker return &value_buf_; 127*6dbdd20aSAndroid Build Coastguard Worker } 128*6dbdd20aSAndroid Build Coastguard Worker struct Hash { operatorHash129*6dbdd20aSAndroid Build Coastguard Worker size_t operator()(const Key& obj) const { 130*6dbdd20aSAndroid Build Coastguard Worker return std::hash<int32_t>()(obj.type_) ^ 131*6dbdd20aSAndroid Build Coastguard Worker static_cast<size_t>(PerfettoFnv1a(obj.value(), obj.value_size_)); 132*6dbdd20aSAndroid Build Coastguard Worker } 133*6dbdd20aSAndroid Build Coastguard Worker }; 134*6dbdd20aSAndroid Build Coastguard Worker 135*6dbdd20aSAndroid Build Coastguard Worker private: 136*6dbdd20aSAndroid Build Coastguard Worker enum class ValueStorage { 137*6dbdd20aSAndroid Build Coastguard Worker kInline, // `value_buf_` is used directly to store the value. 138*6dbdd20aSAndroid Build Coastguard Worker kNonOwnedPtr, // `ptr_` points to an external buffer that stores the 139*6dbdd20aSAndroid Build Coastguard Worker // value. Not owned by this Key. 140*6dbdd20aSAndroid Build Coastguard Worker kOwnedPtr, // `owned_ptr_` points to an external buffer that stores 141*6dbdd20aSAndroid Build Coastguard Worker // the value. Owned by this Key. 142*6dbdd20aSAndroid Build Coastguard Worker }; 143*6dbdd20aSAndroid Build Coastguard Worker Key() = default; 144*6dbdd20aSAndroid Build Coastguard Worker int32_t type_; 145*6dbdd20aSAndroid Build Coastguard Worker ValueStorage val_type_; 146*6dbdd20aSAndroid Build Coastguard Worker size_t value_size_; 147*6dbdd20aSAndroid Build Coastguard Worker union { 148*6dbdd20aSAndroid Build Coastguard Worker char value_buf_[sizeof(uint64_t)]; 149*6dbdd20aSAndroid Build Coastguard Worker const void* ptr_; 150*6dbdd20aSAndroid Build Coastguard Worker char* owned_ptr_; 151*6dbdd20aSAndroid Build Coastguard Worker }; 152*6dbdd20aSAndroid Build Coastguard Worker }; 153*6dbdd20aSAndroid Build Coastguard Worker 154*6dbdd20aSAndroid Build Coastguard Worker base::FlatHashMap<Key, uint64_t, Key::Hash> map_; 155*6dbdd20aSAndroid Build Coastguard Worker base::FlatHashMap<int32_t, uint64_t> last_iid_by_type_; 156*6dbdd20aSAndroid Build Coastguard Worker }; 157*6dbdd20aSAndroid Build Coastguard Worker 158*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto 159*6dbdd20aSAndroid Build Coastguard Worker 160*6dbdd20aSAndroid Build Coastguard Worker #endif // SRC_SHARED_LIB_INTERN_MAP_H_ 161