• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
17 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
18 #include "ecmascript/pgo_profiler/pgo_trace.h"
19 #include "ecmascript/platform/file.h"
20 #include "ecmascript/platform/os.h"
21 
22 namespace panda::ecmascript::pgo {
23 
Save(const std::shared_ptr<PGOInfo> pgoInfo)24 bool PGOProfilerEncoder::Save(const std::shared_ptr<PGOInfo> pgoInfo)
25 {
26     return InternalSave(pgoInfo);
27 }
28 
SaveAndRename(const std::shared_ptr<PGOInfo> info,const SaveTask * task)29 bool PGOProfilerEncoder::SaveAndRename(const std::shared_ptr<PGOInfo> info, const SaveTask* task)
30 {
31     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PGOProfilerEncoder::SaveAndRename");
32     LOG_PGO(INFO) << "start save and rename ap file to " << path_;
33     ClockScope start;
34     umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
35     static const char* tempSuffix = ".tmp";
36     auto tmpOutPath = path_ + "." + std::to_string(getpid()) + tempSuffix;
37     std::fstream fileStream(tmpOutPath.c_str(),
38                             std::fstream::binary | std::fstream::out | std::fstream::in | std::fstream::trunc);
39     if (!fileStream.is_open()) {
40         LOG_PGO(ERROR) << "can't open the file path (" << tmpOutPath << ") errno: " << errno;
41         return false;
42     }
43     if (info->GetHeaderPtr() == nullptr) {
44         LOG_PGO(FATAL) << "[PGOProfilerEncoder::SaveAndRename] header_ is not initialized";
45     }
46     info->GetPandaFileInfos().ProcessToBinary(fileStream, info->GetHeaderPtr()->GetPandaInfoSection());
47     info->GetRecordDetailInfosPtr()->ProcessToBinary(task, fileStream, info->GetHeaderPtr());
48     PGOFileSectionInterface::ProcessSectionToBinary(
49         info->GetRecordDetailInfos(), fileStream, info->GetHeaderPtr(), *info->GetAbcFilePool().GetPool());
50     info->GetHeaderPtr()->SetFileSize(static_cast<uint32_t>(fileStream.tellp()));
51     info->GetHeaderPtr()->SetCompatibleAnVersion(AOTFileVersion::AN_VERSION);
52     info->GetHeaderPtr()->ProcessToBinary(fileStream);
53     if (info->GetHeaderPtr()->SupportFileConsistency()) {
54         AddChecksum(fileStream);
55     }
56     fileStream.close();
57     if (task && task->IsTerminate()) {
58         return false;
59     }
60     if (FileExist(path_.c_str()) && remove(path_.c_str())) {
61         LOG_PGO(ERROR) << "remove " << path_ << " failed, errno: " << errno;
62         return false;
63     }
64     if (rename(tmpOutPath.c_str(), path_.c_str())) {
65         LOG_PGO(ERROR) << "rename " << tmpOutPath << " to " << path_ << " failed, errno: " << errno;
66         return false;
67     }
68     PGOProfilerManager::GetInstance()->RequestAot();
69     if (PGOTrace::GetInstance()->IsEnable()) {
70         PGOTrace::GetInstance()->SetSaveTime(start.TotalSpentTime());
71         PGOTrace::GetInstance()->Print();
72     }
73     LOG_PGO(INFO) << "successfully save and rename ap file to " << path_;
74     return true;
75 }
76 
InternalSave(const std::shared_ptr<PGOInfo> rtInfo,const SaveTask * task)77 bool PGOProfilerEncoder::InternalSave(const std::shared_ptr<PGOInfo> rtInfo, const SaveTask* task)
78 {
79     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PGOProfilerEncoder::InternalSave");
80     LOG_PGO(INFO) << (mode_ == MERGE ? "MERGE(1)" : "OVERWRITE(0)") << " pgo info";
81     if ((mode_ == MERGE) && FileExist(path_.c_str())) {
82         auto info = std::make_shared<PGOInfo>(rtInfo->GetHotnessThreshold());
83         PGOProfilerDecoder decoder(path_, rtInfo->GetHotnessThreshold());
84         info->MergeWithExistProfile(*rtInfo, decoder, task);
85         return SaveAndRename(info, task);
86     }
87     return SaveAndRename(rtInfo, task);
88 }
89 
AddChecksum(std::fstream & fileStream)90 void PGOProfilerEncoder::AddChecksum(std::fstream& fileStream)
91 {
92     static constexpr uint32_t KILO_BYTES = 1024;
93     static constexpr uint32_t STEP_IN_KB = 256;
94     static constexpr uint32_t STEP_SIZE = STEP_IN_KB * KILO_BYTES;
95     uint32_t size = static_cast<uint32_t>(fileStream.seekp(0, std::fstream::end).tellp());
96     std::unique_ptr<std::vector<uint8_t>> buffer = std::make_unique<std::vector<uint8_t>>(STEP_SIZE);
97     // first, calculate the version field's checksum.
98     fileStream.seekg(PGOProfilerHeader::MAGIC_SIZE, std::fstream::beg)
99         .read(reinterpret_cast<char*>(buffer->data()), PGOProfilerHeader::VERSION_SIZE);
100     uint32_t checksum = adler32(0, reinterpret_cast<const Bytef*>(buffer->data()), PGOProfilerHeader::VERSION_SIZE);
101     // second, calculate the checksum for remaining content(exclude checksum field).
102     uint32_t remainingSize = size - PGOProfilerHeader::CHECKSUM_END_OFFSET;
103     fileStream.seekg(PGOProfilerHeader::CHECKSUM_END_OFFSET);
104     while (remainingSize > 0) {
105         uint32_t readSize = std::min(STEP_SIZE, remainingSize);
106         remainingSize = remainingSize - readSize;
107         fileStream.read(reinterpret_cast<char*>(buffer->data()), readSize);
108         checksum = adler32(checksum, reinterpret_cast<const Bytef*>(buffer->data()), readSize);
109     }
110     // third, write the checksum back to the checksum field in the output stream.
111     fileStream.seekp(PGOProfilerHeader::MAGIC_SIZE + PGOProfilerHeader::VERSION_SIZE, std::fstream::beg);
112     fileStream.write(reinterpret_cast<char*>(&checksum), sizeof(checksum));
113 }
114 
TerminateSaveTask()115 void PGOProfilerEncoder::TerminateSaveTask()
116 {
117     Taskpool::GetCurrentTaskpool()->TerminateTask(GLOBAL_TASK_ID, TaskType::PGO_SAVE_TASK);
118 }
119 
PostSaveTask(const std::string & path,ApGenMode mode,const std::shared_ptr<PGOInfo> pgoInfo)120 void PGOProfilerEncoder::PostSaveTask(const std::string& path,
121                                       ApGenMode mode,
122                                       const std::shared_ptr<PGOInfo> pgoInfo)
123 {
124     LOG_PGO(INFO) << "dispatch save task, path: " << path;
125     auto encoder = std::make_shared<PGOProfilerEncoder>(path, mode);
126     Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<SaveTask>(encoder, pgoInfo, GLOBAL_TASK_ID));
127 }
128 
StartSaveTask(const std::shared_ptr<PGOInfo> info,const SaveTask * task)129 void PGOProfilerEncoder::StartSaveTask(const std::shared_ptr<PGOInfo> info, const SaveTask* task)
130 {
131     if (task == nullptr) {
132         return;
133     }
134     if (task->IsTerminate()) {
135         LOG_PGO(ERROR) << "save task is terminated";
136         return;
137     }
138     LockHolder lock(PGOProfilerManager::GetPGOInfoMutex());
139     InternalSave(info, task);
140 }
141 
GetApGenMode() const142 ApGenMode PGOProfilerEncoder::GetApGenMode() const
143 {
144     return mode_;
145 }
146 
SetApGenMode(ApGenMode mode)147 void PGOProfilerEncoder::SetApGenMode(ApGenMode mode)
148 {
149     mode_ = mode;
150 }
151 } // namespace panda::ecmascript::pgo
152