1 /*
2 * Copyright (c) 2024 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 "gtest/gtest.h"
17
18 #include "ecmascript/compiler/aot_compilation_env.h"
19 #include "ecmascript/compiler/aot_compiler_preprocessor.h"
20 #include "ecmascript/compiler/aot_compiler_stats.h"
21 #include "ecmascript/compiler/aot_file/an_file_data_manager.h"
22 #include "ecmascript/compiler/aot_file/tests/aot_file_generator_mock.h"
23 #include "ecmascript/compiler/pass_manager.h"
24 #include "ecmascript/compiler/pass_options.h"
25 #include "ecmascript/js_runtime_options.h"
26 #include "ecmascript/ohos/ohos_pkg_args.h"
27 #include "ecmascript/platform/filesystem.h"
28 #include "ecmascript/tests/test_helper.h"
29
30 using namespace panda;
31 using namespace panda::ecmascript;
32 using namespace panda::ecmascript::kungfu;
33 using namespace panda::ecmascript::pgo;
34 using namespace panda::panda_file;
35 using namespace panda::ecmascript::filesystem;
36
37 namespace panda::test {
38 class AOTFileTest : public testing::Test {
39 public:
SetUpTestCase()40 static void SetUpTestCase()
41 {
42 GTEST_LOG_(INFO) << "SetUpTestCase";
43 }
44
TearDownTestCase()45 static void TearDownTestCase()
46 {
47 GTEST_LOG_(INFO) << "TearDownTestCase";
48 }
49
SetUp()50 void SetUp() override
51 {
52 this->testDir_ = std::string(TARGET_ABC_PATH);
53 }
54
TearDown()55 void TearDown() override
56 {
57 if (Exists(this->testAnPath_.c_str())) {
58 Unlink(this->testAnPath_.c_str());
59 }
60 if (Exists(this->testApPath_.c_str())) {
61 Unlink(this->testApPath_.c_str());
62 }
63 if (Exists(this->testAiPath_.c_str())) {
64 Unlink(this->testAiPath_.c_str());
65 }
66 this->testDir_.clear();
67 this->testAbcPath_.clear();
68 this->testRecordName_.clear();
69 this->testApPath_.clear();
70 this->testAnPath_.clear();
71 this->testAiPath_.clear();
72 this->testAotPath_.clear();
73 this->testAnExpectedSize_ = 0;
74 }
75
76 protected:
SetTestAbcPath(const std::string & abcFile)77 void SetTestAbcPath(const std::string &abcFile)
78 {
79 testAbcPath_ = testDir_ + abcFile;
80 ASSERT_TRUE(Exists(testAbcPath_));
81 }
82
SetApPath()83 void SetApPath()
84 {
85 testApPath_ = testDir_ + testRecordName_ + ".ap";
86 }
87
SetAotPath()88 void SetAotPath()
89 {
90 testAotPath_ = testDir_ + testRecordName_;
91 }
92
SetAnPath()93 void SetAnPath()
94 {
95 testAnPath_ = testDir_ + testRecordName_ + ".an";
96 }
97
SetAiPath()98 void SetAiPath()
99 {
100 testAiPath_ = testDir_ + testRecordName_ + ".ai";
101 }
102
SetEnvrionmentForTest(const std::string & abcFile)103 void SetEnvrionmentForTest(const std::string &abcFile)
104 {
105 SetTestAbcPath(abcFile);
106 SetRecordName(abcFile);
107 SetApPath();
108 SetAotPath();
109 SetAnPath();
110 SetAiPath();
111 }
112
113 // Get .ap pgo profile for provided abc file
GetApFileInTest()114 void GetApFileInTest()
115 {
116 JSRuntimeOptions runtimeOptions;
117 runtimeOptions.SetEnablePGOProfiler(true);
118 runtimeOptions.SetPGOProfilerPath(testApPath_);
119 runtimeOptions.SetEntryPoint(testRecordName_);
120 EcmaVM *vm = JSNApi::CreateEcmaVM(runtimeOptions);
121 ASSERT_TRUE(vm != nullptr);
122 bool isMergeAbc = runtimeOptions.GetMergeAbc();
123 JSNApi::SetBundle(vm, !isMergeAbc);
124 bool res = JSNApi::Execute(vm, testAbcPath_, runtimeOptions.GetEntryPoint());
125 ASSERT_TRUE(res);
126 JSNApi::DestroyJSVM(vm);
127 ASSERT_TRUE(Exists(testApPath_));
128 }
129
GetAnFileInTest(size_t limitSizeByte=0)130 void GetAnFileInTest(size_t limitSizeByte = 0)
131 {
132 bool ret = true;
133 JSRuntimeOptions runtimeOptions;
134 runtimeOptions.SetPGOProfilerPath(testApPath_);
135 runtimeOptions.SetAOTOutputFile(testAotPath_);
136 runtimeOptions.SetEnableAsmInterpreter(false);
137 runtimeOptions.SetOptionsForTargetCompilation();
138 ecmascript::AnFileDataManager::GetInstance()->SetEnable(true);
139 EcmaVM *vm = JSNApi::CreateEcmaVM(runtimeOptions);
140
141 ASSERT_TRUE(vm != nullptr);
142 {
143 AOTCompilationEnv aotCompilationEnv(vm);
144 ThreadManagedScope managedScope(vm->GetJSThread());
145 LocalScope scope(vm);
146 arg_list_t pandaFileNames {testAbcPath_};
147 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
148 CompilationOptions cOptions(runtimeOptions);
149 CompilerLog log(cOptions.logOption_);
150 AotMethodLogList logList(cOptions.logMethodsList_);
151 PGOProfilerDecoder profilerDecoder;
152 AotCompilerPreprocessor cPreprocessor(vm, runtimeOptions, pkgArgsMap, profilerDecoder, pandaFileNames);
153 AotCompilerStats compilerStats;
154 compilerStats.SetAotFilePath(cOptions.outputFileName_);
155 compilerStats.SetPgoPath(cOptions.profilerIn_);
156 compilerStats.StartCompiler();
157 profilerDecoder.SetHotnessThreshold(cOptions.hotnessThreshold_);
158 profilerDecoder.SetInPath(cOptions.profilerIn_);
159 cPreprocessor.AOTInitialize();
160 std::unordered_map<CString, uint32_t> originFilenameToChecksumMap;
161 cPreprocessor.GenerateAbcFileInfos(originFilenameToChecksumMap);
162 ret = cPreprocessor.GetCompilerResult();
163 cPreprocessor.HandleMergedPgoFile(originFilenameToChecksumMap);
164 cPreprocessor.Process(cOptions);
165 PassOptions::Builder optionsBuilder;
166 PassOptions passOptions = optionsBuilder.Build();
167 PassManager passManager(&aotCompilationEnv, cOptions.triple_, cOptions.optLevel_, cOptions.relocMode_, &log,
168 &logList, cOptions.maxAotMethodSize_, cOptions.maxMethodsInModule_, profilerDecoder,
169 &passOptions, cPreprocessor.GetCallMethodFlagMap(), cPreprocessor.GetAbcFileInfo(),
170 cPreprocessor.GetBcInfoCollectors(), cOptions.optBCRange_);
171 AOTFileGeneratorMock generator(&log, &logList, &aotCompilationEnv, cOptions.triple_, false, limitSizeByte);
172 passManager.CompileValidFiles(generator, ret, compilerStats);
173 if (generator.SaveAndGetAOTFileSize(cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AN, "",
174 testAnExpectedSize_, originFilenameToChecksumMap)) {
175 generator.SaveSnapshotFile();
176 }
177 }
178 JSNApi::DestroyJSVM(vm);
179 GTEST_LOG_(INFO) << "testAnPath_: " << testAnPath_;
180 }
181
SetRecordName(const std::string & abcFile)182 void SetRecordName(const std::string &abcFile)
183 {
184 testRecordName_ = abcFile.substr(0, abcFile.find_last_of("."));
185 ASSERT_TRUE(!testRecordName_.empty());
186 }
187
188 std::string testDir_;
189 std::string testAbcPath_;
190 std::string testRecordName_;
191 std::string testApPath_;
192 std::string testAnPath_;
193 std::string testAiPath_;
194 std::string testAotPath_;
195 size_t testAnExpectedSize_ = 0;
196 };
197
HWTEST_F_L0(AOTFileTest,fileSizeEqualExpectedTest)198 HWTEST_F_L0(AOTFileTest, fileSizeEqualExpectedTest)
199 {
200 // This case use to test the compiler out .an file size equal to expected size by calculate.
201 // Test file use file_size_test.abc
202 std::string testFile = "file_size_test.abc";
203 SetEnvrionmentForTest(testFile);
204 GetApFileInTest();
205 GetAnFileInTest();
206 ASSERT_TRUE(Exists(testAnPath_));
207 ASSERT_TRUE(Exists(testAiPath_));
208 ASSERT_EQ(testAnExpectedSize_, FileSize(testAnPath_));
209 }
210
HWTEST_F_L0(AOTFileTest,dontSaveAnFile)211 HWTEST_F_L0(AOTFileTest, dontSaveAnFile)
212 {
213 // This case use to test the compiler out .an file size less than provided limit
214 // Then generator will not save .an and .ai file
215 // Test file use file_size_test.abc
216 std::string testFile = "file_size_test.abc";
217 SetEnvrionmentForTest(testFile);
218 GetApFileInTest();
219 GetAnFileInTest(1);
220 ASSERT_FALSE(Exists(testAnPath_));
221 ASSERT_FALSE(Exists(testAiPath_));
222 // We can still calculate the correct size
223 ASSERT_NE(testAnExpectedSize_, 0);
224 }
225 } // namespace panda::test
226