1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H 17 #define ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H 18 19 #include <cstdint> 20 #include <fstream> 21 #include <unordered_map> 22 #include <memory> 23 24 #include "ecmascript/common.h" 25 #include "ecmascript/log.h" 26 #include "ecmascript/log_wrapper.h" 27 #include "ecmascript/mem/c_string.h" 28 #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h" 29 #include "ecmascript/pgo_profiler/ap_file/pool_template.h" 30 #include "ecmascript/pgo_profiler/pgo_utils.h" 31 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h" 32 #include "macros.h" 33 34 namespace panda::ecmascript::pgo { 35 class PGOProfilerHeader; 36 37 class PGOStringPool { 38 public: 39 class Entry : public PGOFileDataInterface { 40 public: Entry(CString name)41 explicit Entry(CString name) : name_(std::move(name)) {} 42 Entry() = default; GetEntryId()43 ApEntityId GetEntryId() const 44 { 45 return entryId_; 46 } 47 SetEntryId(ApEntityId entryId)48 void SetEntryId(ApEntityId entryId) 49 { 50 entryId_ = entryId; 51 } 52 GetData()53 const CString &GetData() const 54 { 55 return name_; 56 } 57 ProcessToBinary(PGOContext & context,std::fstream & stream)58 uint32_t ProcessToBinary([[maybe_unused]] PGOContext &context, std::fstream &stream) override 59 { 60 stream << name_ << '\0'; 61 return 1; 62 } 63 ParseFromBinary(PGOContext & context,void ** buffer,PGOProfilerHeader const * header)64 uint32_t ParseFromBinary([[maybe_unused]] PGOContext &context, void **buffer, 65 [[maybe_unused]] PGOProfilerHeader const *header) override 66 { 67 name_ = base::ReadBuffer(buffer); 68 return 1; 69 } 70 ProcessToText(std::ofstream & stream)71 bool ProcessToText(std::ofstream &stream) override 72 { 73 stream << name_; 74 return true; 75 } 76 77 private: 78 ApEntityId entryId_ {0}; 79 CString name_; 80 }; 81 using PoolType = PoolTemplate<Entry, CString>; 82 PGOStringPool(const std::string & poolName,uint32_t reservedCount)83 PGOStringPool(const std::string &poolName, uint32_t reservedCount) 84 { 85 pool_ = std::make_shared<PoolType>(poolName, reservedCount); 86 }; ~PGOStringPool()87 ~PGOStringPool() 88 { 89 Clear(); 90 } 91 TryAdd(const CString & value,ApEntityId & entryId)92 bool TryAdd(const CString &value, ApEntityId &entryId) 93 { 94 return pool_->TryAdd(value, entryId); 95 } 96 GetEntryId(const CString & value,ApEntityId & entryId)97 bool GetEntryId(const CString &value, ApEntityId &entryId) const 98 { 99 return pool_->GetEntryId(value, entryId); 100 } 101 GetEntry(ApEntityId entryId)102 const Entry *GetEntry(ApEntityId entryId) const 103 { 104 return pool_->GetEntry(entryId); 105 } 106 GetEntryIdByNormalizedName(const CString & value,ApEntityId & entryId)107 bool GetEntryIdByNormalizedName(const CString &value, ApEntityId &entryId) const 108 { 109 return pool_->GetEntryIdByNormalizedName(value, entryId); 110 } 111 Clear()112 void Clear() 113 { 114 pool_->Clear(); 115 } 116 GetPool()117 std::shared_ptr<PoolType> &GetPool() 118 { 119 return pool_; 120 } 121 122 protected: 123 NO_COPY_SEMANTIC(PGOStringPool); 124 NO_MOVE_SEMANTIC(PGOStringPool); 125 std::shared_ptr<PoolType> pool_; 126 }; 127 128 class PGORecordPool : public PGOFileSectionInterface { 129 public: 130 PGORecordPool() = default; Support(PGOProfilerHeader const * header)131 bool Support(PGOProfilerHeader const *header) const override 132 { 133 return header->SupportRecordPool(); 134 } 135 GetSection(PGOProfilerHeader const * header)136 SectionInfo *GetSection(PGOProfilerHeader const *header) const override 137 { 138 return header->GetRecordPoolSection(); 139 } 140 ProcessToBinary(PGOContext & context,std::fstream & stream)141 uint32_t ProcessToBinary(PGOContext &context, std::fstream &stream) override 142 { 143 LOG_ECMA(DEBUG) << "[PGORecordPool] ProcessToBinary, count: " << pool_.size(); 144 SectionInfo secInfo; 145 secInfo.number_ = pool_.size(); 146 secInfo.offset_ = sizeof(SectionInfo); 147 auto secInfoPos = stream.tellp(); 148 stream.seekp(secInfo.offset_, std::ofstream::cur); 149 for (auto &entry : pool_) { 150 ProfileTypeRef profileTypeRef(context, entry.first); 151 stream.write(reinterpret_cast<const char *>(&(profileTypeRef)), sizeof(ApEntityId)); 152 stream.write(entry.second.c_str(), entry.second.length() + 1); 153 } 154 secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos); 155 auto tail = stream.tellp(); 156 stream.seekp(secInfoPos, std::ofstream::beg); 157 stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo)); 158 stream.seekp(tail, std::ofstream::beg); 159 return 1; 160 } 161 ParseFromBinary(PGOContext & context,void ** buffer,PGOProfilerHeader const * header)162 uint32_t ParseFromBinary(PGOContext &context, void **buffer, 163 [[maybe_unused]] PGOProfilerHeader const *header) override 164 { 165 auto secInfo = base::ReadBuffer<SectionInfo>(buffer); 166 for (uint32_t i = 0; i < secInfo.number_; i++) { 167 ProfileTypeRef profileTypeRef(base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId))); 168 ProfileType profileType(context, profileTypeRef); 169 pool_.try_emplace(profileType, base::ReadBuffer(buffer)); 170 } 171 return 1; 172 } 173 ProcessToText(std::ofstream & stream)174 bool ProcessToText(std::ofstream &stream) override 175 { 176 bool isFirst = true; 177 for (auto &entry : pool_) { 178 if (isFirst) { 179 stream << DumpUtils::NEW_LINE; 180 stream << "RecordPool"; 181 stream << DumpUtils::BLOCK_START; 182 isFirst = false; 183 } 184 stream << DumpUtils::NEW_LINE; 185 stream << entry.first.GetTypeString(); 186 stream << DumpUtils::SPACE; 187 stream << DumpUtils::ARRAY_START; 188 stream << entry.second; 189 stream << DumpUtils::ARRAY_END; 190 } 191 if (!isFirst) { 192 stream << (DumpUtils::SPACE + DumpUtils::NEW_LINE); 193 } 194 return true; 195 } 196 Merge(const PGORecordPool & recordPool)197 void Merge(const PGORecordPool &recordPool) 198 { 199 for (const auto &entry : recordPool.pool_) { 200 Add(ProfileType(entry.first), entry.second); 201 } 202 } 203 Add(ProfileType profileType,const CString & recordName)204 void Add(ProfileType profileType, const CString &recordName) 205 { 206 ASSERT(profileType.GetKind() == ProfileType::Kind::RecordClassId); 207 auto result = pool_.try_emplace(profileType, recordName); 208 if (result.second) { 209 LOG_ECMA(DEBUG) << "Add Record. profile: " << profileType.GetTypeString() << ", recordName: " << recordName; 210 } 211 } 212 GetName(ProfileType profileType)213 const char *GetName(ProfileType profileType) const 214 { 215 auto iter = pool_.find(profileType); 216 if (iter == pool_.end()) { 217 return ""; 218 } 219 return iter->second.c_str(); 220 } 221 Clear()222 void Clear() 223 { 224 pool_.clear(); 225 } 226 227 private: 228 std::unordered_map<ProfileType, CString, HashProfileType> pool_; 229 }; 230 231 class PGOAbcFilePool : public PGOStringPool { 232 public: 233 enum class ReservedType : uint8_t { EMPTY_ABC_FILE_ID = 0, END }; 234 static constexpr uint32_t RESERVED_COUNT = 64; 235 static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT); 236 IsReserved(const CString & value)237 static bool IsReserved(const CString &value) 238 { 239 return value.empty(); 240 } 241 GetReservedId(const CString & value)242 static ApEntityId GetReservedId([[maybe_unused]] const CString &value) 243 { 244 ASSERT(value.empty()); 245 return ApEntityId(static_cast<uint32_t>(ReservedType::EMPTY_ABC_FILE_ID)); 246 } 247 Support(PGOProfilerHeader const * header)248 static bool Support(PGOProfilerHeader const *header) 249 { 250 return header->SupportProfileTypeWithAbcId(); 251 } 252 GetSection(PGOProfilerHeader const * header)253 static SectionInfo *GetSection(PGOProfilerHeader const *header) 254 { 255 return header->GetAbcFilePoolSection(); 256 } 257 PGOAbcFilePool()258 PGOAbcFilePool() : PGOStringPool("AbcFilePool", RESERVED_COUNT) 259 { 260 pool_->SetIsReservedCb(IsReserved); 261 pool_->SetGetReservedIdCb(GetReservedId); 262 pool_->SetGetSectionCb(GetSection); 263 pool_->SetSupportCb(Support); 264 } 265 Merge(const PGOContext & context,PGOAbcFilePool & pool)266 void Merge(const PGOContext &context, PGOAbcFilePool &pool) 267 { 268 if (pool.GetPool() == nullptr) { 269 return; 270 } 271 pool_->Merge(*pool.GetPool(), [&](ApEntityId oldEntryId, ApEntityId newEntryId) { 272 context.AddAbcIdRemap(oldEntryId, newEntryId); 273 }); 274 } 275 Copy(const std::shared_ptr<PGOAbcFilePool> & pool)276 void Copy(const std::shared_ptr<PGOAbcFilePool> &pool) 277 { 278 for (auto &entry : pool->GetPool()->GetPool()) { 279 auto emplacedEntry = GetPool()->GetPool().try_emplace(entry.first, entry.second.GetData()); 280 emplacedEntry.first->second.SetEntryId(entry.first); 281 GetPool()->GetValueToId().try_emplace(entry.second.GetData(), entry.first); 282 } 283 } 284 }; 285 286 } // namespace panda::ecmascript::pgo 287 #endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H 288