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 TryAddSafe(const CString & value,ApEntityId & entryId)97 bool TryAddSafe(const CString& value, ApEntityId& entryId) 98 { 99 WriteLockHolder lock(poolLock_); 100 return TryAdd(value, entryId); 101 } 102 GetEntryId(const CString & value,ApEntityId & entryId)103 bool GetEntryId(const CString &value, ApEntityId &entryId) const 104 { 105 return pool_->GetEntryId(value, entryId); 106 } 107 GetEntryIdSafe(const CString & value,ApEntityId & entryId)108 bool GetEntryIdSafe(const CString& value, ApEntityId& entryId) 109 { 110 ReadLockHolder lock(poolLock_); 111 return GetEntryId(value, entryId); 112 } 113 GetPandaFileDescSafe(ApEntityId abcId,CString & desc)114 bool GetPandaFileDescSafe(ApEntityId abcId, CString& desc) 115 { 116 ReadLockHolder lock(poolLock_); 117 const auto* entry = GetEntry(abcId); 118 if (entry == nullptr) { 119 return false; 120 } 121 desc = entry->GetData(); 122 return true; 123 } 124 GetEntry(ApEntityId entryId)125 const Entry *GetEntry(ApEntityId entryId) const 126 { 127 return pool_->GetEntry(entryId); 128 } 129 GetEntryIdByNormalizedName(const CString & value,ApEntityId & entryId)130 bool GetEntryIdByNormalizedName(const CString &value, ApEntityId &entryId) const 131 { 132 return pool_->GetEntryIdByNormalizedName(value, entryId); 133 } 134 Clear()135 void Clear() 136 { 137 pool_->Clear(); 138 } 139 ClearSafe()140 void ClearSafe() 141 { 142 WriteLockHolder lock(poolLock_); 143 Clear(); 144 } 145 GetPool()146 std::shared_ptr<PoolType> &GetPool() 147 { 148 return pool_; 149 } 150 151 protected: 152 NO_COPY_SEMANTIC(PGOStringPool); 153 NO_MOVE_SEMANTIC(PGOStringPool); 154 std::shared_ptr<PoolType> pool_; 155 RWLock poolLock_; 156 }; 157 158 class PGORecordPool : public PGOFileSectionInterface { 159 public: 160 PGORecordPool() = default; Support(PGOProfilerHeader const * header)161 bool Support(PGOProfilerHeader const *header) const override 162 { 163 return header->SupportRecordPool(); 164 } 165 GetSection(PGOProfilerHeader const * header)166 SectionInfo *GetSection(PGOProfilerHeader const *header) const override 167 { 168 return header->GetRecordPoolSection(); 169 } 170 ProcessToBinary(PGOContext & context,std::fstream & stream)171 uint32_t ProcessToBinary(PGOContext &context, std::fstream &stream) override 172 { 173 LOG_ECMA(DEBUG) << "[PGORecordPool] ProcessToBinary, count: " << pool_.size(); 174 SectionInfo secInfo; 175 secInfo.number_ = pool_.size(); 176 secInfo.offset_ = sizeof(SectionInfo); 177 auto secInfoPos = stream.tellp(); 178 stream.seekp(secInfo.offset_, std::ofstream::cur); 179 for (auto &entry : pool_) { 180 ProfileTypeRef profileTypeRef(context, entry.first); 181 stream.write(reinterpret_cast<const char *>(&(profileTypeRef)), sizeof(ApEntityId)); 182 stream.write(entry.second.c_str(), entry.second.length() + 1); 183 } 184 secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos); 185 auto tail = stream.tellp(); 186 stream.seekp(secInfoPos, std::ofstream::beg); 187 stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo)); 188 stream.seekp(tail, std::ofstream::beg); 189 return 1; 190 } 191 ParseFromBinary(PGOContext & context,void ** buffer,PGOProfilerHeader const * header)192 uint32_t ParseFromBinary(PGOContext &context, void **buffer, 193 [[maybe_unused]] PGOProfilerHeader const *header) override 194 { 195 auto secInfo = base::ReadBuffer<SectionInfo>(buffer); 196 for (uint32_t i = 0; i < secInfo.number_; i++) { 197 ProfileTypeRef profileTypeRef(base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId))); 198 ProfileType profileType(context, profileTypeRef); 199 pool_.try_emplace(profileType, base::ReadBuffer(buffer)); 200 } 201 return 1; 202 } 203 ProcessToText(std::ofstream & stream)204 bool ProcessToText(std::ofstream &stream) override 205 { 206 bool isFirst = true; 207 for (auto &entry : pool_) { 208 if (isFirst) { 209 stream << DumpUtils::NEW_LINE; 210 stream << "RecordPool"; 211 stream << DumpUtils::BLOCK_START; 212 isFirst = false; 213 } 214 stream << DumpUtils::NEW_LINE; 215 stream << entry.first.GetTypeString(); 216 stream << DumpUtils::SPACE; 217 stream << DumpUtils::ARRAY_START; 218 stream << entry.second; 219 stream << DumpUtils::ARRAY_END; 220 } 221 if (!isFirst) { 222 stream << (DumpUtils::SPACE + DumpUtils::NEW_LINE); 223 } 224 return true; 225 } 226 Merge(const PGORecordPool & recordPool)227 void Merge(const PGORecordPool &recordPool) 228 { 229 for (const auto &entry : recordPool.pool_) { 230 Add(ProfileType(entry.first), entry.second); 231 } 232 } 233 Add(ProfileType profileType,const CString & recordName)234 void Add(ProfileType profileType, const CString &recordName) 235 { 236 ASSERT(profileType.GetKind() == ProfileType::Kind::RecordClassId); 237 auto result = pool_.try_emplace(profileType, recordName); 238 if (result.second) { 239 LOG_ECMA(DEBUG) << "Add Record. profile: " << profileType.GetTypeString() << ", recordName: " << recordName; 240 } 241 } 242 GetName(ProfileType profileType)243 const char *GetName(ProfileType profileType) const 244 { 245 auto iter = pool_.find(profileType); 246 if (iter == pool_.end()) { 247 return ""; 248 } 249 return iter->second.c_str(); 250 } 251 Clear()252 void Clear() 253 { 254 pool_.clear(); 255 } 256 257 private: 258 std::unordered_map<ProfileType, CString, HashProfileType> pool_; 259 }; 260 261 class PGOAbcFilePool : public PGOStringPool { 262 public: 263 enum class ReservedType : uint8_t { EMPTY_ABC_FILE_ID = 0, END }; 264 static constexpr uint32_t RESERVED_COUNT = 64; 265 static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT); 266 IsReserved(const CString & value)267 static bool IsReserved(const CString &value) 268 { 269 return value.empty(); 270 } 271 GetReservedId(const CString & value)272 static ApEntityId GetReservedId([[maybe_unused]] const CString &value) 273 { 274 ASSERT(value.empty()); 275 return ApEntityId(static_cast<uint32_t>(ReservedType::EMPTY_ABC_FILE_ID)); 276 } 277 Support(PGOProfilerHeader const * header)278 static bool Support(PGOProfilerHeader const *header) 279 { 280 return header->SupportProfileTypeWithAbcId(); 281 } 282 GetSection(PGOProfilerHeader const * header)283 static SectionInfo *GetSection(PGOProfilerHeader const *header) 284 { 285 return header->GetAbcFilePoolSection(); 286 } 287 PGOAbcFilePool()288 PGOAbcFilePool() : PGOStringPool("AbcFilePool", RESERVED_COUNT) 289 { 290 pool_->SetIsReservedCb(IsReserved); 291 pool_->SetGetReservedIdCb(GetReservedId); 292 pool_->SetGetSectionCb(GetSection); 293 pool_->SetSupportCb(Support); 294 } 295 Merge(const PGOContext & context,PGOAbcFilePool & pool)296 void Merge(const PGOContext &context, PGOAbcFilePool &pool) 297 { 298 if (pool.GetPool() == nullptr) { 299 return; 300 } 301 pool_->Merge(*pool.GetPool(), [&](ApEntityId oldEntryId, ApEntityId newEntryId) { 302 context.AddAbcIdRemap(oldEntryId, newEntryId); 303 }); 304 } 305 Copy(const std::shared_ptr<PGOAbcFilePool> & pool)306 void Copy(const std::shared_ptr<PGOAbcFilePool> &pool) 307 { 308 for (auto &entry : pool->GetPool()->GetPool()) { 309 auto emplacedEntry = GetPool()->GetPool().try_emplace(entry.first, entry.second.GetData()); 310 emplacedEntry.first->second.SetEntryId(entry.first); 311 GetPool()->GetValueToId().try_emplace(entry.second.GetData(), entry.first); 312 } 313 } 314 CopySafe(const std::shared_ptr<PGOAbcFilePool> & pool)315 void CopySafe(const std::shared_ptr<PGOAbcFilePool>& pool) 316 { 317 WriteLockHolder lock(poolLock_); 318 Copy(pool); 319 } 320 }; 321 } // namespace panda::ecmascript::pgo 322 #endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H 323