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 16const { 17 MODULE_PATH, 18 ARK_ETS_STDLIB_PATH, 19 ARK_ETS_INTEROP_JS_GTEST_ABC_PATH, 20 VMB_BENCH_UNIT_NAME, 21 VMB_BENCH_UNIT_ITERATIONS 22} = process.env; 23 24const DEFAULT_ITERATIONS = 100000; 25 26globalThis.require = require; 27 28const capitalize = (str = '') => { 29 return str.split('_') 30 .filter(Boolean) 31 .map((substring, i) => 32 substring[0].toUpperCase() + substring.substring(1)) 33 .join(''); 34}; 35 36class Benchmark { 37 #ark = require(MODULE_PATH + '/ets_interop_js_napi.node'); 38 #benchName = capitalize(VMB_BENCH_UNIT_NAME); 39 #benchmark; 40 #passedTime = BigInt(0); 41 #binaries = []; 42 constructor(...binaries) { 43 this.#binaries = binaries; 44 this.#__init(); 45 } 46 47 #__init() { 48 const isOk = this.#ark.createRuntime({ 49 'boot-panda-files': [ARK_ETS_STDLIB_PATH, ...this.#binaries].join(':'), 50 'panda-files': this.#binaries.join(':'), 51 'gc-trigger-type': 'heap-trigger', 52 'compiler-enable-jit': 'false', 53 'run-gc-in-place': 'true', 54 'log-components': 'ets_interop_js', 55 'load-runtimes': 'ets' 56 }); 57 58 if (!isOk) { 59 throw new Error('Failed to initialize'); 60 } 61 } 62 63 #prepare() { 64 const TestClass = this.#ark.getClass(`L${this.#benchName};`); 65 this.#benchmark = new TestClass(); 66 this.#benchmark.setup(); 67 } 68 69 #loopFromJS(iterations = DEFAULT_ITERATIONS) { 70 if (!Number.isFinite(iterations)) { 71 throw new Error(`Iteration count should be a valid integer, ${iterations} given instead`); 72 } 73 for (let i = 0; i < iterations ?? this.iterations; i++) { 74 const startTimeNsec = process.hrtime.bigint(); 75 this.#benchmark.test(); 76 const endTimeNSec = process.hrtime.bigint(); 77 this.#passedTime += (endTimeNSec - startTimeNsec); 78 } 79 return this.#passedTime; 80 } 81 82 #loopFromArk(iterations = DEFAULT_ITERATIONS) { 83 if (!Number.isFinite(iterations)) { 84 throw new Error(`Iteration count should be a valid integer, ${iterations} given instead`); 85 } 86 this.#benchmark.runsLeft = iterations; 87 return Number(this.#benchmark.test()); 88 } 89 90 run(iterations = DEFAULT_ITERATIONS) { 91 this.#prepare(); 92 const isSelfTimed = this.#benchmark.totalTime !== undefined; 93 const testRunner = isSelfTimed ? this.#loopFromArk.bind(this) : this.#loopFromJS.bind(this); 94 const timing = testRunner(iterations); 95 console.log(`Benchmark result: ${this.#benchName.toLowerCase()} ` + timing); 96 } 97} 98 99const benchmark = new Benchmark(ARK_ETS_INTEROP_JS_GTEST_ABC_PATH); 100 101const iterations = (VMB_BENCH_UNIT_ITERATIONS && Number.isFinite(Number(VMB_BENCH_UNIT_ITERATIONS))) 102 ? Number(VMB_BENCH_UNIT_ITERATIONS) 103 : DEFAULT_ITERATIONS; 104 105benchmark.run(iterations);