From c7372391ab981df4a1fcc2d28e099bc4d9136dc3 Mon Sep 17 00:00:00 2001 From: sunlian Date: Wed, 27 Nov 2024 14:49:59 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0cpu=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E6=B5=8B=E8=AF=95case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sunlian --- OHBM/entry/build-profile.json5 | 20 +- .../src/main/ets/cases/BenchmarkMeasure.ts | 190 ++++++++++++++++++ .../src/main/ets/cases/performance/base64.ts | 109 ++++++++++ OHBM/entry/src/main/ets/pages/Performance.ets | 97 ++++++++- OHBM/entry/src/main/ets/utils/Logger.ts | 45 +++++ .../main/ets/workers/PerformanceWorker.ets | 82 ++++++++ 6 files changed, 522 insertions(+), 21 deletions(-) create mode 100644 OHBM/entry/src/main/ets/cases/BenchmarkMeasure.ts create mode 100644 OHBM/entry/src/main/ets/cases/performance/base64.ts create mode 100644 OHBM/entry/src/main/ets/utils/Logger.ts create mode 100644 OHBM/entry/src/main/ets/workers/PerformanceWorker.ets diff --git a/OHBM/entry/build-profile.json5 b/OHBM/entry/build-profile.json5 index b16430789..bde011c3c 100644 --- a/OHBM/entry/build-profile.json5 +++ b/OHBM/entry/build-profile.json5 @@ -1,21 +1,11 @@ -/* - * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - { "apiType": "stageMode", "buildOption": { + "sourceOption": { + "workers": [ + './src/main/ets/workers/PerformanceWorker.ets' + ] + } }, "buildOptionSet": [ { diff --git a/OHBM/entry/src/main/ets/cases/BenchmarkMeasure.ts b/OHBM/entry/src/main/ets/cases/BenchmarkMeasure.ts new file mode 100644 index 000000000..227a69bcd --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/BenchmarkMeasure.ts @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ThreadWorkerGlobalScope } from '@kit.ArkTS'; + +const TAG = 'Benchmark' + +class BenchmarkRNG { + static resetRNG() { + Math.random = (function () { + var seed = 49734321; + return function () { + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; + return (seed & 0xfffffff) / 0x10000000; + }; + })(); + } + + static nextDouble() { + return Math.random() + } +} + +class WorkerMessage { + name: string; + type: number; + time: number; + latency: number; + x: number; + y: number; + r: number; + g: number; + b: number; + + constructor(name: string, type: number, time: number, latency: number, x: number, y: number, r: number, g: number, + b: number) { + this.name = name; + this.type = type; + this.time = time; + this.latency = latency; + this.x = x; + this.y = y; + this.r = r; + this.g = g; + this.b = b; + } +} + +class BenchmarkResult { + time: number; + latency: number; + + constructor(time: number, latency: number) { + this.time = time; + this.latency = latency; + } +} + +class Benchmark { + name: string; + doWarmup: boolean; + doDeterministic: boolean; + run: Function; + setup: Function | undefined; + tearDown: Function | undefined; + rmsResult: Function | undefined; + minIterations: number; + data: { + runs: number, + elapsed: number + } | undefined; + + constructor(name: string, doWarmup: boolean, doDeterministic: boolean, run: Function, + setup?: Function, tearDown?: Function, rmsResult?: Function, minIterations?: number) { + this.name = name; + this.doWarmup = doWarmup; + this.doDeterministic = doDeterministic; + this.run = run; + this.setup = setup; + this.tearDown = tearDown + this.rmsResult = rmsResult + this.minIterations = minIterations ? minIterations : 32; + this.data = undefined + } + + runSetup(benchmarkResult: BenchmarkResult, workerPort: ThreadWorkerGlobalScope): void { + this.setup?.(); + this.runBenchmark(benchmarkResult, workerPort); + } + + runBenchmark(benchmarkResult: BenchmarkResult, workerPort: ThreadWorkerGlobalScope): void { + this.runSingle(benchmarkResult, workerPort); + !this.data ? this.runTearDown() : this.runBenchmark(benchmarkResult, workerPort); + } + + runTearDown(): void { + this.tearDown?.(); + } + + runSingle(benchmarkResult: BenchmarkResult, workerPort: ThreadWorkerGlobalScope): void { + if (!this.doWarmup && !this.data) { + this.data = { runs: 0, elapsed: 0 }; + } + + if (!this.data) { + this.measure(workerPort); + this.data = { runs: 0, elapsed: 0 }; + } else { + this.measure(workerPort); + if (this.data.runs < this.minIterations) { + return; + } + const usec: number = (this.data.elapsed * 1000) / this.data.runs; + const rms: number = (this.rmsResult != null) ? this.rmsResult() : 0; + benchmarkResult.time = usec; + benchmarkResult.latency = rms; + this.data = undefined; + } + } + + measure(workerPort: ThreadWorkerGlobalScope): void { + let elapsed: number = 0; + let start: number = new Date().getTime(); + + let i = 0 + for (; (this.doDeterministic ? i < this.minIterations : elapsed < 1000); i++) { + this.run(workerPort); + elapsed = new Date().getTime() - start; + workerPort.postMessage(new WorkerMessage(this.name+`(第${i + 1}次)`, 0, elapsed, 0, 0, 0, 0, 0, 0)) + } + if (this.data != null) { + this.data.runs += i; + this.data.elapsed += elapsed; + } + } +} + + +class BenchmarkRun { + benchmark: Benchmark + name:string + + constructor(name: string, doWarmup: boolean, doDeterministic: boolean, run: Function, + setup?: Function, tearDown?: Function, rmsResult?: Function, minIterations?: number) { + this.benchmark = new Benchmark(name, doWarmup, doDeterministic, run, setup, tearDown, rmsResult, minIterations) + this.name = name + } + + run(workerPort: ThreadWorkerGlobalScope) { + let result = new BenchmarkResult(0, 0) + try { + BenchmarkRNG.resetRNG() + this.benchmark.runSetup(result, workerPort) + this.printResult(result) + workerPort.postMessage(new WorkerMessage(this.name+'(完成)', 0, result.time, result.latency, 0, 0, 0, 0, 0)) + } catch (error) { + this.printErrorMessage(JSON.stringify(error)) + } + + } + + printErrorMessage(errorMessage: String) { + console.info(TAG, `${this.benchmark.name} Error: ${errorMessage}`) + } + + printResult(result: BenchmarkResult) { + console.info(TAG, + `${this.benchmark.name}: usec = ${result.time}\n${this.benchmark.name}: latency = ${result.latency}`) + } +} + +BenchmarkRNG.resetRNG() + +export { BenchmarkRun, Benchmark, BenchmarkResult, BenchmarkRNG, WorkerMessage } diff --git a/OHBM/entry/src/main/ets/cases/performance/base64.ts b/OHBM/entry/src/main/ets/cases/performance/base64.ts new file mode 100644 index 000000000..481343256 --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/base64.ts @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BenchmarkRun } from "../BenchmarkMeasure"; + + +/**************************source code********************************/ + +const toBase64Table: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +const base64Pad: string = '='; + +const toBinaryTable: number[] = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 +]; + +function base64ToString(data: string): string { + let result: string = ''; + let leftbits: number = 0; + let leftdata: number = 0; + + for (let i = 0; i < data.length; i++) { + let c: number = toBinaryTable[data.charCodeAt(i) & 0x7f]; + let padding: boolean = (data.charCodeAt(i) == base64Pad.charCodeAt(0)); + if (c == -1) { + continue; + } + leftdata = (leftdata << 6) | c; + leftbits += 6; + if (leftbits >= 8) { + leftbits -= 8; + if (!padding) { + result += String.fromCharCode((leftdata >> leftbits) & 0xff); + } + leftdata &= (1 << leftbits) - 1; + } + } + if (leftbits) { + throw new Error('Corrupted base64 string'); + } + return result; +} + + +function toBase64(data: string): string { + let result: string = ''; + const length: number = data.length; + let i: number; + + for (i = 0; i < (length - 2); i += 3) { + result += toBase64Table[data.charCodeAt(i) >> 2]; + result += toBase64Table[((data.charCodeAt(i) & 0x03) << 4) + (data.charCodeAt(i + 1) >> 4)]; + result += toBase64Table[((data.charCodeAt(i + 1) & 0x0f) << 2) + (data.charCodeAt(i + 2) >> 6)]; + result += toBase64Table[data.charCodeAt(i + 2) & 0x3f]; + } + if (length % 3) { + i = length - (length % 3); + result += toBase64Table[data.charCodeAt(i) >> 2]; + if ((length % 3) == 2) { + result += toBase64Table[((data.charCodeAt(i) & 0x03) << 4) + (data.charCodeAt(i + 1) >> 4)]; + result += toBase64Table[(data.charCodeAt(i + 1) & 0x0f) << 2]; + result += base64Pad; + } else { + result += toBase64Table[(data.charCodeAt(i) & 0x03) << 4]; + result += base64Pad + base64Pad; + } + } + return result; +} + + +function Base64Run(): void { + let str: string = ""; + for (let i = 0; i < 8192; i++) { + str += String.fromCharCode((25 * Math.random()) + 97); + } + for (let i: number = 8192; i <= 16384; i *= 2) { + let base64: string; + base64 = toBase64(str); + let encoded: string = base64ToString(base64); + if (encoded !== str) { + throw new Error("ERROR: bad result: expected " + str + " but got " + encoded); + } + // Double the string + str += str; + } +} + + +/**************************configure and run benchmark********************************/ +export { Base64Run } diff --git a/OHBM/entry/src/main/ets/pages/Performance.ets b/OHBM/entry/src/main/ets/pages/Performance.ets index 6308b21a5..f44e8a414 100644 --- a/OHBM/entry/src/main/ets/pages/Performance.ets +++ b/OHBM/entry/src/main/ets/pages/Performance.ets @@ -12,25 +12,110 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { worker, MessageEvents, ErrorEvent } from '@kit.ArkTS'; +import { WorkerMessage } from '../cases/BenchmarkMeasure'; +import Logger from '../utils/Logger'; @Entry @Component struct Performance { + @State output: string = '' + @State isRunning: boolean = false; + @State testResult: string = '' + @State totalResult: string = '' + private TAG: string = 'Performance'; + private performanceWorker: worker.ThreadWorker | undefined = undefined; + private settings: RenderingContextSettings = new RenderingContextSettings(true) + private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) build() { Column() { Scroll() { Column() { - Column() { - Text('性能评分') + Text(this.isRunning ? '正在测试……' : '性能评分') + .fontSize(18) + .margin(8) + Row() { + Canvas(this.context) + .width(200) + .height(200) + .backgroundColor('#ffff00') } - Column() { - } - .margin({ bottom: 80 }) + Text(this.testResult) + .fontColor(Color.Red) + .fontSize(20) + .margin(8) + Button(this.isRunning ? '停止' : '开始') + .height(100) + .width(200) + .fontSize(20) + .margin(8) + .onClick(() => { + if (this.isRunning) { + if (this.performanceWorker !== undefined) { + try { + this.performanceWorker.terminate(); + } catch (e) { + } + } + } else { + if (this.performanceWorker === undefined) { + this.performanceWorker = new worker.ThreadWorker('entry/ets/workers/PerformanceWorker.ets'); + } + this.context.clearRect(0, 0, 200, 200); + this.totalResult = ''; + this.performanceWorker.postMessage('Start'); + this.performanceWorker.onmessage = (e: MessageEvents): void => { + let data: WorkerMessage = e.data; + switch (data.type) { + case 0: + let result = `${data.name}:time = ${data.time},latency = ${data.latency}`; + Logger.info(this.TAG, result); + this.context.clearRect(0, 0, 200, 200); + if (data.name.indexOf('完成') !== -1) { + this.totalResult = this.totalResult +'\n'+ result; + } else { + this.testResult = result; + } + break; + case 1: + let red = Math.floor(data.r * 255); + let green = Math.floor(data.g * 255); + let blue = Math.floor(data.b * 255); + Logger.info(this.TAG, + `RayTrace pixel: (x:${data.x},y:${data.y}),rgb(${red},${green},${blue})`); + this.context.fillStyle = `rgb(${red},${green},${blue})` + this.context.fillRect(data.x * 10, data.y * 10, 10, 10) + break; + default: + if (data.name.indexOf('全部完成') !== -1) { + this.isRunning = false; + } + break; + } + } + + this.performanceWorker.onexit = (code) => { + Logger.info(this.TAG, "main thread terminate"); + this.performanceWorker === undefined; + this.isRunning = false; + } + + this.performanceWorker.onerror = (err: ErrorEvent) => { + Logger.info(this.TAG, "main error message " + err.message); + this.isRunning = false; + } + this.isRunning = true; + } + }) + Text(this.totalResult) + .fontSize(18) + .margin(8) } + .justifyContent(FlexAlign.Center) .constraintSize({ minHeight: '100%' }) + .width('100%') } .height('100%') .padding({ left: 12, right: 12 }) diff --git a/OHBM/entry/src/main/ets/utils/Logger.ts b/OHBM/entry/src/main/ets/utils/Logger.ts new file mode 100644 index 000000000..5c14bbac9 --- /dev/null +++ b/OHBM/entry/src/main/ets/utils/Logger.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xFF00; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[OHBM]'); \ No newline at end of file diff --git a/OHBM/entry/src/main/ets/workers/PerformanceWorker.ets b/OHBM/entry/src/main/ets/workers/PerformanceWorker.ets new file mode 100644 index 000000000..dca87bb53 --- /dev/null +++ b/OHBM/entry/src/main/ets/workers/PerformanceWorker.ets @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS'; +import { BenchmarkRun, WorkerMessage } from "../cases/BenchmarkMeasure"; +import { Base64Run } from '../cases/performance/base64'; +import { AESRun } from '../cases/performance/crypto-aes'; +import { Md5Run } from '../cases/performance/crypto-md5'; +import { Sha1Run } from '../cases/performance/crypto-sha1'; +import { DeltablueRun } from '../cases/performance/deltablue'; +import { NavierstokesRun, NavierStokesSetup } from '../cases/performance/navier-stoke'; +import { RaytraceRun } from "../cases/performance/RayTrace"; +import { runRichards } from '../cases/performance/richards'; +import Logger from '../utils/Logger'; + +const workerPort: ThreadWorkerGlobalScope = worker.workerPort; + +/** + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessage = (e: MessageEvents) => { + let data: string = e.data; + if (data === 'Start') { + let benchmarkRunRaytrace = + new BenchmarkRun('raytrace', true, true, RaytraceRun, undefined, undefined, undefined, 20); + benchmarkRunRaytrace.run(workerPort); + let benchmarkRunRichards = + new BenchmarkRun('richards', true, true, runRichards, undefined, undefined, undefined, 100) + benchmarkRunRichards.run(workerPort) + let benchmarkRunDeltablue = + new BenchmarkRun('deltablue', true, true, DeltablueRun, undefined, undefined, undefined, 20) + benchmarkRunDeltablue.run(workerPort) + let benchmarkRunNavierstokes = + new BenchmarkRun('navier-stokes', true, true, NavierstokesRun, NavierStokesSetup, undefined, undefined, 20) + benchmarkRunNavierstokes.run(workerPort) + + let benchmarkRunBase64 = new BenchmarkRun('base64', true, true, Base64Run, undefined, undefined, undefined, 10) + benchmarkRunBase64.run(workerPort); + let benchmarkRunAES = new BenchmarkRun('crypto-aes', true, true, AESRun, undefined, undefined, undefined, 10) + benchmarkRunAES.run(workerPort) + let benchmarkRunMd5 = new BenchmarkRun('crypto-md5', true, true, Md5Run, undefined, undefined, undefined, 20) + benchmarkRunMd5.run(workerPort) + let benchmarkRunSha1 = new BenchmarkRun('crypto-sha1', true, true, Sha1Run, undefined, undefined, undefined, 20) + benchmarkRunSha1.run(workerPort) + //const benchmarkRunBox2d = new BenchmarkRun('box2d', true, true, runBox2D, undefined, tearDownBox2D, undefined, 32) + //benchmarkRunBox2d.run(workerPort) + workerPort.postMessage(new WorkerMessage(`全部完成`, -1, 0, 0, 0, 0, 0, 0, 0)) + } +} + +/** + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = (e: MessageEvents) => { +} + +/** + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = (e: ErrorEvent) => { +} \ No newline at end of file -- Gitee From bd95f1ac1fc1cc8f3fd136b29b33cbf47630a842 Mon Sep 17 00:00:00 2001 From: sunlian Date: Wed, 27 Nov 2024 14:54:00 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0cpu=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E6=B5=8B=E8=AF=95case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sunlian --- .../main/ets/cases/performance/RayTrace.ts | 723 ++++++++++++++++++ .../main/ets/cases/performance/crypto-aes.ts | 322 ++++++++ .../main/ets/cases/performance/crypto-md5.ts | 202 +++++ .../main/ets/cases/performance/crypto-sha1.ts | 142 ++++ 4 files changed, 1389 insertions(+) create mode 100644 OHBM/entry/src/main/ets/cases/performance/RayTrace.ts create mode 100644 OHBM/entry/src/main/ets/cases/performance/crypto-aes.ts create mode 100644 OHBM/entry/src/main/ets/cases/performance/crypto-md5.ts create mode 100644 OHBM/entry/src/main/ets/cases/performance/crypto-sha1.ts diff --git a/OHBM/entry/src/main/ets/cases/performance/RayTrace.ts b/OHBM/entry/src/main/ets/cases/performance/RayTrace.ts new file mode 100644 index 000000000..ccef4fdfd --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/RayTrace.ts @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ThreadWorkerGlobalScope } from '@kit.ArkTS'; +import { WorkerMessage } from '../BenchmarkMeasure'; + +class Color { + red: number; + green: number; + blue: number; + + constructor(r?: number, g?: number, b?: number) { + this.red = r ? r : 0.0; + this.green = g ? g : 0.0; + this.blue = b ? b : 0.0; + } + + static add(c1: Color, c2: Color): Color { + const result: Color = new Color(0, 0, 0); + result.red = c1.red + c2.red; + result.green = c1.green + c2.green; + result.blue = c1.blue + c2.blue; + return result; + } + + static addScalar(c1: Color, s: number): Color { + const result: Color = new Color(0, 0, 0); + result.red = c1.red + s; + result.green = c1.green + s; + result.blue = c1.blue + s; + result.limit(); + return result; + } + + static subtract(c1: Color, c2: Color): Color { + const result = new Color(0, 0, 0); + result.red = c1.red - c2.red; + result.green = c1.green - c2.green; + result.blue = c1.blue - c2.blue; + return result; + } + + static multiply(c1: Color, c2: Color): Color { + const result = new Color(0, 0, 0); + result.red = c1.red * c2.red; + result.green = c1.green * c2.green; + result.blue = c1.blue * c2.blue; + return result; + } + + static multiplyScalar(c1: Color, f: number): Color { + const result = new Color(0, 0, 0); + result.red = c1.red * f; + result.green = c1.green * f; + result.blue = c1.blue * f; + return result; + } + + static divideFactor(c1: Color, f: number): Color { + const result: Color = new Color(0, 0, 0); + result.red = c1.red / f; + result.green = c1.green / f; + result.blue = c1.blue / f; + return result; + } + + limit(): void { + this.red = (this.red > 0.0) ? ((this.red > 1.0) ? 1.0 : this.red) : 0.0; + this.green = (this.green > 0.0) ? ((this.green > 1.0) ? 1.0 : this.green) : 0.0; + this.blue = (this.blue > 0.0) ? ((this.blue > 1.0) ? 1.0 : this.blue) : 0.0; + } + + distance(color: Color): number { + return Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue); + } + + + static blend(c1: Color, c2: Color, w: number) { + let result: Color = new Color(0, 0, 0); + result = Color.add(Color.multiplyScalar(c1, 1 - w), Color.multiplyScalar(c2, w)); + return result; + } + + brightness(): number { + const r: number = Math.floor(this.red * 255); + const g: number = Math.floor(this.green * 255); + const b: number = Math.floor(this.blue * 255); + return (r * 77 + g * 150 + b * 29) >> 8; + } + + toString() { + const r: number = Math.floor(this.red * 255); + const g: number = Math.floor(this.green * 255); + const b: number = Math.floor(this.blue * 255); + return "rgb(" + r + "," + g + "," + b + ")"; + } +} + + +class Vector { + x: number; + y: number; + z: number; + + constructor(x?: number, y?: number, z?: number) { + this.x = (x ? x : 0); + this.y = (y ? y : 0); + this.z = (z ? z : 0); + } + + copy(vector: Vector): void { + this.x = vector.x; + this.y = vector.y; + this.z = vector.z; + } + + normalize(): Vector { + const m: number = this.magnitude(); + return new Vector(this.x / m, this.y / m, this.z / m); + } + + magnitude(): number { + return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z)); + } + + cross(w: Vector): Vector { + return new Vector( + -this.z * w.y + this.y * w.z, + this.z * w.x - this.x * w.z, + -this.y * w.x + this.x * w.y + ); + } + + dot(w: Vector): number { + return this.x * w.x + this.y * w.y + this.z * w.z; + } + + multiplyScalar(w: number): Vector { + return new Vector(this.x * w, this.y * w, this.z * w); + } + + subtract(w: Vector): Vector { + return new Vector(this.x - w.x, this.y - w.y, this.z - w.z); + } + + add(w: Vector): Vector { + return new Vector(w.x + this.x, w.y + this.y, w.z + this.z); + } + + static add(v: Vector, w: Vector): Vector { + return new Vector(w.x + v.x, w.y + v.y, w.z + v.z); + } + + static subtract(v: Vector, w: Vector): Vector { + return new Vector(v.x - w.x, v.y - w.y, v.z - w.z); + } + + static multiplyVector(v: Vector, w: Vector): Vector { + return new Vector(v.x * w.x, v.y * w.y, v.z * w.z); + } + + static multiplyScalar(v: Vector, w: number): Vector { + return new Vector(v.x * w, v.y * w, v.z * w); + } + + toString(): string { + return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']'; + } +} + +class Light { + position: Vector; + color: Color; + intensity: number; + + constructor(pos: Vector, color: Color, intensity?: number) { + this.position = pos; + this.color = color; + this.intensity = intensity ? intensity : 10.0; + } + + toString(): string { + return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']'; + } +} + +class Ray { + position: Vector; + direction: Vector; + + constructor(pos: Vector, dir: Vector) { + this.position = pos; + this.direction = dir; + } + + toString(): string { + return 'Ray [' + this.position + ',' + this.direction + ']'; + } +} + +class Scene { + camera: Camera; + shapes: Shape[]; + lights: Light[]; + background: Background; + + constructor() { + this.camera = new Camera( + new Vector(0, 0, -5), + new Vector(0, 0, 1), + new Vector(0, 1, 0) + ); + this.shapes = []; + this.lights = []; + this.background = new Background(new Color(0, 0, 0.5), 0.2); + } +} + +abstract class BaseMaterial { + gloss: number; + transparency: number; + reflection: number; + refraction: number; + hasTexture: boolean; + + abstract getColor(u: number, v: number): Color; + + constructor() { + this.gloss = 2.0; + this.transparency = 0.0; + this.reflection = 0.0; + this.refraction = 0.50; + this.hasTexture = false; + } + + wrapUp(t: number): number { + t = t % 2.0; + if (t < -1) { + t += 2.0; + } + if (t >= 1) { + t -= 2.0; + } + return t; + } + + toString() { + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture + + ']'; + } +} + +class Solid extends BaseMaterial { + color: Color; + + constructor(color: Color, reflection: number, refraction: number, transparency: number, gloss: number) { + super(); + this.color = color; + this.reflection = reflection; + this.transparency = transparency; + this.gloss = gloss; + this.hasTexture = false; + } + + getColor(u: number, v: number): Color { + return this.color; + } + + toString() { + return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + + this.hasTexture + ']'; + } +} + +class Chessboard extends BaseMaterial { + colorEven: Color; + colorOdd: Color; + density: number; + + constructor(colorEven: Color, colorOdd: Color, reflection: number, transparency: number, gloss: number, + density: number) { + super(); + this.colorEven = colorEven; + this.colorOdd = colorOdd; + this.reflection = reflection; + this.transparency = transparency; + this.gloss = gloss; + this.density = density; + this.hasTexture = true; + } + + getColor(u: number, v: number): Color { + let t: number = this.wrapUp(u * this.density) * this.wrapUp(v * this.density); + if (t < 0.0) { + return this.colorEven; + } else { + return this.colorOdd; + } + } + + toString() { + return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + + this.hasTexture + ']'; + } +} + + +abstract class Shape { + position: Vector; + material: BaseMaterial; + + constructor(position: Vector, material: BaseMaterial) { + this.position = position; + this.material = material; + } + + abstract intersect(ray: Ray): IntersectionInfo; +} + + +class Sphere extends Shape { + radius: number; + + constructor(pos: Vector, radius: number, material: BaseMaterial) { + super(pos, material) + this.radius = radius; + } + + intersect(ray: Ray): IntersectionInfo { + const info: IntersectionInfo = new IntersectionInfo(); + info.shape = this; + const dst: Vector = Vector.subtract(ray.position, this.position); + const B: number = dst.dot(ray.direction); + const C: number = dst.dot(dst) - (this.radius * this.radius); + const D: number = (B * B) - C; + if (D > 0) { + info.isHit = true; + info.distance = (-B) - Math.sqrt(D); + info.position = Vector.add( + ray.position, + Vector.multiplyScalar( + ray.direction, + info.distance + ) + ); + info.normal = Vector.subtract( + info.position, + this.position + ).normalize(); + info.color = this.material.getColor(0, 0); + } else { + info.isHit = false; + } + return info; + } + + toString() { + return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']'; + } +} + +class Plane extends Shape { + d: number; + + constructor(pos: Vector, d: number, material: BaseMaterial) { + super(pos, material) + this.d = d; + } + + intersect(ray: Ray): IntersectionInfo { + const info: IntersectionInfo = new IntersectionInfo(); + const Vd: number = this.position.dot(ray.direction); + if (Vd == 0) { + return info; // no intersection + } + const t: number = -(this.position.dot(ray.position) + this.d) / Vd; + if (t <= 0) { + return info; + } + info.shape = this; + info.isHit = true; + info.position = ray.position.add(ray.direction.multiplyScalar(t)); + info.normal = this.position; + info.distance = t; + if (this.material.hasTexture) { + const vU: Vector = new Vector(this.position.y, this.position.z, -this.position.x); + const vV: Vector = vU.cross(this.position); + const u: number = info.position.dot(vU); + const v: number = info.position.dot(vV); + info.color = this.material.getColor(u, v); + } else { + info.color = this.material.getColor(0, 0); + } + return info; + } + + toString(): string { + return 'Plane [' + this.position + ', d=' + this.d + ']'; + } +} + +class IntersectionInfo { + isHit: boolean; + hitCount: number; + shape: Shape | null = null; + position: Vector; + normal: Vector; + color: Color; + distance: number; + + constructor() { + this.color = new Color(0, 0, 0); + this.position = new Vector(); + this.normal = new Vector(); + this.distance = 0; + this.isHit = false; + this.hitCount = 0; + } + + toString(): string { + return 'Intersection [' + this.position + ']'; + } +} + +class Camera { + position: Vector; + lookAt: Vector; + equator: Vector; + up: Vector; + screen: Vector; + + constructor(pos: Vector, lookAt: Vector, up: Vector) { + this.position = pos; + this.lookAt = lookAt; + this.up = up; + this.equator = lookAt.normalize().cross(this.up); + this.screen = this.position.add(this.lookAt); + } + + getRay(vx: number, vy: number): Ray { + const pos: Vector = this.screen.subtract(this.equator.multiplyScalar(vx).subtract(this.up.multiplyScalar(vy))); + pos.y = pos.y * -1; + const dir: Vector = pos.subtract(this.position); + const ray: Ray = new Ray(pos, dir.normalize()); + return ray; + } + + toString(): string { + return 'Ray []'; + } +} + +class Background { + color: Color; + ambience: number = 0.0; + + constructor(color: Color, ambience: number) { + this.color = color; + this.ambience = ambience; + } +} + +class Options { + canvasHeight: number = 100; + canvasWidth: number = 100; + pixelWidth: number = 2; + pixelHeight: number = 2; + renderDiffuse: boolean = false; + renderShadows: boolean = false; + renderHighlights: boolean = false; + renderReflections: boolean = false; + rayDepth: number = 2 +} + + +let checkNumber: number; + +class Engine { + options: Options; + + constructor(options: Options) { + this.options = options; + this.options.canvasHeight /= this.options.pixelHeight; + this.options.canvasWidth /= this.options.pixelWidth; + } + + setPixel(x: number, y: number, color: Color): void { + if (x === y) { + checkNumber += color.brightness(); + } + } + + renderScene(scene: Scene, workerPort: ThreadWorkerGlobalScope) { + checkNumber = 0; + const canvasHeight: number = this.options.canvasHeight; + const canvasWidth: number = this.options.canvasWidth; + for (let y = 0; y < canvasHeight; y++) { + for (let x = 0; x < canvasWidth; x++) { + const yp: number = y * 1.0 / canvasHeight * 2 - 1; + const xp: number = x * 1.0 / canvasWidth * 2 - 1; + const ray: Ray = scene.camera.getRay(xp, yp); + const color: Color = this.getPixelColor(ray, scene); + this.setPixel(x, y, color); + workerPort.postMessage(new WorkerMessage('RayTrace(光追)', 1, 0, 0, x, y, color.red, color.green, color.blue)) + } + } + if (checkNumber !== 2321) { + throw new Error("Scene rendered incorrectly"); + } + } + + getPixelColor(ray: Ray, scene: Scene): Color { + const info: IntersectionInfo = this.testIntersection(ray, scene, null); + if (info.isHit) { + const color: Color = this.rayTrace(info, ray, scene, 0); + return color; + } + return scene.background.color; + } + + testIntersection(ray: Ray, scene: Scene, exclude: Shape | null) { + let hits: number = 0; + let best: IntersectionInfo = new IntersectionInfo(); + best.distance = 2000; + for (let i = 0; i < scene.shapes.length; i++) { + const shape = scene.shapes[i]; + if (shape != exclude) { + const info: IntersectionInfo = shape.intersect(ray); + if (info.isHit && info.distance >= 0 && info.distance < best.distance) { + best = info; + hits++; + } + } + } + best.hitCount = hits; + return best; + } + + getReflectionRay(P: Vector, N: Vector, V: Vector): Ray { + const c1: number = -N.dot(V); + const R1: Vector = Vector.add( + Vector.multiplyScalar(N, 2 * c1), + V + ); + return new Ray(P, R1); + } + + rayTrace(info: IntersectionInfo, ray: Ray, scene: Scene, depth: number) { + let color: Color = Color.multiplyScalar(info.color, scene.background.ambience); + const shininess: number = Math.pow(10, info.shape!.material.gloss + 1); + for (let i = 0; i < scene.lights.length; i++) { + const light = scene.lights[i]; + const v: Vector = Vector.subtract( + light.position, + info.position + ).normalize(); + if (this.options.renderDiffuse) { + const L: number = v.dot(info.normal); + if (L > 0.0) { + color = Color.add( + color, + Color.multiply( + info.color, + Color.multiplyScalar( + light.color, + L + ) + ) + ); + } + } + if (depth <= this.options.rayDepth) { + if (this.options.renderReflections && info.shape!.material.reflection > 0) { + const reflectionRay: Ray = this.getReflectionRay(info.position, info.normal, ray.direction); + const refl: IntersectionInfo = this.testIntersection(reflectionRay, scene, info.shape); + if (refl.isHit && refl.distance > 0) { + refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1); + } else { + refl.color = scene.background.color; + } + color = Color.blend( + color, + refl.color, + info.shape!.material.reflection + ); + } + } + let shadowInfo: IntersectionInfo = new IntersectionInfo(); + if (this.options.renderShadows) { + const shadowRay: Ray = new Ray(info.position, v); + shadowInfo = this.testIntersection(shadowRay, scene, info.shape); + if (shadowInfo.isHit && shadowInfo.shape != info.shape) { + const vA: Color = Color.multiplyScalar(color, 0.5); + const dB: number = (0.5 * Math.pow(shadowInfo.shape!.material.transparency, 0.5)); + color = Color.addScalar(vA, dB); + } + } + if (this.options.renderHighlights && !shadowInfo.isHit && info.shape!.material.gloss > 0) { + const Lv: Vector = Vector.subtract( + info.shape!.position, + light.position + ).normalize(); + const E: Vector = Vector.subtract( + scene.camera.position, + info.shape!.position + ).normalize(); + const H: Vector = Vector.subtract( + E, + Lv + ).normalize(); + const glossWeight: number = Math.pow(Math.max(info.normal.dot(H), 0), shininess); + color = Color.add( + Color.multiplyScalar(light.color, glossWeight), + color + ); + } + } + color.limit(); + return color; + } +} + +function RaytraceRun(workerPort: ThreadWorkerGlobalScope) { + const scene: Scene = new Scene(); + scene.camera = new Camera( + new Vector(0, 0, -15), + new Vector(-0.2, 0, 5), + new Vector(0, 1, 0) + ); + scene.background = new Background( + new Color(0.5, 0.5, 0.5), + 0.4 + ); + + const sphere: Sphere = new Sphere( + new Vector(-1.5, 1.5, 2), + 1.5, + new Solid( + new Color(0, 0.5, 0.5), + 0.3, + 0.0, + 0.0, + 2.0 + ) + ); + + const sphere1: Sphere = new Sphere( + new Vector(1, 0.25, 1), + 0.5, + new Solid( + new Color(0.9, 0.9, 0.9), + 0.1, + 0.0, + 0.0, + 1.5 + ) + ); + + const plane: Plane = new Plane( + new Vector(0.1, 0.9, -0.5).normalize(), + 1.2, + new Chessboard( + new Color(1, 1, 1), + new Color(0, 0, 0), + 0.2, + 0.0, + 1.0, + 0.7 + ) + ); + + scene.shapes.push(plane); + scene.shapes.push(sphere); + scene.shapes.push(sphere1); + + const light: Light = new Light( + new Vector(5, 10, -1), + new Color(0.8, 0.8, 0.8) + ); + + const light1: Light = new Light( + new Vector(-3, 5, -15), + new Color(0.8, 0.8, 0.8), + 100 + ); + scene.lights.push(light); + scene.lights.push(light1); + + const imageWidth: number = 100; + const imageHeight: number = 100; + const pixelSize: string[] = "5,5".split(','); + const renderDiffuse: boolean = true; + const renderShadows: boolean = true; + const renderHighlights: boolean = true; + const renderReflections: boolean = true; + const rayDepth: number = 2; + + const options: Options = new Options(); + options.canvasWidth = imageWidth; + options.canvasHeight = imageHeight; + options.pixelWidth = Number(pixelSize[0]); + options.pixelHeight = Number(pixelSize[1]); + options.renderDiffuse = renderDiffuse; + options.renderHighlights = renderHighlights; + options.renderShadows = renderShadows; + options.renderReflections = renderReflections; + options.rayDepth = rayDepth; + const raytracer = new Engine(options); + raytracer.renderScene(scene, workerPort); +} + +export { RaytraceRun } diff --git a/OHBM/entry/src/main/ets/cases/performance/crypto-aes.ts b/OHBM/entry/src/main/ets/cases/performance/crypto-aes.ts new file mode 100644 index 000000000..aa4283c60 --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/crypto-aes.ts @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { BenchmarkRun } from "../BenchmarkMeasure"; + + +/**************************source code********************************/ + +const Rcon: number[][] = [[0x00, 0x00, 0x00, 0x00], + [0x01, 0x00, 0x00, 0x00], + [0x02, 0x00, 0x00, 0x00], + [0x04, 0x00, 0x00, 0x00], + [0x08, 0x00, 0x00, 0x00], + [0x10, 0x00, 0x00, 0x00], + [0x20, 0x00, 0x00, 0x00], + [0x40, 0x00, 0x00, 0x00], + [0x80, 0x00, 0x00, 0x00], + [0x1b, 0x00, 0x00, 0x00], + [0x36, 0x00, 0x00, 0x00]]; + + +const Sbox: number[] = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]; + + +function RotWord(w: number[]): number[] { + w[4] = w[0]; + for (let i = 0; i < 4; i++) { + w[i] = w[i + 1]; + } + return w; +} + +function SubWord(w: number[]): number[] { + for (let i = 0; i < 4; i++) { + w[i] = Sbox[w[i]]; + } + return w; +} + +function KeyExpansion(key: number[]): number[][] { + const Nb: number = 4; + const Nk: number = key.length / 4; + const Nr: number = Nk + 6; + const w: number[][] = new Array(Nb * (Nr + 1)); + let temp: number[] = new Array(4); + for (let i = 0; i < Nk; i++) { + const r: number[] = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]; + w[i] = r; + } + for (let i = Nk; i < Nb * (Nr + 1); i++) { + w[i] = new Array(4); + for (let t = 0; t < 4; t++) { + temp[t] = w[i - 1][t]; + } + if (i % Nk === 0) { + temp = SubWord(RotWord(temp)); + for (let t = 0; t < 4; t++) { + temp[t] ^= Rcon[i / Nk][t]; + } + } else if (Nk > 6 && i % Nk === 4) { + temp = SubWord(temp); + } + for (let t = 0; t < 4; t++) { + w[i][t] = w[i - Nk][t] ^ temp[t]; + } + } + return w; +} + + +function escCtrlChars(str: string): string { + return str.replace(/[\0\t\n\v\f\r\xa0'"!-]/g, function (c) { + return '!' + c.charCodeAt(0) + '!'; + }); +} + +function unescCtrlChars(str: string): string { + return str.replace(/!\d\d?\d?!/g, function (c) { + return String.fromCharCode(Number(c.slice(1, -1))); + }); +} + +function AddRoundKey(state: number[][], w: number[][], rnd: number, Nb: number): number[][] { + for (let r = 0; r < 4; r++) { + for (let c = 0; c < Nb; c++) { + state[r][c] ^= w[rnd * 4 + c][r]; + } + } + return state; +} + +function SubBytes(s: number[][], Nb: number): number[][] { + for (let r = 0; r < 4; r++) { + for (let c = 0; c < Nb; c++) { + s[r][c] = Sbox[s[r][c]]; + } + } + return s; +} + +function ShiftRows(s: number[][], Nb: number): number[][] { + const t: number[] = new Array(4); + for (let r = 1; r < 4; r++) { + for (let c = 0; c < 4; c++) { + t[c] = s[r][(c + r) % Nb]; + } // shift into temp copy + for (let c = 0; c < 4; c++) { + s[r][c] = t[c]; + } // and copy back + } + return s; +} + +function MixColumns(s: number[][], Nb: number): number[][] { + for (let c = 0; c < 4; c++) { + const a: number[] = []; // 'a' is a copy of the current column from 's' + const b: number[] = []; // 'b' is a•{02} in GF(2^8) + for (let i = 0; i < 4; i++) { + a[i] = s[i][c]; + b[i] = s[i][c] & 0x80 ? s[i][c] << 1 ^ 0x011b : s[i][c] << 1; + } + // a[n] ^ b[n] is a•{03} in GF(2^8) + s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3 + s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3 + s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3 + s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3 + } + return s; +} + +function Cipher(input: number[], w: number[][]): number[] { + const Nb: number = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + const Nr: number = w.length / Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys + let state: number[][] = [[], [], [], []]; // initialise 4xNb byte-array 'state' with input [§3.4] + for (let i = 0; i < 4 * Nb; i++) { + state[i % 4][Math.floor(i / 4)] = input[i]; + } + state = AddRoundKey(state, w, 0, Nb); + for (let round = 1; round < Nr; round++) { + state = SubBytes(state, Nb); + state = ShiftRows(state, Nb); + state = MixColumns(state, Nb); + state = AddRoundKey(state, w, round, Nb); + } + state = SubBytes(state, Nb); + state = ShiftRows(state, Nb); + state = AddRoundKey(state, w, Nr, Nb); + const output: number[] = new Array(4 * Nb); // convert state to 1-d array before returning [§3.4] + for (let i = 0; i < 4 * Nb; i++) { + output[i] = state[i % 4][Math.floor(i / 4)]; + } + return output; +} + + +function AESEncryptCtr(plaintext: string, password: string, nBits: number): string { + if (!(nBits === 128 || nBits === 192 || nBits === 256)) { + return ''; + } + const nBytes: number = nBits / 8; + const pwBytes: number[] = new Array(nBytes); + for (let i = 0; i < nBytes; i++) { + pwBytes[i] = password.charCodeAt(i) & 0xff; + } + let key: number[] = Cipher(pwBytes, KeyExpansion(pwBytes)); + key = key.concat(key.slice(0, nBytes - 16)); + const blockSize: number = 16; + const counterBlock: number[] = new Array(blockSize); + const nonce: number = (new Date()).getTime(); + + for (let i = 0; i < 4; i++) { + counterBlock[i] = (nonce >>> i * 8) & 0xff; + } + for (let i = 0; i < 4; i++) { + counterBlock[i + 4] = (nonce / 0x100000000 >>> i * 8) & 0xff; + } + const keySchedule: number[][] = KeyExpansion(key); + const blockCount: number = Math.ceil(plaintext.length / blockSize); + const ciphertext: string[] = new Array(blockCount); + for (let b = 0; b < blockCount; b++) { + for (let c = 0; c < 4; c++) { + counterBlock[15 - c] = (b >>> c * 8) & 0xff; + } + for (let c = 0; c < 4; c++) { + counterBlock[15 - c - 4] = (b / 0x100000000 >>> c * 8); + } + const cipherCntr: number[] = Cipher(counterBlock, keySchedule); + const blockLength: number = b < blockCount - 1 ? blockSize : (plaintext.length - 1) % blockSize + 1; + let ct: string = ''; + for (let i = 0; i < blockLength; i++) { + const plaintextByte: number = plaintext.charCodeAt(b * blockSize + i); + const cipherByte: number = plaintextByte ^ cipherCntr[i]; + ct += String.fromCharCode(cipherByte); + } + ciphertext[b] = escCtrlChars(ct); + } + + let ctrTxt: string = ''; + for (let i = 0; i < 8; i++) { + ctrTxt += String.fromCharCode(counterBlock[i]); + } + ctrTxt = escCtrlChars(ctrTxt); + return ctrTxt + '-' + ciphertext.join('-'); +} + + +function AESDecryptCtr(ciphertexta: string, password: string, nBits: number): string { + if (!(nBits === 128 || nBits === 192 || nBits === 256)) { + return ''; + } // standard allows 128/192/256 bit keys + const nBytes: number = nBits / 8; // no bytes in key + const pwBytes: number[] = []; + for (let i = 0; i < nBytes; i++) { + pwBytes[i] = password.charCodeAt(i) & 0xff; + } + const pwKeySchedule: number[][] = KeyExpansion(pwBytes); + let key: number[] = Cipher(pwBytes, pwKeySchedule); + key = key.concat(key.slice(0, nBytes - 16)); + const keySchedule: number[][] = KeyExpansion(key); + + const ciphertext: string[] = ciphertexta.split('-'); + const blockSize: number = 16; + const counterBlock: number[] = new Array(blockSize); + const ctrTxt: string = unescCtrlChars(ciphertext[0]); + for (let i = 0; i < 8; i++) { + counterBlock[i] = ctrTxt.charCodeAt(i); + } + const plaintext: string[] = new Array(ciphertext.length - 1); + for (let b = 1; b < ciphertext.length; b++) { + for (let c = 0; c < 4; c++) { + counterBlock[15 - c] = ((b - 1) >>> c * 8) & 0xff; + } + for (let c = 0; c < 4; c++) { + counterBlock[15 - c - 4] = ((b / 0x100000000 - 1) >>> c * 8) & 0xff; + } + const cipherCntr: number[] = Cipher(counterBlock, keySchedule); + ciphertext[b] = unescCtrlChars(ciphertext[b]); + let pt: string = ''; + for (let i = 0; i < ciphertext[b].length; i++) { + const ciphertextByte: number = ciphertext[b].charCodeAt(i); + const plaintextByte: number = ciphertextByte ^ cipherCntr[i]; + pt += String.fromCharCode(plaintextByte); + } + plaintext[b - 1] = pt; + } + return plaintext.join(''); +} + + +function AESRun() { + const plainText: string = "ROMEO: But, soft! what light through yonder window breaks?\n\ + It is the east, and Juliet is the sun.\n\ + Arise, fair sun, and kill the envious moon,\n\ + Who is already sick and pale with grief,\n\ + That thou her maid art far more fair than she:\n\ + Be not her maid, since she is envious;\n\ + Her vestal livery is but sick and green\n\ + And none but fools do wear it; cast it off.\n\ + It is my lady, O, it is my love!\n\ + O, that she knew she were!\n\ + She speaks yet she says nothing: what of that?\n\ + Her eye discourses; I will answer it.\n\ + I am too bold, 'tis not to me she speaks:\n\ + Two of the fairest stars in all the heaven,\n\ + Having some business, do entreat her eyes\n\ + To twinkle in their spheres till they return.\n\ + What if her eyes were there, they in her head?\n\ + The brightness of her cheek would shame those stars,\n\ + As daylight doth a lamp; her eyes in heaven\n\ + Would through the airy region stream so bright\n\ + That birds would sing and think it were not night.\n\ + See, how she leans her cheek upon her hand!\n\ + O, that I were a glove upon that hand,\n\ + That I might touch that cheek!\n\ + JULIET: Ay me!\n\ + ROMEO: She speaks:\n\ + O, speak again, bright angel! for thou art\n\ + As glorious to this night, being o'er my head\n\ + As is a winged messenger of heaven\n\ + Unto the white-upturned wondering eyes\n\ + Of mortals that fall back to gaze on him\n\ + When he bestrides the lazy-pacing clouds\n\ + And sails upon the bosom of the air."; + + const password: string = "O Romeo, Romeo! wherefore art thou Romeo?"; + const cipherText: string = AESEncryptCtr(plainText, password, 256); + const decryptedText: string = AESDecryptCtr(cipherText, password, 256); + if (decryptedText !== plainText) { + throw new Error(`ERROR: bad result: expected ${plainText} but got ${decryptedText}`); + } +} + +/**************************configure and run benchmark********************************/ +export { AESRun } diff --git a/OHBM/entry/src/main/ets/cases/performance/crypto-md5.ts b/OHBM/entry/src/main/ets/cases/performance/crypto-md5.ts new file mode 100644 index 000000000..c79f7a43f --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/crypto-md5.ts @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { BenchmarkRun } from "../BenchmarkMeasure"; + + +/**************************source code********************************/ + +const hexcase: number = 0; +const chrsz: number = 8; + +function safe_add(x: number, y: number): number { + const lsw: number = (x & 0xFFFF) + (y & 0xFFFF); + const msw: number = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +function bit_rol(num: number, cnt: number): number { + return (num << cnt) | (num >>> (32 - cnt)); +} + +function md5_cmn(q: number, a: number, b: number, x: number, s: number, t: number): number { + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); +} + +function md5_ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number { + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} + +function md5_gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number { + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} + +function md5_hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number { + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} + +function md5_ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number { + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +function str2binl(str: string): number[] { + const bin: number[] = []; + const mask: number = (1 << chrsz) - 1; + for (let i: number = 0; i < str.length * chrsz; i += chrsz) { + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32); + } + return bin; +} + +function core_md5(x: number[], len: number): number[] { + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + let a: number = 1732584193; + let b: number = -271733879; + let c: number = -1732584194; + let d: number = 271733878; + for (let i = 0; i < x.length; i += 16) { + let olda: number = a; + let oldb: number = b; + let oldc: number = c; + let oldd: number = d; + a = md5_ff(a, b, c, d, x[i+ 0], 7, -680876936); + d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i+ 4], 7, -176418897); + d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i+ 8], 7, 1770035416); + d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i+12], 7, 1804603682); + d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + a = md5_gg(a, b, c, d, x[i+ 1], 5, -165796510); + d = md5_gg(d, a, b, c, x[i+ 6], 9, -1069501632); + c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i+ 5], 5, -701558691); + d = md5_gg(d, a, b, c, x[i+10], 9, 38016083); + c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5, 568446438); + d = md5_gg(d, a, b, c, x[i+14], 9, -1019803690); + c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i+13], 5, -1444681467); + d = md5_gg(d, a, b, c, x[i+ 2], 9, -51403784); + c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + a = md5_hh(a, b, c, d, x[i+ 5], 4, -378558); + d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i+ 1], 4, -1530992060); + d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i+13], 4, 681279174); + d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4, -640364487); + d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + a = md5_ii(a, b, c, d, x[i+ 0], 6, -198630844); + d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i+12], 6, 1700485571); + d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i+ 8], 6, 1873313359); + d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i+ 4], 6, -145523070); + d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return [a, b, c, d]; +} + + +function binl2hex(binarray: number[]): string { + const hex_tab: string = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + let str: string = ""; + for (let i: number = 0; i < binarray.length * 4; i++) { + str += hex_tab.charAt((binarray[i>>2] >> ((i % 4) * 8 + 4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((i % 4) * 8)) & 0xF); + } + return str; +} + +function hex_md5(s: string): string { + return binl2hex(core_md5(str2binl(s), s.length * chrsz)); +} + + +function Md5Run() { + + let plainText: string = "Rebellious subjects, enemies to peace,\n\ +Profaners of this neighbour-stained steel,--\n\ +Will they not hear? What, ho! you men, you beasts,\n\ +That quench the fire of your pernicious rage\n\ +With purple fountains issuing from your veins,\n\ +On pain of torture, from those bloody hands\n\ +Throw your mistemper'd weapons to the ground,\n\ +And hear the sentence of your moved prince.\n\ +Three civil brawls, bred of an airy word,\n\ +By thee, old Capulet, and Montague,\n\ +Have thrice disturb'd the quiet of our streets,\n\ +And made Verona's ancient citizens\n\ +Cast by their grave beseeming ornaments,\n\ +To wield old partisans, in hands as old,\n\ +Canker'd with peace, to part your canker'd hate:\n\ +If ever you disturb our streets again,\n\ +Your lives shall pay the forfeit of the peace.\n\ +For this time, all the rest depart away:\n\ +You Capulet; shall go along with me:\n\ +And, Montague, come you this afternoon,\n\ +To know our further pleasure in this case,\n\ +To old Free-town, our common judgment-place.\n\ +Once more, on pain of death, all men depart."; + for (let i = 0; i < 4; i++) { + plainText += plainText; + } + const md5Output: string = hex_md5(plainText); + const expected: string = "a831e91e0f70eddcb70dc61c6f82f6cd"; + if (md5Output !== expected) { + throw new Error(`ERROR: bad result: expected ${expected} but got ${md5Output}`); + } +} + + +/**************************configure and run benchmark********************************/ + +export { Md5Run } diff --git a/OHBM/entry/src/main/ets/cases/performance/crypto-sha1.ts b/OHBM/entry/src/main/ets/cases/performance/crypto-sha1.ts new file mode 100644 index 000000000..7806bb3d6 --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/crypto-sha1.ts @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { BenchmarkRun } from "../BenchmarkMeasure"; + + +/**************************source code********************************/ + +const chrsz: number = 8; +const hexcase: number = 0; + +function binb2hex(binarray: number[]): string { + const hex_tab: string = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + let str: string = ""; + for (let i: number = 0; i < binarray.length * 4; i++) { + str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xF); + } + return str; +} + +function str2binb(str: string): number[] { + const bin: number[] = []; + const mask: number = (1 << chrsz) - 1; + for (let i: number = 0; i < str.length * chrsz; i += chrsz) { + bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i % 32); + } + return bin; +} + +function safe_add(x: number, y: number): number { + const lsw: number = (x & 0xFFFF) + (y & 0xFFFF); + const msw: number = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +function rol(num: number, cnt: number): number { + return (num << cnt) | (num >>> (32 - cnt)); +} + +function sha1_ft(t: number, b: number, c: number, d: number): number { + if (t < 20) { + return (b & c) | ((~b) & d); + } + if (t < 40) { + return b ^ c ^ d; + } + if (t < 60) { + return (b & c) | (b & d) | (c & d); + } + return b ^ c ^ d; +} + +function sha1_kt(t: number): number { + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +function core_sha1(x: number[], len: number): number[] { + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + const w: number[] = new Array(80); + let a: number = 1732584193; + let b: number = -271733879; + let c: number = -1732584194; + let d: number = 271733878; + let e: number = -1009589776; + for (let i: number = 0; i < x.length; i += 16) { + const olda: number = a; + const oldb: number = b; + const oldc: number = c; + const oldd: number = d; + const olde: number = e; + for (let j: number = 0; j < 80; j++) { + if (j < 16) { + w[j] = x[i + j]; + } else { + w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); + } + const t: number = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return [a, b, c, d, e]; +} + +function hex_sha1(s: string): string { + return binb2hex(core_sha1(str2binb(s), s.length * chrsz)); +} + + +function Sha1Run(): void { + let plainText: string = "Two households, both alike in dignity,\n\ +In fair Verona, where we lay our scene,\n\ +From ancient grudge break to new mutiny,\n\ +Where civil blood makes civil hands unclean.\n\ +From forth the fatal loins of these two foes\n\ +A pair of star-cross'd lovers take their life;\n\ +Whole misadventured piteous overthrows\n\ +Do with their death bury their parents' strife.\n\ +The fearful passage of their death-mark'd love,\n\ +And the continuance of their parents' rage,\n\ +Which, but their children's end, nought could remove,\n\ +Is now the two hours' traffic of our stage;\n\ +The which if you with patient ears attend,\n\ +What here shall miss, our toil shall strive to mend."; + for (let i: number = 0; i < 4; i++) { + plainText += plainText; + } + let sha1Output: string = hex_sha1(plainText); + let expected: string = "2524d264def74cce2498bf112bedf00e6c0b796d"; + if (sha1Output != expected) { + throw "ERROR: bad result: expected " + expected + " but got " + sha1Output; + } +} + + +/**************************configure and run benchmark********************************/ +export { Sha1Run } \ No newline at end of file -- Gitee From 92590693a2e2b0a26b34a43ff583fe440d00823b Mon Sep 17 00:00:00 2001 From: sunlian Date: Wed, 27 Nov 2024 14:54:17 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0cpu=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E6=B5=8B=E8=AF=95case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sunlian --- .../main/ets/cases/performance/deltablue.ts | 679 ++++++++++++++++++ .../ets/cases/performance/navier-stoke.ts | 410 +++++++++++ .../main/ets/cases/performance/richards.ts | 430 +++++++++++ 3 files changed, 1519 insertions(+) create mode 100644 OHBM/entry/src/main/ets/cases/performance/deltablue.ts create mode 100644 OHBM/entry/src/main/ets/cases/performance/navier-stoke.ts create mode 100644 OHBM/entry/src/main/ets/cases/performance/richards.ts diff --git a/OHBM/entry/src/main/ets/cases/performance/deltablue.ts b/OHBM/entry/src/main/ets/cases/performance/deltablue.ts new file mode 100644 index 000000000..c13b1bac7 --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/deltablue.ts @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BenchmarkRun } from "../BenchmarkMeasure"; + +/**************************source code********************************/ +declare function print(arg: any, arg1?: any): string; + +class Strength { + strengthValue: number; + name: string; + + static REQUIRED = new Strength(0, "required"); + static STONG_PREFERRED = new Strength(1, "strongPreferred"); + static PREFERRED = new Strength(2, "preferred"); + static STRONG_DEFAULT = new Strength(3, "strongDefault"); + static NORMAL = new Strength(4, "normal"); + static WEAK_DEFAULT = new Strength(5, "weakDefault"); + static WEAKEST = new Strength(6, "weakest"); + + constructor(strengthValue: number, name: string) { + this.strengthValue = strengthValue; + this.name = name; + } + + static stronger(s1: Strength, s2: Strength): boolean { + return s1.strengthValue < s2.strengthValue; + } + + static weaker(s1: Strength, s2: Strength): boolean { + return s1.strengthValue > s2.strengthValue; + } + + static weakestOf(s1: Strength, s2: Strength): Strength { + return this.weaker(s1, s2) ? s1 : s2; + } + + static strongest(s1: Strength, s2: Strength): Strength { + return this.stronger(s1, s2) ? s1 : s2; + } + + nextWeaker(): Strength { + switch (this.strengthValue) { + case 0: + return Strength.WEAKEST; + case 1: + return Strength.WEAK_DEFAULT; + case 2: + return Strength.NORMAL; + case 3: + return Strength.STRONG_DEFAULT; + case 4: + return Strength.PREFERRED; + case 5: + return Strength.REQUIRED; + default: + return new Strength(0, ""); + } + } +} + +abstract class Constraint { + strength: Strength; + + abstract addToGraph(): void; + + abstract chooseMethod(mark: number): void; + + abstract isSatisfied(): boolean; + + abstract markInputs(mark: number): void; + + abstract output(): Variable; + + abstract removeFromGraph(): void; + + abstract markUnsatisfied(): void; + + abstract execute(): void; + + abstract inputsKnown(mark: number): boolean; + + abstract recalculate(): void; + + constructor(strength: Strength) { + this.strength = strength; + } + + addConstraint(): void { + this.addToGraph(); + planner.incrementalAdd(this); + } + + satisfy(mark: number): Constraint | null { + this.chooseMethod(mark); + if (!this.isSatisfied()) { + if (this.strength === Strength.REQUIRED) { + print("Could not satisfy a required constraint!"); + } + return null; + } + this.markInputs(mark); + const out: Variable = this.output(); + const overridden: Constraint | null = out.determinedBy; + if (overridden != null) { + overridden.markUnsatisfied(); + } + out.determinedBy = this; + if (!planner.addPropagate(this, mark)) { + print("Cycle encountered"); + } + out.mark = mark; + return overridden; + } + + public destroyConstraint(): void { + if (this.isSatisfied()) { + planner.incrementalRemove(this); + } else { + this.removeFromGraph(); + } + } + + public isInput(): boolean { + return false; + } +} + +enum Direction { + NONE = 0, + FORWARD = 1, + BACKWARD = -1 +} + +abstract class BinaryConstraint extends Constraint { + v1: Variable; + v2: Variable; + direction: Direction; + + constructor(var1: Variable, var2: Variable, strength: Strength) { + super(strength); + this.v1 = var1; + this.v2 = var2; + this.direction = Direction.NONE; + // this.addConstraint(); + } + + chooseMethod(mark: number): void { + if (this.v1.mark == mark) { + this.direction = (this.v2.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength)) + ? Direction.FORWARD + : Direction.NONE; + } + if (this.v2.mark == mark) { + this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v1.walkStrength)) + ? Direction.BACKWARD + : Direction.NONE; + } + if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) { + this.direction = Strength.stronger(this.strength, this.v1.walkStrength) + ? Direction.BACKWARD + : Direction.NONE; + } else { + this.direction = Strength.stronger(this.strength, this.v2.walkStrength) + ? Direction.FORWARD + : Direction.BACKWARD; + } + } + + addToGraph(): void { + this.v1.addConstraint(this); + this.v2.addConstraint(this); + this.direction = Direction.NONE; + } + + isSatisfied(): boolean { + return this.direction != Direction.NONE; + } + + markInputs(mark: number): void { + this.input().mark = mark; + } + + input(): Variable { + return (this.direction == Direction.FORWARD) ? this.v1 : this.v2; + } + + output(): Variable { + return (this.direction == Direction.FORWARD) ? this.v2 : this.v1; + } + + recalculate(): void { + let ihn: Variable = this.input(); + let out: Variable = this.output(); + out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength); + out.stay = ihn.stay; + if (out.stay) { + this.execute(); + } + } + + markUnsatisfied(): void { + this.direction = Direction.NONE; + } + + inputsKnown(mark: number): boolean { + let i: Variable = this.input(); + return i.mark == mark || i.stay || i.determinedBy == null; + } + + removeFromGraph(): void { + if (this.v1 != null) { + this.v1.removeConstraint(this); + } + if (this.v2 != null) { + this.v2.removeConstraint(this); + } + this.direction = Direction.NONE; + } +} + +class ScaleConstraint extends BinaryConstraint { + scale: Variable; + offset: Variable; + + constructor(src: Variable, scale: Variable, offset: Variable, dest: Variable, strength: Strength) { + super(src, dest, strength); + this.scale = scale; + this.direction = Direction.NONE; + this.offset = offset; + this.addScaAndOffToGraph(); + this.addConstraint(); + } + + addScaAndOffToGraph(): void { + this.scale.addConstraint(this); + this.offset.addConstraint(this); + } + + removeFromGraph(): void { + if (this.scale != null) { + this.scale.removeConstraint(this); + } + if (this.offset != null) { + this.offset.removeConstraint(this); + } + } + + markInputs(mark: number): void { + this.scale.mark = this.offset.mark = mark; + } + + execute(): void { + if (this.direction == Direction.FORWARD) { + this.v2.value = this.v1.value * this.scale.value + this.offset.value; + } else { + this.v1.value = (this.v2.value - this.offset.value) / this.scale.value; + } + } + + recalculate(): void { + let ihn: Variable = this.input(); + let out: Variable = this.output(); + out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength); + out.stay = ihn.stay && this.scale.stay && this.offset.stay; + if (out.stay) { + this.execute(); + } + } +} + + +class EqualityConstraint extends BinaryConstraint { + constructor(var1: Variable, var2: Variable, strength: Strength) { + super(var1, var2, strength); + this.addConstraint(); + } + + execute(): void { + this.output().value = this.input().value; + } +} + + +abstract class UnaryConstraint extends Constraint { + myOutput: Variable; + satisfied: boolean; + + constructor(v: Variable, strength: Strength) { + super(strength); + this.myOutput = v; + this.satisfied = false; + this.addConstraint(); + } + + addToGraph(): void { + this.myOutput.addConstraint(this); + this.satisfied = false; + } + + chooseMethod(mark: number): void { + this.satisfied = (this.myOutput.mark !== mark) && Strength.stronger(this.strength, this.myOutput.walkStrength); + } + + isSatisfied(): boolean { + return this.satisfied; + } + + markInputs(mark: number): void { + // has no inputs + } + + output(): Variable { + return this.myOutput; + } + + recalculate(): void { + this.myOutput.walkStrength = this.strength; + this.myOutput.stay = !this.isInput(); + if (this.myOutput.stay) { + this.execute(); + } + } + + markUnsatisfied(): void { + this.satisfied = false; + } + + inputsKnown(mark: number): boolean { + return true; + } + + removeFromGraph(): void { + if (this.myOutput != null) { + this.myOutput.removeConstraint(this); + } + this.satisfied = false; + } +} + +class EditConstraint extends UnaryConstraint { + constructor(v: Variable, str: Strength) { + super(v, str); + } + + isInput(): boolean { + return true; + } + + execute(): void { + } +} + +class StayConstraint extends UnaryConstraint { + constructor(v: Variable, str: Strength) { + super(v, str); + } + + execute(): void { + + } +} + + +class OrderedCollection { + elms: T[]; + + constructor() { + this.elms = []; + } + + add(elm: T): void { + this.elms.push(elm); + } + + at(index: number): T { + return this.elms[index]; + } + + size(): number { + return this.elms.length; + } + + removeFirst(): T | undefined { + return this.elms.pop(); + } + + remove(elm: T): void { + let index: number = 0, skipped: number = 0; + for (let i = 0; i < this.elms.length; i++) { + let value: T = this.elms[i]; + if (value !== elm) { + this.elms[index] = value; + index++; + } else { + skipped++; + } + } + for (let i = 0; i < skipped; i++) { + this.elms.pop(); + } + } +} + + +class Variable { + value: number; + constraints: OrderedCollection; + determinedBy: Constraint | null; + mark: number; + walkStrength: Strength; + stay: boolean; + name: string; + + constructor(name: string, initialValue?: number) { + this.value = initialValue || 0; + this.constraints = new OrderedCollection(); + this.determinedBy = null; + this.mark = 0; + this.walkStrength = Strength.WEAKEST; + this.stay = true; + this.name = name; + } + + addConstraint(c: Constraint): void { + this.constraints.add(c); + } + + removeConstraint(c: Constraint): void { + this.constraints.remove(c); + if (this.determinedBy === c) { + this.determinedBy = null; + } + } +} + +class Plan { + v: OrderedCollection; + + constructor() { + this.v = new OrderedCollection(); + } + + addConstraint(c: Constraint): void { + this.v.add(c); + } + + size(): number { + return this.v.size(); + } + + constraintAt(index: number): Constraint { + return this.v.at(index); + } + + execute() { + for (let i = 0; i < this.size(); i++) { + let c: Constraint = this.constraintAt(i); + c.execute(); + } + } +} + +class Planner { + currentMark: number; + + constructor() { + this.currentMark = 0; + } + + incrementalAdd(c: Constraint): void { + const mark: number = this.newMark(); + let overridden: Constraint | null = c.satisfy(mark); + while (overridden !== null) { + overridden = overridden.satisfy(mark); + } + } + + incrementalRemove(c: Constraint): void { + const out: Variable = c.output(); + c.markUnsatisfied(); + c.removeFromGraph(); + const unsatisfied = this.removePropagateFrom(out); + let strength: Strength = Strength.REQUIRED; + do { + for (let i = 0; i < unsatisfied.size(); i++) { + const u = unsatisfied.at(i); + if (u.strength == strength) { + this.incrementalAdd(u); + } + } + strength = strength.nextWeaker(); + } while (strength != Strength.WEAKEST); + } + + newMark(): number { + return ++this.currentMark; + } + + makePlan(sources: OrderedCollection) { + const mark = this.newMark(); + const plan = new Plan(); + const todo = sources; + while (todo.size() > 0) { + const c: Constraint | undefined = todo.removeFirst(); + if (c!.output().mark != mark && c!.inputsKnown(mark)) { + plan.addConstraint(c!); + c!.output().mark = mark; + this.addConstraintsConsumingTo(c!.output(), todo); + } + } + return plan; + } + + extractPlanFromConstraints(constraints: OrderedCollection): Plan { + const sources: OrderedCollection = new OrderedCollection(); + for (let i = 0; i < constraints.size(); i++) { + const c: Constraint = constraints.at(i); + if (c.isInput() && c.isSatisfied()) { + sources.add(c); + } + } + return this.makePlan(sources); + } + + addPropagate(c: Constraint, mark: number): boolean { + const todo: OrderedCollection = new OrderedCollection(); + todo.add(c); + while (todo.size() > 0) { + const d: Constraint | undefined = todo.removeFirst(); + if (d!.output().mark == mark) { + this.incrementalRemove(c); + return false; + } + d!.recalculate(); + this.addConstraintsConsumingTo(d!.output(), todo); + } + return true; + } + + removePropagateFrom(out: Variable): OrderedCollection { + out.determinedBy = null; + out.walkStrength = Strength.WEAKEST; + out.stay = true; + const unsatisfied: OrderedCollection = new OrderedCollection(); + const todo: OrderedCollection = new OrderedCollection(); + todo.add(out); + while (todo.size() > 0) { + const v: Variable | undefined = todo.removeFirst(); + for (let i = 0; i < v!.constraints.size(); i++) { + const c: Constraint = v!.constraints.at(i); + if (!c.isSatisfied()) { + unsatisfied.add(c); + } + } + const determining = v!.determinedBy; + for (let i = 0; i < v!.constraints.size(); i++) { + const next = v!.constraints.at(i); + if (next != determining && next.isSatisfied()) { + next.recalculate(); + todo.add(next.output()); + } + } + } + return unsatisfied; + } + + addConstraintsConsumingTo(v: Variable, coll: OrderedCollection) { + const determining: Constraint | null = v.determinedBy; + const cc: OrderedCollection = v.constraints; + for (let i = 0; i < cc.size(); i++) { + const c: Constraint = cc.at(i); + if (c != determining && c.isSatisfied()) { + coll.add(c); + } + } + } +} + +function change(v: Variable, newValue: number): void { + const edit: EditConstraint = new EditConstraint(v, Strength.PREFERRED); + const edits: OrderedCollection = new OrderedCollection(); + edits.add(edit); + const plan: Plan = planner.extractPlanFromConstraints(edits); + for (let i: number = 0; i < 10; i++) { + v.value = newValue; + plan.execute(); + } + edit.destroyConstraint(); +} + +let planner: Planner; + + +function chainTest(n: number): void { + planner = new Planner(); + let prev: Variable | null = null, first: Variable | null = null, last: Variable | null = null; + for (let i = 0; i <= n; i++) { + let name: string = "v" + i; + let v: Variable = new Variable(name); + if (prev !== null) { + new EqualityConstraint(prev, v, Strength.REQUIRED); + } + if (i === 0) { + first = v; + } + if (i === n) { + last = v; + } + prev = v; + } + new StayConstraint(last!, Strength.STRONG_DEFAULT); + let edit: EditConstraint = new EditConstraint(first!, Strength.PREFERRED); + let edits: OrderedCollection = new OrderedCollection(); + edits.add(edit); + let plan: Plan = planner.extractPlanFromConstraints(edits); + for (let i = 0; i < 100; i++) { + first!.value = i; + plan.execute(); + if (last!.value !== i) { + throw new Error("Chain test failed."); + } + } +} + +function projectionTest(n: number): void { + planner = new Planner(); + let scale: Variable = new Variable("scale", 10); + let offset: Variable = new Variable("offset", 1000); + let src: Variable, dst: Variable; + let dests: OrderedCollection = new OrderedCollection(); + for (let i = 0; i < n; i++) { + src = new Variable("src" + i, i); + dst = new Variable("dst" + i, i); + dests.add(dst); + new StayConstraint(src, Strength.NORMAL); + new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED); + } + change(src!, 17); + if (dst!.value !== 1170) { + throw new Error("Projection 1 failed"); + } + change(dst!, 1050); + if (src!.value !== 5) { + throw new Error("Projection 2 failed"); + } + change(scale, 5); + for (let i = 0; i < n - 1; i++) { + if (dests.at(i).value !== i * 5 + 1000) { + throw new Error("Projection 3 failed"); + } + } + change(offset, 2000); + for (let i = 0; i < n - 1; i++) { + if (dests.at(i).value !== i * 5 + 2000) { + throw new Error("Projection 4 failed"); + } + } +} + +function DeltablueRun(): void { + chainTest(100); + projectionTest(100); +} + +/**************************configure and run benchmark********************************/ +export { DeltablueRun } \ No newline at end of file diff --git a/OHBM/entry/src/main/ets/cases/performance/navier-stoke.ts b/OHBM/entry/src/main/ets/cases/performance/navier-stoke.ts new file mode 100644 index 000000000..d063c3470 --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/navier-stoke.ts @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BenchmarkRun } from "../BenchmarkMeasure"; + +/**************************source code********************************/ +class Field { + dens: number[] = []; + u: number[] = []; + v: number[] = []; + fluidField: FluidField; + + constructor(fluidField: FluidField, dens: number[], u: number[], v: number[]) { + this.fluidField = fluidField; + this.dens = dens; + this.u = u; + this.v = v; + + } + + setDensity(x: number, y: number, d: number): void { + this.dens[(x + 1) + (y + 1) * this.fluidField.rowSize] = d; + } + + getDensity(x: number, y: number): number { + return this.dens[(x + 1) + (y + 1) * this.fluidField.rowSize]; + } + + setVelocity(x: number, y: number, xv: number, yv: number): void { + this.u[(x + 1) + (y + 1) * this.fluidField.rowSize] = xv; + this.v[(x + 1) + (y + 1) * this.fluidField.rowSize] = yv; + } + + getXVelocity(x: number, y: number): number { + return this.u[(x + 1) + (y + 1) * this.fluidField.rowSize]; + } + + public getYVelocity(x: number, y: number): number { + return this.v[(x + 1) + (y + 1) * this.fluidField.rowSize]; + } +}; + + +class FluidField { + iterations: number = 10; + visc: number = 0.5; + dt: number = 0.1; + dens: number[] = []; + dens_prev: number[] = []; + u: number[] = []; + u_prev: number[] = []; + v: number[] = []; + v_prev: number[] = []; + width: number = 0; + height: number = 0; + rowSize: number = 0; + size: number = 0; + displayFunc: Function = () => { + }; + uiCallback: Function = () => { + }; + + constructor() { + this.setResolution(64, 64); + } + + addFields(x: number[], s: number[], dt: number): void { + for (let i = 0; i < this.size; i++) { + x[i] += dt * s[i]; + } + } + + set_bnd(b: number, x: number[]): void { + if (b === 1) { + for (let i = 1; i <= this.width; i++) { + x[i] = x[i + this.rowSize]; + x[i + (this.height + 1) * this.rowSize] = x[i + this.height * this.rowSize]; + } + for (let j = 1; j <= this.height; j++) { + x[j * this.rowSize] = -x[1 + j * this.rowSize]; + x[(this.width + 1) + j * this.rowSize] = -x[this.width + j * this.rowSize]; + } + } else if (b === 2) { + for (let i = 1; i <= this.width; i++) { + x[i] = -x[i + this.rowSize]; + x[i + (this.height + 1) * this.rowSize] = -x[i + this.height * this.rowSize]; + } + for (let j = 1; j <= this.height; j++) { + x[j * this.rowSize] = x[1 + j * this.rowSize]; + x[(this.width + 1) + j * this.rowSize] = x[this.width + j * this.rowSize]; + } + } else { + for (let i = 1; i <= this.width; i++) { + x[i] = x[i + this.rowSize]; + x[i + (this.height + 1) * this.rowSize] = x[i + this.height * this.rowSize]; + } + for (let j = 1; j <= this.height; j++) { + x[j * this.rowSize] = x[1 + j * this.rowSize]; + x[(this.width + 1) + j * this.rowSize] = x[this.width + j * this.rowSize]; + } + } + const maxEdge = (this.height + 1) * this.rowSize; + x[0] = 0.5 * (x[1] + x[this.rowSize]); + x[maxEdge] = 0.5 * (x[1 + maxEdge] + x[this.height * this.rowSize]); + x[(this.width + 1)] = 0.5 * (x[this.width] + x[(this.width + 1) + this.rowSize]); + x[(this.width + 1) + maxEdge] = 0.5 * (x[this.width + maxEdge] + x[(this.width + 1) + this.height * this.rowSize]); + } + + + lin_solve(b: number, x: number[], x0: number[], a: number, c: number): void { + if (a === 0 && c === 1) { + for (let j = 1; j <= this.height; j++) { + let currentRow = j * this.rowSize; + currentRow++; + for (let i = 0; i < this.width; i++) { + x[currentRow] = x0[currentRow]; + currentRow++; + } + } + this.set_bnd(b, x); + } else { + const invC = 1 / c + for (let k = 0; k < this.iterations; k++) { + for (let j = 1; j <= this.height; j++) { + let lastRow = (j - 1) * this.rowSize; + let currentRow = j * this.rowSize; + let nextRow = (j + 1) * this.rowSize; + let lastX = x[currentRow]; + currentRow++; + for (let i = 1; i <= this.width; i++) { + lastX = + x[currentRow] = (x0[currentRow] + a * (lastX + x[++currentRow] + x[++lastRow] + x[++nextRow])) * invC; + } + } + this.set_bnd(b, x); + } + } + } + + + diffuse(b: number, x: number[], x0: number[], dt: number): void { + const a: number = 0; + this.lin_solve(b, x, x0, a, 1 + 4 * a); + } + + + lin_solve2(x: number[], x0: number[], y: number[], y0: number[], a: number, c: number): void { + if (a === 0 && c === 1) { + for (let j = 1; j <= this.height; j++) { + let currentRow = j * this.rowSize; + currentRow++; + for (let i = 0; i < this.width; i++) { + x[currentRow] = x0[currentRow]; + y[currentRow] = y0[currentRow]; + currentRow++; + } + } + this.set_bnd(1, x); + this.set_bnd(2, y); + } else { + const invC = 1 / c; + for (let k = 0; k < this.iterations; k++) { + for (let j = 1; j <= this.height; j++) { + let lastRow = (j - 1) * this.rowSize; + let currentRow = j * this.rowSize; + let nextRow = (j + 1) * this.rowSize; + let lastX = x[currentRow]; + let lastY = y[currentRow]; + currentRow++; + for (let i = 1; i <= this.width; i++) { + lastX = x[currentRow] = (x0[currentRow] + a * (lastX + x[currentRow] + x[lastRow] + x[nextRow])) * invC; + lastY = + y[currentRow] = (y0[currentRow] + a * (lastY + y[++currentRow] + y[++lastRow] + y[++nextRow])) * invC; + } + } + this.set_bnd(1, x); + this.set_bnd(2, y); + } + } + } + + diffuse2(x: number[], x0: number[], y: number[], y0: number[], dt: number): void { + const a: number = 0; + this.lin_solve2(x, x0, y, y0, a, 1 + 4 * a); + } + + advect(b: number, d: number[], d0: number[], u: number[], v: number[], dt: number): void { + + const Wdt0 = dt * this.width; + const Hdt0 = dt * this.height; + const Wp5 = this.width + 0.5; + const Hp5 = this.height + 0.5; + for (let j = 1; j <= this.height; j++) { + let pos = j * this.rowSize; + for (let i = 1; i <= this.width; i++) { + let x = i - Wdt0 * u[++pos]; + let y = j - Hdt0 * v[pos]; + if (x < 0.5) { + x = 0.5; + } else if (x > Wp5) { + x = Wp5; + } + const i0 = x | 0; + const i1 = i0 + 1; + if (y < 0.5) { + y = 0.5; + } else if (y > Hp5) { + y = Hp5; + } + const j0 = y | 0; + const j1 = j0 + 1; + const s1 = x - i0; + const s0 = 1 - s1; + const t1 = y - j0; + const t0 = 1 - t1; + const row1 = j0 * this.rowSize; + const row2 = j1 * this.rowSize; + d[pos] = s0 * (t0 * d0[i0 + row1] + t1 * d0[i0 + row2]) + s1 * (t0 * d0[i1 + row1] + t1 * d0[i1 + row2]); + } + } + this.set_bnd(b, d); + } + + + project(u: number[], v: number[], p: number[], div: number[]): void { + + const h = -0.5 / Math.sqrt(this.width * this.height); + + for (let j = 1; j <= this.height; j++) { + const row = j * this.rowSize; + let previousRow = (j - 1) * this.rowSize; + let prevValue = row - 1; + let currentRow = row; + let nextValue = row + 1; + let nextRow = (j + 1) * this.rowSize; + for (let i = 1; i <= this.width; i++) { + div[++currentRow] = h * (u[++nextValue] - u[++prevValue] + v[++nextRow] - v[++previousRow]); + p[currentRow] = 0; + } + } + this.set_bnd(0, div); + this.set_bnd(0, p); + this.lin_solve(0, p, div, 1, 4); + const wScale = 0.5 * this.width; + const hScale = 0.5 * this.height; + for (let j = 1; j <= this.height; j++) { + let prevPos = j * this.rowSize - 1; + let currentPos = j * this.rowSize; + let nextPos = j * this.rowSize + 1; + let prevRow = (j - 1) * this.rowSize; + let nextRow = (j + 1) * this.rowSize; + for (let i = 1; i <= this.width; i++) { + u[++currentPos] -= wScale * (p[++nextPos] - p[++prevPos]); + v[currentPos] -= hScale * (p[++nextRow] - p[++prevRow]); + } + } + this.set_bnd(1, u); + this.set_bnd(2, v); + } + + dens_step(x: number[], x0: number[], u: number[], v: number[], dt: number): void { + this.addFields(x, x0, dt); + this.diffuse(0, x0, x, dt); + this.advect(0, x, x0, u, v, dt); + } + + + vel_step(u: number[], v: number[], u0: number[], v0: number[], dt: number): void { + this.addFields(u, u0, dt); + this.addFields(v, v0, dt); + [u, u0] = [u0, u]; + [v, v0] = [v0, v]; + this.diffuse2(u, u0, v, v0, dt); + this.project(u, v, u0, v0); + [u, u0] = [u0, u]; + [v, v0] = [v0, v]; + this.advect(1, u, u0, u0, v0, dt); + this.advect(2, v, v0, u0, v0, dt); + this.project(u, v, u0, v0); + } + + queryUI(d: number[], u: number[], v: number[]): void { + for (let i = 0; i < this.size; i++) { + u[i] = v[i] = d[i] = 0.0; + } + this.uiCallback(new Field(this, d, u, v)); + } + + + update(): void { + this.queryUI(this.dens_prev, this.u_prev, this.v_prev); + this.vel_step(this.u, this.v, this.u_prev, this.v_prev, this.dt); + this.dens_step(this.dens, this.dens_prev, this.u, this.v, this.dt); + this.displayFunc(new Field(this, this.dens, this.u, this.v)); + } + + setDisplayFunction(func: Function): void { + this.displayFunc = func; + } + + setIterations(iters: number): void { + if (iters > 0 && iters <= 100) { + this.iterations = iters; + } + } + + setUICallback(callback: Function): void { + this.uiCallback = callback; + } + + reset(): void { + this.rowSize = this.width + 2; + this.size = this.rowSize * (this.height + 2); + this.dens = new Array(this.size).fill(0); + this.dens_prev = new Array(this.size).fill(0); + this.u = new Array(this.size).fill(0); + this.u_prev = new Array(this.size).fill(0); + this.v = new Array(this.size).fill(0); + this.v_prev = new Array(this.size).fill(0); + } + + getDens(): number[] { + return this.dens; + } + + setResolution(hRes: number, wRes: number): boolean { + const res: number = wRes * hRes; + if (res > 0 && res < 1000000 && (wRes !== this.width || hRes !== this.height)) { + this.width = wRes; + this.height = hRes; + this.reset(); + return true; + } else { + return false; + } + } +} + +let framesTillAddingPoints: number = 0; +let framesBetweenAddingPoints: number = 5; + + +function addPoints(field: Field): void { + const n: number = 64; + for (let i: number = 1; i <= n; i++) { + field.setVelocity(i, i, n, n); + field.setDensity(i, i, 5); + field.setVelocity(i, n - i, -n, -n); + field.setDensity(i, n - i, 20); + field.setVelocity(128 - i, n + i, -n, -n); + field.setDensity(128 - i, n + i, 30); + } +} + +function prepareFrame(field: Field): void { + if (framesTillAddingPoints === 0) { + addPoints(field); + framesTillAddingPoints = framesBetweenAddingPoints; + framesBetweenAddingPoints++; + } else { + framesTillAddingPoints--; + } +} + + +const solver: FluidField = new FluidField(); +let nsFrameCounter: number = 0; + +function NavierStokesSetup(): void { + solver.setResolution(128, 128); + solver.setIterations(20); + solver.setDisplayFunction(function () { + }); + solver.setUICallback(prepareFrame); + solver.reset(); +} + +function NavierstokesRun(): void { + solver.update(); + nsFrameCounter++; + if (nsFrameCounter == 15) { + checkResult(solver.getDens()) + } +} + +function checkResult(dens: number[]): void { + let result: number = 0; + for (let i = 7000; i < 7100; i++) { + result += ~~(dens[i] * 10); + } + if (result !== 77) { + throw new Error("checksum failed"); + } +} + + +/**************************configure and run benchmark********************************/ +export { NavierstokesRun, NavierStokesSetup } diff --git a/OHBM/entry/src/main/ets/cases/performance/richards.ts b/OHBM/entry/src/main/ets/cases/performance/richards.ts new file mode 100644 index 000000000..175fbe548 --- /dev/null +++ b/OHBM/entry/src/main/ets/cases/performance/richards.ts @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BenchmarkRun } from "../BenchmarkMeasure"; + +/**************************source code********************************/ + +class Scheduler { + queueCount: number; + holdCount: number; + blocks: (TaskControlBlock | undefined)[]; + list: TaskControlBlock | undefined; + currentTcb: TaskControlBlock | undefined; + currentId: number | undefined; + + constructor() { + this.queueCount = 0; + this.holdCount = 0; + this.blocks = Array(NUMBER_OF_IDS).fill(undefined); + this.list = undefined; + this.currentTcb = undefined; + this.currentId = undefined; + } + + addIdleTask(id: number, priority: number, queue: Packet | undefined, count: number): void { + this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count)); + } + + addWorkerTask(id: number, priority: number, queue: Packet): void { + this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0)); + } + + addHandlerTask(id: number, priority: number, queue: Packet): void { + this.addTask(id, priority, queue, new HandlerTask(this)); + } + + addDeviceTask(id: number, priority: number, queue: Packet | undefined): void { + this.addTask(id, priority, queue, new DeviceTask(this)); + } + + addRunningTask(id: number, priority: number, queue: Packet | undefined, task: Task): void { + this.addTask(id, priority, queue, task); + this.currentTcb!.setRunning(); + } + + addTask(id: number, priority: number, queue: Packet | undefined, task: Task): void { + this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task); + this.list = this.currentTcb; + this.blocks[id] = this.currentTcb; + } + + schedule(): void { + this.currentTcb = this.list; + while (this.currentTcb !== undefined) { + if (this.currentTcb.isHeldOrSuspended()) { + this.currentTcb = this.currentTcb.link; + } else { + this.currentId = this.currentTcb.id; + this.currentTcb = this.currentTcb.run(); + } + } + } + + release(id: number): TaskControlBlock | undefined { + const tcb = this.blocks[id]; + if (tcb === undefined) return tcb; + tcb.markAsNotHeld(); + if (tcb.priority > this.currentTcb!.priority) { + return tcb; + } else { + return this.currentTcb; + } + } + + holdCurrent(): TaskControlBlock | undefined { + this.holdCount += 1; + this.currentTcb?.markAsHeld(); + return this.currentTcb?.link; + } + + suspendCurrent(): TaskControlBlock | undefined { + this.currentTcb?.markAsSuspended(); + return this.currentTcb; + } + + queue(packet: Packet): TaskControlBlock | undefined { + const t = this.blocks[packet.id]; + if (t === undefined) return t; + this.queueCount += 1; + packet.link = undefined; + packet.id = this.currentId!; + return t.checkPriorityAdd(this.currentTcb!, packet); + } +} + +const ID_IDLE = 0; +const ID_WORKER = 1; +const ID_HANDLER_A = 2; +const ID_HANDLER_B = 3; +const ID_DEVICE_A = 4; +const ID_DEVICE_B = 5; +const NUMBER_OF_IDS = 6; + +const KIND_DEVICE = 0; +const KIND_WORK = 1; + +class TaskControlBlock { + link: TaskControlBlock | undefined; + id: number; + priority: number; + queue: Packet | undefined; + task: Task; + state: number; + + constructor(link: TaskControlBlock | undefined, id: number, priority: number, queue: Packet | undefined, task: Task) { + this.link = link; + this.id = id; + this.priority = priority; + this.queue = queue; + this.task = task; + if (queue === undefined) { + this.state = STATE_SUSPENDED; + } else { + this.state = STATE_SUSPENDED_RUNNABLE; + } + } + + setRunning(): void { + this.state = STATE_RUNNING; + } + + markAsNotHeld(): void { + this.state = this.state & STATE_NOT_HELD; + } + + markAsHeld(): void { + this.state = this.state | STATE_HELD; + } + + isHeldOrSuspended(): boolean { + return (this.state & STATE_HELD) !== 0 || (this.state === STATE_SUSPENDED); + } + + markAsSuspended(): void { + this.state = this.state | STATE_SUSPENDED; + } + + markAsRunnable(): void { + this.state = this.state | STATE_RUNNABLE; + } + + run(): TaskControlBlock | undefined { + let packet: Packet | undefined; + if (this.state === STATE_SUSPENDED_RUNNABLE) { + packet = this.queue; + this.queue = packet?.link; + if (this.queue === undefined) { + this.state = STATE_RUNNING; + } else { + this.state = STATE_RUNNABLE; + } + } else { + packet = undefined; + } + return this.task.run(packet); + } + + checkPriorityAdd(taskControlBlock: TaskControlBlock, packet: Packet): TaskControlBlock | undefined { + if (this.queue === undefined) { + this.queue = packet; + this.markAsRunnable(); + if (this.priority > taskControlBlock.priority) { + return this; + } + } else { + this.queue = packet.addTo(this.queue); + } + return taskControlBlock; + } + + toString(): string { + return `tcb { ${this.task}@${this.state} }` ; + } +} + +const STATE_RUNNING = 0; +const STATE_RUNNABLE = 1; +const STATE_SUSPENDED = 2; +const STATE_HELD = 4; +const STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE; +const STATE_NOT_HELD = ~STATE_HELD; + +interface Task { + run(packet: Packet|undefined): TaskControlBlock | undefined; +} + +class IdleTask implements Task { + scheduler: Scheduler; + v1: number; + count: number; + + constructor(scheduler: Scheduler, v1: number, count: number) { + this.scheduler = scheduler; + this.v1 = v1; + this.count = count; + } + + run(packet: Packet|undefined): TaskControlBlock | undefined { + this.count -= 1; + if (this.count === 0) { + return this.scheduler.holdCurrent(); + } + if ((this.v1 & 1) === 0) { + this.v1 = this.v1 >> 1; + return this.scheduler.release(ID_DEVICE_A); + } else { + this.v1 = (this.v1 >> 1) ^ 0xD008; + return this.scheduler.release(ID_DEVICE_B); + } + } + + toString(): string { + return "IdleTask"; + } +} + +class DeviceTask implements Task { + scheduler: Scheduler; + v1: Packet | undefined; + + constructor(scheduler: Scheduler) { + this.scheduler = scheduler; + this.v1 = undefined; + } + + run(packet: Packet|undefined): TaskControlBlock | undefined { + if (packet === undefined) { + if (this.v1 === undefined) { + return this.scheduler.suspendCurrent(); + } + const v = this.v1; + this.v1 = undefined; + return this.scheduler.queue(v); + } else { + this.v1 = packet; + return this.scheduler.holdCurrent(); + } + } + + toString(): string { + return "DeviceTask"; + } +} + +class WorkerTask implements Task { + scheduler: Scheduler; + v1: number; + v2: number; + + constructor(scheduler: Scheduler, v1: number, v2: number) { + this.scheduler = scheduler; + this.v1 = v1; + this.v2 = v2; + } + + run(packet: Packet|undefined): TaskControlBlock | undefined { + if (packet === undefined) { + return this.scheduler.suspendCurrent(); + } else { + if (this.v1 === ID_HANDLER_A) { + this.v1 = ID_HANDLER_B; + } else { + this.v1 = ID_HANDLER_A; + } + packet.id = this.v1; + packet.a1 = 0; + for (let i = 0; i < DATA_SIZE; i++) { + this.v2 += 1; + if (this.v2 > 26) { + this.v2 = 1; + } + packet.a2[i] = this.v2; + } + return this.scheduler.queue(packet); + } + } + + toString(): string { + return "WorkerTask"; + } +} + +class HandlerTask implements Task { + scheduler: Scheduler; + v1: Packet | undefined; + v2: Packet | undefined; + + constructor(scheduler: Scheduler) { + this.scheduler = scheduler; + this.v1 = undefined; + this.v2 = undefined; + } + + run(packet: Packet|undefined): TaskControlBlock | undefined { + if (packet !== undefined) { + if (packet.kind === KIND_WORK) { + this.v1 = packet.addTo(this.v1); + } else { + this.v2 = packet.addTo(this.v2); + } + } + + if (this.v1 !== undefined) { + const count = this.v1.a1; + let v: Packet | undefined; + if (count < DATA_SIZE) { + if (this.v2 !== undefined) { + v = this.v2; + this.v2 = this.v2.link; + v.a1 = this.v1.a2[count]; + this.v1.a1 = count + 1; + return this.scheduler.queue(v); + } + } else { + v = this.v1; + this.v1 = this.v1.link; + return this.scheduler.queue(v); + } + } + + return this.scheduler.suspendCurrent(); + } + + toString(): string { + return "HandlerTask"; + } +} + +const DATA_SIZE:number = 4; + +class Packet { + link: Packet | undefined; + id: number; + kind: number; + a1: number; + a2: number[]; + + constructor(link: Packet | undefined, id: number, kind: number) { + this.link = link; + this.id = id; + this.kind = kind; + this.a1 = 0; + this.a2 = Array(DATA_SIZE).fill(0); + } + + addTo(queue: Packet | undefined): Packet { + this.link = undefined; + if (queue === undefined) { + return this; + } + let peek: Packet | undefined; + let next = queue; + while (next !== undefined) { + peek = next.link; + if (peek === undefined) { + break; + } + next = peek; + } + if (next !== undefined) { + next.link = this; + } + return queue; + } + + toString(): string { + return "Packet"; + } +} + +const COUNT = 1000; +const EXPECTED_QUEUE_COUNT = 2322; +const EXPECTED_HOLD_COUNT = 928; + +function runRichards(): void { + const scheduler = new Scheduler(); + scheduler.addIdleTask(ID_IDLE, 0, undefined, COUNT); + + let queue = new Packet(undefined, ID_WORKER, KIND_WORK); + queue = new Packet(queue, ID_WORKER, KIND_WORK); + scheduler.addWorkerTask(ID_WORKER, 1000, queue); + + queue = new Packet(undefined, ID_DEVICE_A, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); + scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue); + + queue = new Packet(undefined, ID_DEVICE_B, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); + scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue); + + scheduler.addDeviceTask(ID_DEVICE_A, 4000, undefined); + + scheduler.addDeviceTask(ID_DEVICE_B, 5000, undefined); + + scheduler.schedule(); + + if (scheduler.queueCount !== EXPECTED_QUEUE_COUNT || + scheduler.holdCount !== EXPECTED_HOLD_COUNT) { + const msg = `Error during execution: queueCount = ${scheduler.queueCount}, holdCount = ${scheduler.holdCount}.` ; + throw Error(msg); + } +} + + +/**************************configure and run benchmark********************************/ +export {runRichards} -- Gitee