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_saver.h"
17
18 #include "ecmascript/platform/file.h"
19
20 namespace panda::ecmascript {
21 static const std::string PROFILE_FILE_NAME = "/modules.ap";
Destroy()22 void PGOProfilerSaver::Destroy()
23 {
24 if (!isInitialized_) {
25 return;
26 }
27 PGOProfilerHeader::Destroy(&header_);
28 pandaFileInfos_.reset();
29 globalRecordInfos_->Clear();
30 globalRecordInfos_.reset();
31 isInitialized_ = false;
32 }
33
InitializeData()34 bool PGOProfilerSaver::InitializeData()
35 {
36 if (!isInitialized_) {
37 if (!RealPath(outDir_, realOutPath_, false)) {
38 return false;
39 }
40 realOutPath_ += PROFILE_FILE_NAME;
41 LOG_ECMA(INFO) << "Save profiler to file:" << realOutPath_;
42 PGOProfilerHeader::Build(&header_, PGOProfilerHeader::LastSize());
43 pandaFileInfos_ = std::make_unique<PGOPandaFileInfos>();
44 globalRecordInfos_ = std::make_unique<PGORecordDetailInfos>(hotnessThreshold_);
45 isInitialized_ = true;
46 }
47 return true;
48 }
49
SamplePandaFileInfo(uint32_t checksum)50 void PGOProfilerSaver::SamplePandaFileInfo(uint32_t checksum)
51 {
52 if (!isInitialized_) {
53 return;
54 }
55 pandaFileInfos_->Sample(checksum);
56 }
57
Merge(const PGORecordDetailInfos & recordInfos)58 void PGOProfilerSaver::Merge(const PGORecordDetailInfos &recordInfos)
59 {
60 if (!isInitialized_) {
61 return;
62 }
63 os::memory::LockHolder lock(mutex_);
64 globalRecordInfos_->Merge(recordInfos);
65 }
66
Save()67 void PGOProfilerSaver::Save()
68 {
69 if (!isInitialized_) {
70 return;
71 }
72 os::memory::LockHolder lock(mutex_);
73 SaveProfiler();
74 }
75
SaveProfiler(const SaveTask * task)76 void PGOProfilerSaver::SaveProfiler(const SaveTask *task)
77 {
78 std::ofstream fileStream(realOutPath_.c_str());
79 if (!fileStream.is_open()) {
80 LOG_ECMA(ERROR) << "The file path(" << realOutPath_ << ") open failure!";
81 return;
82 }
83 pandaFileInfos_->ProcessToBinary(fileStream, header_->GetPandaInfoSection());
84 globalRecordInfos_->ProcessToBinary(task, fileStream, header_->GetRecordInfoSection());
85 header_->ProcessToBinary(fileStream);
86 fileStream.close();
87 }
88
TerminateSaveTask()89 void PGOProfilerSaver::TerminateSaveTask()
90 {
91 if (!isInitialized_) {
92 return;
93 }
94 Taskpool::GetCurrentTaskpool()->TerminateTask(GLOBAL_TASK_ID, TaskType::PGO_SAVE_TASK);
95 }
96
PostSaveTask()97 void PGOProfilerSaver::PostSaveTask()
98 {
99 if (!isInitialized_) {
100 return;
101 }
102 Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<SaveTask>(this, GLOBAL_TASK_ID));
103 }
104
StartSaveTask(const SaveTask * task)105 void PGOProfilerSaver::StartSaveTask(const SaveTask *task)
106 {
107 if (task == nullptr) {
108 return;
109 }
110 if (task->IsTerminate()) {
111 LOG_ECMA(ERROR) << "StartSaveTask: task is already terminate";
112 return;
113 }
114 os::memory::LockHolder lock(mutex_);
115 SaveProfiler(task);
116 }
117
LoadAPTextFile(const std::string & inPath)118 bool PGOProfilerSaver::LoadAPTextFile(const std::string &inPath)
119 {
120 if (!isInitialized_) {
121 return false;
122 }
123 std::string realPath;
124 if (!RealPath(inPath, realPath)) {
125 return false;
126 }
127
128 std::ifstream fileStream(realPath.c_str());
129 if (!fileStream.is_open()) {
130 LOG_ECMA(ERROR) << "The file path(" << realOutPath_ << ") open failure!";
131 return false;
132 }
133
134 if (!header_->ParseFromText(fileStream)) {
135 LOG_ECMA(ERROR) << "header format error";
136 return false;
137 }
138 if (!pandaFileInfos_->ParseFromText(fileStream)) {
139 LOG_ECMA(ERROR) << "panda file info format error";
140 return false;
141 }
142 if (!globalRecordInfos_->ParseFromText(fileStream)) {
143 LOG_ECMA(ERROR) << "record info format error";
144 return false;
145 }
146
147 return true;
148 }
149 } // namespace panda::ecmascript
150