1 /* 2 * Copyright (c) 2023-2024 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_POOL_TEMPLATE_H 17 #define ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H 18 19 #include <cstdint> 20 #include <fstream> 21 #include <unordered_map> 22 #include <utility> 23 24 #include "ecmascript/common.h" 25 #include "ecmascript/jspandafile/js_pandafile.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/pgo_utils.h" 30 #include "macros.h" 31 32 namespace panda::ecmascript::pgo { 33 template <typename Entry, typename V> 34 class PoolTemplate : public PGOFileSectionInterface { 35 public: 36 using IsReservedCb = std::function<bool(const V &value)>; 37 using GetReservedIdCb = std::function<ApEntityId(const V &value)>; 38 39 using SupportCb = std::function<bool(PGOProfilerHeader const *header)>; 40 using GetSectionCb = std::function<SectionInfo *(PGOProfilerHeader const *header)>; 41 PoolTemplate(std::string poolName, uint32_t reservedCount)42 PoolTemplate(std::string poolName, uint32_t reservedCount) 43 : poolName_(std::move(poolName)), RESERVED_COUNT(reservedCount) {}; 44 45 ~PoolTemplate() override 46 { 47 Clear(); 48 } 49 TryAdd(const V &value, ApEntityId &entryId)50 bool TryAdd(const V &value, ApEntityId &entryId) 51 { 52 auto it = valueToId_.find(value); 53 if (it != valueToId_.end()) { 54 entryId = it->second; 55 return true; 56 } 57 58 entryId = ApEntityId(IsReserved(value) ? (++reservedUsed_, GetReservedId(value)) 59 : RESERVED_COUNT + pool_.size() - reservedUsed_); 60 61 auto result = pool_.emplace(entryId, value); 62 valueToId_.emplace(value, entryId); 63 auto &entry = result.first->second; 64 entry.SetEntryId(entryId); 65 return true; 66 } 67 GetEntryId(const V &value, ApEntityId &entryId) const68 bool GetEntryId(const V &value, ApEntityId &entryId) const 69 { 70 for (const auto &entry : pool_) { 71 if (entry.second.GetData() == value) { 72 entryId = entry.first; 73 return true; 74 } 75 } 76 return false; 77 } 78 GetEntry(ApEntityId id) const79 const Entry *GetEntry(ApEntityId id) const 80 { 81 auto iter = pool_.find(id); 82 if (iter == pool_.end()) { 83 return nullptr; 84 } 85 return &(iter->second); 86 } 87 GetEntryIdByNormalizedName(const V &value, ApEntityId &entryId) const88 bool GetEntryIdByNormalizedName(const V &value, ApEntityId &entryId) const 89 { 90 for (const auto &entry : pool_) { 91 if (JSPandaFile::GetNormalizedFileDesc(entry.second.GetData()) == value) { 92 entryId = entry.first; 93 return true; 94 } 95 } 96 return false; 97 } 98 Clear()99 void Clear() 100 { 101 pool_.clear(); 102 valueToId_.clear(); 103 reservedUsed_ = 0; 104 } 105 Empty() const106 bool Empty() const 107 { 108 return pool_.empty(); 109 } 110 Merge(const PoolTemplate &pool, const std::function<void(ApEntityId, ApEntityId)> &callback)111 void Merge(const PoolTemplate &pool, const std::function<void(ApEntityId, ApEntityId)> &callback) 112 { 113 for (const auto &entry : pool.pool_) { 114 ApEntityId newId(0); 115 TryAdd(entry.second.GetData(), newId); 116 if (callback != nullptr) { 117 callback(entry.first, newId); 118 } 119 } 120 } 121 122 uint32_t ProcessToBinary([[maybe_unused]] PGOContext &context, std::fstream &stream) override 123 { 124 LOG_ECMA(DEBUG) << "ProcessToBinary. name: " << poolName_ << ", count: " << pool_.size(); 125 SectionInfo secInfo; 126 secInfo.number_ = pool_.size(); 127 secInfo.offset_ = sizeof(SectionInfo); 128 auto secInfoPos = stream.tellp(); 129 stream.seekp(secInfo.offset_, std::ofstream::cur); 130 for (auto &entry : pool_) { 131 stream.write(reinterpret_cast<const char *>(&(entry.first)), sizeof(ApEntityId)); 132 entry.second.ProcessToBinary(context, stream); 133 } 134 secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos); 135 auto tail = stream.tellp(); 136 stream.seekp(secInfoPos, std::ofstream::beg); 137 stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo)); 138 stream.seekp(tail, std::ofstream::beg); 139 return 1; 140 } 141 142 bool ProcessToText(std::ofstream &stream) override 143 { 144 bool isFirst = true; 145 for (auto &entry : pool_) { 146 if (isFirst) { 147 stream << DumpUtils::NEW_LINE; 148 stream << poolName_; 149 stream << DumpUtils::BLOCK_START; 150 isFirst = false; 151 } 152 stream << DumpUtils::NEW_LINE; 153 stream << std::to_string(entry.first); 154 stream << DumpUtils::SPACE; 155 stream << DumpUtils::ARRAY_START; 156 entry.second.ProcessToText(stream); 157 stream << DumpUtils::ARRAY_END; 158 } 159 if (!isFirst) { 160 stream << (DumpUtils::SPACE + DumpUtils::NEW_LINE); 161 } 162 return true; 163 } 164 ProcessToJson(std::vector<ProfileType::StringMap> &abcPoolArray)165 void ProcessToJson(std::vector<ProfileType::StringMap> &abcPoolArray) 166 { 167 for (auto &entry : pool_) { 168 ProfileType::StringMap abcPool; 169 abcPool.insert(std::make_pair(DumpJsonUtils::ABC_ID, std::to_string(entry.first))); 170 abcPool.insert(std::make_pair(DumpJsonUtils::ABC_FILE, entry.second.GetData())); 171 abcPoolArray.push_back(abcPool); 172 } 173 } 174 uint32_t ParseFromBinary([[maybe_unused]] PGOContext &context, void **buffer, 175 PGOProfilerHeader const *header) override 176 { 177 auto secInfo = base::ReadBuffer<SectionInfo>(buffer); 178 for (uint32_t i = 0; i < secInfo.number_; i++) { 179 auto entryId = base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId)); 180 auto result = pool_.try_emplace(entryId); 181 result.first->second.SetEntryId(entryId); 182 result.first->second.ParseFromBinary(context, buffer, header); 183 } 184 return 1; 185 } 186 SetIsReservedCb(const IsReservedCb &isReservedCb)187 void SetIsReservedCb(const IsReservedCb &isReservedCb) 188 { 189 isReservedCb_ = isReservedCb; 190 } 191 SetGetReservedIdCb(const GetReservedIdCb &getReservedIdCb)192 void SetGetReservedIdCb(const GetReservedIdCb &getReservedIdCb) 193 { 194 getReservedIdCb_ = getReservedIdCb; 195 } 196 SetSupportCb(const SupportCb &supportCb)197 void SetSupportCb(const SupportCb &supportCb) 198 { 199 supportCb_ = supportCb; 200 } 201 SetGetSectionCb(const GetSectionCb &getSectionCb)202 void SetGetSectionCb(const GetSectionCb &getSectionCb) 203 { 204 getSectionCb_ = getSectionCb; 205 } 206 GetPool()207 std::unordered_map<ApEntityId, Entry> &GetPool() 208 { 209 return pool_; 210 } 211 GetValueToId()212 std::unordered_map<V, ApEntityId> &GetValueToId() 213 { 214 return valueToId_; 215 } 216 217 private: 218 NO_COPY_SEMANTIC(PoolTemplate); 219 NO_MOVE_SEMANTIC(PoolTemplate); 220 221 bool Support(PGOProfilerHeader const *header) const override 222 { 223 return supportCb_(header); 224 } 225 226 SectionInfo *GetSection(PGOProfilerHeader const *header) const override 227 { 228 return getSectionCb_(header); 229 } 230 IsReserved(const V &value)231 bool IsReserved(const V &value) 232 { 233 return isReservedCb_(value); 234 } 235 GetReservedId(const V &value)236 ApEntityId GetReservedId(const V &value) 237 { 238 return getReservedIdCb_(value); 239 } 240 241 const std::string poolName_; 242 const uint32_t RESERVED_COUNT {}; 243 uint32_t reservedUsed_ {0}; 244 245 IsReservedCb isReservedCb_; 246 GetReservedIdCb getReservedIdCb_; 247 SupportCb supportCb_; 248 GetSectionCb getSectionCb_; 249 std::unordered_map<ApEntityId, Entry> pool_; 250 std::unordered_map<V, ApEntityId> valueToId_; 251 }; 252 } // namespace panda::ecmascript::pgo 253 254 namespace std { 255 using panda::ecmascript::pgo::ProfileType; 256 template<> 257 struct hash<ProfileType> { 258 size_t operator()(const ProfileType& type) const noexcept 259 { 260 return type.GetRaw(); 261 } 262 }; 263 } // namespace std 264 #endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H 265