• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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