mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
!4898 Save abcId in ProfileType
Merge pull request !4898 from hzzhouzebin/SaveAbcIdInProfileType
This commit is contained in:
commit
4906107bce
@ -370,7 +370,8 @@ std::shared_ptr<JSPandaFile> JSPandaFileManager::OpenJSPandaFileFromBuffer(uint8
|
||||
std::shared_ptr<JSPandaFile> JSPandaFileManager::NewJSPandaFile(const panda_file::File *pf, const CString &desc)
|
||||
{
|
||||
std::shared_ptr<JSPandaFile> jsPandaFile = std::make_shared<JSPandaFile>(pf, desc);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(jsPandaFile->GetChecksum());
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(jsPandaFile->GetChecksum(),
|
||||
jsPandaFile->GetJSPandaFileDesc());
|
||||
return jsPandaFile;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "ecmascript/patch/quick_fix_manager.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler.h"
|
||||
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "libpandafile/class_data_accessor-inl.h"
|
||||
#include "libpandafile/index_accessor.h"
|
||||
|
||||
@ -312,7 +314,11 @@ public:
|
||||
JSObject::DefinePropertyByLiteral(thread, obj, key, valueHandle);
|
||||
}
|
||||
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(obj.GetTaggedType(), id.GetOffset());
|
||||
pgo::ApEntityId abcId(0);
|
||||
pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(jsPandaFile->GetJSPandaFileDesc(),
|
||||
abcId);
|
||||
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(obj.GetTaggedType(), abcId,
|
||||
id.GetOffset());
|
||||
}
|
||||
val = obj.GetTaggedValue();
|
||||
break;
|
||||
|
@ -3692,6 +3692,7 @@ std::string JSNApi::GetBundleName(EcmaVM *vm)
|
||||
void JSNApi::SetModuleName(EcmaVM *vm, const std::string &moduleName)
|
||||
{
|
||||
ecmascript::CString name = moduleName.c_str();
|
||||
ecmascript::pgo::PGOProfilerManager::GetInstance()->SetModuleName(moduleName);
|
||||
vm->SetModuleName(name);
|
||||
}
|
||||
|
||||
|
@ -102,16 +102,18 @@ public:
|
||||
static constexpr VersionType ELEMENTS_KIND_MINI_VERSION = {0, 0, 0, 8};
|
||||
static constexpr VersionType RECORD_POOL_MINI_VERSION = {0, 0, 0, 9};
|
||||
static constexpr VersionType WIDE_CLASS_TYPE_MINI_VERSION = {0, 0, 0, 10};
|
||||
static constexpr VersionType PROFILE_TYPE_WITH_ABC_ID_MINI_VERSION = {0, 0, 0, 11};
|
||||
static constexpr VersionType FILE_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
|
||||
static constexpr VersionType HEADER_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
|
||||
static constexpr VersionType ELASTIC_HEADER_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
|
||||
static constexpr VersionType LAST_VERSION = {0, 0, 0, 10};
|
||||
static constexpr size_t SECTION_SIZE = 5;
|
||||
static constexpr VersionType LAST_VERSION = {0, 0, 0, 11};
|
||||
static constexpr size_t SECTION_SIZE = 6;
|
||||
static constexpr size_t PANDA_FILE_SECTION_INDEX = 0;
|
||||
static constexpr size_t RECORD_INFO_SECTION_INDEX = 1;
|
||||
static constexpr size_t LAYOUT_DESC_SECTION_INDEX = 2;
|
||||
static constexpr size_t RECORD_POOL_SECTION_INDEX = 3;
|
||||
static constexpr size_t CLASS_TYPE_POOL_SECTION_INDEX = 4;
|
||||
static constexpr size_t ABC_FILE_POOL_SECTION_INDEX = 5;
|
||||
|
||||
PGOProfilerHeader() : base::FileHeaderElastic(LAST_VERSION), sectionNumber_(SECTION_SIZE)
|
||||
{
|
||||
@ -203,6 +205,11 @@ public:
|
||||
return GetSectionInfo(CLASS_TYPE_POOL_SECTION_INDEX);
|
||||
}
|
||||
|
||||
SectionInfo *GetAbcFilePoolSection() const
|
||||
{
|
||||
return GetSectionInfo(ABC_FILE_POOL_SECTION_INDEX);
|
||||
}
|
||||
|
||||
bool SupportType() const
|
||||
{
|
||||
return CompatibleVerify(TYPE_MINI_VERSION);
|
||||
@ -253,6 +260,11 @@ public:
|
||||
return CompatibleVerify(WIDE_CLASS_TYPE_MINI_VERSION);
|
||||
}
|
||||
|
||||
bool SupportProfileTypeWithAbcId() const
|
||||
{
|
||||
return CompatibleVerify(PROFILE_TYPE_WITH_ABC_ID_MINI_VERSION);
|
||||
}
|
||||
|
||||
NO_COPY_SEMANTIC(PGOProfilerHeader);
|
||||
NO_MOVE_SEMANTIC(PGOProfilerHeader);
|
||||
|
||||
@ -293,7 +305,7 @@ public:
|
||||
PGOFileDataInterface() = default;
|
||||
virtual ~PGOFileDataInterface() = default;
|
||||
virtual uint32_t ProcessToBinary(std::fstream &stream) = 0;
|
||||
virtual uint32_t ParseFromBinary(void **buffer, PGOProfilerHeader *const header) = 0;
|
||||
virtual uint32_t ParseFromBinary(void **buffer, PGOProfilerHeader const *header) = 0;
|
||||
virtual bool ProcessToText(std::ofstream &stream) = 0;
|
||||
// not support yet
|
||||
virtual bool ParseFromText([[maybe_unused]] std::ifstream &stream)
|
||||
@ -305,5 +317,43 @@ private:
|
||||
NO_COPY_SEMANTIC(PGOFileDataInterface);
|
||||
NO_MOVE_SEMANTIC(PGOFileDataInterface);
|
||||
};
|
||||
|
||||
class PGOFileSectionInterface : public PGOFileDataInterface {
|
||||
public:
|
||||
PGOFileSectionInterface() = default;
|
||||
~PGOFileSectionInterface() override = default;
|
||||
virtual bool Support(PGOProfilerHeader const *header) const = 0;
|
||||
virtual SectionInfo *GetSection(PGOProfilerHeader const *header) const = 0;
|
||||
|
||||
static bool ParseSectionFromBinary(void *buffer, PGOProfilerHeader const *header, PGOFileSectionInterface §ion)
|
||||
{
|
||||
if (section.Support(header)) {
|
||||
SectionInfo *info = section.GetSection(header);
|
||||
if (info == nullptr) {
|
||||
return false;
|
||||
}
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
section.ParseFromBinary(&addr, header);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ProcessSectionToBinary(std::fstream &fileStream, PGOProfilerHeader *const header,
|
||||
PGOFileSectionInterface §ion)
|
||||
{
|
||||
auto *info = section.GetSection(header);
|
||||
if (info == nullptr) {
|
||||
return false;
|
||||
}
|
||||
info->offset_ = static_cast<uint32_t>(fileStream.tellp());
|
||||
info->number_ = section.ProcessToBinary(fileStream);
|
||||
info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(PGOFileSectionInterface);
|
||||
NO_MOVE_SEMANTIC(PGOFileSectionInterface);
|
||||
};
|
||||
} // namespace panda::ecmascript::pgo
|
||||
#endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_BASE_INFO_H
|
@ -102,7 +102,7 @@ bool PGOMethodTypeSet::ProcessToBinary(PGOContext &context, std::stringstream &s
|
||||
}
|
||||
}
|
||||
|
||||
for (auto typeInfo : objDefOpTypeInfos_) {
|
||||
for (const auto &typeInfo : objDefOpTypeInfos_) {
|
||||
ObjDefOpTypeInfoRef infoRef(typeInfo.GetOffset(),
|
||||
PGOSampleTypeRef::ConvertFrom(context, typeInfo.GetType()),
|
||||
PGOSampleTypeRef::ConvertFrom(context, typeInfo.GetSuperType()));
|
||||
|
@ -18,180 +18,152 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "ecmascript/common.h"
|
||||
#include "ecmascript/log.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/mem/mem.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pool_template.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
class PGOProfileTypePool : public PGOFileDataInterface {
|
||||
class PGOProfileTypePool {
|
||||
public:
|
||||
class Entry {
|
||||
class Entry : public PGOFileDataInterface {
|
||||
public:
|
||||
explicit Entry(ProfileType type) : type_(type) {}
|
||||
Entry() = default;
|
||||
ApEntityId GetEntryId() const
|
||||
{
|
||||
return id_;
|
||||
return entryId_;
|
||||
}
|
||||
|
||||
void SetId(ApEntityId id)
|
||||
void SetEntryId(ApEntityId entryId)
|
||||
{
|
||||
id_ = id;
|
||||
entryId_ = entryId;
|
||||
}
|
||||
|
||||
const ProfileType &GetProfileType() const
|
||||
ProfileType GetProfileType() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
const ProfileType &GetData() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
uint32_t ProcessToBinary(std::fstream &stream) override
|
||||
{
|
||||
auto profileType = type_.GetRaw();
|
||||
stream.write(reinterpret_cast<const char *>(&(profileType)), sizeof(ProfileType));
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t ParseFromBinary(void **buffer, [[maybe_unused]] PGOProfilerHeader const *header) override
|
||||
{
|
||||
type_ = base::ReadBuffer<ProfileType>(buffer, sizeof(ProfileType));
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ProcessToText(std::ofstream &stream) override
|
||||
{
|
||||
stream << type_.GetTypeString();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ApEntityId id_ {};
|
||||
ApEntityId entryId_ {0};
|
||||
ProfileType type_;
|
||||
};
|
||||
|
||||
enum class ReservedType : uint8_t {
|
||||
NONE_CLASS_TYPE_REF = 0,
|
||||
END
|
||||
};
|
||||
using PoolType = PoolTemplate<Entry, ProfileType>;
|
||||
|
||||
enum class ReservedType : uint8_t { NONE_CLASS_TYPE_REF = 0, END };
|
||||
static constexpr uint32_t RESERVED_COUNT = 64;
|
||||
|
||||
static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT);
|
||||
|
||||
PGOProfileTypePool() = default;
|
||||
~PGOProfileTypePool() override
|
||||
static bool IsReserved(const ProfileType &value)
|
||||
{
|
||||
return value.IsNone();
|
||||
}
|
||||
|
||||
static ApEntityId GetReservedId([[maybe_unused]] const ProfileType &value)
|
||||
{
|
||||
ASSERT(value.IsNone());
|
||||
return ApEntityId(static_cast<uint32_t>(ReservedType::NONE_CLASS_TYPE_REF));
|
||||
}
|
||||
|
||||
static bool Support(PGOProfilerHeader const *header)
|
||||
{
|
||||
return header->SupportWideProfileType();
|
||||
}
|
||||
|
||||
static SectionInfo *GetSection(PGOProfilerHeader const *header)
|
||||
{
|
||||
return header->GetProfileTypeSection();
|
||||
}
|
||||
|
||||
PGOProfileTypePool()
|
||||
{
|
||||
pool_ = std::make_shared<PoolType>("ProfileTypePool", RESERVED_COUNT);
|
||||
pool_->SetIsReservedCb(IsReserved);
|
||||
pool_->SetGetReservedIdCb(GetReservedId);
|
||||
pool_->SetGetSectionCb(GetSection);
|
||||
pool_->SetSupportCb(Support);
|
||||
}
|
||||
~PGOProfileTypePool()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool TryAdd(const ProfileType &profileType, ApEntityId &id)
|
||||
bool TryAdd(const ProfileType &profileType, ApEntityId &entryId)
|
||||
{
|
||||
for (auto &record : pool_) {
|
||||
if (record.second.GetProfileType() == profileType) {
|
||||
id = record.second.GetEntryId();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
id = ApEntityId(IsReserved(profileType) ? GetReservedId(profileType).GetOffset()
|
||||
: RESERVED_COUNT + pool_.size());
|
||||
|
||||
auto result = pool_.emplace(id, profileType);
|
||||
auto &record = result.first->second;
|
||||
record.SetId(id);
|
||||
return true;
|
||||
return pool_->TryAdd(profileType, entryId);
|
||||
}
|
||||
|
||||
bool GetRecordId(const ProfileType &profileType, ApEntityId &recordId) const
|
||||
bool GetEntryId(const ProfileType &profileType, ApEntityId &entryId) const
|
||||
{
|
||||
for (auto [id, record] : pool_) {
|
||||
if (record.GetProfileType() == profileType) {
|
||||
recordId = id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return pool_->GetEntryId(profileType, entryId);
|
||||
}
|
||||
|
||||
const Entry *GetRecord(ApEntityId id) const
|
||||
const Entry *GetEntry(ApEntityId entryId) const
|
||||
{
|
||||
auto iter = pool_.find(id);
|
||||
if (iter == pool_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(iter->second);
|
||||
return pool_->GetEntry(entryId);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
pool_.clear();
|
||||
pool_->Clear();
|
||||
}
|
||||
|
||||
void Merge(const PGOProfileTypePool &recordPool, std::map<ApEntityId, ApEntityId> &idMapping)
|
||||
void Merge(const PGOProfileTypePool &profileTypePool, std::map<ApEntityId, ApEntityId> &idMapping)
|
||||
{
|
||||
for (auto [id, record] : recordPool.pool_) {
|
||||
ApEntityId apId;
|
||||
TryAdd(record.GetProfileType(), apId);
|
||||
idMapping.emplace(id, apId);
|
||||
}
|
||||
pool_->Merge(*profileTypePool.pool_, [&](ApEntityId oldEntryId, ApEntityId newEntryId) {
|
||||
idMapping.try_emplace(oldEntryId, newEntryId);
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t ProcessToBinary(std::fstream &stream) override
|
||||
std::shared_ptr<PoolType> &GetPool()
|
||||
{
|
||||
SectionInfo secInfo;
|
||||
secInfo.number_ = pool_.size();
|
||||
secInfo.offset_ = sizeof(SectionInfo);
|
||||
auto secInfoPos = stream.tellp();
|
||||
stream.seekp(secInfo.offset_, std::ofstream::cur);
|
||||
for (const auto &record : pool_) {
|
||||
stream.write(reinterpret_cast<const char *>(&(record.first)), sizeof(ApEntityId));
|
||||
auto profileType = record.second.GetProfileType().GetRaw();
|
||||
stream.write(reinterpret_cast<const char *>(&(profileType)), sizeof(ProfileType));
|
||||
}
|
||||
secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos);
|
||||
auto tail = stream.tellp();
|
||||
stream.seekp(secInfoPos, std::ofstream::beg);
|
||||
stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo));
|
||||
stream.seekp(tail, std::ofstream::beg);
|
||||
return tail - secInfoPos;
|
||||
}
|
||||
|
||||
bool ProcessToText(std::ofstream &stream) override
|
||||
{
|
||||
std::string profilerString;
|
||||
bool isFirst = true;
|
||||
for (auto [id, record] : pool_) {
|
||||
if (isFirst) {
|
||||
profilerString += DumpUtils::NEW_LINE;
|
||||
profilerString += "ProfileTypePool";
|
||||
profilerString += DumpUtils::BLOCK_START;
|
||||
isFirst = false;
|
||||
}
|
||||
profilerString += DumpUtils::NEW_LINE;
|
||||
profilerString += std::to_string(id.GetOffset());
|
||||
profilerString += DumpUtils::ELEMENT_SEPARATOR;
|
||||
profilerString += record.GetProfileType().GetTypeString();
|
||||
}
|
||||
if (!isFirst) {
|
||||
profilerString += (DumpUtils::SPACE + DumpUtils::NEW_LINE);
|
||||
stream << profilerString;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ParseFromBinary(void **buffer, [[maybe_unused]] PGOProfilerHeader *const header) override
|
||||
{
|
||||
auto *startBuffer = *buffer;
|
||||
auto secInfo = base::ReadBuffer<SectionInfo>(buffer);
|
||||
for (uint32_t i = 0; i < secInfo.number_; i++) {
|
||||
auto recordId = base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId));
|
||||
auto profileType = base::ReadBuffer<ProfileType>(buffer, sizeof(ProfileType));
|
||||
auto result = pool_.emplace(recordId, profileType);
|
||||
result.first->second.SetId(recordId);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(*buffer) - reinterpret_cast<uintptr_t>(startBuffer);
|
||||
return pool_;
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(PGOProfileTypePool);
|
||||
NO_MOVE_SEMANTIC(PGOProfileTypePool);
|
||||
|
||||
static bool IsReserved(ProfileType type)
|
||||
{
|
||||
return type.IsNone();
|
||||
}
|
||||
|
||||
static ApEntityId GetReservedId([[maybe_unused]] ProfileType type)
|
||||
{
|
||||
ASSERT(type.IsNone());
|
||||
return ApEntityId(static_cast<uint32_t>(ReservedType::NONE_CLASS_TYPE_REF));
|
||||
}
|
||||
|
||||
std::unordered_map<ApEntityId, Entry> pool_;
|
||||
std::shared_ptr<PoolType> pool_;
|
||||
};
|
||||
} // namespace panda::ecmascript::pgo
|
||||
} // namespace panda::ecmascript::pgo
|
||||
#endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_PROFILE_TYPE_POOL_H
|
||||
|
@ -19,176 +19,181 @@
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include "ecmascript/common.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pool_template.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
class PGOProfilerHeader;
|
||||
|
||||
class PGORecordPool : public PGOFileDataInterface {
|
||||
class PGOStringPool {
|
||||
public:
|
||||
class Entry {
|
||||
class Entry : public PGOFileDataInterface {
|
||||
public:
|
||||
explicit Entry(CString name) : name_(std::move(name)) {}
|
||||
Entry() = default;
|
||||
ApEntityId GetEntryId() const
|
||||
{
|
||||
return id_;
|
||||
return entryId_;
|
||||
}
|
||||
|
||||
void SetId(ApEntityId id)
|
||||
void SetEntryId(ApEntityId entryId)
|
||||
{
|
||||
id_ = id;
|
||||
entryId_ = entryId;
|
||||
}
|
||||
|
||||
const CString &GetRecordName() const
|
||||
const CString &GetData() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
uint32_t ProcessToBinary(std::fstream &stream) override
|
||||
{
|
||||
stream << name_ << '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t ParseFromBinary(void **buffer, [[maybe_unused]] PGOProfilerHeader const *header) override
|
||||
{
|
||||
name_ = base::ReadBuffer(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ProcessToText(std::ofstream &stream) override
|
||||
{
|
||||
stream << name_;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ApEntityId id_ {};
|
||||
ApEntityId entryId_ {};
|
||||
CString name_;
|
||||
};
|
||||
enum class ReservedType : uint8_t {
|
||||
EMPTY_RECORD_ID = 0,
|
||||
END
|
||||
using PoolType = PoolTemplate<Entry, CString>;
|
||||
|
||||
PGOStringPool(const std::string &poolName, uint32_t reservedCount)
|
||||
{
|
||||
pool_ = std::make_shared<PoolType>(poolName, reservedCount);
|
||||
};
|
||||
static constexpr uint32_t RESERVED_COUNT = 64;
|
||||
|
||||
static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT);
|
||||
|
||||
PGORecordPool() = default;
|
||||
~PGORecordPool() override
|
||||
~PGOStringPool()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool TryAdd(const CString &recordName, ApEntityId &id)
|
||||
bool TryAdd(const CString &value, ApEntityId &entryId)
|
||||
{
|
||||
for (auto &record : pool_) {
|
||||
if (record.second.GetRecordName() == recordName) {
|
||||
id = record.second.GetEntryId();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
id = ApEntityId(IsReserved(recordName) ? GetReservedId(recordName).GetOffset()
|
||||
: RESERVED_COUNT + pool_.size());
|
||||
|
||||
auto result = pool_.emplace(id, recordName);
|
||||
auto &record = result.first->second;
|
||||
record.SetId(id);
|
||||
return true;
|
||||
return pool_->TryAdd(value, entryId);
|
||||
}
|
||||
|
||||
bool GetRecordId(const CString &recordName, ApEntityId &recordId) const
|
||||
bool GetEntryId(const CString &value, ApEntityId &entryId) const
|
||||
{
|
||||
for (auto [id, record] : pool_) {
|
||||
if (record.GetRecordName() == recordName) {
|
||||
recordId = id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return pool_->GetEntryId(value, entryId);
|
||||
}
|
||||
|
||||
const Entry *GetRecord(ApEntityId id) const
|
||||
const Entry *GetEntry(ApEntityId entryId) const
|
||||
{
|
||||
auto iter = pool_.find(id);
|
||||
if (iter == pool_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(iter->second);
|
||||
return pool_->GetEntry(entryId);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
pool_.clear();
|
||||
pool_->Clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<PoolType> &GetPool()
|
||||
{
|
||||
return pool_;
|
||||
}
|
||||
|
||||
protected:
|
||||
NO_COPY_SEMANTIC(PGOStringPool);
|
||||
NO_MOVE_SEMANTIC(PGOStringPool);
|
||||
std::shared_ptr<PoolType> pool_;
|
||||
};
|
||||
|
||||
class PGORecordPool : public PGOStringPool {
|
||||
public:
|
||||
enum class ReservedType : uint8_t { EMPTY_RECORD_ID = 0, END };
|
||||
static constexpr uint32_t RESERVED_COUNT = 64;
|
||||
static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT);
|
||||
|
||||
static bool IsReserved(const CString &value)
|
||||
{
|
||||
return value.empty();
|
||||
}
|
||||
|
||||
static ApEntityId GetReservedId([[maybe_unused]] const CString &value)
|
||||
{
|
||||
ASSERT(value.empty());
|
||||
return ApEntityId(static_cast<uint32_t>(ReservedType::EMPTY_RECORD_ID));
|
||||
}
|
||||
|
||||
static bool Support(PGOProfilerHeader const *header)
|
||||
{
|
||||
return header->SupportRecordPool();
|
||||
}
|
||||
|
||||
static SectionInfo *GetSection(PGOProfilerHeader const *header)
|
||||
{
|
||||
return header->GetRecordPoolSection();
|
||||
}
|
||||
|
||||
PGORecordPool() : PGOStringPool("RecordPool", RESERVED_COUNT)
|
||||
{
|
||||
pool_->SetIsReservedCb(IsReserved);
|
||||
pool_->SetGetReservedIdCb(GetReservedId);
|
||||
pool_->SetGetSectionCb(GetSection);
|
||||
pool_->SetSupportCb(Support);
|
||||
}
|
||||
|
||||
void Merge(const PGORecordPool &recordPool, std::map<ApEntityId, ApEntityId> &idMapping)
|
||||
{
|
||||
for (auto [oldId, record] : recordPool.pool_) {
|
||||
ApEntityId newId;
|
||||
TryAdd(record.GetRecordName(), newId);
|
||||
idMapping.emplace(oldId, newId);
|
||||
}
|
||||
pool_->Merge(*recordPool.pool_,
|
||||
[&](ApEntityId oldId, ApEntityId newId) { idMapping.try_emplace(oldId, newId); });
|
||||
}
|
||||
|
||||
uint32_t ProcessToBinary(std::fstream &stream) override
|
||||
{
|
||||
SectionInfo secInfo;
|
||||
secInfo.number_ = pool_.size();
|
||||
secInfo.offset_ = sizeof(SectionInfo);
|
||||
auto secInfoPos = stream.tellp();
|
||||
stream.seekp(secInfo.offset_, std::ofstream::cur);
|
||||
for (const auto &record : pool_) {
|
||||
stream.write(reinterpret_cast<const char *>(&(record.first)), sizeof(ApEntityId));
|
||||
stream << record.second.GetRecordName() << '\0';
|
||||
}
|
||||
secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos);
|
||||
auto tail = stream.tellp();
|
||||
stream.seekp(secInfoPos, std::ofstream::beg);
|
||||
stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo));
|
||||
stream.seekp(tail, std::ofstream::beg);
|
||||
return tail - secInfoPos;
|
||||
}
|
||||
|
||||
bool ProcessToText(std::ofstream &stream) override
|
||||
{
|
||||
std::string profilerString;
|
||||
bool isFirst = true;
|
||||
for (auto [id, record] : pool_) {
|
||||
if (isFirst) {
|
||||
profilerString += DumpUtils::NEW_LINE;
|
||||
profilerString += "RecordPool";
|
||||
profilerString += DumpUtils::BLOCK_START;
|
||||
isFirst = false;
|
||||
}
|
||||
profilerString += DumpUtils::NEW_LINE;
|
||||
profilerString += std::to_string(id.GetOffset());
|
||||
profilerString += DumpUtils::ELEMENT_SEPARATOR;
|
||||
profilerString += record.GetRecordName();
|
||||
}
|
||||
if (!isFirst) {
|
||||
profilerString += (DumpUtils::SPACE + DumpUtils::NEW_LINE);
|
||||
stream << profilerString;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ParseFromBinary(void **buffer, [[maybe_unused]] PGOProfilerHeader *const header) override
|
||||
{
|
||||
auto *startBuffer = *buffer;
|
||||
auto secInfo = base::ReadBuffer<SectionInfo>(buffer);
|
||||
for (uint32_t i = 0; i < secInfo.number_; i++) {
|
||||
auto recordId = base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId));
|
||||
auto *recordName = base::ReadBuffer(buffer);
|
||||
auto result = pool_.emplace(recordId, recordName);
|
||||
result.first->second.SetId(recordId);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(*buffer) - reinterpret_cast<uintptr_t>(startBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(PGORecordPool);
|
||||
NO_MOVE_SEMANTIC(PGORecordPool);
|
||||
|
||||
static bool IsReserved(const CString &recordName)
|
||||
{
|
||||
return recordName.empty();
|
||||
}
|
||||
|
||||
static ApEntityId GetReservedId([[maybe_unused]]const CString &recordName)
|
||||
{
|
||||
ASSERT(recordName.empty());
|
||||
return ApEntityId(static_cast<uint32_t>(ReservedType::EMPTY_RECORD_ID));
|
||||
}
|
||||
|
||||
std::unordered_map<ApEntityId, Entry> pool_;
|
||||
};
|
||||
} // namespace panda::ecmascript::pgo
|
||||
|
||||
class PGOAbcFilePool : public PGOStringPool {
|
||||
public:
|
||||
enum class ReservedType : uint8_t { EMPTY_ABC_FILE_ID = 0, END };
|
||||
static constexpr uint32_t RESERVED_COUNT = 64;
|
||||
static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT);
|
||||
|
||||
static bool IsReserved(const CString &value)
|
||||
{
|
||||
return value.empty();
|
||||
}
|
||||
|
||||
static ApEntityId GetReservedId([[maybe_unused]] const CString &value)
|
||||
{
|
||||
ASSERT(value.empty());
|
||||
return ApEntityId(static_cast<uint32_t>(ReservedType::EMPTY_ABC_FILE_ID));
|
||||
}
|
||||
|
||||
static bool Support(PGOProfilerHeader const *header)
|
||||
{
|
||||
return header->SupportProfileTypeWithAbcId();
|
||||
}
|
||||
|
||||
static SectionInfo *GetSection(PGOProfilerHeader const *header)
|
||||
{
|
||||
return header->GetAbcFilePoolSection();
|
||||
}
|
||||
|
||||
PGOAbcFilePool() : PGOStringPool("AbcFilePool", RESERVED_COUNT)
|
||||
{
|
||||
pool_->SetIsReservedCb(IsReserved);
|
||||
pool_->SetGetReservedIdCb(GetReservedId);
|
||||
pool_->SetGetSectionCb(GetSection);
|
||||
pool_->SetSupportCb(Support);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace panda::ecmascript::pgo
|
||||
#endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H
|
||||
|
225
ecmascript/pgo_profiler/ap_file/pool_template.h
Normal file
225
ecmascript/pgo_profiler/ap_file/pool_template.h
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H
|
||||
#define ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "ecmascript/common.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
template <typename Entry, typename V>
|
||||
class PoolTemplate : public PGOFileSectionInterface {
|
||||
public:
|
||||
using IsReservedCb = std::function<bool(const V &value)>;
|
||||
using GetReservedIdCb = std::function<ApEntityId(const V &value)>;
|
||||
|
||||
using SupportCb = std::function<bool(PGOProfilerHeader const *header)>;
|
||||
using GetSectionCb = std::function<SectionInfo *(PGOProfilerHeader const *header)>;
|
||||
|
||||
PoolTemplate(std::string poolName, uint32_t reservedCount)
|
||||
: poolName_(std::move(poolName)), RESERVED_COUNT(reservedCount) {};
|
||||
|
||||
~PoolTemplate() override
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool TryAdd(const V &value, ApEntityId &entryId)
|
||||
{
|
||||
for (auto &entry : pool_) {
|
||||
if (entry.second.GetData() == value) {
|
||||
entryId = entry.second.GetEntryId();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
entryId = ApEntityId(IsReserved(value) ? (++reservedUsed_, GetReservedId(value))
|
||||
: RESERVED_COUNT + pool_.size() - reservedUsed_);
|
||||
|
||||
auto result = pool_.emplace(entryId, value);
|
||||
auto &entry = result.first->second;
|
||||
entry.SetEntryId(entryId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetEntryId(const V &value, ApEntityId &entryId) const
|
||||
{
|
||||
for (const auto &entry : pool_) {
|
||||
if (entry.second.GetData() == value) {
|
||||
entryId = entry.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Entry *GetEntry(ApEntityId id) const
|
||||
{
|
||||
auto iter = pool_.find(id);
|
||||
if (iter == pool_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(iter->second);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
pool_.clear();
|
||||
reservedUsed_ = 0;
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
return pool_.empty();
|
||||
}
|
||||
|
||||
void Merge(const PoolTemplate &pool, const std::function<void(ApEntityId, ApEntityId)> &callback)
|
||||
{
|
||||
for (const auto &entry : pool.pool_) {
|
||||
ApEntityId newId(0);
|
||||
TryAdd(entry.second.GetData(), newId);
|
||||
if (callback != nullptr) {
|
||||
callback(entry.first, newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ProcessToBinary(std::fstream &stream) override
|
||||
{
|
||||
LOG_ECMA(DEBUG) << "ProcessToBinary. name: " << poolName_ << ", count: " << pool_.size();
|
||||
SectionInfo secInfo;
|
||||
secInfo.number_ = pool_.size();
|
||||
secInfo.offset_ = sizeof(SectionInfo);
|
||||
auto secInfoPos = stream.tellp();
|
||||
stream.seekp(secInfo.offset_, std::ofstream::cur);
|
||||
for (auto &entry : pool_) {
|
||||
stream.write(reinterpret_cast<const char *>(&(entry.first)), sizeof(ApEntityId));
|
||||
entry.second.ProcessToBinary(stream);
|
||||
}
|
||||
secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos);
|
||||
auto tail = stream.tellp();
|
||||
stream.seekp(secInfoPos, std::ofstream::beg);
|
||||
stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo));
|
||||
stream.seekp(tail, std::ofstream::beg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ProcessToText(std::ofstream &stream) override
|
||||
{
|
||||
bool isFirst = true;
|
||||
for (auto &entry : pool_) {
|
||||
if (isFirst) {
|
||||
stream << DumpUtils::NEW_LINE;
|
||||
stream << poolName_;
|
||||
stream << DumpUtils::BLOCK_START;
|
||||
isFirst = false;
|
||||
}
|
||||
stream << DumpUtils::NEW_LINE;
|
||||
stream << std::to_string(entry.first);
|
||||
stream << DumpUtils::SPACE;
|
||||
stream << DumpUtils::ARRAY_START;
|
||||
entry.second.ProcessToText(stream);
|
||||
stream << DumpUtils::ARRAY_END;
|
||||
}
|
||||
if (!isFirst) {
|
||||
stream << (DumpUtils::SPACE + DumpUtils::NEW_LINE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ParseFromBinary(void **buffer, PGOProfilerHeader const *header) override
|
||||
{
|
||||
auto secInfo = base::ReadBuffer<SectionInfo>(buffer);
|
||||
for (uint32_t i = 0; i < secInfo.number_; i++) {
|
||||
auto entryId = base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId));
|
||||
auto result = pool_.try_emplace(entryId);
|
||||
result.first->second.SetEntryId(entryId);
|
||||
result.first->second.ParseFromBinary(buffer, header);
|
||||
}
|
||||
LOG_ECMA(DEBUG) << "ParseFromBinary. name: " << poolName_ << ", count: " << secInfo.number_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SetIsReservedCb(const IsReservedCb &isReservedCb)
|
||||
{
|
||||
isReservedCb_ = isReservedCb;
|
||||
}
|
||||
|
||||
void SetGetReservedIdCb(const GetReservedIdCb &getReservedIdCb)
|
||||
{
|
||||
getReservedIdCb_ = getReservedIdCb;
|
||||
}
|
||||
|
||||
void SetSupportCb(const SupportCb &supportCb)
|
||||
{
|
||||
supportCb_ = supportCb;
|
||||
}
|
||||
|
||||
void SetGetSectionCb(const GetSectionCb &getSectionCb)
|
||||
{
|
||||
getSectionCb_ = getSectionCb;
|
||||
}
|
||||
|
||||
std::unordered_map<ApEntityId, Entry> &GetPool()
|
||||
{
|
||||
return pool_;
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(PoolTemplate);
|
||||
NO_MOVE_SEMANTIC(PoolTemplate);
|
||||
|
||||
bool Support(PGOProfilerHeader const *header) const override
|
||||
{
|
||||
return supportCb_(header);
|
||||
}
|
||||
|
||||
SectionInfo *GetSection(PGOProfilerHeader const *header) const override
|
||||
{
|
||||
return getSectionCb_(header);
|
||||
}
|
||||
|
||||
bool IsReserved(const V &value)
|
||||
{
|
||||
return isReservedCb_(value);
|
||||
}
|
||||
|
||||
ApEntityId GetReservedId(const V &value)
|
||||
{
|
||||
return getReservedIdCb_(value);
|
||||
}
|
||||
|
||||
const std::string poolName_;
|
||||
const uint32_t RESERVED_COUNT {};
|
||||
uint32_t reservedUsed_ {0};
|
||||
|
||||
IsReservedCb isReservedCb_;
|
||||
GetReservedIdCb getReservedIdCb_;
|
||||
SupportCb supportCb_;
|
||||
GetSectionCb getSectionCb_;
|
||||
std::unordered_map<ApEntityId, Entry> pool_;
|
||||
};
|
||||
} // namespace panda::ecmascript::pgo
|
||||
#endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H
|
@ -25,7 +25,7 @@
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
class PGORecordPool;
|
||||
class PGOAbcFilePool;
|
||||
class PGOProfileTypePool;
|
||||
class PGOProfilerHeader;
|
||||
|
||||
@ -33,7 +33,6 @@ class PGOContext {
|
||||
public:
|
||||
PGOContext() = default;
|
||||
virtual ~PGOContext() = default;
|
||||
virtual std::shared_ptr<PGORecordPool> GetRecordPool() const = 0;
|
||||
virtual std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const = 0;
|
||||
virtual uint32_t GetHotnessThreshold() const = 0;
|
||||
virtual PGOProfilerHeader *GetHeader() const = 0;
|
||||
|
@ -21,9 +21,15 @@
|
||||
#include "ecmascript/ic/profile_type_info.h"
|
||||
#include "ecmascript/interpreter/interpreter-inl.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/module/js_module_source_text.h"
|
||||
#include "ecmascript/jspandafile/js_pandafile.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
void PGOProfiler::ProfileCall(JSTaggedType callTarget, SampleMode mode, int32_t incCount)
|
||||
@ -45,10 +51,11 @@ void PGOProfiler::ProfileCall(JSTaggedType callTarget, SampleMode mode, int32_t
|
||||
return;
|
||||
}
|
||||
CString calleeRecordName = ConvertToString(calleeRecordNameValue);
|
||||
recordInfos_->AddMethod(calleeRecordName, calleeMethod, mode, incCount);
|
||||
ProfileType calleeRecordType = GetRecordProfileType(JSFunction::Cast(calleeFunc), calleeRecordName);
|
||||
recordInfos_->AddMethod(calleeRecordType, calleeMethod, mode, incCount);
|
||||
}
|
||||
|
||||
void PGOProfiler::ProfileCreateObject(JSTaggedType object, int32_t traceId)
|
||||
void PGOProfiler::ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId)
|
||||
{
|
||||
if (!isEnable_) {
|
||||
return;
|
||||
@ -58,7 +65,7 @@ void PGOProfiler::ProfileCreateObject(JSTaggedType object, int32_t traceId)
|
||||
if (objectValue.IsJSObject()) {
|
||||
auto hclass = objectValue.GetTaggedObject()->GetClass();
|
||||
hclass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
|
||||
InsertLiteralId(JSTaggedType(hclass), traceId);
|
||||
InsertLiteralTraceId(JSTaggedType(hclass), abcId, traceId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,13 +87,13 @@ void PGOProfiler::ProfileDefineClass(JSTaggedType ctor)
|
||||
auto traceId = ctorMethod->GetMethodId().GetOffset();
|
||||
auto ctorMethodHClass = ctorFunc->GetClass();
|
||||
ctorMethodHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
|
||||
InsertLiteralId(JSTaggedType(ctorFunc->GetClass()), traceId);
|
||||
InsertLiteralTraceId(JSTaggedType(ctorFunc->GetClass()), GetMethodAbcId(ctorFunc), traceId);
|
||||
|
||||
auto prototype = ctorFunc->GetProtoOrHClass();
|
||||
if (prototype.IsJSObject()) {
|
||||
auto prototypeHClass = prototype.GetTaggedObject()->GetClass();
|
||||
prototypeHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
|
||||
InsertLiteralId(JSTaggedType(prototypeHClass), traceId);
|
||||
InsertLiteralTraceId(JSTaggedType(prototypeHClass), GetMethodAbcId(ctorFunc), traceId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,7 +210,8 @@ void PGOProfiler::HandlePGOPreDump()
|
||||
continue;
|
||||
}
|
||||
CString recordName = ConvertToString(recordNameValue);
|
||||
ProfileByteCode(recordName, methodValue);
|
||||
auto abcId = GetMethodAbcId(func);
|
||||
ProfileByteCode(abcId, recordName, methodValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,7 +235,8 @@ void PGOProfiler::HandlePGODump()
|
||||
continue;
|
||||
}
|
||||
CString recordName = ConvertToString(recordNameValue);
|
||||
ProfileByteCode(recordName, methodValue);
|
||||
auto abcId = GetMethodAbcId(func);
|
||||
ProfileByteCode(abcId, recordName, methodValue);
|
||||
methodCount_++;
|
||||
current = PopFromProfileQueue();
|
||||
}
|
||||
@ -270,7 +279,7 @@ JSTaggedValue PGOProfiler::PopFromProfileQueue()
|
||||
return result;
|
||||
}
|
||||
|
||||
void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
void PGOProfiler::ProfileByteCode(ApEntityId abcId, const CString &recordName, JSTaggedValue value)
|
||||
{
|
||||
Method *method = Method::Cast(value.GetTaggedObject());
|
||||
JSTaggedValue profileTypeInfoVal = method->GetProfileTypeInfo();
|
||||
@ -290,49 +299,49 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
|
||||
case EcmaOpcode::LDOBJBYNAME_IMM8_ID16: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpICByName(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
|
||||
case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpICByName(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
|
||||
case EcmaOpcode::LDTHISBYVALUE_IMM8: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpICByValue(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
|
||||
case EcmaOpcode::LDTHISBYVALUE_IMM16: {
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpICByValue(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
|
||||
case EcmaOpcode::STTHISBYNAME_IMM8_ID16: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpICByName(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
|
||||
case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpICByName(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
|
||||
case EcmaOpcode::STTHISBYVALUE_IMM8_V8: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpICByValue(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
|
||||
case EcmaOpcode::STTHISBYVALUE_IMM16_V8: {
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpICByValue(recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
|
||||
break;
|
||||
}
|
||||
// Op
|
||||
@ -361,7 +370,7 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
|
||||
case EcmaOpcode::STRICTEQ_IMM8_V8: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpOpType(recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
DumpOpType(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
break;
|
||||
}
|
||||
// Call
|
||||
@ -376,13 +385,13 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
|
||||
case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpCall(recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
|
||||
case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpCall(recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
|
||||
@ -393,12 +402,12 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
// Create object
|
||||
case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpDefineClass(recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpDefineClass(recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
|
||||
@ -408,7 +417,7 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
auto traceId =
|
||||
static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
|
||||
uint8_t slotId = READ_INST_8_0();
|
||||
DumpCreateObject(recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
|
||||
DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
|
||||
@ -418,7 +427,7 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
auto traceId =
|
||||
static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
|
||||
uint16_t slotId = READ_INST_16_0();
|
||||
DumpCreateObject(recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
|
||||
DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
|
||||
break;
|
||||
}
|
||||
case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
|
||||
@ -429,8 +438,8 @@ void PGOProfiler::ProfileByteCode(CString recordName, JSTaggedValue value)
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpICByName(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, BCType type)
|
||||
void PGOProfiler::DumpICByName(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type)
|
||||
{
|
||||
JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
|
||||
if (!firstValue.IsHeapObject()) {
|
||||
@ -441,15 +450,15 @@ void PGOProfiler::DumpICByName(const CString &recordName, EntityId methodId, int
|
||||
if (object->GetClass()->IsHClass()) {
|
||||
JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
|
||||
JSHClass *hclass = JSHClass::Cast(object);
|
||||
DumpICByNameWithHandler(recordName, methodId, bcOffset, hclass, secondValue, type);
|
||||
DumpICByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue, type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
DumpICByNameWithPoly(recordName, methodId, bcOffset, firstValue, type);
|
||||
DumpICByNameWithPoly(abcId, recordName, methodId, bcOffset, firstValue, type);
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpICByValue(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, BCType type)
|
||||
void PGOProfiler::DumpICByValue(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type)
|
||||
{
|
||||
JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
|
||||
if (!firstValue.IsHeapObject()) {
|
||||
@ -460,21 +469,21 @@ void PGOProfiler::DumpICByValue(const CString &recordName, EntityId methodId, in
|
||||
if (object->GetClass()->IsHClass()) {
|
||||
JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
|
||||
JSHClass *hclass = JSHClass::Cast(object);
|
||||
DumpICByValueWithHandler(recordName, methodId, bcOffset, hclass, secondValue, type);
|
||||
DumpICByValueWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue, type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Check key
|
||||
if ((firstValue.IsString() || firstValue.IsSymbol())) {
|
||||
JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
|
||||
DumpICByNameWithPoly(recordName, methodId, bcOffset, secondValue, type);
|
||||
DumpICByNameWithPoly(abcId, recordName, methodId, bcOffset, secondValue, type);
|
||||
return;
|
||||
}
|
||||
// Check without key
|
||||
DumpICByValueWithPoly(recordName, methodId, bcOffset, firstValue, type);
|
||||
DumpICByValueWithPoly(abcId, recordName, methodId, bcOffset, firstValue, type);
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpICByNameWithPoly(
|
||||
void PGOProfiler::DumpICByNameWithPoly(ApEntityId abcId,
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
|
||||
{
|
||||
if (cacheValue.IsWeak()) {
|
||||
@ -494,11 +503,11 @@ void PGOProfiler::DumpICByNameWithPoly(
|
||||
continue;
|
||||
}
|
||||
JSHClass *hclass = JSHClass::Cast(object);
|
||||
DumpICByNameWithHandler(recordName, methodId, bcOffset, hclass, handler, type);
|
||||
DumpICByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, handler, type);
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpICByValueWithPoly(
|
||||
void PGOProfiler::DumpICByValueWithPoly(ApEntityId abcId,
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
|
||||
{
|
||||
if (cacheValue.IsWeak()) {
|
||||
@ -518,12 +527,12 @@ void PGOProfiler::DumpICByValueWithPoly(
|
||||
continue;
|
||||
}
|
||||
JSHClass *hclass = JSHClass::Cast(object);
|
||||
DumpICByValueWithHandler(recordName, methodId, bcOffset, hclass, handler, type);
|
||||
DumpICByValueWithHandler(abcId, recordName, methodId, bcOffset, hclass, handler, type);
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpICByNameWithHandler(const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, JSTaggedValue secondValue, BCType type)
|
||||
void PGOProfiler::DumpICByNameWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
|
||||
int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)
|
||||
{
|
||||
if (type == BCType::LOAD) {
|
||||
if (secondValue.IsInt()) {
|
||||
@ -532,18 +541,18 @@ void PGOProfiler::DumpICByNameWithHandler(const CString &recordName, EntityId me
|
||||
return;
|
||||
}
|
||||
auto kind = PGOObjKind::LOCAL;
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
if (secondValue.IsPrototypeHandler()) {
|
||||
auto kind = PGOObjKind::PROTOTYPE;
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
// LoadGlobal
|
||||
return;
|
||||
}
|
||||
if (secondValue.IsInt()) {
|
||||
auto kind = PGOObjKind::LOCAL;
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
if (secondValue.IsTransitionHandler()) {
|
||||
auto kind = PGOObjKind::LOCAL;
|
||||
@ -551,7 +560,7 @@ void PGOProfiler::DumpICByNameWithHandler(const CString &recordName, EntityId me
|
||||
auto transitionHClassVal = transitionHandler->GetTransitionHClass();
|
||||
if (transitionHClassVal.IsJSHClass()) {
|
||||
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
|
||||
AddObjectInfo(recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
}
|
||||
}
|
||||
if (secondValue.IsTransWithProtoHandler()) {
|
||||
@ -560,7 +569,7 @@ void PGOProfiler::DumpICByNameWithHandler(const CString &recordName, EntityId me
|
||||
auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
|
||||
if (transitionHClassVal.IsJSHClass()) {
|
||||
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
|
||||
AddObjectInfo(recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
}
|
||||
}
|
||||
if (secondValue.IsTransitionHandler()) {
|
||||
@ -569,12 +578,12 @@ void PGOProfiler::DumpICByNameWithHandler(const CString &recordName, EntityId me
|
||||
auto transitionHClassVal = transitionHandler->GetTransitionHClass();
|
||||
if (transitionHClassVal.IsJSHClass()) {
|
||||
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
|
||||
AddObjectInfo(recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
}
|
||||
}
|
||||
if (secondValue.IsPrototypeHandler()) {
|
||||
auto kind = PGOObjKind::PROTOTYPE;
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
if (secondValue.IsPropertyBox()) {
|
||||
// StoreGlobal
|
||||
@ -588,12 +597,12 @@ void PGOProfiler::DumpICByNameWithHandler(const CString &recordName, EntityId me
|
||||
return;
|
||||
}
|
||||
auto kind = PGOObjKind::LOCAL;
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpICByValueWithHandler(const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, JSTaggedValue secondValue, BCType type)
|
||||
void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
|
||||
int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)
|
||||
{
|
||||
if (type == BCType::LOAD) {
|
||||
if (secondValue.IsInt()) {
|
||||
@ -602,7 +611,7 @@ void PGOProfiler::DumpICByValueWithHandler(const CString &recordName, EntityId m
|
||||
if (HandlerBase::IsJSArray(handlerInfo)) {
|
||||
kind = PGOObjKind::ELEMENT;
|
||||
}
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -612,7 +621,7 @@ void PGOProfiler::DumpICByValueWithHandler(const CString &recordName, EntityId m
|
||||
if (HandlerBase::IsJSArray(handlerInfo)) {
|
||||
kind = PGOObjKind::ELEMENT;
|
||||
}
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
} else if (secondValue.IsTransitionHandler()) {
|
||||
auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
|
||||
auto transitionHClassVal = transitionHandler->GetTransitionHClass();
|
||||
@ -626,7 +635,7 @@ void PGOProfiler::DumpICByValueWithHandler(const CString &recordName, EntityId m
|
||||
}
|
||||
if (transitionHClassVal.IsJSHClass()) {
|
||||
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
|
||||
AddObjectInfo(recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
}
|
||||
} else if (secondValue.IsTransWithProtoHandler()) {
|
||||
auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
|
||||
@ -641,7 +650,7 @@ void PGOProfiler::DumpICByValueWithHandler(const CString &recordName, EntityId m
|
||||
}
|
||||
if (transitionHClassVal.IsJSHClass()) {
|
||||
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
|
||||
AddObjectInfo(recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, transitionHClass, kind);
|
||||
}
|
||||
} else {
|
||||
ASSERT(secondValue.IsPrototypeHandler());
|
||||
@ -659,22 +668,23 @@ void PGOProfiler::DumpICByValueWithHandler(const CString &recordName, EntityId m
|
||||
if (HandlerBase::IsJSArray(handlerInfo)) {
|
||||
kind = PGOObjKind::ELEMENT;
|
||||
}
|
||||
AddObjectInfo(recordName, methodId, bcOffset, hclass, kind);
|
||||
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, kind);
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpOpType(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
|
||||
void PGOProfiler::DumpOpType(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
|
||||
{
|
||||
JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
|
||||
if (slotValue.IsInt()) {
|
||||
auto type = slotValue.GetInt();
|
||||
recordInfos_->AddType(recordName, methodId, bcOffset, PGOSampleType(type));
|
||||
ProfileType recordType = GetRecordProfileType(abcId, recordName);
|
||||
recordInfos_->AddType(recordType, methodId, bcOffset, PGOSampleType(type));
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpDefineClass(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
|
||||
void PGOProfiler::DumpDefineClass(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
|
||||
{
|
||||
JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
|
||||
if (!slotValue.IsHeapObject() || !slotValue.IsWeak()) {
|
||||
@ -687,21 +697,24 @@ void PGOProfiler::DumpDefineClass(
|
||||
if (!ctorMethod.IsMethod()) {
|
||||
return;
|
||||
}
|
||||
ApEntityId ctorAbcId = GetMethodAbcId(ctorFunction);
|
||||
auto ctorJSMethod = Method::Cast(ctorMethod);
|
||||
int32_t ctorMethodId = static_cast<int32_t>(ctorJSMethod->GetMethodId().GetOffset());
|
||||
auto currentType = PGOSampleType::CreateProfileType(ctorMethodId);
|
||||
auto currentType = PGOSampleType::CreateProfileType(ctorAbcId, ctorMethodId);
|
||||
|
||||
auto superFuncValue = ctorFunction->GetJSHClass()->GetPrototype();
|
||||
PGOSampleType superType = PGOSampleType::CreateProfileType(0);
|
||||
PGOSampleType superType(ProfileType::PROFILE_TYPE_NONE);
|
||||
if (superFuncValue.IsJSFunction()) {
|
||||
auto superFuncFunction = JSFunction::Cast(superFuncValue);
|
||||
if (superFuncFunction->GetMethod().IsMethod()) {
|
||||
ApEntityId superAbcId = GetMethodAbcId(superFuncFunction);
|
||||
auto superMethod = Method::Cast(superFuncFunction->GetMethod());
|
||||
auto superMethodId = superMethod->GetMethodId().GetOffset();
|
||||
superType = PGOSampleType::CreateProfileType(superMethodId);
|
||||
superType = PGOSampleType::CreateProfileType(superAbcId, superMethodId);
|
||||
}
|
||||
}
|
||||
recordInfos_->AddDefine(recordName, methodId, bcOffset, currentType, superType);
|
||||
ProfileType recordType = GetRecordProfileType(abcId, recordName);
|
||||
recordInfos_->AddDefine(recordType, methodId, bcOffset, currentType, superType);
|
||||
|
||||
auto hclassValue = ctorFunction->GetProtoOrHClass();
|
||||
if (!hclassValue.IsJSHClass()) {
|
||||
@ -723,32 +736,34 @@ void PGOProfiler::DumpDefineClass(
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpCreateObject(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, int32_t traceId)
|
||||
void PGOProfiler::DumpCreateObject(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo, int32_t traceId)
|
||||
{
|
||||
JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
|
||||
if (!slotValue.IsHeapObject()) {
|
||||
return;
|
||||
}
|
||||
ProfileType recordType = GetRecordProfileType(abcId, recordName);
|
||||
if (slotValue.IsWeak()) {
|
||||
auto object = slotValue.GetWeakReferentUnChecked();
|
||||
if (object->GetClass()->IsHClass()) {
|
||||
auto newHClass = JSHClass::Cast(object);
|
||||
ASSERT(newHClass->IsJSObject());
|
||||
auto iter = traceIds_.find(JSTaggedType(newHClass));
|
||||
if (iter == traceIds_.end()) {
|
||||
auto iter = tracedProfiles_.find(JSTaggedType(newHClass));
|
||||
if (iter == tracedProfiles_.end()) {
|
||||
return;
|
||||
}
|
||||
auto currentType = PGOSampleType::CreateProfileType(iter->second, ProfileType::Kind::LiteralId);
|
||||
auto superType = PGOSampleType::CreateProfileType(0);
|
||||
recordInfos_->AddDefine(recordName, methodId, bcOffset, currentType, superType);
|
||||
ASSERT(iter->second.GetKind() == ProfileType::Kind::LiteralId);
|
||||
PGOSampleType currentType(iter->second);
|
||||
PGOSampleType superType(ProfileType::PROFILE_TYPE_NONE);
|
||||
recordInfos_->AddDefine(recordType, methodId, bcOffset, currentType, superType);
|
||||
PGOObjKind kind = PGOObjKind::LOCAL;
|
||||
recordInfos_->AddLayout(currentType, JSTaggedType(newHClass), kind);
|
||||
}
|
||||
} else if (slotValue.IsTrackInfoObject()) {
|
||||
auto currentType = PGOSampleType::CreateProfileType(traceId);
|
||||
auto superType = PGOSampleType::CreateProfileType(0);
|
||||
recordInfos_->AddDefine(recordName, methodId, bcOffset, currentType, superType);
|
||||
auto currentType = PGOSampleType::CreateProfileType(abcId, traceId);
|
||||
PGOSampleType superType(ProfileType::PROFILE_TYPE_NONE);
|
||||
recordInfos_->AddDefine(recordType, methodId, bcOffset, currentType, superType);
|
||||
TrackInfo *trackInfo = TrackInfo::Cast(slotValue.GetTaggedObject());
|
||||
auto cachedHClass = trackInfo->GetCachedHClass();
|
||||
if (cachedHClass.IsJSHClass()) {
|
||||
@ -761,8 +776,8 @@ void PGOProfiler::DumpCreateObject(const CString &recordName, EntityId methodId,
|
||||
}
|
||||
}
|
||||
|
||||
void PGOProfiler::DumpCall(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
|
||||
void PGOProfiler::DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
|
||||
{
|
||||
JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
|
||||
if (!slotValue.IsInt()) {
|
||||
@ -770,35 +785,37 @@ void PGOProfiler::DumpCall(
|
||||
}
|
||||
auto calleeMethodId = slotValue.GetInt();
|
||||
|
||||
PGOSampleType type = PGOSampleType::CreateProfileType(calleeMethodId);
|
||||
recordInfos_->AddCallTargetType(recordName, methodId, bcOffset, type);
|
||||
PGOSampleType type = PGOSampleType::CreateProfileType(abcId, calleeMethodId);
|
||||
ProfileType recordType = GetRecordProfileType(abcId, recordName);
|
||||
recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
|
||||
}
|
||||
|
||||
void PGOProfiler::AddObjectInfo(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *hclass, PGOObjKind kind)
|
||||
void PGOProfiler::AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, PGOObjKind kind)
|
||||
{
|
||||
ProfileType recordType = GetRecordProfileType(abcId, recordName);
|
||||
if (hclass->IsClassConstructor()) {
|
||||
kind = PGOObjKind::CONSTRUCTOR;
|
||||
auto rootHClass = JSHClass::FindRootHClass(hclass);
|
||||
AddObjectInfoByTraceId(recordName, methodId, bcOffset, rootHClass, ProfileType::Kind::ClassId, kind);
|
||||
AddObjectInfoByTraceId(abcId, recordName, methodId, bcOffset, rootHClass, ProfileType::Kind::ClassId, kind);
|
||||
} else if (hclass->IsJSArray()) {
|
||||
if (kind == PGOObjKind::ELEMENT) {
|
||||
auto elementsKind = hclass->GetElementsKind();
|
||||
auto profileType = ProfileType(static_cast<uint32_t>(elementsKind), ProfileType::Kind::ElementId);
|
||||
auto profileType = ProfileType(abcId, static_cast<uint32_t>(elementsKind), ProfileType::Kind::ElementId);
|
||||
PGOObjectInfo info(profileType, kind);
|
||||
recordInfos_->AddObjectInfo(recordName, methodId, bcOffset, info);
|
||||
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
|
||||
}
|
||||
} else if (hclass->IsTypedArray()) {
|
||||
// Depend to TypedArray IC
|
||||
auto id = static_cast<uint32_t>(hclass->GetObjectType());
|
||||
PGOObjectInfo info(ProfileType(id, ProfileType::Kind::BuiltinsId), kind);
|
||||
recordInfos_->AddObjectInfo(recordName, methodId, bcOffset, info);
|
||||
PGOObjectInfo info(ProfileType(abcId, id, ProfileType::Kind::BuiltinsId), kind);
|
||||
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
|
||||
} else {
|
||||
if (hclass->IsJSObject()) {
|
||||
// maybe object literal
|
||||
auto rootHClass = JSHClass::FindRootHClass(hclass);
|
||||
auto profileKind = ProfileType::Kind::LiteralId;
|
||||
if (AddObjectInfoByTraceId(recordName, methodId, bcOffset, rootHClass, profileKind, kind)) {
|
||||
if (AddObjectInfoByTraceId(abcId, recordName, methodId, bcOffset, rootHClass, profileKind, kind)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -807,39 +824,46 @@ void PGOProfiler::AddObjectInfo(
|
||||
// maybe class object
|
||||
auto prototypeHClass = prototype.GetTaggedObject()->GetClass();
|
||||
auto rootHClass = JSHClass::FindRootHClass(prototypeHClass);
|
||||
if (AddObjectInfoByTraceId(recordName, methodId, bcOffset, rootHClass, ProfileType::Kind::ClassId, kind)) {
|
||||
if (AddObjectInfoByTraceId(abcId, recordName, methodId, bcOffset, rootHClass, ProfileType::Kind::ClassId,
|
||||
kind)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto profileType = ProfileType(static_cast<uint32_t>(0), ProfileType::Kind::UnknowId);
|
||||
auto profileType = ProfileType(abcId, static_cast<uint32_t>(0), ProfileType::Kind::UnknowId);
|
||||
PGOObjectInfo info(profileType, kind);
|
||||
recordInfos_->AddObjectInfo(recordName, methodId, bcOffset, info);
|
||||
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
|
||||
}
|
||||
}
|
||||
|
||||
bool PGOProfiler::AddObjectInfoByTraceId(const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, ProfileType::Kind classKind, PGOObjKind kind)
|
||||
bool PGOProfiler::AddObjectInfoByTraceId(ApEntityId abcId, const CString &recordName, EntityId methodId,
|
||||
int32_t bcOffset, JSHClass *hclass, ProfileType::Kind classKind,
|
||||
PGOObjKind kind)
|
||||
{
|
||||
auto iter = traceIds_.find(JSTaggedType(hclass));
|
||||
if (iter != traceIds_.end()) {
|
||||
PGOObjectInfo info(ProfileType(iter->second, classKind), kind);
|
||||
recordInfos_->AddObjectInfo(recordName, methodId, bcOffset, info);
|
||||
ProfileType recordType = GetRecordProfileType(abcId, recordName);
|
||||
auto iter = tracedProfiles_.find(JSTaggedType(hclass));
|
||||
if (iter != tracedProfiles_.end()) {
|
||||
ProfileType traceType = iter->second;
|
||||
traceType.UpdateKind(classKind);
|
||||
PGOObjectInfo info(traceType, kind);
|
||||
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t PGOProfiler::InsertLiteralId(JSTaggedType hclass, int32_t traceId)
|
||||
ProfileType PGOProfiler::InsertLiteralTraceId(JSTaggedType hclass, ApEntityId abcId, int32_t traceId)
|
||||
{
|
||||
ProfileType literalType(abcId, traceId, ProfileType::Kind::LiteralId);
|
||||
return InsertTraceId(hclass, literalType);
|
||||
}
|
||||
|
||||
ProfileType PGOProfiler::InsertTraceId(JSTaggedType hclass, ProfileType traceType)
|
||||
{
|
||||
if (!isEnable_) {
|
||||
return traceId;
|
||||
return traceType;
|
||||
}
|
||||
auto iter = traceIds_.find(hclass);
|
||||
if (iter != traceIds_.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
traceIds_.emplace(hclass, traceId);
|
||||
return traceId;
|
||||
auto result = tracedProfiles_.try_emplace(hclass, traceType);
|
||||
return result.first->second;
|
||||
}
|
||||
|
||||
void PGOProfiler::ProcessReferences(const WeakRootVisitor &visitor)
|
||||
@ -847,11 +871,11 @@ void PGOProfiler::ProcessReferences(const WeakRootVisitor &visitor)
|
||||
if (!isEnable_) {
|
||||
return;
|
||||
}
|
||||
for (auto iter = traceIds_.begin(); iter != traceIds_.end();) {
|
||||
for (auto iter = tracedProfiles_.begin(); iter != tracedProfiles_.end();) {
|
||||
JSTaggedType object = iter->first;
|
||||
auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
|
||||
if (fwd == nullptr) {
|
||||
iter = traceIds_.erase(iter);
|
||||
iter = tracedProfiles_.erase(iter);
|
||||
continue;
|
||||
}
|
||||
if (fwd != reinterpret_cast<TaggedObject *>(object)) {
|
||||
@ -916,4 +940,43 @@ void PGOProfiler::Reset(bool isEnable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApEntityId PGOProfiler::GetMethodAbcId(JSFunction *jsFunction)
|
||||
{
|
||||
CString pfName;
|
||||
auto jsMethod = jsFunction->GetMethod();
|
||||
if (jsMethod.IsMethod()) {
|
||||
const auto *pf = Method::Cast(jsMethod)->GetJSPandaFile();
|
||||
if (pf != nullptr) {
|
||||
pfName = pf->GetJSPandaFileDesc();
|
||||
}
|
||||
}
|
||||
ApEntityId abcId(0);
|
||||
if (!PGOProfilerManager::GetInstance()->GetPandaFileId(pfName, abcId) && !pfName.empty()) {
|
||||
LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << pfName;
|
||||
}
|
||||
return abcId;
|
||||
}
|
||||
|
||||
ApEntityId PGOProfiler::GetRecordId(const CString &recordName)
|
||||
{
|
||||
ApEntityId recordId(0);
|
||||
recordInfos_->GetRecordPool()->TryAdd(recordName, recordId);
|
||||
return recordId;
|
||||
}
|
||||
|
||||
ProfileType PGOProfiler::GetRecordProfileType(JSFunction *jsFunction, const CString &recordName)
|
||||
{
|
||||
return GetRecordProfileType(GetMethodAbcId(jsFunction), GetRecordId(recordName));
|
||||
}
|
||||
|
||||
ProfileType PGOProfiler::GetRecordProfileType(ApEntityId abcId, const CString &recordName)
|
||||
{
|
||||
return GetRecordProfileType(abcId, GetRecordId(recordName));
|
||||
}
|
||||
|
||||
ProfileType PGOProfiler::GetRecordProfileType(ApEntityId abcId, ApEntityId recordId)
|
||||
{
|
||||
return {abcId, recordId, ProfileType::Kind::LocalRecordId};
|
||||
}
|
||||
} // namespace panda::ecmascript::pgo
|
||||
|
@ -26,9 +26,13 @@
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
#include "ecmascript/mem/visitor.h"
|
||||
#include "ecmascript/taskpool/task.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
class ProfileTypeInfo;
|
||||
class JSFunction;
|
||||
|
||||
namespace pgo {
|
||||
class PGORecordDetailInfos;
|
||||
|
||||
@ -42,8 +46,9 @@ public:
|
||||
NO_COPY_SEMANTIC(PGOProfiler);
|
||||
NO_MOVE_SEMANTIC(PGOProfiler);
|
||||
|
||||
static ProfileType GetRecordProfileType(ApEntityId abcId, ApEntityId recordId);
|
||||
void ProfileCall(JSTaggedType callTarget, SampleMode mode = SampleMode::CALL_MODE, int32_t incCount = 1);
|
||||
void ProfileCreateObject(JSTaggedType object, int32_t traceId);
|
||||
void ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId);
|
||||
void ProfileDefineClass(JSTaggedType ctor);
|
||||
|
||||
void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)
|
||||
@ -65,7 +70,8 @@ public:
|
||||
void Iterate(const RootVisitor &visitor);
|
||||
|
||||
void UpdateTrackInfo(JSTaggedValue trackInfoVal, ElementsKind newKind);
|
||||
int32_t InsertLiteralId(JSTaggedType hclass, int32_t traceId);
|
||||
ProfileType InsertLiteralTraceId(JSTaggedType hclass, ApEntityId abcId, int32_t traceId);
|
||||
ProfileType InsertTraceId(JSTaggedType hclass, ProfileType traceType);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t MERGED_EVERY_COUNT = 50;
|
||||
@ -81,36 +87,36 @@ private:
|
||||
START,
|
||||
};
|
||||
|
||||
void ProfileByteCode(CString recordName, JSTaggedValue value);
|
||||
void ProfileByteCode(ApEntityId abcId, const CString &recordName, JSTaggedValue value);
|
||||
|
||||
void DumpICByName(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, BCType type);
|
||||
void DumpICByValue(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, BCType type);
|
||||
void DumpICByName(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, BCType type);
|
||||
void DumpICByValue(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type);
|
||||
|
||||
void DumpICByNameWithPoly(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type);
|
||||
void DumpICByValueWithPoly(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type);
|
||||
void DumpICByNameWithPoly(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSTaggedValue cacheValue, BCType type);
|
||||
void DumpICByValueWithPoly(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSTaggedValue cacheValue, BCType type);
|
||||
|
||||
void DumpICByNameWithHandler(const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *hclass,
|
||||
JSTaggedValue secondValue, BCType type);
|
||||
void DumpICByValueWithHandler(const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *hclass,
|
||||
JSTaggedValue secondValue, BCType type);
|
||||
void DumpICByNameWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, JSTaggedValue secondValue, BCType type);
|
||||
void DumpICByValueWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, JSTaggedValue secondValue, BCType type);
|
||||
|
||||
void DumpOpType(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo);
|
||||
void DumpDefineClass(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo);
|
||||
void DumpCreateObject(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo, int32_t traceId);
|
||||
void DumpCall(const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo);
|
||||
void DumpOpType(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo);
|
||||
void DumpDefineClass(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
|
||||
void DumpCreateObject(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
uint32_t slotId, ProfileTypeInfo *profileTypeInfo, int32_t traceId);
|
||||
void DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
|
||||
ProfileTypeInfo *profileTypeInfo);
|
||||
|
||||
void AddObjectInfo(
|
||||
const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *hclass, PGOObjKind kind);
|
||||
bool AddObjectInfoByTraceId(const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *hclass,
|
||||
ProfileType::Kind classKind, PGOObjKind kind);
|
||||
void AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, PGOObjKind kind);
|
||||
bool AddObjectInfoByTraceId(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
|
||||
JSHClass *hclass, ProfileType::Kind classKind, PGOObjKind kind);
|
||||
|
||||
JSTaggedValue PopFromProfileQueue();
|
||||
|
||||
@ -135,6 +141,11 @@ private:
|
||||
|
||||
virtual ~PGOProfiler();
|
||||
|
||||
static ApEntityId GetMethodAbcId(JSFunction *jsFunction);
|
||||
ApEntityId GetRecordId(const CString &recordName);
|
||||
ProfileType GetRecordProfileType(JSFunction *jsFunction, const CString &recordName);
|
||||
ProfileType GetRecordProfileType(ApEntityId abcId, const CString &recordName);
|
||||
|
||||
void Reset(bool isEnable);
|
||||
|
||||
EcmaVM *vm_ { nullptr };
|
||||
@ -146,10 +157,10 @@ private:
|
||||
os::memory::ConditionVariable condition_;
|
||||
CList<JSTaggedType> dumpWorkList_;
|
||||
CSet<JSTaggedType> preDumpWorkList_;
|
||||
CMap<JSTaggedType, int32_t> traceIds_;
|
||||
CMap<JSTaggedType, ProfileType> tracedProfiles_;
|
||||
std::unique_ptr<PGORecordDetailInfos> recordInfos_;
|
||||
friend class PGOProfilerManager;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
} // namespace pgo
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_PGO_PROFILER_H
|
||||
|
@ -39,9 +39,16 @@ bool PGOProfilerDecoder::Load()
|
||||
return false;
|
||||
}
|
||||
pandaFileInfos_.ParseFromBinary(addr, header_->GetPandaInfoSection());
|
||||
|
||||
if (!recordSimpleInfos_) {
|
||||
recordSimpleInfos_ = std::make_unique<PGORecordSimpleInfos>(hotnessThreshold_);
|
||||
}
|
||||
if (!abcFilePool_) {
|
||||
abcFilePool_ = std::make_unique<PGOAbcFilePool>();
|
||||
}
|
||||
if (header_->SupportProfileTypeWithAbcId()) {
|
||||
PGOFileSectionInterface::ParseSectionFromBinary(addr, header_, *abcFilePool_->GetPool());
|
||||
}
|
||||
recordSimpleInfos_->ParseFromBinary(addr, header_);
|
||||
UnLoadAPBinaryFile();
|
||||
|
||||
@ -97,6 +104,14 @@ bool PGOProfilerDecoder::LoadFull()
|
||||
if (!recordDetailInfos_) {
|
||||
recordDetailInfos_ = std::make_shared<PGORecordDetailInfos>(hotnessThreshold_);
|
||||
}
|
||||
|
||||
if (!abcFilePool_) {
|
||||
abcFilePool_ = std::make_unique<PGOAbcFilePool>();
|
||||
}
|
||||
|
||||
if (header_->SupportProfileTypeWithAbcId()) {
|
||||
PGOFileSectionInterface::ParseSectionFromBinary(addr, header_, *abcFilePool_->GetPool());
|
||||
}
|
||||
recordDetailInfos_->ParseFromBinary(addr, header_);
|
||||
|
||||
isLoaded_ = true;
|
||||
@ -123,6 +138,7 @@ bool PGOProfilerDecoder::SaveAPTextFile(const std::string &outPath)
|
||||
}
|
||||
pandaFileInfos_.ProcessToText(fileStream);
|
||||
recordDetailInfos_->ProcessToText(fileStream);
|
||||
abcFilePool_->GetPool()->ProcessToText(fileStream);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -163,6 +179,9 @@ void PGOProfilerDecoder::Clear()
|
||||
hotnessThreshold_ = 0;
|
||||
PGOProfilerHeader::Destroy(&header_);
|
||||
pandaFileInfos_.Clear();
|
||||
if (abcFilePool_) {
|
||||
abcFilePool_->Clear();
|
||||
}
|
||||
if (recordDetailInfos_) {
|
||||
recordDetailInfos_->Clear();
|
||||
}
|
||||
@ -181,7 +200,7 @@ bool PGOProfilerDecoder::Match(const CString &recordName, PGOMethodId methodId)
|
||||
if (!isVerifySuccess_) {
|
||||
return false;
|
||||
}
|
||||
return recordSimpleInfos_->Match(recordName, methodId);
|
||||
return recordSimpleInfos_->Match(recordName, EntityId(methodId));
|
||||
}
|
||||
|
||||
bool PGOProfilerDecoder::GetHClassLayoutDesc(PGOSampleType profileType, PGOHClassLayoutDesc **desc) const
|
||||
|
@ -152,6 +152,7 @@ private:
|
||||
uint32_t hotnessThreshold_ {0};
|
||||
PGOProfilerHeader *header_ {nullptr};
|
||||
PGOPandaFileInfos pandaFileInfos_;
|
||||
std::shared_ptr<PGOAbcFilePool> abcFilePool_;
|
||||
std::shared_ptr<PGORecordDetailInfos> recordDetailInfos_;
|
||||
std::unique_ptr<PGORecordSimpleInfos> recordSimpleInfos_;
|
||||
MemMap fileMapAddr_;
|
||||
|
@ -20,13 +20,18 @@
|
||||
#include <string>
|
||||
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
|
||||
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/platform/file.h"
|
||||
#include "os/mutex.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
static const std::string PROFILE_FILE_NAME = "/modules.ap";
|
||||
static const std::string AP_SUFFIX = ".ap";
|
||||
static const std::string PROFILE_FILE_NAME = "/modules" + AP_SUFFIX;
|
||||
static const std::string RUNTIME_AP_PREFIX = "/rt_";
|
||||
void PGOProfilerEncoder::Destroy()
|
||||
{
|
||||
if (!isInitialized_) {
|
||||
@ -39,32 +44,63 @@ void PGOProfilerEncoder::Destroy()
|
||||
isInitialized_ = false;
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::ResetOutPathByModuleName(const std::string &moduleName)
|
||||
{
|
||||
os::memory::LockHolder lock(mutex_);
|
||||
// only first assign takes effect
|
||||
if (!moduleName_.empty() || moduleName.empty()) {
|
||||
return false;
|
||||
}
|
||||
moduleName_ = moduleName;
|
||||
return ResetOutPath(RUNTIME_AP_PREFIX + moduleName_ + AP_SUFFIX);
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::ResetOutPath(const std::string &profileFileName)
|
||||
{
|
||||
if (!RealPath(outDir_, realOutPath_, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (realOutPath_.compare(realOutPath_.length() - AP_SUFFIX.length(), AP_SUFFIX.length(), AP_SUFFIX)) {
|
||||
realOutPath_ += profileFileName;
|
||||
}
|
||||
LOG_ECMA(INFO) << "Save profiler to file:" << realOutPath_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::InitializeData()
|
||||
{
|
||||
if (!isInitialized_) {
|
||||
if (!RealPath(outDir_, realOutPath_, false)) {
|
||||
if (!ResetOutPath(PROFILE_FILE_NAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const std::string endString = ".ap";
|
||||
if (realOutPath_.compare(realOutPath_.length() - endString.length(), endString.length(), endString)) {
|
||||
realOutPath_ += PROFILE_FILE_NAME;
|
||||
}
|
||||
LOG_ECMA(INFO) << "Save profiler to file:" << realOutPath_;
|
||||
PGOProfilerHeader::Build(&header_, PGOProfilerHeader::LastSize());
|
||||
pandaFileInfos_ = std::make_unique<PGOPandaFileInfos>();
|
||||
abcFilePool_ = std::make_unique<PGOAbcFilePool>();
|
||||
globalRecordInfos_ = std::make_shared<PGORecordDetailInfos>(hotnessThreshold_);
|
||||
isInitialized_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PGOProfilerEncoder::SamplePandaFileInfo(uint32_t checksum)
|
||||
void PGOProfilerEncoder::SamplePandaFileInfo(uint32_t checksum, const CString &abcName)
|
||||
{
|
||||
if (!isInitialized_) {
|
||||
return;
|
||||
}
|
||||
os::memory::WriteLockHolder lock(rwLock_);
|
||||
pandaFileInfos_->Sample(checksum);
|
||||
ApEntityId entryId(0);
|
||||
abcFilePool_->TryAdd(abcName, entryId);
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::GetPandaFileId(const CString &abcName, ApEntityId &entryId)
|
||||
{
|
||||
if (!isInitialized_) {
|
||||
return false;
|
||||
}
|
||||
os::memory::ReadLockHolder lock(rwLock_);
|
||||
return abcFilePool_->GetEntryId(abcName, entryId);
|
||||
}
|
||||
|
||||
void PGOProfilerEncoder::Merge(const PGORecordDetailInfos &recordInfos)
|
||||
@ -102,31 +138,10 @@ bool PGOProfilerEncoder::Save()
|
||||
return InternalSave();
|
||||
}
|
||||
|
||||
void PGOProfilerEncoder::MergeWithExistProfile(PGOProfilerEncoder &encoder, PGOProfilerDecoder &decoder,
|
||||
const SaveTask *task)
|
||||
{
|
||||
if (!decoder.LoadFull()) {
|
||||
LOG_ECMA(ERROR) << "Fail to load ap: " << realOutPath_;
|
||||
} else {
|
||||
Merge(decoder.GetPandaFileInfos());
|
||||
globalRecordInfos_ = decoder.GetRecordDetailInfosPtr();
|
||||
}
|
||||
if (task && task->IsTerminate()) {
|
||||
LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
|
||||
return;
|
||||
}
|
||||
Merge(*encoder.pandaFileInfos_);
|
||||
if (task && task->IsTerminate()) {
|
||||
LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
|
||||
return;
|
||||
}
|
||||
Merge(*encoder.globalRecordInfos_);
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::SaveAndRename(const SaveTask *task)
|
||||
{
|
||||
static const char *tempSuffix = ".tmp";
|
||||
auto tmpOutPath = realOutPath_ + "." + std::to_string(getpid()) + "." + tempSuffix;
|
||||
auto tmpOutPath = realOutPath_ + "." + std::to_string(getpid()) + tempSuffix;
|
||||
std::fstream fileStream(tmpOutPath.c_str(),
|
||||
std::fstream::binary | std::fstream::out | std::fstream::in | std::fstream::trunc);
|
||||
if (!fileStream.is_open()) {
|
||||
@ -135,6 +150,11 @@ bool PGOProfilerEncoder::SaveAndRename(const SaveTask *task)
|
||||
}
|
||||
pandaFileInfos_->ProcessToBinary(fileStream, header_->GetPandaInfoSection());
|
||||
globalRecordInfos_->ProcessToBinary(task, fileStream, header_);
|
||||
{
|
||||
os::memory::ReadLockHolder lock(rwLock_);
|
||||
PGOFileSectionInterface::ProcessSectionToBinary(fileStream, header_, *abcFilePool_->GetPool());
|
||||
}
|
||||
header_->SetFileSize(static_cast<uint32_t>(fileStream.tellp()));
|
||||
header_->ProcessToBinary(fileStream);
|
||||
if (header_->SupportFileConsistency()) {
|
||||
AddChecksum(fileStream);
|
||||
@ -161,13 +181,6 @@ bool PGOProfilerEncoder::InternalSave(const SaveTask *task)
|
||||
if (!isInitialized_) {
|
||||
return false;
|
||||
}
|
||||
if ((mode_ == MERGE) && FileExist(realOutPath_.c_str())) {
|
||||
PGOProfilerEncoder encoder(realOutPath_, hotnessThreshold_, mode_);
|
||||
encoder.InitializeData();
|
||||
PGOProfilerDecoder decoder(realOutPath_, hotnessThreshold_);
|
||||
encoder.MergeWithExistProfile(*this, decoder, task);
|
||||
return encoder.SaveAndRename(task);
|
||||
}
|
||||
return SaveAndRename(task);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
#ifndef ECMASCRIPT_PGO_PROFILER_ENCODER_H
|
||||
#define ECMASCRIPT_PGO_PROFILER_ENCODER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
|
||||
#include "macros.h"
|
||||
|
||||
@ -23,7 +25,7 @@ namespace panda::ecmascript::pgo {
|
||||
class PGOProfilerDecoder;
|
||||
class PGOProfilerEncoder {
|
||||
public:
|
||||
enum ApGenMode { OVERWRITE, MERGE };
|
||||
enum ApGenMode { OVERWRITE };
|
||||
|
||||
PGOProfilerEncoder(const std::string &outDir, uint32_t hotnessThreshold, ApGenMode mode)
|
||||
: outDir_(outDir), hotnessThreshold_(hotnessThreshold), mode_(mode) {}
|
||||
@ -42,7 +44,8 @@ public:
|
||||
return isInitialized_;
|
||||
}
|
||||
|
||||
void SamplePandaFileInfo(uint32_t checksum);
|
||||
void SamplePandaFileInfo(uint32_t checksum, const CString &abcName);
|
||||
bool GetPandaFileId(const CString &abcName, ApEntityId &entryId);
|
||||
void Merge(const PGORecordDetailInfos &recordInfos);
|
||||
void Merge(const PGOPandaFileInfos &pandaFileInfos);
|
||||
void Merge(const PGOProfilerEncoder &encoder);
|
||||
@ -59,12 +62,13 @@ public:
|
||||
|
||||
bool PUBLIC_API LoadAPTextFile(const std::string &inPath);
|
||||
|
||||
bool ResetOutPathByModuleName(const std::string &moduleName);
|
||||
|
||||
private:
|
||||
void StartSaveTask(const SaveTask *task);
|
||||
bool InternalSave(const SaveTask *task = nullptr);
|
||||
bool SaveAndRename(const SaveTask *task = nullptr);
|
||||
void MergeWithExistProfile(PGOProfilerEncoder &encoder, PGOProfilerDecoder &decoder,
|
||||
const SaveTask *task = nullptr);
|
||||
bool ResetOutPath(const std::string& profileFileName);
|
||||
|
||||
bool isInitialized_ {false};
|
||||
std::string outDir_;
|
||||
@ -72,8 +76,11 @@ private:
|
||||
std::string realOutPath_;
|
||||
PGOProfilerHeader *header_ {nullptr};
|
||||
std::unique_ptr<PGOPandaFileInfos> pandaFileInfos_;
|
||||
std::shared_ptr<PGOAbcFilePool> abcFilePool_;
|
||||
std::shared_ptr<PGORecordDetailInfos> globalRecordInfos_;
|
||||
os::memory::Mutex mutex_;
|
||||
os::memory::RWLock rwLock_;
|
||||
std::string moduleName_;
|
||||
ApGenMode mode_ {OVERWRITE};
|
||||
friend SaveTask;
|
||||
};
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
|
||||
#include "ecmascript/base/bit_helper.h"
|
||||
#include "ecmascript/base/file_header.h"
|
||||
@ -24,11 +25,13 @@
|
||||
#include "ecmascript/jspandafile/method_literal.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_method_type_set.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_profile_type_pool.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_record_pool.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
|
||||
@ -36,6 +39,20 @@
|
||||
#include "securec.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
namespace {
|
||||
bool ParseSectionsFromBinary(const std::list<std::weak_ptr<PGOFileSectionInterface>> §ionList, void *buffer,
|
||||
PGOProfilerHeader const *header)
|
||||
{
|
||||
return std::all_of(sectionList.begin(), sectionList.end(), [&](const auto §ionWeak) {
|
||||
auto section = sectionWeak.lock();
|
||||
if (section == nullptr) {
|
||||
return true;
|
||||
}
|
||||
return PGOFileSectionInterface::ParseSectionFromBinary(buffer, header, *section);
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
using StringHelper = base::StringHelper;
|
||||
void PGOPandaFileInfos::ParseFromBinary(void *buffer, SectionInfo *const info)
|
||||
{
|
||||
@ -320,8 +337,8 @@ bool PGOMethodInfoMap::ParseFromBinary(Chunk *chunk, PGOContext &context, void *
|
||||
return !methodInfos_.empty();
|
||||
}
|
||||
|
||||
bool PGOMethodInfoMap::ProcessToBinary(PGOContext &context, ApEntityId recordId, const SaveTask *task,
|
||||
std::fstream &stream, PGOProfilerHeader *const header) const
|
||||
bool PGOMethodInfoMap::ProcessToBinary(PGOContext &context, ProfileTypeRef recordProfileRef, const SaveTask *task,
|
||||
std::fstream &stream, PGOProfilerHeader *const header) const
|
||||
{
|
||||
SectionInfo secInfo;
|
||||
std::stringstream methodStream;
|
||||
@ -361,7 +378,7 @@ bool PGOMethodInfoMap::ProcessToBinary(PGOContext &context, ApEntityId recordId,
|
||||
if (secInfo.number_ > 0) {
|
||||
secInfo.offset_ = sizeof(SectionInfo);
|
||||
secInfo.size_ = static_cast<uint32_t>(methodStream.tellp());
|
||||
stream.write(reinterpret_cast<char *>(&recordId), sizeof(uint32_t));
|
||||
stream.write(reinterpret_cast<char *>(&recordProfileRef), sizeof(uint32_t));
|
||||
stream.write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo));
|
||||
stream << methodStream.rdbuf();
|
||||
return true;
|
||||
@ -540,8 +557,7 @@ void PGODecodeMethodInfo::Merge(const PGODecodeMethodInfo &from)
|
||||
PGORecordDetailInfos::PGORecordDetailInfos(uint32_t hotnessThreshold) : hotnessThreshold_(hotnessThreshold)
|
||||
{
|
||||
chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
|
||||
recordPool_ = std::make_shared<PGORecordPool>();
|
||||
profileTypePool_ = std::make_shared<PGOProfileTypePool>();
|
||||
InitSections();
|
||||
};
|
||||
|
||||
PGORecordDetailInfos::~PGORecordDetailInfos()
|
||||
@ -549,55 +565,54 @@ PGORecordDetailInfos::~PGORecordDetailInfos()
|
||||
Clear();
|
||||
}
|
||||
|
||||
PGOMethodInfoMap *PGORecordDetailInfos::GetMethodInfoMap(const CString &recordName)
|
||||
PGOMethodInfoMap *PGORecordDetailInfos::GetMethodInfoMap(ProfileType recordProfileType)
|
||||
{
|
||||
ApEntityId recordId;
|
||||
recordPool_->TryAdd(recordName, recordId);
|
||||
auto iter = recordInfos_.find(recordId);
|
||||
auto iter = recordInfos_.find(recordProfileType);
|
||||
if (iter != recordInfos_.end()) {
|
||||
return iter->second;
|
||||
} else {
|
||||
auto curMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
|
||||
recordInfos_.emplace(recordId, curMethodInfos);
|
||||
recordInfos_.emplace(recordProfileType, curMethodInfos);
|
||||
return curMethodInfos;
|
||||
}
|
||||
}
|
||||
|
||||
bool PGORecordDetailInfos::AddMethod(const CString &recordName, Method *jsMethod, SampleMode mode, int32_t incCount)
|
||||
bool PGORecordDetailInfos::AddMethod(ProfileType recordProfileType, Method *jsMethod, SampleMode mode, int32_t incCount)
|
||||
{
|
||||
auto curMethodInfos = GetMethodInfoMap(recordName);
|
||||
auto curMethodInfos = GetMethodInfoMap(recordProfileType);
|
||||
ASSERT(curMethodInfos != nullptr);
|
||||
ASSERT(jsMethod != nullptr);
|
||||
return curMethodInfos->AddMethod(&nativeAreaAllocator_, jsMethod, mode, incCount);
|
||||
}
|
||||
|
||||
bool PGORecordDetailInfos::AddType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type)
|
||||
bool PGORecordDetailInfos::AddType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset,
|
||||
PGOSampleType type)
|
||||
{
|
||||
auto curMethodInfos = GetMethodInfoMap(recordName);
|
||||
auto curMethodInfos = GetMethodInfoMap(recordProfileType);
|
||||
ASSERT(curMethodInfos != nullptr);
|
||||
return curMethodInfos->AddType(chunk_.get(), methodId, offset, type);
|
||||
}
|
||||
|
||||
bool PGORecordDetailInfos::AddCallTargetType(const CString &recordName, PGOMethodId methodId, int32_t offset,
|
||||
bool PGORecordDetailInfos::AddCallTargetType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset,
|
||||
PGOSampleType type)
|
||||
{
|
||||
auto curMethodInfos = GetMethodInfoMap(recordName);
|
||||
auto curMethodInfos = GetMethodInfoMap(recordProfileType);
|
||||
ASSERT(curMethodInfos != nullptr);
|
||||
return curMethodInfos->AddCallTargetType(chunk_.get(), methodId, offset, type);
|
||||
}
|
||||
|
||||
bool PGORecordDetailInfos::AddObjectInfo(
|
||||
const CString &recordName, EntityId methodId, int32_t offset, const PGOObjectInfo &info)
|
||||
ProfileType recordProfileType, EntityId methodId, int32_t offset, const PGOObjectInfo &info)
|
||||
{
|
||||
auto curMethodInfos = GetMethodInfoMap(recordName);
|
||||
auto curMethodInfos = GetMethodInfoMap(recordProfileType);
|
||||
ASSERT(curMethodInfos != nullptr);
|
||||
return curMethodInfos->AddObjectInfo(chunk_.get(), methodId, offset, info);
|
||||
}
|
||||
|
||||
bool PGORecordDetailInfos::AddDefine(
|
||||
const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType)
|
||||
ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType)
|
||||
{
|
||||
auto curMethodInfos = GetMethodInfoMap(recordName);
|
||||
auto curMethodInfos = GetMethodInfoMap(recordProfileType);
|
||||
ASSERT(curMethodInfos != nullptr);
|
||||
curMethodInfos->AddDefine(chunk_.get(), methodId, offset, type, superType);
|
||||
|
||||
@ -646,18 +661,20 @@ void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos)
|
||||
{
|
||||
std::map<ApEntityId, ApEntityId> idMapping;
|
||||
recordPool_->Merge(*recordInfos.recordPool_, idMapping);
|
||||
|
||||
for (auto iter = recordInfos.recordInfos_.begin(); iter != recordInfos.recordInfos_.end(); iter++) {
|
||||
auto oldRecordId = iter->first;
|
||||
auto newRecordId = idMapping.at(oldRecordId);
|
||||
|
||||
auto oldRecordType = iter->first;
|
||||
auto newIter = idMapping.find(oldRecordType.GetId());
|
||||
if (newIter == idMapping.end()) {
|
||||
continue;
|
||||
}
|
||||
auto newRecordType = PGOProfiler::GetRecordProfileType(oldRecordType.GetAbcId(), newIter->second);
|
||||
auto fromMethodInfos = iter->second;
|
||||
|
||||
auto recordInfosIter = recordInfos_.find(newRecordId);
|
||||
auto recordInfosIter = recordInfos_.find(newRecordType);
|
||||
PGOMethodInfoMap *toMethodInfos = nullptr;
|
||||
if (recordInfosIter == recordInfos_.end()) {
|
||||
toMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
|
||||
recordInfos_.emplace(newRecordId, toMethodInfos);
|
||||
recordInfos_.emplace(newRecordType, toMethodInfos);
|
||||
} else {
|
||||
toMethodInfos = recordInfosIter->second;
|
||||
}
|
||||
@ -667,11 +684,12 @@ void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos)
|
||||
// Merge global layout desc infos to global method info map
|
||||
for (auto info = recordInfos.moduleLayoutDescInfos_.begin(); info != recordInfos.moduleLayoutDescInfos_.end();
|
||||
info++) {
|
||||
auto result = moduleLayoutDescInfos_.find(*info);
|
||||
auto fromInfo = *info;
|
||||
auto result = moduleLayoutDescInfos_.find(fromInfo);
|
||||
if (result == moduleLayoutDescInfos_.end()) {
|
||||
moduleLayoutDescInfos_.emplace(*info);
|
||||
moduleLayoutDescInfos_.emplace(fromInfo);
|
||||
} else {
|
||||
const_cast<PGOHClassLayoutDesc &>(*result).Merge(*info);
|
||||
const_cast<PGOHClassLayoutDesc &>(*result).Merge(fromInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -679,37 +697,29 @@ void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos)
|
||||
void PGORecordDetailInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
|
||||
{
|
||||
header_ = header;
|
||||
// parse pools first
|
||||
if (header->SupportRecordPool()) {
|
||||
SectionInfo *info = header->GetRecordPoolSection();
|
||||
if (info == nullptr) {
|
||||
return;
|
||||
}
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
recordPool_->ParseFromBinary(&addr, header);
|
||||
if (!ParseSectionsFromBinary(apSectionList_, buffer, header)) {
|
||||
return;
|
||||
}
|
||||
if (header->SupportWideProfileType()) {
|
||||
SectionInfo *info = header->GetProfileTypeSection();
|
||||
if (info == nullptr) {
|
||||
return;
|
||||
}
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
profileTypePool_->ParseFromBinary(&addr, header);
|
||||
}
|
||||
|
||||
SectionInfo *info = header->GetRecordInfoSection();
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
for (uint32_t i = 0; i < info->number_; i++) {
|
||||
ApEntityId recordId(0);
|
||||
if (header->SupportRecordPool()) {
|
||||
ProfileType recordType;
|
||||
if (header->SupportProfileTypeWithAbcId()) {
|
||||
auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
|
||||
recordType = ProfileType(*this, recordTypeRef);
|
||||
recordId = recordType.GetId();
|
||||
} else if (header->SupportRecordPool()) {
|
||||
recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
|
||||
} else {
|
||||
auto *recordName = base::ReadBuffer(&addr);
|
||||
recordPool_->TryAdd(recordName, recordId);
|
||||
}
|
||||
recordType.UpdateId(recordId);
|
||||
recordType.UpdateKind(ProfileType::Kind::LocalRecordId);
|
||||
PGOMethodInfoMap *methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
|
||||
if (methodInfos->ParseFromBinary(chunk_.get(), *this, &addr)) {
|
||||
recordInfos_.emplace(recordId, methodInfos);
|
||||
recordInfos_.emplace(recordType, methodInfos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,7 +760,7 @@ void PGORecordDetailInfos::ProcessToBinary(
|
||||
}
|
||||
auto recordId = iter->first;
|
||||
auto curMethodInfos = iter->second;
|
||||
if (curMethodInfos->ProcessToBinary(*this, recordId, task, fileStream, header)) {
|
||||
if (curMethodInfos->ProcessToBinary(*this, ProfileTypeRef(*this, recordId), task, fileStream, header)) {
|
||||
info->number_++;
|
||||
}
|
||||
}
|
||||
@ -770,24 +780,13 @@ void PGORecordDetailInfos::ProcessToBinary(
|
||||
}
|
||||
info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
|
||||
|
||||
info = header->GetRecordPoolSection();
|
||||
if (info == nullptr) {
|
||||
return;
|
||||
for (const auto §ionWeak : apSectionList_) {
|
||||
auto section = sectionWeak.lock();
|
||||
if (section == nullptr) {
|
||||
continue;
|
||||
}
|
||||
PGOFileSectionInterface::ProcessSectionToBinary(fileStream, header, *section);
|
||||
}
|
||||
info->number_ = 0;
|
||||
info->offset_ = static_cast<uint32_t>(fileStream.tellp());
|
||||
info->number_ = recordPool_->ProcessToBinary(fileStream);
|
||||
info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
|
||||
|
||||
info = header->GetProfileTypeSection();
|
||||
if (info == nullptr) {
|
||||
return;
|
||||
}
|
||||
info->number_ = 0;
|
||||
info->offset_ = static_cast<uint32_t>(fileStream.tellp());
|
||||
info->number_ = profileTypePool_->ProcessToBinary(fileStream);
|
||||
info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
|
||||
header->SetFileSize(static_cast<uint32_t>(fileStream.tellp()));
|
||||
}
|
||||
|
||||
bool PGORecordDetailInfos::ProcessToBinaryForLayout(
|
||||
@ -852,13 +851,14 @@ bool PGORecordDetailInfos::ParseFromText(std::ifstream &stream)
|
||||
continue;
|
||||
}
|
||||
|
||||
ApEntityId recordId;
|
||||
ApEntityId recordId(0);
|
||||
recordPool_->TryAdd(recordName, recordId);
|
||||
auto methodInfosIter = recordInfos_.find(recordId);
|
||||
ProfileType profileType(0, recordId, ProfileType::Kind::LocalRecordId);
|
||||
auto methodInfosIter = recordInfos_.find(profileType);
|
||||
PGOMethodInfoMap *methodInfos = nullptr;
|
||||
if (methodInfosIter == recordInfos_.end()) {
|
||||
methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
|
||||
recordInfos_.emplace(recordId, methodInfos);
|
||||
recordInfos_.emplace(profileType, methodInfos);
|
||||
} else {
|
||||
methodInfos = methodInfosIter->second;
|
||||
}
|
||||
@ -888,13 +888,21 @@ void PGORecordDetailInfos::ProcessToText(std::ofstream &stream) const
|
||||
stream << profilerString;
|
||||
}
|
||||
for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
|
||||
auto recordId = iter->first;
|
||||
auto recordName = recordPool_->GetRecord(recordId)->GetRecordName();
|
||||
auto recordId = ApEntityId(iter->first.GetId());
|
||||
auto recordName = recordPool_->GetEntry(recordId)->GetData();
|
||||
auto methodInfos = iter->second;
|
||||
methodInfos->ProcessToText(hotnessThreshold_, recordName, stream);
|
||||
}
|
||||
recordPool_->ProcessToText(stream);
|
||||
profileTypePool_->ProcessToText(stream);
|
||||
recordPool_->GetPool()->ProcessToText(stream);
|
||||
profileTypePool_->GetPool()->ProcessToText(stream);
|
||||
}
|
||||
|
||||
void PGORecordDetailInfos::InitSections()
|
||||
{
|
||||
recordPool_ = std::make_unique<PGORecordPool>();
|
||||
apSectionList_.emplace_back(recordPool_->GetPool());
|
||||
profileTypePool_ = std::make_unique<PGOProfileTypePool>();
|
||||
apSectionList_.emplace_back(profileTypePool_->GetPool());
|
||||
}
|
||||
|
||||
void PGORecordDetailInfos::Clear()
|
||||
@ -906,9 +914,9 @@ void PGORecordDetailInfos::Clear()
|
||||
recordInfos_.clear();
|
||||
recordPool_->Clear();
|
||||
profileTypePool_->Clear();
|
||||
apSectionList_.clear();
|
||||
chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
|
||||
recordPool_ = std::make_unique<PGORecordPool>();
|
||||
profileTypePool_ = std::make_unique<PGOProfileTypePool>();
|
||||
InitSections();
|
||||
}
|
||||
|
||||
bool PGORecordSimpleInfos::Match(const CString &recordName, EntityId methodId)
|
||||
@ -923,29 +931,20 @@ bool PGORecordSimpleInfos::Match(const CString &recordName, EntityId methodId)
|
||||
void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
|
||||
{
|
||||
header_ = header;
|
||||
if (header->SupportRecordPool()) {
|
||||
SectionInfo *info = header->GetRecordPoolSection();
|
||||
if (info == nullptr) {
|
||||
return;
|
||||
}
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
recordPool_->ParseFromBinary(&addr, header);
|
||||
}
|
||||
if (header->SupportWideProfileType()) {
|
||||
SectionInfo *info = header->GetProfileTypeSection();
|
||||
if (info == nullptr) {
|
||||
return;
|
||||
}
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
profileTypePool_->ParseFromBinary(&addr, header);
|
||||
}
|
||||
ParseSectionsFromBinary(apSectionList_, buffer, header);
|
||||
SectionInfo *info = header->GetRecordInfoSection();
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
for (uint32_t i = 0; i < info->number_; i++) {
|
||||
CString recordName;
|
||||
if (header->SupportRecordPool()) {
|
||||
ProfileType recordType;
|
||||
if (header->SupportProfileTypeWithAbcId()) {
|
||||
auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
|
||||
recordType = ProfileType(*this, recordTypeRef);
|
||||
auto recordId = recordType.GetId();
|
||||
recordName = recordPool_->GetEntry(recordId)->GetData();
|
||||
} else if (header->SupportRecordPool()) {
|
||||
auto recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
|
||||
recordName = recordPool_->GetRecord(recordId)->GetRecordName();
|
||||
recordName = recordPool_->GetEntry(recordId)->GetData();
|
||||
} else {
|
||||
recordName = base::ReadBuffer(&addr);
|
||||
}
|
||||
@ -1003,6 +1002,14 @@ bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
|
||||
return true;
|
||||
}
|
||||
|
||||
void PGORecordSimpleInfos::InitSections()
|
||||
{
|
||||
recordPool_ = std::make_unique<PGORecordPool>();
|
||||
apSectionList_.emplace_back(recordPool_->GetPool());
|
||||
profileTypePool_ = std::make_unique<PGOProfileTypePool>();
|
||||
apSectionList_.emplace_back(profileTypePool_->GetPool());
|
||||
}
|
||||
|
||||
void PGORecordSimpleInfos::Clear()
|
||||
{
|
||||
for (const auto &iter : methodIds_) {
|
||||
@ -1012,16 +1019,15 @@ void PGORecordSimpleInfos::Clear()
|
||||
methodIds_.clear();
|
||||
recordPool_->Clear();
|
||||
profileTypePool_->Clear();
|
||||
apSectionList_.clear();
|
||||
chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
|
||||
recordPool_ = std::make_shared<PGORecordPool>();
|
||||
profileTypePool_ = std::make_shared<PGOProfileTypePool>();
|
||||
InitSections();
|
||||
}
|
||||
|
||||
PGORecordSimpleInfos::PGORecordSimpleInfos(uint32_t threshold) : hotnessThreshold_(threshold)
|
||||
{
|
||||
chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
|
||||
recordPool_ = std::make_shared<PGORecordPool>();
|
||||
profileTypePool_ = std::make_shared<PGOProfileTypePool>();
|
||||
InitSections();
|
||||
}
|
||||
|
||||
PGORecordSimpleInfos::~PGORecordSimpleInfos()
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_record_pool.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
|
||||
#include "ecmascript/property_attributes.h"
|
||||
#include "macros.h"
|
||||
@ -282,8 +283,8 @@ public:
|
||||
void Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos);
|
||||
|
||||
bool ParseFromBinary(Chunk *chunk, PGOContext &context, void **buffer);
|
||||
bool ProcessToBinary(PGOContext &context, ApEntityId recordId, const SaveTask *task, std::fstream &fileStream,
|
||||
PGOProfilerHeader *const header) const;
|
||||
bool ProcessToBinary(PGOContext &context, ProfileTypeRef recordProfileRef, const SaveTask *task,
|
||||
std::fstream &fileStream, PGOProfilerHeader *const header) const;
|
||||
|
||||
bool ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content);
|
||||
void ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const;
|
||||
@ -454,14 +455,15 @@ public:
|
||||
~PGORecordDetailInfos() override;
|
||||
|
||||
void Clear();
|
||||
void InitSections();
|
||||
|
||||
// If it is a new method, return true.
|
||||
bool AddMethod(const CString &recordName, Method *jsMethod, SampleMode mode, int32_t incCount);
|
||||
bool AddType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type);
|
||||
bool AddCallTargetType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type);
|
||||
bool AddObjectInfo(const CString &recordName, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
|
||||
bool AddMethod(ProfileType recordProfileType, Method *jsMethod, SampleMode mode, int32_t incCount);
|
||||
bool AddType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type);
|
||||
bool AddCallTargetType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type);
|
||||
bool AddObjectInfo(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
|
||||
bool AddDefine(
|
||||
const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType);
|
||||
ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType);
|
||||
bool AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjKind kind);
|
||||
bool UpdateElementsKind(PGOSampleType type, ElementsKind kind);
|
||||
void Merge(const PGORecordDetailInfos &recordInfos);
|
||||
@ -474,15 +476,16 @@ public:
|
||||
bool ParseFromText(std::ifstream &stream);
|
||||
void ProcessToText(std::ofstream &stream) const;
|
||||
|
||||
const CMap<ApEntityId, PGOMethodInfoMap *> &GetRecordInfos() const
|
||||
const CMap<ProfileType, PGOMethodInfoMap *> &GetRecordInfos() const
|
||||
{
|
||||
return recordInfos_;
|
||||
}
|
||||
|
||||
std::shared_ptr<PGORecordPool> GetRecordPool() const override
|
||||
std::shared_ptr<PGORecordPool> GetRecordPool() const
|
||||
{
|
||||
return recordPool_;
|
||||
}
|
||||
|
||||
std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
|
||||
{
|
||||
return profileTypePool_;
|
||||
@ -508,16 +511,17 @@ public:
|
||||
NO_MOVE_SEMANTIC(PGORecordDetailInfos);
|
||||
|
||||
private:
|
||||
PGOMethodInfoMap *GetMethodInfoMap(const CString &recordName);
|
||||
PGOMethodInfoMap *GetMethodInfoMap(ProfileType recordProfileType);
|
||||
bool ParseFromBinaryForLayout(void **buffer);
|
||||
bool ProcessToBinaryForLayout(NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream);
|
||||
|
||||
uint32_t hotnessThreshold_ {2};
|
||||
NativeAreaAllocator nativeAreaAllocator_;
|
||||
std::unique_ptr<Chunk> chunk_;
|
||||
CMap<ApEntityId, PGOMethodInfoMap *> recordInfos_;
|
||||
CMap<ProfileType, PGOMethodInfoMap *> recordInfos_;
|
||||
std::set<PGOHClassLayoutDesc> moduleLayoutDescInfos_;
|
||||
PGOProfilerHeader *header_;
|
||||
PGOProfilerHeader *header_ {nullptr};
|
||||
std::list<std::weak_ptr<PGOFileSectionInterface>> apSectionList_;
|
||||
std::shared_ptr<PGORecordPool> recordPool_;
|
||||
std::shared_ptr<PGOProfileTypePool> profileTypePool_;
|
||||
};
|
||||
@ -530,6 +534,8 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
void InitSections();
|
||||
|
||||
bool Match(const CString &recordName, EntityId methodId);
|
||||
|
||||
template <typename Callback>
|
||||
@ -607,10 +613,6 @@ public:
|
||||
|
||||
void Merge(const PGORecordSimpleInfos &simpleInfos);
|
||||
|
||||
std::shared_ptr<PGORecordPool> GetRecordPool() const override
|
||||
{
|
||||
return recordPool_;
|
||||
}
|
||||
std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
|
||||
{
|
||||
return profileTypePool_;
|
||||
@ -642,7 +644,8 @@ private:
|
||||
NativeAreaAllocator nativeAreaAllocator_;
|
||||
std::unique_ptr<Chunk> chunk_;
|
||||
CUnorderedMap<CString, PGOMethodIdSet *> methodIds_;
|
||||
PGOProfilerHeader *header_;
|
||||
PGOProfilerHeader *header_ {nullptr};
|
||||
std::list<std::weak_ptr<PGOFileSectionInterface>> apSectionList_;
|
||||
std::shared_ptr<PGORecordPool> recordPool_;
|
||||
std::shared_ptr<PGOProfileTypePool> profileTypePool_;
|
||||
std::set<PGOHClassLayoutDesc> moduleLayoutDescInfos_;
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
void Initialize(const std::string &outDir, uint32_t hotnessThreshold)
|
||||
{
|
||||
// For FA jsvm, merge with existed output file
|
||||
encoder_ = std::make_unique<PGOProfilerEncoder>(outDir, hotnessThreshold, ApGenMode::MERGE);
|
||||
encoder_ = std::make_unique<PGOProfilerEncoder>(outDir, hotnessThreshold, ApGenMode::OVERWRITE);
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
@ -91,13 +91,28 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SamplePandaFileInfo(uint32_t checksum)
|
||||
void SamplePandaFileInfo(uint32_t checksum, const CString &abcName)
|
||||
{
|
||||
if (encoder_) {
|
||||
encoder_->SamplePandaFileInfo(checksum);
|
||||
encoder_->SamplePandaFileInfo(checksum, abcName);
|
||||
}
|
||||
}
|
||||
|
||||
void SetModuleName(const std::string &moduleName)
|
||||
{
|
||||
if (encoder_) {
|
||||
encoder_->ResetOutPathByModuleName(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetPandaFileId(const CString &abcName, ApEntityId &entryId) const
|
||||
{
|
||||
if (encoder_) {
|
||||
return encoder_->GetPandaFileId(abcName, entryId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetApGenMode(ApGenMode mode)
|
||||
{
|
||||
if (encoder_) {
|
||||
|
@ -24,7 +24,8 @@
|
||||
namespace panda::ecmascript::pgo {
|
||||
static constexpr Alignment ALIGN_SIZE = Alignment::LOG_ALIGN_4;
|
||||
using PGOMethodId = panda_file::File::EntityId;
|
||||
using ApEntityId = panda_file::File::EntityId;
|
||||
using ApEntityId = uint32_t;
|
||||
|
||||
class DumpUtils {
|
||||
public:
|
||||
static const std::string ELEMENT_SEPARATOR;
|
||||
|
@ -22,13 +22,13 @@
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/base/file_header.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
class PGOContextMock : public PGOContext {
|
||||
public:
|
||||
explicit PGOContextMock(base::FileHeaderBase::VersionType version)
|
||||
{
|
||||
recordPool_ = std::make_shared<PGORecordPool>();
|
||||
profileTypePool_ = std::make_shared<PGOProfileTypePool>();
|
||||
PGOProfilerHeader::Build(&header_, sizeof(PGOProfilerHeader));
|
||||
header_->SetVersion(version);
|
||||
@ -38,10 +38,7 @@ public:
|
||||
delete header_;
|
||||
header_ = nullptr;
|
||||
};
|
||||
std::shared_ptr<PGORecordPool> GetRecordPool() const override
|
||||
{
|
||||
return recordPool_;
|
||||
}
|
||||
|
||||
std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
|
||||
{
|
||||
return profileTypePool_;
|
||||
@ -63,7 +60,6 @@ public:
|
||||
private:
|
||||
NO_COPY_SEMANTIC(PGOContextMock);
|
||||
NO_MOVE_SEMANTIC(PGOContextMock);
|
||||
std::shared_ptr<PGORecordPool> recordPool_;
|
||||
std::shared_ptr<PGOProfileTypePool> profileTypePool_;
|
||||
PGOProfilerHeader *header_ {};
|
||||
uint32_t threshold_ {};
|
||||
|
@ -21,8 +21,11 @@
|
||||
|
||||
#include "ecmascript/elements.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "assembler/assembly-emitter.h"
|
||||
@ -134,7 +137,7 @@ HWTEST_F_L0(PGOProfilerTest, Sample)
|
||||
JSHandle<ConstantPool> constPool = vm_->GetFactory()->NewConstantPool(4);
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler.abc");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
@ -182,7 +185,7 @@ HWTEST_F_L0(PGOProfilerTest, Sample1)
|
||||
JSHandle<ConstantPool> constPool = vm_->GetFactory()->NewConstantPool(4);
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler1.abc");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
@ -249,7 +252,7 @@ HWTEST_F_L0(PGOProfilerTest, Sample2)
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler2.abc");
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
JSHandle<Method> method1 = vm_->GetFactory()->NewMethod(methodLiterals[1]);
|
||||
@ -309,7 +312,7 @@ HWTEST_F_L0(PGOProfilerTest, DisEnableSample)
|
||||
JSHandle<ConstantPool> constPool = vm_->GetFactory()->NewConstantPool(4);
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler3.abc");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
@ -364,7 +367,7 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerManagerSample)
|
||||
option.SetProfileDir(currentPath);
|
||||
vm_ = JSNApi::CreateJSVM(option);
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<JSArray> array = vm_->GetFactory()->NewJSArray();
|
||||
@ -406,14 +409,14 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDoubleVM)
|
||||
JSHandle<ConstantPool> constPool = vm_->GetFactory()->NewConstantPool(4);
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler5.abc");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
// worker vm read profile enable from PGOProfilerManager singleton
|
||||
option.SetEnableProfile(false);
|
||||
auto vm2 = JSNApi::CreateJSVM(option);
|
||||
JSHandle<ConstantPool> constPool2 = vm2->GetFactory()->NewConstantPool(4);
|
||||
constPool2->SetJSPandaFile(pf.get());
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler5.abc");
|
||||
ASSERT_TRUE(vm2 != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<Method> method = vm2->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
@ -475,7 +478,7 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDecoderNoHotMethod)
|
||||
JSHandle<ConstantPool> constPool = vm_->GetFactory()->NewConstantPool(4);
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler8.abc");
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
|
||||
@ -520,7 +523,7 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerPostTask)
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SetApGenMode(ApGenMode::OVERWRITE);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler9.abc");
|
||||
|
||||
JSHandle<JSTaggedValue> recordName(vm_->GetFactory()->NewFromStdString("test"));
|
||||
for (int i = 61; i < 91; i++) {
|
||||
@ -572,6 +575,7 @@ HWTEST_F_L0(PGOProfilerTest, BinaryToText)
|
||||
|
||||
PGOProfilerHeader *header = nullptr;
|
||||
PGOProfilerHeader::Build(&header, PGOProfilerHeader::LastSize());
|
||||
std::unique_ptr<PGOAbcFilePool> abcFilePool = std::make_unique<PGOAbcFilePool>();
|
||||
std::unique_ptr<PGOPandaFileInfos> pandaFileInfos = std::make_unique<PGOPandaFileInfos>();
|
||||
std::unique_ptr<PGORecordDetailInfos> recordInfos = std::make_unique<PGORecordDetailInfos>(2);
|
||||
|
||||
@ -583,12 +587,17 @@ HWTEST_F_L0(PGOProfilerTest, BinaryToText)
|
||||
auto *jsMethod =
|
||||
Method::Cast(vm_->GetFactory()->NewMethod(methodLiteral.get(), MemSpaceType::NON_MOVABLE).GetTaggedValue());
|
||||
|
||||
ASSERT_TRUE(recordInfos->AddMethod("test", jsMethod, SampleMode::CALL_MODE, 1));
|
||||
ASSERT_FALSE(recordInfos->AddMethod("test", jsMethod, SampleMode::CALL_MODE, 1));
|
||||
ASSERT_FALSE(recordInfos->AddMethod("test", jsMethod, SampleMode::CALL_MODE, 1));
|
||||
ApEntityId recordId(0);
|
||||
recordInfos->GetRecordPool()->TryAdd("test", recordId);
|
||||
ProfileType recordType(0, recordId, ProfileType::Kind::LocalRecordId);
|
||||
ASSERT_TRUE(recordInfos->AddMethod(recordType, jsMethod, SampleMode::CALL_MODE, 1));
|
||||
ASSERT_FALSE(recordInfos->AddMethod(recordType, jsMethod, SampleMode::CALL_MODE, 1));
|
||||
ASSERT_FALSE(recordInfos->AddMethod(recordType, jsMethod, SampleMode::CALL_MODE, 1));
|
||||
|
||||
pandaFileInfos->ProcessToBinary(file, header->GetPandaInfoSection());
|
||||
recordInfos->ProcessToBinary(nullptr, file, header);
|
||||
PGOFileSectionInterface::ProcessSectionToBinary(file, header, *abcFilePool->GetPool());
|
||||
header->SetFileSize(static_cast<uint32_t>(file.tellp()));
|
||||
header->ProcessToBinary(file);
|
||||
PGOProfilerEncoder::AddChecksum(file);
|
||||
file.close();
|
||||
@ -615,7 +624,7 @@ HWTEST_F_L0(PGOProfilerTest, TextToBinary)
|
||||
file.close();
|
||||
|
||||
ASSERT_TRUE(PGOProfilerManager::GetInstance()->TextToBinary("ark-profiler10/modules.text", "ark-profiler10/", 2,
|
||||
ApGenMode::MERGE));
|
||||
ApGenMode::OVERWRITE));
|
||||
|
||||
PGOProfilerDecoder loader("ark-profiler10/modules.ap", 2);
|
||||
ASSERT_TRUE(loader.LoadAndVerify(413775942));
|
||||
@ -643,7 +652,7 @@ HWTEST_F_L0(PGOProfilerTest, FailResetProfilerInWorker)
|
||||
// PgoProfiler is disabled as default.
|
||||
vm_ = JSNApi::CreateJSVM(option);
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler12.abc");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
@ -728,7 +737,8 @@ HWTEST_F_L0(PGOProfilerTest, UseClassTypeTest)
|
||||
auto pgoRWOpType = *reinterpret_cast<PGORWOpType *>(type);
|
||||
if (std::string(methodName) == "Foot" || std::string(methodName) == "Arm") {
|
||||
ASSERT_TRUE(pgoRWOpType.GetCount() == 1);
|
||||
ASSERT_EQ(pgoRWOpType.GetObjectInfo(0).GetProfileType(), ProfileType(methodId.GetOffset()));
|
||||
ASSERT_EQ(pgoRWOpType.GetObjectInfo(0).GetProfileType(),
|
||||
ProfileType(ApEntityId(PGORecordPool::RESERVED_COUNT), methodId.GetOffset()));
|
||||
} else if (std::string(methodName) == "foo" || std::string(methodName) == "Body") {
|
||||
ASSERT_TRUE(pgoRWOpType.GetCount() == 3);
|
||||
}
|
||||
@ -772,15 +782,15 @@ HWTEST_F_L0(PGOProfilerTest, DefineClassTypeTest)
|
||||
}
|
||||
ASSERT_EQ(desc->GetCtorLayoutDesc().size(), 3);
|
||||
ASSERT_EQ(desc->GetPtLayoutDesc().size(), 1);
|
||||
auto classId = EntityId(sampleType.GetProfileType().GetRaw());
|
||||
auto classId = EntityId(sampleType.GetProfileType().GetId());
|
||||
auto className = MethodLiteral::GetMethodName(jsPandaFile.get(), classId);
|
||||
if (std::string(className) == "Arm") {
|
||||
auto superClassId = EntityId(desc->GetSuperProfileType().GetRaw());
|
||||
auto superClassId = EntityId(desc->GetSuperProfileType().GetId());
|
||||
auto superClassName = MethodLiteral::GetMethodName(jsPandaFile.get(), superClassId);
|
||||
ASSERT_EQ(std::string(superClassName), "Body");
|
||||
ASSERT_EQ(desc->GetLayoutDesc().size(), 0);
|
||||
} else if (std::string(className) == "Foot") {
|
||||
auto superClassId = EntityId(desc->GetSuperProfileType().GetRaw());
|
||||
auto superClassId = EntityId(desc->GetSuperProfileType().GetId());
|
||||
auto superClassName = MethodLiteral::GetMethodName(jsPandaFile.get(), superClassId);
|
||||
ASSERT_EQ(std::string(superClassName), "Body");
|
||||
ASSERT_EQ(desc->GetLayoutDesc().size(), 0);
|
||||
@ -985,7 +995,7 @@ HWTEST_F_L0(PGOProfilerTest, FileConsistencyCheck)
|
||||
JSHandle<ConstantPool> constPool = vm_->GetFactory()->NewConstantPool(4);
|
||||
constPool->SetJSPandaFile(pf.get());
|
||||
uint32_t checksum = 304293;
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum);
|
||||
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler.abc");
|
||||
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
|
||||
|
||||
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiterals[0]);
|
||||
|
@ -14,13 +14,18 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
#include "ecmascript/log.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::ecmascript::pgo {
|
||||
const ProfileType ProfileType::PROFILE_TYPE_NONE = ProfileType(0, 0);
|
||||
|
||||
ProfileTypeRef::ProfileTypeRef(PGOContext &context, const ProfileType &type)
|
||||
{
|
||||
ApEntityId apId;
|
||||
ApEntityId apId(0);
|
||||
context.GetProfileTypePool()->TryAdd(type, apId);
|
||||
UpdateId(apId);
|
||||
}
|
||||
@ -32,7 +37,7 @@ ProfileType::ProfileType(PGOContext &context, ProfileTypeRef typeRef)
|
||||
UpdateId(legacy.GetId());
|
||||
UpdateKind(legacy.GetKind());
|
||||
} else {
|
||||
const auto *typeEntry = context.GetProfileTypePool()->GetRecord(typeRef.GetId());
|
||||
const auto *typeEntry = context.GetProfileTypePool()->GetEntry(typeRef.GetId());
|
||||
if (typeEntry == nullptr) {
|
||||
LOG_ECMA(ERROR) << "Profile type ref: " << typeRef.GetTypeString() << " not found in ap file.";
|
||||
} else {
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "ecmascript/log.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_context.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "libpandabase/utils/bit_field.h"
|
||||
@ -38,27 +40,31 @@ public:
|
||||
LiteralId,
|
||||
ElementId,
|
||||
BuiltinsId,
|
||||
LegacyKind = BuiltinsId,
|
||||
LocalRecordId,
|
||||
TotalKinds,
|
||||
UnknowId,
|
||||
LegacyKind = UnknowId
|
||||
UnknowId
|
||||
};
|
||||
|
||||
static const ProfileType PROFILE_TYPE_NONE;
|
||||
|
||||
static constexpr uint32_t ID_BITFIELD_NUM = 29;
|
||||
static constexpr uint32_t RECORD_ID_BITFIELD_NUM = 20;
|
||||
static constexpr uint32_t ABC_ID_BITFIELD_NUM = 20;
|
||||
static constexpr uint32_t KIND_BITFIELD_NUM = 15;
|
||||
using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>;
|
||||
using IdRecordBits = IdBits::NextField<uint32_t, RECORD_ID_BITFIELD_NUM>;
|
||||
using KindBits = IdRecordBits::NextField<Kind, KIND_BITFIELD_NUM>;
|
||||
using AbcIdBits = IdBits::NextField<uint32_t, ABC_ID_BITFIELD_NUM>;
|
||||
using KindBits = AbcIdBits::NextField<Kind, KIND_BITFIELD_NUM>;
|
||||
|
||||
static_assert(KindBits::IsValid(Kind::TotalKinds));
|
||||
|
||||
ProfileType() = default;
|
||||
ProfileType(PGOContext &context, ProfileTypeRef typeRef);
|
||||
explicit ProfileType(uint32_t type, Kind kind = Kind::ClassId)
|
||||
ProfileType(ApEntityId abcId, uint32_t type, Kind kind = Kind::ClassId)
|
||||
{
|
||||
if (UNLIKELY(!IdBits::IsValid(type))) {
|
||||
type_ = 0;
|
||||
} else {
|
||||
UpdateAbcId(abcId);
|
||||
UpdateId(type);
|
||||
UpdateKind(kind);
|
||||
}
|
||||
@ -66,7 +72,7 @@ public:
|
||||
|
||||
bool IsNone() const
|
||||
{
|
||||
return type_ == 0;
|
||||
return type_ == PROFILE_TYPE_NONE.type_;
|
||||
}
|
||||
|
||||
uint64_t GetRaw() const
|
||||
@ -99,9 +105,14 @@ public:
|
||||
return KindBits::Decode(type_);
|
||||
}
|
||||
|
||||
uint32_t GetRecordId() const
|
||||
ApEntityId GetAbcId() const
|
||||
{
|
||||
return IdRecordBits::Decode(type_);
|
||||
return AbcIdBits::Decode(type_);
|
||||
}
|
||||
|
||||
void UpdateAbcId(ApEntityId abcId)
|
||||
{
|
||||
type_ = AbcIdBits::Update(type_, abcId);
|
||||
}
|
||||
|
||||
bool operator<(const ProfileType &right) const
|
||||
@ -121,12 +132,22 @@ public:
|
||||
|
||||
std::string GetTypeString() const
|
||||
{
|
||||
return std::to_string(type_);
|
||||
std::stringstream stream;
|
||||
stream << "type: " << std::showbase << std::hex << type_ <<
|
||||
"(kind: " << std::showbase << std::dec << static_cast<uint32_t>(GetKind()) <<
|
||||
", abcId: " << GetAbcId() <<
|
||||
", id: " << GetId() << ")";
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
void UpdateRecordId(uint32_t recordId)
|
||||
void UpdateId(uint32_t id)
|
||||
{
|
||||
type_ = IdRecordBits::Update(type_, recordId);
|
||||
type_ = IdBits::Update(type_, id);
|
||||
}
|
||||
|
||||
void UpdateKind(Kind kind)
|
||||
{
|
||||
type_ = KindBits::Update(type_, kind);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -135,10 +156,6 @@ private:
|
||||
type_ = IdBits::Update(type_, type);
|
||||
}
|
||||
|
||||
void UpdateKind(Kind kind)
|
||||
{
|
||||
type_ = KindBits::Update(type_, kind);
|
||||
}
|
||||
uint64_t type_ {0};
|
||||
};
|
||||
|
||||
@ -153,7 +170,7 @@ public:
|
||||
|
||||
bool IsNone() const
|
||||
{
|
||||
return typeId_.GetOffset() == 0;
|
||||
return typeId_ == 0;
|
||||
}
|
||||
|
||||
ApEntityId GetId() const
|
||||
@ -173,7 +190,7 @@ public:
|
||||
|
||||
std::string GetTypeString() const
|
||||
{
|
||||
return std::to_string(typeId_.GetOffset());
|
||||
return std::to_string(typeId_);
|
||||
}
|
||||
|
||||
void UpdateId(ApEntityId typeId)
|
||||
@ -184,6 +201,7 @@ public:
|
||||
private:
|
||||
ApEntityId typeId_ {0};
|
||||
};
|
||||
static_assert(sizeof(ProfileTypeRef) == sizeof(uint32_t));
|
||||
|
||||
class ProfileTypeLegacy {
|
||||
public:
|
||||
@ -206,10 +224,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
explicit ProfileTypeLegacy(ProfileTypeRef profileTypeRef)
|
||||
{
|
||||
type_ = profileTypeRef.GetId().GetOffset();
|
||||
}
|
||||
explicit ProfileTypeLegacy(ProfileTypeRef profileTypeRef) : type_(profileTypeRef.GetId()) {}
|
||||
|
||||
bool IsNone() const
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_utils.h"
|
||||
#include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
|
||||
#include "libpandabase/utils/bit_field.h"
|
||||
#include "macros.h"
|
||||
@ -96,10 +97,10 @@ public:
|
||||
return PGOSampleTemplate(static_cast<PGOSampleTemplate::Type>(from.GetType()));
|
||||
}
|
||||
|
||||
static PGOSampleTemplate CreateProfileType(int32_t profileType,
|
||||
static PGOSampleTemplate CreateProfileType(ApEntityId recordId, int32_t profileType,
|
||||
typename ProfileType::Kind kind = ProfileType::Kind::ClassId)
|
||||
{
|
||||
return PGOSampleTemplate(PGOProfileType(profileType, kind));
|
||||
return PGOSampleTemplate(PGOProfileType(recordId, profileType, kind));
|
||||
}
|
||||
|
||||
static PGOSampleTemplate NoneType()
|
||||
@ -197,7 +198,7 @@ public:
|
||||
uint32_t newMethodId = type.GetProfileType().GetId();
|
||||
// If we have recorded a valid method if before, invalidate it.
|
||||
if ((oldMethodId != newMethodId) && (oldMethodId != 0)) {
|
||||
type_ = PGOProfileType(0);
|
||||
type_ = ProfileType::PROFILE_TYPE_NONE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user