mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
!4381 Support Merge Ap for profdump tool and aot compiler
Merge pull request !4381 from hzzhouzebin/MergeAp
This commit is contained in:
commit
f8240a77bb
1
BUILD.gn
1
BUILD.gn
@ -742,6 +742,7 @@ ecma_source = [
|
||||
"ecmascript/pgo_profiler/pgo_profiler_encoder.cpp",
|
||||
"ecmascript/pgo_profiler/pgo_profiler_info.cpp",
|
||||
"ecmascript/pgo_profiler/pgo_profiler_layout.cpp",
|
||||
"ecmascript/pgo_profiler/pgo_profiler_manager.cpp",
|
||||
"ecmascript/stackmap/ark_stackmap_builder.cpp",
|
||||
"ecmascript/stackmap/ark_stackmap_parser.cpp",
|
||||
"ecmascript/stackmap/llvm_stackmap_parser.cpp",
|
||||
|
@ -81,13 +81,18 @@ public:
|
||||
return version_ >= expectVersion;
|
||||
}
|
||||
|
||||
VersionType GetVersion() const
|
||||
{
|
||||
return version_;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit FileHeaderBase(const VersionType &lastVersion) : magic_(MAGIC), version_(lastVersion) {}
|
||||
|
||||
static bool VerifyVersion(const char *fileDesc, const VersionType &currVersion, const VersionType &lastVersion,
|
||||
bool strictMatch)
|
||||
{
|
||||
bool matched = strictMatch ? currVersion == lastVersion : currVersion <= lastVersion;
|
||||
bool matched = strictMatch ? (currVersion == lastVersion) : (currVersion <= lastVersion);
|
||||
if (!matched) {
|
||||
LOG_HOST_TOOL_ERROR << fileDesc << " version error, expected version should be "
|
||||
<< (strictMatch ? "equal to " : "less or equal than ") << ConvToStr(lastVersion)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ecmascript/ecma_handle_scope.h"
|
||||
#include "ecmascript/jspandafile/js_pandafile_manager.h"
|
||||
#include "ecmascript/jspandafile/panda_file_translator.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
#include "ecmascript/snapshot/mem/snapshot.h"
|
||||
#include "ecmascript/ts_types/ts_manager.h"
|
||||
|
||||
@ -39,7 +40,7 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!profilerDecoder_.LoadAndVerify(jsPandaFile->GetChecksum())) {
|
||||
if (!PGOProfilerManager::MergeApFiles(jsPandaFile->GetChecksum(), profilerDecoder_)) {
|
||||
LOG_COMPILER(ERROR) << "Load and verify profiler failure";
|
||||
return false;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ecmascript/compiler/file_generators.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
#include "ecmascript/ts_types/ts_manager.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
@ -166,7 +167,7 @@ private: \
|
||||
|
||||
class PassManager {
|
||||
public:
|
||||
PassManager(EcmaVM* vm, std::string entry, std::string &triple, size_t optLevel, size_t relocMode,
|
||||
PassManager(EcmaVM* vm, std::string &entry, std::string &triple, size_t optLevel, size_t relocMode,
|
||||
CompilerLog *log, AotMethodLogList *logList, size_t maxAotMethodSize, size_t maxMethodsInModule,
|
||||
const std::string &profIn, uint32_t hotnessThreshold, PassOptions *passOptions)
|
||||
: vm_(vm), entry_(entry), triple_(triple), optLevel_(optLevel), relocMode_(relocMode), log_(log),
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
|
||||
|
||||
#include "ecmascript/base/file_header.h"
|
||||
#include "ecmascript/jspandafile/method_literal.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
|
||||
@ -80,7 +81,8 @@ bool PGOProfilerDecoder::LoadFull()
|
||||
if (isLoaded_) {
|
||||
Clear();
|
||||
}
|
||||
if (!LoadAPBinaryFile()) {
|
||||
// profiler dump tools may write data to memory when merge ap files.
|
||||
if (!LoadAPBinaryFile(PAGE_PROT_READWRITE)) {
|
||||
return false;
|
||||
}
|
||||
void *addr = fileMapAddr_.GetOriginAddr();
|
||||
@ -123,7 +125,7 @@ bool PGOProfilerDecoder::SaveAPTextFile(const std::string &outPath)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PGOProfilerDecoder::LoadAPBinaryFile()
|
||||
bool PGOProfilerDecoder::LoadAPBinaryFile(int prot)
|
||||
{
|
||||
std::string realPath;
|
||||
if (!RealPath(inPath_, realPath)) {
|
||||
@ -136,7 +138,7 @@ bool PGOProfilerDecoder::LoadAPBinaryFile()
|
||||
return false;
|
||||
}
|
||||
LOG_ECMA(INFO) << "Load profiler from file:" << realPath;
|
||||
fileMapAddr_ = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ);
|
||||
fileMapAddr_ = FileMap(realPath.c_str(), FILE_RDONLY, prot);
|
||||
if (fileMapAddr_.GetOriginAddr() == nullptr) {
|
||||
LOG_ECMA(ERROR) << "File mmap failed";
|
||||
return false;
|
||||
@ -197,4 +199,34 @@ void PGOProfilerDecoder::GetMismatchResult(uint32_t &totalMethodCount, uint32_t
|
||||
}
|
||||
return recordSimpleInfos_->GetMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet);
|
||||
}
|
||||
|
||||
bool PGOProfilerDecoder::InitMergeData()
|
||||
{
|
||||
ASSERT(!isLoaded_);
|
||||
if (!recordSimpleInfos_) {
|
||||
recordSimpleInfos_ = std::make_unique<PGORecordSimpleInfos>(hotnessThreshold_);
|
||||
}
|
||||
if (!header_) {
|
||||
// For merge scene, we only care about the ap capability which is in the version field.
|
||||
PGOProfilerHeader::Build(&header_, sizeof(PGOProfilerHeader));
|
||||
memset_s(header_, sizeof(PGOProfilerHeader), 0, sizeof(PGOProfilerHeader));
|
||||
}
|
||||
isLoaded_ = true;
|
||||
isVerifySuccess_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PGOProfilerDecoder::Merge(const PGOProfilerDecoder &decoder)
|
||||
{
|
||||
if (!isLoaded_ || !isVerifySuccess_) {
|
||||
return;
|
||||
}
|
||||
// For merge scene, we chose the highest version from input ap files
|
||||
if (!(header_->CompatibleVerify(decoder.header_->GetVersion()))) {
|
||||
// For merge scene, we only care about the ap capability which is in the version field.
|
||||
memcpy_s(header_, sizeof(base::FileHeaderBase), decoder.header_, sizeof(base::FileHeaderBase));
|
||||
}
|
||||
pandaFileInfos_.Merge(decoder.GetPandaFileInfos());
|
||||
recordSimpleInfos_->Merge(decoder.GetRecordSimpleInfos());
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -43,6 +43,20 @@ public:
|
||||
|
||||
bool PUBLIC_API SaveAPTextFile(const std::string &outPath);
|
||||
|
||||
void Merge(const PGOProfilerDecoder &decoder);
|
||||
|
||||
bool InitMergeData();
|
||||
|
||||
const std::string& GetInPath() const
|
||||
{
|
||||
return inPath_;
|
||||
}
|
||||
|
||||
uint32_t GetHotnessThreshold() const
|
||||
{
|
||||
return hotnessThreshold_;
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void Update(Callback callback)
|
||||
{
|
||||
@ -102,11 +116,26 @@ public:
|
||||
return isLoaded_;
|
||||
}
|
||||
|
||||
PGORecordDetailInfos &GetRecordDetailInfos() const
|
||||
{
|
||||
return *recordDetailInfos_;
|
||||
}
|
||||
|
||||
PGORecordSimpleInfos &GetRecordSimpleInfos() const
|
||||
{
|
||||
return *recordSimpleInfos_;
|
||||
}
|
||||
|
||||
const PGOPandaFileInfos &GetPandaFileInfos() const
|
||||
{
|
||||
return pandaFileInfos_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Load();
|
||||
bool Verify(uint32_t checksum);
|
||||
|
||||
bool LoadAPBinaryFile();
|
||||
bool LoadAPBinaryFile(int prot = PAGE_PROT_READ);
|
||||
void UnLoadAPBinaryFile();
|
||||
|
||||
bool isLoaded_ {false};
|
||||
|
@ -75,6 +75,17 @@ void PGOProfilerEncoder::Merge(const PGORecordDetailInfos &recordInfos)
|
||||
globalRecordInfos_->Merge(recordInfos);
|
||||
}
|
||||
|
||||
void PGOProfilerEncoder::Merge(const PGOPandaFileInfos &pandaFileInfos)
|
||||
{
|
||||
return pandaFileInfos_->Merge(pandaFileInfos);
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::VerifyPandaFileMatched(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
|
||||
const std::string &incoming) const
|
||||
{
|
||||
return pandaFileInfos_->VerifyChecksum(pandaFileInfos, base, incoming);
|
||||
}
|
||||
|
||||
bool PGOProfilerEncoder::Save()
|
||||
{
|
||||
if (!isInitialized_) {
|
||||
|
@ -41,6 +41,9 @@ public:
|
||||
|
||||
void SamplePandaFileInfo(uint32_t checksum);
|
||||
void Merge(const PGORecordDetailInfos &recordInfos);
|
||||
void Merge(const PGOPandaFileInfos &pandaFileInfos);
|
||||
bool VerifyPandaFileMatched(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
|
||||
const std::string &incoming) const;
|
||||
void TerminateSaveTask();
|
||||
void PostSaveTask();
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "ecmascript/base/bit_helper.h"
|
||||
@ -180,7 +181,7 @@ void PGOPandaFileInfos::ParseFromBinary(void *buffer, SectionInfo *const info)
|
||||
{
|
||||
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
|
||||
for (uint32_t i = 0; i < info->number_; i++) {
|
||||
pandaFileInfos_.emplace(*base::ReadBufferInSize<PandaFileInfo>(&addr));
|
||||
fileInfos_.emplace(*base::ReadBufferInSize<FileInfo>(&addr));
|
||||
}
|
||||
LOG_ECMA(DEBUG) << "Profiler panda file count:" << info->number_;
|
||||
}
|
||||
@ -188,13 +189,34 @@ void PGOPandaFileInfos::ParseFromBinary(void *buffer, SectionInfo *const info)
|
||||
void PGOPandaFileInfos::ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const
|
||||
{
|
||||
fileStream.seekp(info->offset_);
|
||||
info->number_ = pandaFileInfos_.size();
|
||||
for (auto localInfo : pandaFileInfos_) {
|
||||
info->number_ = fileInfos_.size();
|
||||
for (auto localInfo : fileInfos_) {
|
||||
fileStream.write(reinterpret_cast<char *>(&localInfo), localInfo.Size());
|
||||
}
|
||||
info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
|
||||
}
|
||||
|
||||
void PGOPandaFileInfos::Merge(const PGOPandaFileInfos &pandaFileInfos)
|
||||
{
|
||||
for (const auto &info : pandaFileInfos.fileInfos_) {
|
||||
fileInfos_.emplace(info.GetChecksum());
|
||||
}
|
||||
}
|
||||
|
||||
bool PGOPandaFileInfos::VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
|
||||
const std::string &incoming) const
|
||||
{
|
||||
std::set<FileInfo> unionChecksum;
|
||||
set_union(fileInfos_.begin(), fileInfos_.end(), pandaFileInfos.fileInfos_.begin(), pandaFileInfos.fileInfos_.end(),
|
||||
inserter(unionChecksum, unionChecksum.begin()));
|
||||
if (!fileInfos_.empty() && unionChecksum.empty()) {
|
||||
LOG_ECMA(ERROR) << "First AP file(" << base << ") and the incoming file(" << incoming
|
||||
<< ") do not come from the same abc file, skip merge the incoming file.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PGOPandaFileInfos::ParseFromText(std::ifstream &stream)
|
||||
{
|
||||
std::string pandaFileInfo;
|
||||
@ -227,7 +249,7 @@ void PGOPandaFileInfos::ProcessToText(std::ofstream &stream) const
|
||||
{
|
||||
std::string pandaFileInfo = NEW_LINE + PANDA_FILE_INFO_HEADER;
|
||||
bool isFirst = true;
|
||||
for (auto &info : pandaFileInfos_) {
|
||||
for (auto &info : fileInfos_) {
|
||||
if (!isFirst) {
|
||||
pandaFileInfo += BLOCK_SEPARATOR + SPACE;
|
||||
} else {
|
||||
@ -242,7 +264,7 @@ void PGOPandaFileInfos::ProcessToText(std::ofstream &stream) const
|
||||
|
||||
bool PGOPandaFileInfos::Checksum(uint32_t checksum) const
|
||||
{
|
||||
if (pandaFileInfos_.find(checksum) == pandaFileInfos_.end()) {
|
||||
if (fileInfos_.find(checksum) == fileInfos_.end()) {
|
||||
LOG_ECMA(ERROR) << "Checksum verification failed. Please ensure that the .abc and .ap match.";
|
||||
return false;
|
||||
}
|
||||
@ -879,13 +901,14 @@ bool PGOMethodIdSet::ParseFromBinary(uint32_t threshold, void **buffer, PGOProfi
|
||||
}
|
||||
continue;
|
||||
}
|
||||
methodInfoMap_.emplace(info->GetMethodName(), info->GetMethodId());
|
||||
auto methodIter = methodInfoMap_.find(info->GetMethodName());
|
||||
ASSERT(methodIter != methodInfoMap_.end());
|
||||
auto &methodInfo = methodIter->second;
|
||||
uint32_t checksum = 0;
|
||||
if (header->SupportMethodChecksum()) {
|
||||
methodInfo.GetConsistencyInfo().SetChecksum(base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t)));
|
||||
checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
|
||||
}
|
||||
auto ret = methodInfoMap_.emplace(info->GetMethodName(), chunk_);
|
||||
ASSERT(ret.second);
|
||||
auto methodNameSetIter = ret.first;
|
||||
auto &methodInfo = methodNameSetIter->second.GetOrCreateMethodInfo(checksum, info->GetMethodId());
|
||||
LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << ELEMENT_SEPARATOR << info->GetCount()
|
||||
<< ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
|
||||
<< ELEMENT_SEPARATOR << info->GetMethodName();
|
||||
@ -902,15 +925,39 @@ void PGOMethodIdSet::GetMismatchResult(const CString &recordName, uint32_t &tota
|
||||
std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
|
||||
{
|
||||
totalMethodCount += methodInfoMap_.size();
|
||||
for (const auto &method : methodInfoMap_) {
|
||||
if (!method.second.IsMatch()) {
|
||||
auto info = std::make_pair(method.first, recordName);
|
||||
mismatchMethodSet.emplace(info);
|
||||
mismatchMethodCount++;
|
||||
for (const auto &methodNameSet : methodInfoMap_) {
|
||||
if (methodNameSet.second.IsMatch()) {
|
||||
continue;
|
||||
}
|
||||
auto info = std::make_pair(methodNameSet.first, recordName);
|
||||
mismatchMethodSet.emplace(info);
|
||||
mismatchMethodCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void PGOMethodIdSet::Merge(const PGOMethodIdSet &from)
|
||||
{
|
||||
for (const auto &methodNameSet : from.methodInfoMap_) {
|
||||
auto iter = methodInfoMap_.find(methodNameSet.first);
|
||||
if (iter == methodInfoMap_.end()) {
|
||||
auto ret = methodInfoMap_.emplace(methodNameSet.first, chunk_);
|
||||
ASSERT(ret.second);
|
||||
iter = ret.first;
|
||||
}
|
||||
const_cast<PGOMethodNameSet &>(iter->second).Merge(methodNameSet.second);
|
||||
}
|
||||
}
|
||||
|
||||
void PGODecodeMethodInfo::Merge(const PGODecodeMethodInfo &from)
|
||||
{
|
||||
ASSERT(methodId_.IsValid() && from.methodId_.IsValid());
|
||||
if (!(methodId_ == from.methodId_)) {
|
||||
LOG_ECMA(ERROR) << "MethodId not match. " << methodId_ << " vs " << from.methodId_;
|
||||
return;
|
||||
}
|
||||
pgoMethodTypeSet_.Merge(&from.pgoMethodTypeSet_);
|
||||
}
|
||||
|
||||
PGOMethodInfoMap *PGORecordDetailInfos::GetMethodInfoMap(const CString &recordName)
|
||||
{
|
||||
auto iter = recordInfos_.find(recordName.c_str());
|
||||
@ -1083,8 +1130,8 @@ bool PGORecordDetailInfos::ProcessToBinaryForLayout(
|
||||
NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream) const
|
||||
{
|
||||
SectionInfo secInfo;
|
||||
std::stringstream layoutDescStream;
|
||||
|
||||
auto layoutBeginPosition = stream.tellp();
|
||||
stream.seekp(sizeof(SectionInfo), std::ofstream::cur);
|
||||
for (const auto &typeInfo : moduleLayoutDescInfos_) {
|
||||
if (task && task->IsTerminate()) {
|
||||
LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
|
||||
@ -1099,17 +1146,16 @@ bool PGORecordDetailInfos::ProcessToBinaryForLayout(
|
||||
void *addr = allocator->Allocate(size);
|
||||
auto descInfos = new (addr) PGOHClassLayoutDescInner(size, classType, superType);
|
||||
descInfos->Merge(typeInfo);
|
||||
layoutDescStream.write(reinterpret_cast<char *>(descInfos), size);
|
||||
stream.write(reinterpret_cast<char *>(descInfos), size);
|
||||
allocator->Delete(addr);
|
||||
secInfo.number_++;
|
||||
}
|
||||
|
||||
secInfo.offset_ = sizeof(SectionInfo);
|
||||
secInfo.size_ = static_cast<uint32_t>(layoutDescStream.tellg());
|
||||
stream.write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo));
|
||||
if (secInfo.number_ > 0) {
|
||||
stream << layoutDescStream.rdbuf();
|
||||
}
|
||||
secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - layoutBeginPosition - sizeof(SectionInfo);
|
||||
stream.seekp(layoutBeginPosition, std::ofstream::beg)
|
||||
.write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo))
|
||||
.seekp(0, std::ofstream::end);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1207,6 +1253,29 @@ void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *cons
|
||||
}
|
||||
}
|
||||
|
||||
void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos)
|
||||
{
|
||||
for (const auto &method : simpleInfos.methodIds_) {
|
||||
auto result = methodIds_.find(method.first);
|
||||
if (result == methodIds_.end()) {
|
||||
PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
|
||||
auto ret = methodIds_.emplace(method.first, methodIds);
|
||||
ASSERT(ret.second);
|
||||
result = ret.first;
|
||||
}
|
||||
const_cast<PGOMethodIdSet &>(*result->second).Merge(*method.second);
|
||||
}
|
||||
// Merge global layout desc infos to global method info map
|
||||
for (const auto &moduleLayoutDescInfo : simpleInfos.moduleLayoutDescInfos_) {
|
||||
auto result = moduleLayoutDescInfos_.find(moduleLayoutDescInfo);
|
||||
if (result == moduleLayoutDescInfos_.end()) {
|
||||
moduleLayoutDescInfos_.emplace(moduleLayoutDescInfo);
|
||||
} else {
|
||||
const_cast<PGOHClassLayoutDesc &>(*result).Merge(moduleLayoutDescInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
|
||||
{
|
||||
SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
|
||||
|
@ -259,16 +259,19 @@ class PGOPandaFileInfos {
|
||||
public:
|
||||
void Sample(uint32_t checksum)
|
||||
{
|
||||
pandaFileInfos_.insert(checksum);
|
||||
fileInfos_.emplace(checksum);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
pandaFileInfos_.clear();
|
||||
fileInfos_.clear();
|
||||
}
|
||||
|
||||
void ParseFromBinary(void *buffer, SectionInfo *const info);
|
||||
void ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const;
|
||||
void Merge(const PGOPandaFileInfos &pandaFileInfos);
|
||||
bool VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
|
||||
const std::string &incoming) const;
|
||||
|
||||
void ProcessToText(std::ofstream &stream) const;
|
||||
bool ParseFromText(std::ifstream &stream);
|
||||
@ -276,22 +279,22 @@ public:
|
||||
bool Checksum(uint32_t checksum) const;
|
||||
|
||||
private:
|
||||
class PandaFileInfo {
|
||||
class FileInfo {
|
||||
public:
|
||||
PandaFileInfo() = default;
|
||||
PandaFileInfo(uint32_t checksum) : size_(LastSize()), checksum_(checksum) {}
|
||||
FileInfo() = default;
|
||||
FileInfo(uint32_t checksum) : size_(LastSize()), checksum_(checksum) {}
|
||||
|
||||
static size_t LastSize()
|
||||
{
|
||||
return sizeof(PandaFileInfo);
|
||||
return sizeof(FileInfo);
|
||||
}
|
||||
|
||||
size_t Size()
|
||||
size_t Size() const
|
||||
{
|
||||
return static_cast<size_t>(size_);
|
||||
}
|
||||
|
||||
bool operator<(const PandaFileInfo &right) const
|
||||
bool operator<(const FileInfo &right) const
|
||||
{
|
||||
return checksum_ < right.checksum_;
|
||||
}
|
||||
@ -307,7 +310,7 @@ private:
|
||||
uint32_t checksum_;
|
||||
};
|
||||
|
||||
std::set<PandaFileInfo> pandaFileInfos_;
|
||||
std::set<FileInfo> fileInfos_;
|
||||
};
|
||||
|
||||
class PGOMethodInfo {
|
||||
@ -658,22 +661,6 @@ class PGODecodeMethodInfo {
|
||||
public:
|
||||
explicit PGODecodeMethodInfo(PGOMethodId id) : methodId_(id) {}
|
||||
|
||||
class ConsistencyInfo {
|
||||
public:
|
||||
void SetChecksum(uint32_t checksum)
|
||||
{
|
||||
checksum_ = checksum;
|
||||
}
|
||||
|
||||
uint32_t GetChecksum() const
|
||||
{
|
||||
return checksum_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t checksum_ {0};
|
||||
};
|
||||
|
||||
PGOMethodId GetMethodId() const
|
||||
{
|
||||
return methodId_;
|
||||
@ -684,26 +671,11 @@ public:
|
||||
return pgoMethodTypeSet_;
|
||||
}
|
||||
|
||||
ConsistencyInfo &GetConsistencyInfo()
|
||||
{
|
||||
return consistencyInfo_;
|
||||
}
|
||||
|
||||
void SetMatch()
|
||||
{
|
||||
methodNameMatch_ = true;
|
||||
}
|
||||
|
||||
bool IsMatch() const
|
||||
{
|
||||
return methodNameMatch_;
|
||||
}
|
||||
void Merge(const PGODecodeMethodInfo &from);
|
||||
|
||||
private:
|
||||
PGOMethodId methodId_ {0};
|
||||
bool methodNameMatch_ {false};
|
||||
PGOMethodTypeSet pgoMethodTypeSet_ {};
|
||||
ConsistencyInfo consistencyInfo_ {};
|
||||
};
|
||||
|
||||
class PGOHClassLayoutDescInner {
|
||||
@ -830,6 +802,11 @@ public:
|
||||
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;
|
||||
|
||||
const CMap<PGOMethodId, PGOMethodInfo *> &GetMethodInfos() const
|
||||
{
|
||||
return methodInfos_;
|
||||
}
|
||||
|
||||
NO_COPY_SEMANTIC(PGOMethodInfoMap);
|
||||
NO_MOVE_SEMANTIC(PGOMethodInfoMap);
|
||||
|
||||
@ -844,12 +821,15 @@ private:
|
||||
|
||||
class PGOMethodIdSet {
|
||||
public:
|
||||
explicit PGOMethodIdSet(Chunk* chunk): methodInfoMap_(chunk) {};
|
||||
explicit PGOMethodIdSet(Chunk* chunk): chunk_(chunk), methodInfoMap_(chunk) {};
|
||||
~PGOMethodIdSet() = default;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
candidateSet_.clear();
|
||||
for (auto &methodNameSet : methodInfoMap_) {
|
||||
methodNameSet.second.Clear();
|
||||
}
|
||||
methodInfoMap_.clear();
|
||||
}
|
||||
|
||||
@ -872,9 +852,10 @@ public:
|
||||
template <typename Callback>
|
||||
void GetTypeInfo(const char *methodName, Callback callback)
|
||||
{
|
||||
// for no function checksum in ap file
|
||||
auto iter = methodInfoMap_.find(methodName);
|
||||
if (iter != methodInfoMap_.end()) {
|
||||
iter->second.GetPGOMethodTypeSet().GetTypeInfo(callback);
|
||||
if ((iter != methodInfoMap_.end()) && (iter->second.GetFirstMethodInfo() != nullptr)) {
|
||||
iter->second.GetFirstMethodInfo()->GetPGOMethodTypeSet().GetTypeInfo(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -882,15 +863,10 @@ public:
|
||||
void GetTypeInfo(const char *methodName, uint32_t checksum, Callback callback)
|
||||
{
|
||||
auto iter = methodInfoMap_.find(methodName);
|
||||
if (iter == methodInfoMap_.end()) {
|
||||
return;
|
||||
if ((iter != methodInfoMap_.end()) && (iter->second.GetMethodInfo(checksum) != nullptr)) {
|
||||
return iter->second.GetMethodInfo(checksum)->GetPGOMethodTypeSet().GetTypeInfo(callback);
|
||||
}
|
||||
auto &methodInfo = iter->second;
|
||||
if (methodInfo.GetConsistencyInfo().GetChecksum() != checksum) {
|
||||
LOG_ECMA(DEBUG) << "Method checksum mismatched, name: " << methodName;
|
||||
return;
|
||||
}
|
||||
return methodInfo.GetPGOMethodTypeSet().GetTypeInfo(callback);
|
||||
LOG_ECMA(DEBUG) << "Method checksum mismatched, name: " << methodName;
|
||||
}
|
||||
|
||||
void MatchAndMarkMethod(const char *methodName, EntityId methodId)
|
||||
@ -909,12 +885,80 @@ public:
|
||||
void GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount,
|
||||
std::set<std::pair<std::string, CString>> &mismatchMethodSet) const;
|
||||
|
||||
void Merge(const PGOMethodIdSet &from);
|
||||
|
||||
class PGOMethodNameSet {
|
||||
public:
|
||||
explicit PGOMethodNameSet(Chunk* chunk): methodMap_(chunk) {};
|
||||
void SetMatch()
|
||||
{
|
||||
methodNameMatch_ = true;
|
||||
}
|
||||
|
||||
bool IsMatch() const
|
||||
{
|
||||
return methodNameMatch_;
|
||||
}
|
||||
|
||||
PGODecodeMethodInfo& GetOrCreateMethodInfo(uint32_t checksum, PGOMethodId methodId)
|
||||
{
|
||||
auto methodIter = methodMap_.find(checksum);
|
||||
if (methodIter == methodMap_.end()) {
|
||||
auto ret = methodMap_.emplace(checksum, methodId);
|
||||
ASSERT(ret.second);
|
||||
methodIter = ret.first;
|
||||
}
|
||||
return methodIter->second;
|
||||
}
|
||||
|
||||
void Merge(const PGOMethodNameSet &from)
|
||||
{
|
||||
for (const auto &method : from.methodMap_) {
|
||||
uint32_t checksum = method.first;
|
||||
auto methodInfo = methodMap_.find(checksum);
|
||||
if (methodInfo == methodMap_.end()) {
|
||||
auto ret = methodMap_.emplace(checksum, method.second.GetMethodId());
|
||||
ASSERT(ret.second);
|
||||
methodInfo = ret.first;
|
||||
}
|
||||
methodInfo->second.Merge(method.second);
|
||||
}
|
||||
}
|
||||
|
||||
PGODecodeMethodInfo *GetFirstMethodInfo()
|
||||
{
|
||||
if (methodMap_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(methodMap_.begin()->second);
|
||||
}
|
||||
|
||||
PGODecodeMethodInfo *GetMethodInfo(uint32_t checksum)
|
||||
{
|
||||
auto methodInfo = methodMap_.find(checksum);
|
||||
if (methodInfo == methodMap_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(methodInfo->second);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
methodMap_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
bool methodNameMatch_ {false};
|
||||
ChunkUnorderedMap<uint32_t, PGODecodeMethodInfo> methodMap_;
|
||||
};
|
||||
|
||||
NO_COPY_SEMANTIC(PGOMethodIdSet);
|
||||
NO_MOVE_SEMANTIC(PGOMethodIdSet);
|
||||
|
||||
private:
|
||||
Chunk* chunk_;
|
||||
std::unordered_set<EntityId> candidateSet_; // methodId in abc file, DO NOT for pgo internal use
|
||||
ChunkUnorderedMap<CString, PGODecodeMethodInfo> methodInfoMap_;
|
||||
ChunkUnorderedMap<CString, PGOMethodNameSet> methodInfoMap_;
|
||||
};
|
||||
|
||||
class PGORecordDetailInfos {
|
||||
@ -954,6 +998,11 @@ public:
|
||||
bool ParseFromText(std::ifstream &stream);
|
||||
void ProcessToText(std::ofstream &stream) const;
|
||||
|
||||
const CMap<CString, PGOMethodInfoMap *> &GetRecordInfos() const
|
||||
{
|
||||
return recordInfos_;
|
||||
}
|
||||
|
||||
NO_COPY_SEMANTIC(PGORecordDetailInfos);
|
||||
NO_MOVE_SEMANTIC(PGORecordDetailInfos);
|
||||
|
||||
@ -983,7 +1032,7 @@ public:
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (const auto& iter : methodIds_) {
|
||||
for (const auto &iter : methodIds_) {
|
||||
iter.second->Clear();
|
||||
nativeAreaAllocator_.Delete(iter.second);
|
||||
}
|
||||
@ -1066,6 +1115,8 @@ public:
|
||||
|
||||
void ParseFromBinary(void *buffer, PGOProfilerHeader *const header);
|
||||
|
||||
void Merge(const PGORecordSimpleInfos &simpleInfos);
|
||||
|
||||
NO_COPY_SEMANTIC(PGORecordSimpleInfos);
|
||||
NO_MOVE_SEMANTIC(PGORecordSimpleInfos);
|
||||
|
||||
|
94
ecmascript/pgo_profiler/pgo_profiler_manager.cpp
Normal file
94
ecmascript/pgo_profiler/pgo_profiler_manager.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/platform/file.h"
|
||||
namespace panda::ecmascript {
|
||||
bool PGOProfilerManager::MergeApFiles(const std::string &inFiles, const std::string &outPath, uint32_t hotnessThreshold)
|
||||
{
|
||||
arg_list_t pandaFileNames = base::StringHelper::SplitString(inFiles, GetFileDelimiter());
|
||||
PGOProfilerEncoder merger(outPath, hotnessThreshold);
|
||||
if (!merger.InitializeData()) {
|
||||
LOG_ECMA(ERROR) << "PGO Profiler encoder initialized failed. outPath: " << outPath
|
||||
<< " ,hotnessThreshold: " << hotnessThreshold;
|
||||
return false;
|
||||
}
|
||||
bool isFirstFile = true;
|
||||
std::string firstApFileName;
|
||||
for (const auto &fileName : pandaFileNames) {
|
||||
if (!base::StringHelper::EndsWith(fileName, ".ap")) {
|
||||
LOG_ECMA(ERROR) << "The file path(" << fileName << ") does not end with .ap";
|
||||
continue;
|
||||
}
|
||||
PGOProfilerDecoder decoder(fileName, hotnessThreshold);
|
||||
if (!decoder.LoadFull()) {
|
||||
LOG_ECMA(ERROR) << "Fail to load file path(" << fileName << "), skip it.";
|
||||
continue;
|
||||
}
|
||||
if (isFirstFile) {
|
||||
firstApFileName = fileName;
|
||||
} else {
|
||||
if (!merger.VerifyPandaFileMatched(decoder.GetPandaFileInfos(), firstApFileName, fileName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
merger.Merge(decoder.GetRecordDetailInfos());
|
||||
merger.Merge(decoder.GetPandaFileInfos());
|
||||
isFirstFile = false;
|
||||
}
|
||||
if (isFirstFile) {
|
||||
LOG_ECMA(ERROR) << "No input file processed. Input files: " << inFiles;
|
||||
return false;
|
||||
}
|
||||
merger.Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PGOProfilerManager::MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger)
|
||||
{
|
||||
uint32_t hotnessThreshold = merger.GetHotnessThreshold();
|
||||
std::string inFiles(merger.GetInPath());
|
||||
arg_list_t pandaFileNames = base::StringHelper::SplitString(inFiles, GetFileDelimiter());
|
||||
if (pandaFileNames.empty()) {
|
||||
return true;
|
||||
}
|
||||
merger.InitMergeData();
|
||||
bool isFirstFile = true;
|
||||
std::string firstApFileName;
|
||||
for (const auto &fileName : pandaFileNames) {
|
||||
PGOProfilerDecoder decoder(fileName, hotnessThreshold);
|
||||
if (!decoder.LoadAndVerify(checksum)) {
|
||||
LOG_ECMA(ERROR) << "Load and verify file(" << fileName << ") failed, skip it.";
|
||||
continue;
|
||||
}
|
||||
if (isFirstFile) {
|
||||
firstApFileName = fileName;
|
||||
} else {
|
||||
if (!merger.GetPandaFileInfos().VerifyChecksum(decoder.GetPandaFileInfos(), firstApFileName, fileName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
merger.Merge(decoder);
|
||||
isFirstFile = false;
|
||||
}
|
||||
if (isFirstFile) {
|
||||
LOG_ECMA(ERROR) << "No input file processed. Input files: " << inFiles;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
@ -131,6 +131,9 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool MergeApFiles(const std::string &inFiles, const std::string &outPath, uint32_t hotnessThreshold);
|
||||
static bool MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger);
|
||||
|
||||
private:
|
||||
bool InitializeData()
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/log_wrapper.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
||||
#include "ecmascript/platform/file.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
static const std::string VERSION = "0.0.0.1";
|
||||
@ -30,6 +31,7 @@ public:
|
||||
VERSION_QUERY,
|
||||
TO_BINARY,
|
||||
TO_TEXT,
|
||||
MERGE,
|
||||
};
|
||||
|
||||
std::string GetProfInPath() const
|
||||
@ -62,6 +64,7 @@ public:
|
||||
{"text", required_argument, nullptr, 't'},
|
||||
{"binary", required_argument, nullptr, 'b'},
|
||||
{"hotness-threshold", required_argument, nullptr, 's'},
|
||||
{"merge", no_argument, nullptr, 'm'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"version", no_argument, nullptr, 'v'},
|
||||
{nullptr, 0, nullptr, 0},
|
||||
@ -83,6 +86,9 @@ public:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
mode_ = Mode::MERGE;
|
||||
break;
|
||||
case 'h':
|
||||
return false;
|
||||
case 'v':
|
||||
@ -112,6 +118,7 @@ public:
|
||||
"-t, --text binary to text.\n"
|
||||
"-b, --binary text to binary.\n"
|
||||
"-s, --hotness-threshold set minimum number of calls to filter method. default: 2\n"
|
||||
"-m, --merge merge multi binary ap files into one.\n"
|
||||
"-h, --help display this help and exit\n"
|
||||
"-v, --version output version information and exit\n";
|
||||
return PROF_DUMP_HELP_HEAD_MSG + PROF_DUMP_HELP_OPTION_MSG;
|
||||
@ -158,6 +165,13 @@ int Main(const int argc, const char **argv)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Option::Mode::MERGE: {
|
||||
if (PGOProfilerManager::MergeApFiles(option.GetProfInPath(), option.GetProfOutPath(),
|
||||
option.GetHotnessThreshold())) {
|
||||
LOG_NO_TAG(ERROR) << "profiler merge success!";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -922,4 +922,36 @@ HWTEST_F_L0(PGOProfilerTest, FileConsistencyCheck)
|
||||
unlink("ark-profiler17/modules.ap");
|
||||
rmdir("ark-profiler17/");
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_ENABLE_ASM_INTERP)
|
||||
HWTEST_F_L0(PGOProfilerTest, MergeApSelfTwice)
|
||||
{
|
||||
mkdir("ark-profiler18/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
const char *targetRecordName = "op_type_test";
|
||||
std::shared_ptr<JSPandaFile> jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler18/", targetRecordName);
|
||||
ASSERT_NE(jsPandaFile, nullptr);
|
||||
|
||||
// Loader
|
||||
PGOProfilerDecoder decoder("ark-profiler18/modules_merge.ap", 1);
|
||||
PGOProfilerDecoder decoderSingle("ark-profiler18/modules.ap", 1);
|
||||
ASSERT_TRUE(PGOProfilerManager::MergeApFiles("ark-profiler18/modules.ap:ark-profiler18/modules.ap",
|
||||
"ark-profiler18/modules_merge.ap", 1));
|
||||
ASSERT_TRUE(decoder.LoadFull());
|
||||
ASSERT_TRUE(decoderSingle.LoadFull());
|
||||
|
||||
auto doubleCount =
|
||||
decoder.GetRecordDetailInfos().GetRecordInfos().begin()->second->GetMethodInfos().begin()->second->GetCount();
|
||||
auto singleCount = decoderSingle.GetRecordDetailInfos()
|
||||
.GetRecordInfos()
|
||||
.begin()
|
||||
->second->GetMethodInfos()
|
||||
.begin()
|
||||
->second->GetCount();
|
||||
ASSERT_EQ(doubleCount, singleCount + singleCount);
|
||||
|
||||
unlink("ark-profiler18/modules.ap");
|
||||
unlink("ark-profiler18/modules_merge.ap");
|
||||
rmdir("ark-profiler18/");
|
||||
}
|
||||
#endif
|
||||
} // namespace panda::test
|
||||
|
Loading…
Reference in New Issue
Block a user