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 <fstream> 17#include <iostream> 18#include <string> 19#include <thread> 20#include <vector> 21 22#include <securec.h> 23#include <uv.h> 24 25#include "ecmascript/base/string_helper.h" 26#include "ecmascript/js_runtime_options.h" 27#include "ecmascript/napi/include/jsnapi.h" 28#include "ecmascript/platform/file.h" 29#include "tooling/utils/utils.h" 30#ifdef PANDA_TARGET_MACOS 31#include <unistd.h> 32#include <sys/syscall.h> 33#endif 34static panda::ecmascript::Mutex g_mutex; 35static std::list<std::string> g_files; 36static std::list<std::string>::iterator g_iter; 37static panda::ecmascript::JSRuntimeOptions g_runtimeOptions; 38static uv_async_t *g_exitSignal = nullptr; 39static int g_threadCount = 0; 40static int g_runningCount = 0; 41 42static constexpr int MAX_THREAD = 1024; 43 44namespace OHOS::ArkCompiler::Toolchain { 45bool ExecutePandaFile(panda::ecmascript::EcmaVM *vm, 46 const panda::ecmascript::JSRuntimeOptions &runtimeOptions, 47 const std::string &file, const std::string &entry) 48{ 49 panda::LocalScope scope(vm); 50 51 panda::ecmascript::EcmaContext *context1 = nullptr; 52 if (runtimeOptions.IsEnableContext()) { 53 context1 = panda::JSNApi::CreateJSContext(vm); 54 panda::JSNApi::SwitchCurrentContext(vm, context1); 55 } 56 57 if (runtimeOptions.WasAOTOutputFileSet()) { 58 panda::JSNApi::LoadAotFile(vm, ""); 59 } 60 61 bool ret = panda::JSNApi::Execute(vm, file, entry); 62 63 if (runtimeOptions.IsEnableContext()) { 64 panda::JSNApi::DestroyJSContext(vm, context1); 65 } 66 67 return ret; 68} 69 70std::pair<std::string, std::string> GetNextPara() 71{ 72 std::string fileName = *g_iter; 73 std::string fileAbc = fileName.substr(fileName.find_last_of('/') + 1); 74 std::string entry = fileAbc.substr(0, fileAbc.size() - 4); 75 g_iter++; 76 g_runningCount++; 77 return {fileName, entry}; 78} 79 80std::string GetMsg(int ret, std::string& msg, std::string& fileName) 81{ 82 if (!ret) { 83#ifdef PANDA_TARGET_MACOS 84 msg = "[FAILED] [" + std::to_string(syscall(SYS_thread_selfid)) + "] Run " + 85 fileName + " failed!"; 86#else 87 msg = "[FAILED] [" + std::to_string(gettid()) + "] Run " + fileName + " failed!"; 88#endif 89 } else { 90#ifdef PANDA_TARGET_MACOS 91 msg = "[PASS] [" + std::to_string(syscall(SYS_thread_selfid)) + "] Run " + 92 fileName + " success!"; 93#else 94 msg = "[PASS] [" + std::to_string(gettid()) + "] Run " + fileName + " success!"; 95#endif 96 } 97 return msg; 98} 99 100bool StartThread(uv_loop_t *loop) 101{ 102 uv_thread_t tid = 0; 103 int ret = uv_thread_create(&tid, [] (void* arg) -> void { 104 while (true) { 105 g_mutex.Lock(); 106 if (g_iter == g_files.end()) { 107 g_threadCount--; 108 if (g_threadCount == 0) { 109 uv_async_send(g_exitSignal); 110 } 111 g_mutex.Unlock(); 112 break; 113 } 114 auto [fileName, entry] = GetNextPara(); 115 g_mutex.Unlock(); 116 panda::ecmascript::EcmaVM *vm = panda::JSNApi::CreateEcmaVM(g_runtimeOptions); 117 if (vm == nullptr) { 118 std::cerr << "Cannot create vm." << std::endl; 119 return; 120 } 121 panda::JSNApi::SetBundle(vm, !g_runtimeOptions.GetMergeAbc()); 122 bool ret = ExecutePandaFile(vm, g_runtimeOptions, fileName, entry); 123 panda::JSNApi::DestroyJSVM(vm); 124 auto loop = static_cast<uv_loop_t *>(arg); 125 auto work = new uv_work_t; 126 std::string msg = GetMsg(ret, msg, fileName); 127 work->data = new char[msg.size() + 1]; 128 if (strncpy_s(static_cast<char*>(work->data), msg.size() + 1, msg.data(), msg.size()) != EOK) { 129 delete[] static_cast<char*>(work->data); 130 delete work; 131 std::abort(); 132 } 133 uv_queue_work(loop, work, [] (uv_work_t*) {}, [] (uv_work_t* work, int) { 134 std::cerr << static_cast<char*>(work->data) << std::endl; 135 delete[] static_cast<char*>(work->data); 136 delete work; 137 }); 138 } 139 }, loop); 140 return ret != 0; 141} 142 143int Main(const int argc, const char **argv) 144{ 145 auto startTime = 146 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()) 147 .count(); 148 149 std::cerr << "Run begin [" << getpid() << "]" << std::endl; 150 if (argc < 3) { // 3: at least have three arguments 151 std::cerr << "At least have three arguments." << std::endl; 152 return -1; 153 } 154 155 std::string countStr = argv[1]; 156 int32_t count; 157 if (!Utils::StrToInt32(countStr, count)) { 158 std::cerr << "The argument about the number of threads is incorrect." << std::endl; 159 return -1; 160 } 161 g_threadCount = std::min(count, MAX_THREAD); 162 163 std::string filePath = argv[2]; 164 std::string realPath; 165 if (!panda::ecmascript::RealPath(filePath, realPath, true)) { 166 std::cerr << "RealPath return fail"; 167 return -1; 168 } 169 170 g_mutex.Lock(); 171 std::string line; 172 std::ifstream in(realPath); 173 while (std::getline(in, line)) { 174 if (line.find_last_of(".abc") == std::string::npos) { // endwith 175 std::cerr << "Not endwith .abc" << line << std::endl; 176 std::abort(); 177 } 178 g_files.emplace_back(line); 179 } 180 g_iter = g_files.begin(); 181 g_mutex.Unlock(); 182 183 bool retOpt = g_runtimeOptions.ParseCommand(argc - 2, argv + 2); 184 if (!retOpt) { 185 std::cerr << "ParseCommand failed." << std::endl; 186 return -1; 187 } 188 panda::ecmascript::EcmaVM *vm = panda::JSNApi::CreateEcmaVM(g_runtimeOptions); 189 if (vm == nullptr) { 190 std::cerr << "Cannot create vm." << std::endl; 191 return -1; 192 } 193 panda::JSNApi::SetBundle(vm, !g_runtimeOptions.GetMergeAbc()); 194 195 uv_loop_t* loop = uv_default_loop(); 196 g_exitSignal = new uv_async_t; 197 g_exitSignal->data = loop; 198 uv_async_init(loop, g_exitSignal, []([[maybe_unused]] uv_async_t* handle) { 199 g_mutex.Lock(); 200 assert (g_threadCount == 0); 201 g_mutex.Unlock(); 202 auto loop = static_cast<uv_loop_t*>(handle->data); 203 uv_stop(loop); 204 }); 205 206 int threadCountLocal = g_threadCount; 207 for (int i = 0; i < threadCountLocal; i++) { 208 StartThread(loop); 209 } 210 211 uv_run(loop, UV_RUN_DEFAULT); 212 213 uv_close(reinterpret_cast<uv_handle_t*>(g_exitSignal), [] (uv_handle_t* handle) { 214 if (handle != nullptr) { 215 delete reinterpret_cast<uv_handle_t*>(handle); 216 handle = nullptr; 217 } 218 }); 219 panda::JSNApi::DestroyJSVM(vm); 220 221 auto endTime = 222 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()) 223 .count(); 224 225 g_mutex.Lock(); 226 const long long timeUnit = 1000'000'000; 227 std::cerr << "Run end, total file count: " << g_runningCount << ", used: " 228 << ((endTime - startTime) / timeUnit) << "s." << std::endl; 229 g_mutex.Unlock(); 230 return 0; 231} 232} // OHOS::ArkCompiler::Toolchain 233 234int main(int argc, const char **argv) 235{ 236 return OHOS::ArkCompiler::Toolchain::Main(argc, argv); 237} 238