├── .ci ├── LICENSE └── LICENSE.sha256 ├── .gitignore ├── AppScope ├── app.json5 └── resources │ └── base │ ├── element │ └── string.json │ └── media │ └── app_icon.png ├── LICENSE ├── README.md ├── build-flang.sh ├── build-linux.sh ├── build-macos.sh ├── build-profile.json5 ├── code-linter.json5 ├── entry ├── .gitignore ├── build-profile.json5 ├── hvigorfile.ts ├── obfuscation-rules.txt ├── oh-package-lock.json5 ├── oh-package.json5 └── src │ ├── main │ ├── cpp │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── napi_init.cpp │ │ ├── switch_stack.S │ │ └── types │ │ │ └── libentry │ │ │ ├── Index.d.ts │ │ │ └── oh-package.json5 │ ├── ets │ │ ├── entryability │ │ │ └── EntryAbility.ets │ │ └── pages │ │ │ ├── Index.ets │ │ │ └── utils.ets │ ├── module.json5 │ └── resources │ │ ├── base │ │ ├── element │ │ │ ├── color.json │ │ │ └── string.json │ │ ├── media │ │ │ ├── background.png │ │ │ ├── foreground.png │ │ │ ├── layered_image.json │ │ │ └── startIcon.png │ │ └── profile │ │ │ └── main_pages.json │ │ └── rawfile │ │ └── .gitignore │ ├── mock │ └── mock-config.json5 │ ├── ohosTest │ ├── ets │ │ └── test │ │ │ ├── Ability.test.ets │ │ │ └── List.test.ets │ └── module.json5 │ └── test │ ├── List.test.ets │ └── LocalUnit.test.ets ├── generate.perl ├── hvigor └── hvigor-config.json5 ├── hvigorfile.ts ├── oh-package-lock.json5 ├── oh-package.json5 ├── push.sh └── results ├── README.md ├── best └── HBN-AL80.csv ├── compute.py ├── full ├── HBN-AL80-001.csv └── HBN-AL80-002.csv └── template.csv /.ci/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /.ci/LICENSE.sha256: -------------------------------------------------------------------------------- 1 | eb3d7b5485466acbd81f2b496f595ab637d2792e268206b27d99e793bdb67549 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /oh_modules 3 | /local.properties 4 | /.idea 5 | **/build 6 | /.hvigor 7 | .cxx 8 | /.clangd 9 | /.clang-format 10 | /.clang-tidy 11 | **/.test 12 | /.appanalyzer 13 | /.cache 14 | /flang 15 | # SPEC CPU 2017 benchspec 16 | /benchspec -------------------------------------------------------------------------------- /AppScope/app.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "bundleName": "je.jia.speccpu2017harmony", 4 | "vendor": "example", 5 | "versionCode": 1000000, 6 | "versionName": "1.0.0", 7 | "icon": "$media:app_icon", 8 | "label": "$string:app_name" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AppScope/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "app_name", 5 | "value": "SPECCPU2017Harmony" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /AppScope/resources/base/media/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/SPECCPU2017Harmony/81724b97190de4ca60e6cd36db8e485f043be0ab/AppScope/resources/base/media/app_icon.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jiajie Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SPEC CPU 2017 Harmony 2 | 3 | Run SPEC CPU 2017 benchmark on OpenHarmony/HarmonyOS NEXT. 4 | 5 | It currently supports running SPEC CPU 2017 int rate-1 and fp rate-1. 6 | 7 | ## Usage 8 | 9 | How to build on macOS (missing support for benchmarks that use Fortran): 10 | 11 | 1. Copy the whole benchspec folder from SPEC CPU 2017 installation to the root folder of this project 12 | 2. Execute `perl generate.perl` under the root folder of this project 13 | 3. Use DevEco Studio to open this project 14 | 4. Setup code signing using DevEco Studio 15 | 5. Execute `./build-macos.sh` under the root folder of this project 16 | 17 | How to build on Linux (all benchmarks are working): 18 | 19 | 1. Install lld-20 and flang-20 from [LLVM APT](https://apt.llvm.org/) 20 | 2. Copy the whole benchspec folder from SPEC CPU 2017 installation to the root folder of this project 21 | 3. Execute `perl generate.perl` under the root folder of this project 22 | 4. Clone llvm-project to $HOME/llvm-project 23 | 5. Execute `./build-flang.sh` under the root folder of this project 24 | 6. Copy code signing config (including build-profile.json5 and ~/.ohos/config) from macOS/Windows 25 | 7. Execute `./build-linux.sh` under the root folder of this project 26 | 27 | To install the application to phone: either use DevEco Studio, or use `push.sh`. 28 | 29 | ## Result 30 | 31 | If you want to find existing benchmark results, please refer to [results](./results/README.md) folder. 32 | 33 | ## How does it work 34 | 35 | Because HarmonyOS NEXT does not permit the execution of binaries in the data folder, each benchmark (including the input generator and output validator) is compiled into a shared library. To execute the benchmark, the shared library is loaded, and its main function is invoked with the appropriate arguments. 36 | 37 | To prevent memory exhaustion caused by potential memory leaks, each benchmark is executed within a forked child process. Upon the child process's termination, the memory is automatically reclaimed. The execution time is measured from the parent process, which includes the minimal overhead of process startup and shutdown. 38 | 39 | Certain benchmarks require an exceptionally large stack size (on the order of hundreds of megabytes). However, setting the stack size limit using `setrlimit` does not function as intended. To address this, a manual switch implemented in assembly is used to run the benchmark on a heap-allocated 1GB stack. 40 | 41 | ## TODO 42 | 43 | - copies>1 of rate tests 44 | - speed tests 45 | -------------------------------------------------------------------------------- /build-flang.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # build missing libraries for aarch64-linux-ohos target 3 | # assume llvm-project is cloned at $HOME/llvm-project 4 | set -x -e 5 | mkdir -p flang 6 | DST=$PWD/flang 7 | cd $HOME/llvm-project 8 | git checkout main 9 | # match hash in flang-new-20 --version 10 | git reset 99354f968f64 --hard 11 | 12 | cd libunwind 13 | rm -rf build 14 | mkdir -p build 15 | cd build 16 | cmake .. -G Ninja \ 17 | -DCMAKE_C_FLAGS="-target aarch64-linux-ohos -fuse-ld=lld" \ 18 | -DCMAKE_C_COMPILER="clang" \ 19 | -DCMAKE_CXX_FLAGS="-target aarch64-linux-ohos -fuse-ld=lld" \ 20 | -DCMAKE_CXX_COMPILER="clang++" 21 | ninja 22 | cp lib/libunwind.a $DST/ 23 | cd ../../ 24 | 25 | cd flang/lib/Decimal 26 | rm -rf build 27 | mkdir -p build 28 | cd build 29 | cmake .. -G Ninja \ 30 | -DCMAKE_C_FLAGS="-target aarch64-linux-ohos -fuse-ld=lld -fPIC" \ 31 | -DCMAKE_C_COMPILER="clang" \ 32 | -DCMAKE_CXX_FLAGS="-target aarch64-linux-ohos -fuse-ld=lld -fPIC" \ 33 | -DCMAKE_CXX_COMPILER="clang++" 34 | ninja 35 | cp libFortranDecimal.a $DST/ 36 | cd ../../../../ 37 | 38 | cd flang/runtime 39 | rm -rf build 40 | mkdir -p build 41 | cd build 42 | cmake .. -G Ninja \ 43 | -DCMAKE_C_FLAGS="-target aarch64-linux-ohos -fuse-ld=lld -fPIC" \ 44 | -DCMAKE_C_COMPILER="clang" \ 45 | -DCMAKE_CXX_FLAGS="-target aarch64-linux-ohos -fuse-ld=lld -fPIC" \ 46 | -DCMAKE_CXX_COMPILER="clang++" 47 | ninja 48 | cp libFortranRuntime.a $DST/ 49 | cd ../../../ 50 | 51 | ls -al $DST -------------------------------------------------------------------------------- /build-linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # build the project on Linux 3 | # assume command-line-tools downloaded from: 4 | # https://developer.huawei.com/consumer/cn/download/ 5 | # and extracted to $HOME/command-line-tools 6 | export TOOL_HOME=$HOME/command-line-tools 7 | export DEVECO_SDK_HOME=$TOOL_HOME/sdk 8 | export PATH=$TOOL_HOME/ohpm/bin:$PATH 9 | export PATH=$TOOL_HOME/hvigor/bin:$PATH 10 | export PATH=$TOOL_HOME/node/bin:$PATH 11 | # assume arkui-x directory to be saved at $HOME/arkui-x 12 | export ARKUIX_SDK_HOME=$HOME/arkui-x 13 | mkdir -p $ARKUIX_SDK_HOME/licenses 14 | cp -r .ci/* $ARKUIX_SDK_HOME/licenses 15 | hvigorw assembleHap 16 | -------------------------------------------------------------------------------- /build-macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # build the project on macOS 3 | # assume deveco studio is downloaded from: 4 | # https://developer.huawei.com/consumer/cn/download/ 5 | # and extracted to /Applications/DevEco-Studio.app 6 | export TOOL_HOME=/Applications/DevEco-Studio.app/Contents 7 | export DEVECO_SDK_HOME=$TOOL_HOME/sdk 8 | export PATH=$TOOL_HOME/tools/ohpm/bin:$PATH 9 | export PATH=$TOOL_HOME/tools/hvigor/bin:$PATH 10 | export PATH=$TOOL_HOME/tools/node/bin:$PATH 11 | hvigorw assembleHap 12 | -------------------------------------------------------------------------------- /build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "signingConfigs": [], 4 | "products": [ 5 | { 6 | "name": "default", 7 | "signingConfig": "default", 8 | "compatibleSdkVersion": "5.0.1(13)", 9 | "runtimeOS": "HarmonyOS", 10 | "buildOption": { 11 | "strictMode": { 12 | "caseSensitiveCheck": true, 13 | } 14 | } 15 | } 16 | ], 17 | "buildModeSet": [ 18 | { 19 | "name": "debug", 20 | }, 21 | { 22 | "name": "release" 23 | } 24 | ] 25 | }, 26 | "modules": [ 27 | { 28 | "name": "entry", 29 | "srcPath": "./entry", 30 | "targets": [ 31 | { 32 | "name": "default", 33 | "applyToProducts": [ 34 | "default" 35 | ] 36 | } 37 | ] 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /code-linter.json5: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "**/*.ets" 4 | ], 5 | "ignore": [ 6 | "**/src/ohosTest/**/*", 7 | "**/src/test/**/*", 8 | "**/src/mock/**/*", 9 | "**/node_modules/**/*", 10 | "**/oh_modules/**/*", 11 | "**/build/**/*", 12 | "**/.preview/**/*" 13 | ], 14 | "ruleSet": [ 15 | "plugin:@performance/recommended", 16 | "plugin:@typescript-eslint/recommended" 17 | ], 18 | "rules": { 19 | } 20 | } -------------------------------------------------------------------------------- /entry/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /oh_modules 3 | /.preview 4 | /build 5 | /.cxx 6 | /.test -------------------------------------------------------------------------------- /entry/build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "apiType": "stageMode", 3 | "buildOption": { 4 | "externalNativeOptions": { 5 | "path": "./src/main/cpp/CMakeLists.txt", 6 | "arguments": "", 7 | "cppFlags": "", 8 | } 9 | }, 10 | "buildOptionSet": [ 11 | { 12 | "name": "release", 13 | "arkOptions": { 14 | "obfuscation": { 15 | "ruleOptions": { 16 | "enable": false, 17 | "files": [ 18 | "./obfuscation-rules.txt" 19 | ] 20 | } 21 | } 22 | }, 23 | "nativeLib": { 24 | "debugSymbol": { 25 | "strip": true, 26 | "exclude": [] 27 | } 28 | } 29 | }, 30 | ], 31 | "targets": [ 32 | { 33 | "name": "default", 34 | "config": { 35 | "deviceType": [ 36 | "phone", 37 | "2in1" 38 | ] 39 | } 40 | }, 41 | { 42 | "name": "ohosTest", 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /entry/hvigorfile.ts: -------------------------------------------------------------------------------- 1 | // Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. 2 | export { HapTasks } from '@ohos/hvigor-ohos-arkui-x-plugin'; 3 | -------------------------------------------------------------------------------- /entry/obfuscation-rules.txt: -------------------------------------------------------------------------------- 1 | # Define project specific obfuscation rules here. 2 | # You can include the obfuscation configuration files in the current module's build-profile.json5. 3 | # 4 | # For more details, see 5 | # https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 6 | 7 | # Obfuscation options: 8 | # -disable-obfuscation: disable all obfuscations 9 | # -enable-property-obfuscation: obfuscate the property names 10 | # -enable-toplevel-obfuscation: obfuscate the names in the global scope 11 | # -compact: remove unnecessary blank spaces and all line feeds 12 | # -remove-log: remove all console.* statements 13 | # -print-namecache: print the name cache that contains the mapping from the old names to new names 14 | # -apply-namecache: reuse the given cache file 15 | 16 | # Keep options: 17 | # -keep-property-name: specifies property names that you want to keep 18 | # -keep-global-name: specifies names that you want to keep in the global scope 19 | 20 | -enable-property-obfuscation 21 | -enable-toplevel-obfuscation 22 | -enable-filename-obfuscation 23 | -enable-export-obfuscation -------------------------------------------------------------------------------- /entry/oh-package-lock.json5: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "stableOrder": true 4 | }, 5 | "lockfileVersion": 3, 6 | "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", 7 | "specifiers": { 8 | "libentry.so@src/main/cpp/types/libentry": "libentry.so@src/main/cpp/types/libentry" 9 | }, 10 | "packages": { 11 | "libentry.so@src/main/cpp/types/libentry": { 12 | "name": "libentry.so", 13 | "version": "1.0.0", 14 | "resolved": "src/main/cpp/types/libentry", 15 | "registryType": "local" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /entry/oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "name": "entry", 3 | "version": "1.0.0", 4 | "description": "Please describe the basic information.", 5 | "main": "", 6 | "author": "", 7 | "license": "", 8 | "dependencies": { 9 | "libentry.so": "file:./src/main/cpp/types/libentry" 10 | } 11 | } -------------------------------------------------------------------------------- /entry/src/main/cpp/.gitignore: -------------------------------------------------------------------------------- 1 | /5**/ 2 | /6**/ 3 | -------------------------------------------------------------------------------- /entry/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # the minimum version of CMake. 2 | cmake_minimum_required(VERSION 3.5.0) 3 | project(SPECCPU2017Harmony) 4 | 5 | # need fortran for 548.exchange2_r 6 | if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux") 7 | set(CMAKE_Fortran_COMPILER_FORCED TRUE) 8 | set(CMAKE_Fortran_COMPILER "flang-new-20") 9 | set(CMAKE_Fortran_FLAGS "-target aarch64-linux-ohos -fuse-ld=lld -L ${CMAKE_CURRENT_SOURCE_DIR}/../../../../flang -nostdlib -L ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../command-line-tools/sdk/default/openharmony/native/sysroot/usr/lib/aarch64-linux-ohos -lc -lm -L ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../command-line-tools/sdk/default/openharmony/native/llvm/lib/clang/15.0.4/lib/aarch64-linux-ohos/ -lclang_rt.builtins -lFortranRuntime -lFortranDecimal") 10 | enable_language(Fortran) 11 | endif() 12 | 13 | set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 14 | 15 | include_directories(${NATIVERENDER_ROOT_PATH} 16 | ${NATIVERENDER_ROOT_PATH}/include) 17 | 18 | enable_language(ASM) 19 | add_library(entry SHARED napi_init.cpp switch_stack.S) 20 | target_compile_definitions(entry PRIVATE "-DCXX_COMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION}") 21 | target_compile_definitions(entry PRIVATE "-DFORTRAN_COMPILER_VERSION=${CMAKE_Fortran_COMPILER_VERSION}") 22 | target_link_libraries(entry PUBLIC libace_napi.z.so) 23 | target_link_libraries(entry PUBLIC libhilog_ndk.z.so) 24 | 25 | # int 26 | add_subdirectory(500.perlbench_r) 27 | add_subdirectory(502.gcc_r) 28 | add_subdirectory(505.mcf_r) 29 | add_subdirectory(520.omnetpp_r) 30 | add_subdirectory(523.xalancbmk_r) 31 | add_subdirectory(525.x264_r) 32 | add_subdirectory(531.deepsjeng_r) 33 | add_subdirectory(541.leela_r) 34 | add_subdirectory(557.xz_r) 35 | 36 | # need fortran 37 | if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux") 38 | add_subdirectory(548.exchange2_r) 39 | endif() 40 | 41 | # fp 42 | add_subdirectory(508.namd_r) 43 | add_subdirectory(510.parest_r) 44 | add_subdirectory(511.povray_r) 45 | add_subdirectory(519.lbm_r) 46 | add_subdirectory(526.blender_r) 47 | add_subdirectory(538.imagick_r) 48 | add_subdirectory(544.nab_r) 49 | 50 | # need fortran 51 | if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux") 52 | add_subdirectory(503.bwaves_r) 53 | add_subdirectory(507.cactuBSSN_r) 54 | add_subdirectory(521.wrf_r) 55 | add_subdirectory(527.cam4_r) 56 | add_subdirectory(549.fotonik3d_r) 57 | add_subdirectory(554.roms_r) 58 | endif() 59 | -------------------------------------------------------------------------------- /entry/src/main/cpp/napi_init.cpp: -------------------------------------------------------------------------------- 1 | #include "napi/native_api.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "hilog/log.h" 14 | #undef LOG_TAG 15 | #define LOG_TAG "mainTag" 16 | 17 | extern "C" void switch_stack(int argc, const char **argv, const char **envp, 18 | int (*callee)(int argc, const char **argv, 19 | const char **envp), 20 | void *sp); 21 | 22 | static std::string get_str(napi_env env, napi_value value) { 23 | size_t size = 0; 24 | assert(napi_get_value_string_utf8(env, value, NULL, 0, &size) == napi_ok); 25 | std::vector buffer(size + 1); 26 | 27 | assert(napi_get_value_string_utf8(env, value, buffer.data(), buffer.size(), 28 | &size) == napi_ok); 29 | std::string s(buffer.data(), size); 30 | return s; 31 | } 32 | 33 | uint64_t get_time() { 34 | struct timeval tv = {}; 35 | gettimeofday(&tv, nullptr); 36 | return (uint64_t)tv.tv_sec * 1000000000 + (uint64_t)tv.tv_usec * 1000; 37 | } 38 | 39 | // measure clock frequency 40 | // parameter 41 | // 1: core index 42 | static napi_value Clock(napi_env env, napi_callback_info info) { 43 | // get args 44 | size_t argc = 1; 45 | napi_value args[1] = {nullptr}; 46 | napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 47 | 48 | // set cpu affinity 49 | cpu_set_t cpuset; 50 | CPU_ZERO(&cpuset); 51 | int core; 52 | napi_get_value_int32(env, args[0], &core); 53 | CPU_SET(core, &cpuset); 54 | assert(sched_setaffinity(0, sizeof(cpuset), &cpuset) == 0); 55 | OH_LOG_INFO(LOG_APP, "Pin to cpu %{public}d", core); 56 | 57 | int n = 500000; 58 | uint64_t before = get_time(); 59 | // learned from lmbench lat_mem_rd 60 | #define FIVE(X) X X X X X 61 | #define TEN(X) FIVE(X) FIVE(X) 62 | #define FIFTY(X) TEN(X) TEN(X) TEN(X) TEN(X) TEN(X) 63 | #define HUNDRED(X) FIFTY(X) FIFTY(X) 64 | #define THOUSAND(X) HUNDRED(TEN(X)) 65 | 66 | for (int i = 0; i < n; i++) { 67 | asm volatile(".align 4\n" THOUSAND("add x1, x1, x1\n") : : : "x1"); 68 | } 69 | uint64_t after = get_time(); 70 | 71 | double freq = (double)n * 1000 / (double)(after - before); 72 | OH_LOG_INFO(LOG_APP, "Clock frequency is %{public}f", freq); 73 | napi_value ret; 74 | napi_create_double(env, freq, &ret); 75 | return ret; 76 | } 77 | 78 | // parameters: 79 | // 0: cwd 80 | // 1: path to stdin 81 | // 2: path to stdout 82 | // 3: path to stderr 83 | // 4: benchmark name 84 | // 5: benchmark args 85 | // 6: core index 86 | static napi_value Run(napi_env env, napi_callback_info info) { 87 | // get args 88 | size_t argc = 7; 89 | napi_value args[7] = {nullptr}; 90 | napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 91 | 92 | // set cpu affinity 93 | cpu_set_t cpuset; 94 | CPU_ZERO(&cpuset); 95 | int core; 96 | napi_get_value_int32(env, args[6], &core); 97 | CPU_SET(core, &cpuset); 98 | assert(sched_setaffinity(0, sizeof(cpuset), &cpuset) == 0); 99 | OH_LOG_INFO(LOG_APP, "Pin to cpu %{public}d", core); 100 | 101 | // change workin directory 102 | std::string cwd = get_str(env, args[0]); 103 | OH_LOG_INFO(LOG_APP, "Change cwd to %{public}s", cwd.c_str()); 104 | chdir(cwd.c_str()); 105 | 106 | // https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-ndk-16-V5 107 | // redirect stdout/stderr to file 108 | std::string stdin_file = get_str(env, args[1]); 109 | std::string stdout_file = get_str(env, args[2]); 110 | std::string stderr_file = get_str(env, args[3]); 111 | if (stdin_file.size() > 0) { 112 | OH_LOG_INFO(LOG_APP, "Redirect stdin to %{public}s", stdin_file.c_str()); 113 | } 114 | OH_LOG_INFO(LOG_APP, "Redirect stdout to %{public}s", stdout_file.c_str()); 115 | OH_LOG_INFO(LOG_APP, "Redirect stderr to %{public}s", stderr_file.c_str()); 116 | 117 | // load benchmark main from library 118 | int (*main)(int argc, const char **argv, const char **envp); 119 | std::string benchmark = get_str(env, args[4]); 120 | OH_LOG_INFO(LOG_APP, "Load benchmark %{public}s", benchmark.c_str()); 121 | std::string library_name = "lib"; 122 | library_name += benchmark; 123 | library_name += ".so"; 124 | void *handle = dlopen(library_name.c_str(), RTLD_LAZY); 125 | if (!handle) { 126 | OH_LOG_INFO(LOG_APP, "Failed to load benchmark %{public}s", 127 | benchmark.c_str()); 128 | // missing shared library 129 | // return -1.0 130 | napi_value ret; 131 | napi_create_double(env, -1.0, &ret); 132 | return ret; 133 | } 134 | 135 | main = (int (*)(int argc, const char **argv, const char **envp))dlsym(handle, 136 | "main"); 137 | 138 | if (!handle) { 139 | OH_LOG_INFO(LOG_APP, "Failed to load benchmark %{public}s", 140 | benchmark.c_str()); 141 | // missing shared library 142 | // return -1.0 143 | napi_value ret; 144 | napi_create_double(env, -1.0, &ret); 145 | return ret; 146 | } 147 | 148 | // construct argv 149 | std::vector argv; 150 | argv.push_back(benchmark); 151 | uint32_t args_length; 152 | napi_get_array_length(env, args[5], &args_length); 153 | for (uint32_t i = 0; i < args_length; i++) { 154 | napi_value element; 155 | napi_get_element(env, args[5], i, &element); 156 | 157 | std::string arg = get_str(env, element); 158 | argv.push_back(arg); 159 | } 160 | 161 | std::vector real_argv; 162 | for (auto &arg : argv) { 163 | real_argv.push_back(arg.c_str()); 164 | } 165 | real_argv.push_back(NULL); 166 | const char *envp[1] = {NULL}; 167 | 168 | // emulate ulimit -s unlimited 169 | // required for 527.cam4_r 170 | // setrlimit not working 171 | // let's create a stack manually 172 | // 1GB stack 173 | uint8_t *stack = NULL; 174 | size_t size = 0x40000000; 175 | posix_memalign((void **)&stack, 0x1000, size); 176 | uint8_t *stack_top = stack + size; 177 | OH_LOG_INFO(LOG_APP, "Allocated stack at %{public}lx-%{public}lx", stack, 178 | stack_top); 179 | 180 | OH_LOG_INFO(LOG_APP, "Start benchmark %{public}s", benchmark.c_str()); 181 | 182 | // io redirection 183 | if (stdin_file.size() > 0) { 184 | freopen(stdin_file.c_str(), "r", stdin); 185 | } 186 | freopen(stdout_file.c_str(), "w+", stdout); 187 | freopen(stderr_file.c_str(), "w+", stderr); 188 | 189 | // use fork 190 | // 502.gcc_r does not free memory, leading to out of memory 191 | // large stack required for some benchmarks 192 | uint64_t before = get_time(); 193 | uint64_t after; 194 | double res = -1; 195 | double time; 196 | pid_t pid = fork(); 197 | if (pid == 0) { 198 | // equivalent to: 199 | // int status = main(1 + args_length, real_argv.data(), envp); 200 | // exit(status); 201 | // run main & exit on the new stack 202 | switch_stack(1 + args_length, real_argv.data(), envp, main, stack_top); 203 | } else { 204 | // in parent process 205 | assert(pid != -1); 206 | int wstatus; 207 | waitpid(pid, &wstatus, 0); 208 | if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) { 209 | // failed 210 | res = -1; 211 | goto cleanup; 212 | } 213 | } 214 | 215 | after = get_time(); 216 | time = (double)(after - before) / 1000000000; 217 | OH_LOG_INFO(LOG_APP, "End benchmark %{public}s in %{public}fs", 218 | benchmark.c_str(), time); 219 | res = time; 220 | 221 | cleanup: 222 | if (handle) { 223 | dlclose(handle); 224 | } 225 | if (stack) { 226 | free(stack); 227 | } 228 | 229 | napi_value ret; 230 | napi_create_double(env, res, &ret); 231 | return ret; 232 | } 233 | 234 | #define S(x) #x 235 | #define STRINGIFY(x) S(x) 236 | static napi_value Info(napi_env env, napi_callback_info info) { 237 | napi_value ret; 238 | std::string res; 239 | 240 | res += "C/C++ Compiler Version: "; 241 | res += STRINGIFY(CXX_COMPILER_VERSION); 242 | res += "\n"; 243 | 244 | res += "Fortran Compiler Version: "; 245 | res += STRINGIFY(FORTRAN_COMPILER_VERSION); 246 | res += "\n"; 247 | 248 | struct utsname tmp; 249 | assert(uname(&tmp) == 0); 250 | res += "Uname: "; 251 | res += tmp.sysname; 252 | res += " "; 253 | res += tmp.nodename; 254 | res += " "; 255 | res += tmp.release; 256 | res += " "; 257 | res += tmp.version; 258 | res += " "; 259 | res += tmp.machine; 260 | 261 | napi_create_string_utf8(env, res.c_str(), res.length(), &ret); 262 | return ret; 263 | } 264 | 265 | EXTERN_C_START 266 | static napi_value Init(napi_env env, napi_value exports) { 267 | napi_property_descriptor desc[] = { 268 | {"run", nullptr, Run, nullptr, nullptr, nullptr, napi_default, nullptr}, 269 | {"clock", nullptr, Clock, nullptr, nullptr, nullptr, napi_default, 270 | nullptr}, 271 | {"info", nullptr, Info, nullptr, nullptr, nullptr, napi_default, nullptr}, 272 | }; 273 | napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 274 | return exports; 275 | } 276 | EXTERN_C_END 277 | 278 | static napi_module demoModule = { 279 | .nm_version = 1, 280 | .nm_flags = 0, 281 | .nm_filename = nullptr, 282 | .nm_register_func = Init, 283 | .nm_modname = "entry", 284 | .nm_priv = ((void *)0), 285 | .reserved = {0}, 286 | }; 287 | 288 | extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { 289 | napi_module_register(&demoModule); 290 | } 291 | -------------------------------------------------------------------------------- /entry/src/main/cpp/switch_stack.S: -------------------------------------------------------------------------------- 1 | .global switch_stack 2 | # arguments: 3 | # r0: argc 4 | # r1: argv 5 | # r2: envp 6 | # r3: callee 7 | # r4: new stack pointer 8 | switch_stack: 9 | mov sp, x4 10 | blr x3 11 | 12 | # flush all buffers via fflush(0) 13 | # w19: callee saved 14 | mov w19, w0 15 | mov x0, 0 16 | bl fflush 17 | 18 | # call exit 19 | # the return value of callee is the first argument of exit 20 | mov w0, w19 21 | bl exit -------------------------------------------------------------------------------- /entry/src/main/cpp/types/libentry/Index.d.ts: -------------------------------------------------------------------------------- 1 | export const run: (cwd: string, stdin: string, stdout: string, stderr: string, benchmark: string, args: string[], core: number) => number; 2 | export const clock: (core: number) => number; 3 | export const info: () => string; -------------------------------------------------------------------------------- /entry/src/main/cpp/types/libentry/oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libentry.so", 3 | "types": "./Index.d.ts", 4 | "version": "1.0.0", 5 | "description": "Please describe the basic information." 6 | } -------------------------------------------------------------------------------- /entry/src/main/ets/entryability/EntryAbility.ets: -------------------------------------------------------------------------------- 1 | import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 2 | import { hilog } from '@kit.PerformanceAnalysisKit'; 3 | import { window } from '@kit.ArkUI'; 4 | import { BusinessError } from '@ohos.base'; 5 | 6 | export default class EntryAbility extends UIAbility { 7 | onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 8 | hilog.info(0x0000, 'mainTag', '%{public}s', 'Ability onCreate'); 9 | } 10 | 11 | onDestroy(): void { 12 | hilog.info(0x0000, 'mainTag', '%{public}s', 'Ability onDestroy'); 13 | } 14 | 15 | onWindowStageCreate(windowStage: window.WindowStage): void { 16 | // Main window is created, set main page for this ability 17 | hilog.info(0x0000, 'mainTag', '%{public}s', 'Ability onWindowStageCreate'); 18 | 19 | windowStage.loadContent('pages/Index', (err) => { 20 | if (err.code) { 21 | hilog.error(0x0000, 'mainTag', 'Failed to load the content: %{public}s', JSON.stringify(err) ?? ''); 22 | return; 23 | } 24 | hilog.info(0x0000, 'mainTag', 'Succeeded in loading the content'); 25 | }); 26 | 27 | // keep screen on 28 | windowStage.getMainWindow((err: BusinessError, data: window.Window) => { 29 | const errCode: number = err.code; 30 | if (errCode == 0) { 31 | hilog.info(0x0000, 'mainTag', 'Succeeded in getting main window'); 32 | data.setWindowKeepScreenOn(true, (err: BusinessError) => { 33 | const errCode: number = err.code; 34 | if (errCode == 0) { 35 | hilog.info(0x0000, 'mainTag', 'Succeeded in keeping screen on'); 36 | } 37 | }); 38 | } 39 | }); 40 | } 41 | 42 | onWindowStageDestroy(): void { 43 | // Main window is destroyed, release UI related resources 44 | hilog.info(0x0000, 'mainTag', '%{public}s', 'Ability onWindowStageDestroy'); 45 | } 46 | 47 | onForeground(): void { 48 | // Ability has brought to foreground 49 | hilog.info(0x0000, 'mainTag', '%{public}s', 'Ability onForeground'); 50 | } 51 | 52 | onBackground(): void { 53 | // Ability has back to background 54 | hilog.info(0x0000, 'mainTag', '%{public}s', 'Ability onBackground'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/Index.ets: -------------------------------------------------------------------------------- 1 | import { hilog } from '@kit.PerformanceAnalysisKit'; 2 | import { zlib } from '@kit.BasicServicesKit'; 3 | import testNapi from 'libentry.so'; 4 | import fs from '@ohos.file.fs'; 5 | import { taskpool } from '@kit.ArkTS'; 6 | import { pasteboard } from '@kit.BasicServicesKit'; 7 | import { isEqual, readWholeFile, CompareOptions } from './utils.ets'; 8 | import { promptAction } from '@kit.ArkUI'; 9 | import { thermal } from '@kit.BasicServicesKit'; 10 | 11 | interface ValidateConfig { 12 | // stdout validation, compare stdout and specified file under output folder 13 | // file validation, compare two files with the same file name under input and output folders 14 | // command validation, run custom command to validate the output 15 | type: "STDOUT" | "FILE" | "COMMAND"; 16 | 17 | // stdout/file validation 18 | file?: string; 19 | 20 | // fp compare option for stdout/file validation 21 | compareOption?: CompareOptions; 22 | 23 | // command to run for validation 24 | command?: string; 25 | } 26 | 27 | interface BenchmarkConfig { 28 | // command argv 29 | args: string; 30 | 31 | // how to validate output 32 | validates: ValidateConfig[]; 33 | } 34 | 35 | type Benchmark = string | BenchmarkConfig; 36 | 37 | @Concurrent 38 | function findBestCore(): number { 39 | // find core with maximum clock frequency 40 | let core = 0; 41 | let max_freq = 0; 42 | for (let i = 0; i < 12; i++) { 43 | let freq: number = testNapi.clock(i); 44 | if (freq > max_freq) { 45 | max_freq = freq; 46 | core = i; 47 | } 48 | } 49 | hilog.info(0x0000, 'mainTag', 'Fastest core is %{public}d', core); 50 | 51 | return core; 52 | } 53 | 54 | @Concurrent 55 | function worker(inputDir: string, outputDir: string, stdinFile: string, benchmark: string, args: string[], core: number, 56 | validates: ValidateConfig[]): number { 57 | hilog.info(0x0000, 'mainTag', 58 | 'Enter worker: %{public}s, %{public}s, %{public}s, %{public}s, %{public}s, %{public}d, %{public}s', inputDir, 59 | outputDir, stdinFile, benchmark, JSON.stringify(args), core, JSON.stringify(validates)); 60 | let ret: number = -1; 61 | try { 62 | // run benchmark 63 | let stdoutFile: string = inputDir + "/stdout.log"; 64 | let stderrFile: string = inputDir + "/stderr.log"; 65 | hilog.info(0x0000, 'mainTag', 66 | 'Run command: %{public}s, %{public}s, %{public}s, %{public}s, %{public}s, %{public}s, %{public}d', 67 | inputDir, stdinFile, stdoutFile, stderrFile, benchmark, JSON.stringify(args), core); 68 | ret = testNapi.run(inputDir, stdinFile, stdoutFile, stderrFile, benchmark, args, core); 69 | hilog.info(0x0000, 'mainTag', 'Got stdout: %{public}s', fs.readTextSync(stdoutFile)); 70 | hilog.info(0x0000, 'mainTag', 'Got stderr: %{public}s', fs.readTextSync(stderrFile)); 71 | 72 | if (ret < 0) { 73 | return ret; 74 | } 75 | 76 | for (let validate of validates) { 77 | // validation 78 | if (validate.type === "STDOUT" || validate.type === "FILE") { 79 | // compare two files 80 | let expectedFile: string = outputDir + "/" + validate.file!; 81 | let actualFile: string = (validate.type === "STDOUT") ? stdoutFile : (inputDir + "/" + validate.file!); 82 | hilog.info(0x0000, 'mainTag', 'Validate %{public}s against %{public}s', actualFile, expectedFile); 83 | 84 | let actual: ArrayBuffer = readWholeFile(actualFile); 85 | let expected: ArrayBuffer = readWholeFile(expectedFile); 86 | if (isEqual(actual, expected, validate.compareOption)) { 87 | hilog.info(0x0000, 'mainTag', 'Validation passed: %{public}d bytes', actual.byteLength); 88 | } else { 89 | hilog.info(0x0000, 'mainTag', 'Validation failed'); 90 | ret = -1; 91 | break; 92 | } 93 | } else if (validate.type === "COMMAND") { 94 | // run command, and then compare its stdout to file 95 | let parts = validate.command!.split(" "); 96 | let validator = parts[0]; 97 | let validator_args = parts.slice(1); 98 | let stdoutFile: string = inputDir + "/validate-stdout.log"; 99 | let stderrFile: string = inputDir + "/validate-stderr.log"; 100 | hilog.info(0x0000, 'mainTag', 101 | 'Run command: %{public}s, %{public}s, %{public}s, %{public}s, %{public}s, %{public}s, %{public}d', 102 | inputDir, "", stdoutFile, stderrFile, validator, JSON.stringify(validator_args), core); 103 | if (testNapi.run(inputDir, "", stdoutFile, stderrFile, validator, validator_args, core) < 0) { 104 | hilog.info(0x0000, 'mainTag', 'Failed to run validation command %{public}s', validate.command!); 105 | ret = -1; 106 | break; 107 | } 108 | hilog.info(0x0000, 'mainTag', 'Got stdout: %{public}s', fs.readTextSync(stdoutFile)); 109 | hilog.info(0x0000, 'mainTag', 'Got stderr: %{public}s', fs.readTextSync(stderrFile)); 110 | 111 | // compare stdout and expected 112 | let actualFile: string = stdoutFile; 113 | let expectedFile: string = outputDir + "/" + validate.file; 114 | 115 | hilog.info(0x0000, 'mainTag', 'Validate %{public}s against %{public}s', actualFile, expectedFile); 116 | let actual: ArrayBuffer = readWholeFile(actualFile); 117 | let expected: ArrayBuffer = readWholeFile(expectedFile); 118 | if (isEqual(actual, expected, validate.compareOption)) { 119 | hilog.info(0x0000, 'mainTag', 'Validation passed: %{public}d bytes', actual.byteLength); 120 | } else { 121 | hilog.info(0x0000, 'mainTag', 'Validation failed'); 122 | ret = -1; 123 | break; 124 | } 125 | } 126 | } 127 | } catch (err) { 128 | hilog.info(0x0000, 'mainTag', 'Got error: %{public}s %{public}s', err.toString(), JSON.stringify(err)); 129 | ret = -1; 130 | } 131 | return ret; 132 | } 133 | 134 | let int_rate = [ 135 | "500.perlbench_r", 136 | "502.gcc_r", 137 | "505.mcf_r", 138 | "520.omnetpp_r", 139 | "523.xalancbmk_r", 140 | "525.x264_r", 141 | "531.deepsjeng_r", 142 | "541.leela_r", 143 | "548.exchange2_r", 144 | "557.xz_r", 145 | ]; 146 | 147 | let fp_rate = [ 148 | "503.bwaves_r", 149 | "507.cactuBSSN_r", 150 | "508.namd_r", 151 | "510.parest_r", 152 | "511.povray_r", 153 | "519.lbm_r", 154 | "521.wrf_r", 155 | "526.blender_r", 156 | "527.cam4_r", 157 | "538.imagick_r", 158 | "544.nab_r", 159 | "549.fotonik3d_r", 160 | "554.roms_r", 161 | ]; 162 | 163 | @Entry 164 | @Component 165 | struct Index { 166 | @State log: string = ''; 167 | @State running: boolean = false; 168 | 169 | onPageShow() { 170 | thermal.registerThermalLevelCallback((level: thermal.ThermalLevel) => { 171 | // https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-thermal-V5#thermallevel 172 | let levels = [ 173 | "COOL", 174 | "NORMAL", 175 | "WARM", 176 | "HOT", 177 | "OVERHEATED", 178 | "WARNING", 179 | "EMERGENCY", 180 | "ESCAPE" 181 | ]; 182 | this.log += "Thermal level is: " + levels[level] + "\n"; 183 | }); 184 | } 185 | 186 | onPageHide() { 187 | thermal.unregisterThermalLevelCallback(); 188 | } 189 | 190 | async runBenchmarks(filter: string[]) { 191 | if (this.running) { 192 | promptAction.showToast({ 193 | message: 'Already running', 194 | duration: 2000 195 | }); 196 | return; 197 | } 198 | this.running = true; 199 | 200 | try { 201 | this.log += testNapi.info() + "\n"; 202 | 203 | let context = getContext(this); 204 | let benchmarks: Map = new Map(); 205 | // int rate 206 | benchmarks.set("500.perlbench_r", [ 207 | { 208 | args: "-I./lib checkspam.pl 2500 5 25 11 150 1 1 1 1", 209 | validates: [{ 210 | type: "STDOUT", 211 | file: "checkspam.2500.5.25.11.150.1.1.1.1.out", 212 | }], 213 | } as BenchmarkConfig, 214 | { 215 | args: "-I./lib diffmail.pl 4 800 10 17 19 300", 216 | validates: [{ 217 | type: "STDOUT", 218 | file: "diffmail.4.800.10.17.19.300.out", 219 | }], 220 | } as BenchmarkConfig, 221 | { 222 | args: "-I./lib splitmail.pl 6400 12 26 16 100 0", 223 | validates: [{ 224 | type: "STDOUT", 225 | file: "splitmail.6400.12.26.16.100.0.out", 226 | }], 227 | } as BenchmarkConfig, 228 | ]); 229 | benchmarks.set("502.gcc_r", [ 230 | { 231 | args: "gcc-pp.c -O3 -finline-limit=0 -fif-conversion -fif-conversion2 -o gcc-pp.opts-O3_-finline-limit_0_-fif-conversion_-fif-conversion2.s", 232 | validates: [{ 233 | type: "FILE", 234 | file: "gcc-pp.opts-O3_-finline-limit_0_-fif-conversion_-fif-conversion2.s", 235 | }], 236 | } as BenchmarkConfig, 237 | { 238 | args: "gcc-pp.c -O2 -finline-limit=36000 -fpic -o gcc-pp.opts-O2_-finline-limit_36000_-fpic.s", 239 | validates: [{ 240 | type: "FILE", 241 | file: "gcc-pp.opts-O2_-finline-limit_36000_-fpic.s", 242 | }], 243 | } as BenchmarkConfig, 244 | { 245 | args: "gcc-smaller.c -O3 -fipa-pta -o gcc-smaller.opts-O3_-fipa-pta.s", 246 | validates: [{ 247 | type: "FILE", 248 | file: "gcc-smaller.opts-O3_-fipa-pta.s", 249 | }], 250 | } as BenchmarkConfig, 251 | { 252 | args: "ref32.c -O5 -o ref32.opts-O5.s", 253 | validates: [{ 254 | type: "FILE", 255 | file: "ref32.opts-O5.s", 256 | }], 257 | } as BenchmarkConfig, 258 | { 259 | args: "ref32.c -O3 -fselective-scheduling -fselective-scheduling2 -o ref32.opts-O3_-fselective-scheduling_-fselective-scheduling2.s", 260 | validates: [{ 261 | type: "FILE", 262 | file: "ref32.opts-O3_-fselective-scheduling_-fselective-scheduling2.s", 263 | }], 264 | } as BenchmarkConfig, 265 | ]); 266 | benchmarks.set("505.mcf_r", [ 267 | { 268 | args: "inp.in", 269 | validates: [{ 270 | type: "STDOUT", 271 | file: "inp.out", 272 | }], 273 | } as BenchmarkConfig, 274 | ]); 275 | benchmarks.set("520.omnetpp_r", [ 276 | { 277 | args: "-c General -r 0", 278 | validates: [{ 279 | type: "FILE", 280 | file: "General-0.sca", 281 | }], 282 | } as BenchmarkConfig, 283 | ]); 284 | benchmarks.set("523.xalancbmk_r", [ 285 | { 286 | args: "-v t5.xml xalanc.xsl", 287 | validates: [{ 288 | type: "STDOUT", 289 | file: "ref-t5.out", 290 | }], 291 | } as BenchmarkConfig, 292 | ]); 293 | benchmarks.set("525.x264_r", [ 294 | "--pass 1 --stats x264_stats.log --bitrate 1000 --frames 1000 -o BuckBunny_New.264 BuckBunny.yuv 1280x720", 295 | "--pass 2 --stats x264_stats.log --bitrate 1000 --dumpyuv 200 --frames 1000 -o BuckBunny_New.264 BuckBunny.yuv 1280x720", 296 | { 297 | args: "--seek 500 --dumpyuv 200 --frames 1250 -o BuckBunny_New.264 BuckBunny.yuv 1280x720", 298 | validates: [200, 400, 600, 700, 800, 900, 999, 1100, 1249].map((frame) => { 299 | return { 300 | type: "COMMAND", 301 | command: "imagevalidate_525 -avg -threshold 0.5 -maxthreshold 20 frame_" + frame + 302 | ".yuv ../compare/frame_" + frame + ".org.tga", 303 | file: "imagevalidate_frame_" + frame + ".out", 304 | compareOption: { 305 | relativeTolerance: 0.085, 306 | } as CompareOptions, 307 | } as ValidateConfig; 308 | }), 309 | } 310 | ]); 311 | benchmarks.set("531.deepsjeng_r", [ 312 | { 313 | args: "ref.txt", 314 | validates: [{ 315 | type: "STDOUT", 316 | file: "ref.out", 317 | }], 318 | } as BenchmarkConfig, 319 | ]); 320 | benchmarks.set("541.leela_r", [ 321 | { 322 | args: "ref.sgf", 323 | validates: [{ 324 | type: "STDOUT", 325 | file: "ref.out", 326 | }], 327 | } as BenchmarkConfig, 328 | ]); 329 | benchmarks.set("548.exchange2_r", [ 330 | { 331 | args: "6", 332 | validates: [{ 333 | type: "FILE", 334 | file: "s.txt", 335 | }], 336 | } as BenchmarkConfig, 337 | ]); 338 | benchmarks.set("557.xz_r", [ 339 | { 340 | args: "cld.tar.xz 160 19cf30ae51eddcbefda78dd06014b4b96281456e078ca7c13e1c0c9e6aaea8dff3efb4ad6b0456697718cede6bd5454852652806a657bb56e07d61128434b474 59796407 61004416 6", 341 | validates: [{ 342 | type: "STDOUT", 343 | file: "cld.tar-160-6.out", 344 | }], 345 | } as BenchmarkConfig, 346 | { 347 | args: "cpu2006docs.tar.xz 250 055ce243071129412e9dd0b3b69a21654033a9b723d874b2015c774fac1553d9713be561ca86f74e4f16f22e664fc17a79f30caa5ad2c04fbc447549c2810fae 23047774 23513385 6e", 348 | validates: [{ 349 | type: "STDOUT", 350 | file: "cpu2006docs.tar-250-6e.out", 351 | }], 352 | } as BenchmarkConfig, 353 | { 354 | args: "input.combined.xz 250 a841f68f38572a49d86226b7ff5baeb31bd19dc637a922a972b2e6d1257a890f6a544ecab967c313e370478c74f760eb229d4eef8a8d2836d233d3e9dd1430bf 40401484 41217675 7", 355 | validates: [{ 356 | type: "STDOUT", 357 | file: "input.combined-250-7.out", 358 | }], 359 | } as BenchmarkConfig, 360 | ]); 361 | 362 | // fp rate 363 | benchmarks.set("503.bwaves_r", [1, 2, 3, 4].map((i) => { 364 | return { 365 | args: "bwaves_" + i + " < bwaves_" + i + ".in", 366 | validates: [{ 367 | type: "STDOUT", 368 | file: "bwaves_" + i + ".out", 369 | compareOption: { 370 | absoluteTolerance: 1e-16, 371 | relativeTolerance: 0.015, 372 | } 373 | }], 374 | } as BenchmarkConfig; 375 | })); 376 | benchmarks.set("507.cactuBSSN_r", [ 377 | { 378 | args: "spec_ref.par", 379 | validates: [{ 380 | type: "STDOUT", 381 | file: "spec_ref.out", 382 | }, { 383 | type: "FILE", 384 | file: "gxx.xl", 385 | compareOption: { 386 | absoluteTolerance: 5e-13, 387 | } 388 | }, { 389 | type: "FILE", 390 | file: "gxy.xl", 391 | compareOption: { 392 | absoluteTolerance: 5e-13, 393 | } 394 | }], 395 | } as BenchmarkConfig, 396 | ]); 397 | benchmarks.set("508.namd_r", [ 398 | { 399 | args: "--input apoa1.input --output apoa1.ref.output --iterations 65", 400 | validates: [{ 401 | type: "FILE", 402 | file: "apoa1.ref.output", 403 | compareOption: { 404 | absoluteTolerance: 5e-05, 405 | } 406 | }], 407 | } as BenchmarkConfig, 408 | ]); 409 | benchmarks.set("510.parest_r", [ 410 | { 411 | args: "ref.prm", 412 | validates: [{ 413 | type: "FILE", 414 | file: "001-m00.vtk", 415 | compareOption: { 416 | absoluteTolerance: 0.001, 417 | } 418 | }, { 419 | type: "FILE", 420 | file: "002-m00.vtk", 421 | compareOption: { 422 | absoluteTolerance: 0.001, 423 | } 424 | }, { 425 | type: "FILE", 426 | file: "003-m00.vtk", 427 | compareOption: { 428 | absoluteTolerance: 0.001, 429 | } 430 | }, { 431 | type: "FILE", 432 | file: "004-m00.vtk", 433 | compareOption: { 434 | absoluteTolerance: 0.001, 435 | } 436 | }, { 437 | type: "FILE", 438 | file: "005-m00.vtk", 439 | compareOption: { 440 | absoluteTolerance: 0.001, 441 | } 442 | }, { 443 | type: "FILE", 444 | file: "006-m00.vtk", 445 | compareOption: { 446 | absoluteTolerance: 0.001, 447 | } 448 | }, { 449 | type: "FILE", 450 | file: "007-m00.vtk", 451 | compareOption: { 452 | absoluteTolerance: 0.001, 453 | } 454 | }, { 455 | type: "FILE", 456 | file: "log", 457 | compareOption: { 458 | absoluteTolerance: 0.001, 459 | } 460 | }, { 461 | type: "FILE", 462 | file: "me.prm", 463 | compareOption: { 464 | absoluteTolerance: 0.001, 465 | } 466 | }, { 467 | type: "FILE", 468 | file: "statistics", 469 | compareOption: { 470 | absoluteTolerance: 0.004, 471 | } 472 | }], 473 | } as BenchmarkConfig, 474 | ]); 475 | benchmarks.set("511.povray_r", [ 476 | { 477 | args: "SPEC-benchmark-ref.ini", 478 | validates: [{ 479 | type: "COMMAND", 480 | command: "imagevalidate_511 SPEC-benchmark.tga ../compare/SPEC-benchmark.org.tga", 481 | file: "imagevalidate_SPEC-benchmark.tga.out", 482 | compareOption: { 483 | relativeTolerance: 0.06, 484 | } 485 | }], 486 | } as BenchmarkConfig, 487 | ]); 488 | benchmarks.set("519.lbm_r", [ 489 | { 490 | args: "3000 reference.dat 0 0 100_100_130_ldc.of", 491 | validates: [{ 492 | type: "STDOUT", 493 | file: "lbm.out", 494 | compareOption: { 495 | absoluteTolerance: 1e-07, 496 | } 497 | }], 498 | } as BenchmarkConfig, 499 | ]); 500 | benchmarks.set("521.wrf_r", [ 501 | { 502 | args: "", 503 | validates: [{ 504 | type: "COMMAND", 505 | command: "diffwrf_521 wrfout_d01_2000-01-24_20_00_00 ../compare/wrf_reference_01", 506 | file: "diffwrf_output_01.txt", 507 | compareOption: { 508 | collapseWhitespace: true, 509 | } 510 | }], 511 | } as BenchmarkConfig, 512 | ]); 513 | benchmarks.set("526.blender_r", [ 514 | { 515 | args: "sh3_no_char.blend --render-output sh3_no_char_ --threads 1 -b -F RAWTGA -s 849 -e 849 -a", 516 | validates: [{ 517 | type: "COMMAND", 518 | command: "imagevalidate_526 -avg -threshold 0.75 -maxthreshold 0.01 sh3_no_char_0849.tga ../compare/sh3_no_char_0849.org.tga", 519 | file: "imagevalidate_sh3_no_char_0849.out", 520 | compareOption: { 521 | relativeTolerance: 0.05, 522 | } 523 | }], 524 | } as BenchmarkConfig, 525 | ]); 526 | benchmarks.set("527.cam4_r", [ 527 | { 528 | args: "", 529 | validates: [{ 530 | type: "COMMAND", 531 | command: "cam4_validate_527 10 0.0035 ../compare/h0_ctrl.nc h0.nc", 532 | file: "cam4_validate.txt", 533 | compareOption: { 534 | collapseWhitespace: true, 535 | } 536 | }], 537 | } as BenchmarkConfig, 538 | ]); 539 | benchmarks.set("538.imagick_r", [ 540 | { 541 | args: "-limit disk 0 refrate_input.tga -edge 41 -resample 181% -emboss 31 -colorspace YUV -mean-shift 19x19+15% -resize 30% refrate_output.tga", 542 | validates: [{ 543 | type: "COMMAND", 544 | command: "imagevalidate_538 -avg -threshold 0.95 -maxthreshold 0.001 refrate_output.tga ../compare/refrate_expected.tga", 545 | file: "refrate_validate.out", 546 | compareOption: { 547 | relativeTolerance: 0.01, 548 | } 549 | }], 550 | } as BenchmarkConfig, 551 | ]); 552 | benchmarks.set("544.nab_r", [ 553 | { 554 | args: "1am0 1122214447 122", 555 | validates: [{ 556 | type: "STDOUT", 557 | file: "1am0.out", 558 | compareOption: { 559 | relativeTolerance: 0.01, 560 | skipRelativeTolerance: 2 561 | } 562 | }], 563 | } as BenchmarkConfig, 564 | ]); 565 | benchmarks.set("549.fotonik3d_r", [ 566 | { 567 | args: "", 568 | validates: [{ 569 | type: "FILE", 570 | file: "pscyee.out", 571 | compareOption: { 572 | absoluteTolerance: 1e-27, 573 | relativeTolerance: 1e-10, 574 | // TODO: off-by-one --obiwan 575 | } 576 | }], 577 | } as BenchmarkConfig, 578 | ]); 579 | benchmarks.set("554.roms_r", [ 580 | { 581 | args: "< ocean_benchmark2.in.x", 582 | validates: [{ 583 | type: "STDOUT", 584 | file: "ocean_benchmark2.log", 585 | compareOption: { 586 | absoluteTolerance: 1e-07, 587 | relativeTolerance: 1e-07, 588 | // although not specified in Spec/object.pm, 589 | // we found that the only diff was whitespaces.. 590 | collapseWhitespace: true, 591 | } 592 | }], 593 | } as BenchmarkConfig, 594 | ]); 595 | 596 | // from data/refrate/reftime 597 | let reftime: Map = new Map(); 598 | // int rate 599 | reftime.set("500.perlbench_r", 1592); 600 | reftime.set("502.gcc_r", 1416); 601 | reftime.set("505.mcf_r", 1616); 602 | reftime.set("520.omnetpp_r", 1312); 603 | reftime.set("523.xalancbmk_r", 1056); 604 | reftime.set("525.x264_r", 1751); 605 | reftime.set("531.deepsjeng_r", 1146); 606 | reftime.set("541.leela_r", 1656); 607 | reftime.set("548.exchange2_r", 2620); 608 | reftime.set("557.xz_r", 1080); 609 | 610 | // fp rate 611 | reftime.set("503.bwaves_r", 10028); 612 | reftime.set("507.cactuBSSN_r", 1266); 613 | reftime.set("508.namd_r", 950); 614 | reftime.set("510.parest_r", 2616); 615 | reftime.set("511.povray_r", 2335); 616 | reftime.set("519.lbm_r", 1054); 617 | reftime.set("521.wrf_r", 2240); 618 | reftime.set("526.blender_r", 1523); 619 | reftime.set("527.cam4_r", 1749); 620 | reftime.set("538.imagick_r", 2487); 621 | reftime.set("544.nab_r", 1683); 622 | reftime.set("549.fotonik3d_r", 3897); 623 | reftime.set("554.roms_r", 1589); 624 | 625 | this.log += "Finding fastest core\n"; 626 | let task: taskpool.Task = new taskpool.Task(findBestCore); 627 | let core = await taskpool.execute(task); 628 | this.log += "Found fastest core is " + core + "\n"; 629 | 630 | let result: Map = new Map(); 631 | let failed: boolean = false; 632 | for (let benchmark of filter) { 633 | this.log += "Run benchmark " + benchmark + "\n"; 634 | hilog.info(0x0000, 'mainTag', 'Extracting files for %{public}s', benchmark); 635 | let value = await context.resourceManager.getRawFileContent(benchmark + ".zip"); 636 | // each benchmark has its own directory 637 | let filesDir = context.filesDir + "/" + benchmark; 638 | if (!await fs.access(filesDir)) { 639 | await fs.mkdir(filesDir); 640 | } 641 | 642 | // copy rawfile to files dir 643 | let filePath = filesDir + "/" + benchmark + ".zip"; 644 | let file = await fs.open(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 645 | await fs.write(file.fd, value.buffer); 646 | await fs.close(file); 647 | 648 | // extract to files dir 649 | let options: zlib.Options = { 650 | level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION 651 | }; 652 | await zlib.decompressFile(filePath, filesDir, options); 653 | 654 | let inputDir = filesDir + "/input"; 655 | let outputDir = filesDir + "/output"; 656 | 657 | if (benchmark === "525.x264_r") { 658 | // generate BuckBunny.yuv 659 | hilog.info(0x0000, 'mainTag', 'Generating BuckBunny.yuv'); 660 | this.log += 'Generating BuckBunny.yuv for 525.x264_r\n'; 661 | let task: taskpool.Task = 662 | new taskpool.Task(worker, inputDir, outputDir, "", "ldecod_r", "-i BuckBunny.264 -o BuckBunny.yuv".split(" "), 663 | core, []); 664 | await taskpool.execute(task); 665 | } 666 | 667 | hilog.info(0x0000, 'mainTag', 'Got files under benchmark folder: %{public}s', 668 | JSON.stringify(fs.listFileSync(filesDir))); 669 | hilog.info(0x0000, 'mainTag', 'Got files under input folder: %{public}s', 670 | JSON.stringify(fs.listFileSync(inputDir))); 671 | hilog.info(0x0000, 'mainTag', 'Got files under output folder: %{public}s', 672 | JSON.stringify(fs.listFileSync(outputDir))); 673 | 674 | // run benchmark in background 675 | let totalTime: number = 0; 676 | let index: number = 0; 677 | for (let b of benchmarks.get(benchmark)!) { 678 | index += 1; 679 | let arg: string; 680 | let validates: ValidateConfig[] = []; 681 | if (typeof b === "string") { 682 | arg = b; 683 | } else { 684 | arg = (b as BenchmarkConfig).args; 685 | validates = (b as BenchmarkConfig).validates; 686 | } 687 | 688 | this.log += "Run benchmark " + benchmark + " #" + index + " with args " + arg + "\n"; 689 | hilog.info(0x0000, 'mainTag', 'Run benchmark %{public}s #%{public}d with %{public}s', benchmark, index, arg); 690 | let args = arg.split(" "); 691 | let stdinFile = ""; 692 | if (args.length >= 2 && args[args.length-2] === "<") { 693 | // handle input redirection 694 | stdinFile = args.pop()!; 695 | args.pop(); 696 | } 697 | 698 | let task: taskpool.Task = 699 | new taskpool.Task(worker, inputDir, outputDir, stdinFile, benchmark, args, core, validates); 700 | let time: number = await taskpool.execute(task) as number; 701 | if (time < 0) { 702 | hilog.info(0x0000, 'mainTag', 'Failed benchmark %{public}s with args %{public}s', benchmark, 703 | arg); 704 | this.log += "Failed benchmark " + benchmark + " #" + index + " with args " + arg + "\n"; 705 | failed = true; 706 | break; 707 | } 708 | 709 | hilog.info(0x0000, 'mainTag', 'Finished benchmark %{public}s with args %{public}s in %{public}ss', benchmark, 710 | arg, time.toString()); 711 | this.log += "Finished benchmark " + benchmark + " #" + index + " with args " + arg + " in " + time + "s\n"; 712 | 713 | if (validates.length > 0) { 714 | this.log += "Output validation passed for " + benchmark + " #" + index + "\n"; 715 | } 716 | 717 | totalTime += time; 718 | } 719 | 720 | if (failed) { 721 | break; 722 | } 723 | 724 | let ratio: number = reftime.get(benchmark)! 725 | / totalTime; 726 | this.log += "Finished whole benchmark " + benchmark + " in " + totalTime + "s, ratio is " + ratio + "\n"; 727 | hilog.info(0x0000, 'mainTag', 'Finished whole benchmark %{public}s in %{public}ss, ratio is %{public}s', 728 | benchmark, 729 | totalTime.toString(), ratio.toString()); 730 | result.set(benchmark, totalTime); 731 | } 732 | 733 | if (failed) { 734 | this.log += "Aborted due to failure\n"; 735 | } else { 736 | // print summary 737 | this.log += "Summary:\n"; 738 | let ratios: number[] = []; 739 | let geomean = 1.0; 740 | this.log += "=================================================================================\n"; 741 | for (let benchmark of result.keys()) { 742 | let time: number = result.get(benchmark)!; 743 | let timeString: string = time.toPrecision(3); 744 | // keep integral part if >= 1000 745 | if (time >= 1000) { 746 | timeString = Math.round(time).toString(); 747 | } 748 | 749 | let ratio: number = reftime.get(benchmark)! 750 | / result.get(benchmark)!; 751 | this.log += benchmark + " 1 " + timeString + " " + ratio.toPrecision(3) + " *\n"; 752 | ratios.push(ratio); 753 | geomean *= ratio; 754 | } 755 | this.log += "Est. SPECrate(R)2017_int/fp_base " + Math.pow(geomean, 1 / result.size).toPrecision(3) + "\n"; 756 | } 757 | } catch (err) { 758 | hilog.info(0x0000, 'mainTag', 'Got error: %{public}s %{public}s', err.toString(), JSON.stringify(err)); 759 | this.log += "Got exception: " + err.toString() + "\n"; 760 | } 761 | this.running = false; 762 | } 763 | 764 | @Builder 765 | benchmarkMenu() { 766 | Menu() { 767 | MenuItem({ content: "int rate-1" }) 768 | .onClick(() => { 769 | this.runBenchmarks(int_rate); 770 | }) 771 | ForEach(int_rate, (item: string) => { 772 | MenuItem({ content: item }) 773 | .onClick(() => { 774 | this.runBenchmarks([item]); 775 | }) 776 | }) 777 | MenuItem({ content: "fp rate-1" }) 778 | .onClick(() => { 779 | this.runBenchmarks(fp_rate); 780 | }) 781 | ForEach(fp_rate, (item: string) => { 782 | MenuItem({ content: item }) 783 | .onClick(() => { 784 | this.runBenchmarks([item]); 785 | }) 786 | }) 787 | } 788 | } 789 | 790 | build() { 791 | Row() { 792 | Column() { 793 | Scroll() { 794 | Text(this.log) 795 | .fontSize(10) 796 | .fontFamily('monospace') 797 | .width('100%') 798 | } 799 | 800 | Text("Run Benchmarks") 801 | .fontSize(30) 802 | .fontWeight(FontWeight.Bold) 803 | .bindMenu(this.benchmarkMenu) 804 | Text("Copy Result") 805 | .fontSize(30) 806 | .fontWeight(FontWeight.Bold) 807 | .onClick(() => { 808 | let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.log); 809 | let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); 810 | systemPasteboard.setData(pasteData, (err, data) => { 811 | if (err) { 812 | hilog.info(0x0000, 'mainTag', 'Failed to set pastboard: %{public}s', JSON.stringify(err)); 813 | return; 814 | } 815 | }); 816 | }) 817 | } 818 | .width('100%') 819 | } 820 | .height('90%') 821 | } 822 | } 823 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/utils.ets: -------------------------------------------------------------------------------- 1 | import fs from '@ohos.file.fs'; 2 | import { util } from '@kit.ArkTS'; 3 | import { hilog } from '@kit.PerformanceAnalysisKit'; 4 | 5 | export function readWholeFile(path: string): ArrayBuffer { 6 | let size = fs.statSync(path).size; 7 | hilog.info(0x0000, 'mainTag', 'File %{public}s has %{public}d bytes', path, size); 8 | let file = fs.openSync(path, fs.OpenMode.READ_ONLY); 9 | let res = new Uint8Array(size); 10 | 11 | let buf = new ArrayBuffer(4096); 12 | let bytesRead: number = 0; 13 | while (bytesRead < size) { 14 | let length: number = fs.readSync(file.fd, buf); 15 | if (length > 0) { 16 | res.set(new Uint8Array(buf, 0, length), bytesRead); 17 | bytesRead += length; 18 | } 19 | } 20 | fs.closeSync(file); 21 | return res; 22 | } 23 | 24 | function isEqualBinary(a: ArrayBuffer, b: ArrayBuffer): boolean { 25 | if (a.byteLength != b.byteLength) { 26 | hilog.info(0x0000, 'mainTag', 'Length mismatch: %{public}d vs %{public}d', a.byteLength, b.byteLength); 27 | return false; 28 | } 29 | 30 | let aa = new Int8Array(a); 31 | let bb = new Int8Array(b); 32 | for (let i = 0; i < a.byteLength; i++) { 33 | if (aa[i] !== bb[i]) { 34 | hilog.info(0x0000, 'mainTag', 'Byte mismatch: %{public}d vs %{public}d', aa[i], bb[i]); 35 | return false; 36 | } 37 | } 38 | return true; 39 | } 40 | 41 | 42 | export interface CompareOptions { 43 | // relative error tolerance 44 | // --reltol 45 | relativeTolerance?: number; 46 | 47 | // skip the first occurrences of relative error violation 48 | // --skipreltol 49 | skipRelativeTolerance?: number; 50 | 51 | // absolute error tolerance 52 | // --abstol 53 | absoluteTolerance?: number; 54 | 55 | // collapse whitespace 56 | // --cw 57 | collapseWhitespace?: boolean; 58 | } 59 | 60 | // mimic specdiff, allowing fp tolerance 61 | export function isEqual(a: ArrayBuffer, b: ArrayBuffer, options?: CompareOptions): boolean { 62 | // fallback to more efficient implementation 63 | if (options === null || options === undefined) { 64 | return isEqualBinary(a, b); 65 | } 66 | 67 | // decode utf-8 68 | let decoder = new util.TextDecoder('utf-8'); 69 | let aStr: string = decoder.decodeToString(new Uint8Array(a)); 70 | let bStr: string = decoder.decodeToString(new Uint8Array(b)); 71 | hilog.info(0x0000, 'mainTag', 'Got a: %{public}s', aStr); 72 | hilog.info(0x0000, 'mainTag', 'Got b: %{public}s', bStr); 73 | 74 | // compare each line 75 | let aLines: string[] = aStr.split("\n"); 76 | let bLines: string[] = bStr.split("\n"); 77 | if (aLines.length !== bLines.length) { 78 | hilog.info(0x0000, 'mainTag', 'Number of lines mismatch: %{public}d vs %{public}d', aLines.length, bLines.length); 79 | return false; 80 | } 81 | 82 | let skippedRelativeTolerance: number = 0; 83 | 84 | for (let i = 0; i < aLines.length; i++) { 85 | let aLine: string = aLines[i]; 86 | let bLine: string = bLines[i]; 87 | 88 | let aParts: string[] = aLine.split(" "); 89 | let bParts: string[] = bLine.split(" "); 90 | if (options.collapseWhitespace) { 91 | // drop empty strings 92 | aParts = aParts.filter((part) => { 93 | return part.length > 0; 94 | }); 95 | bParts = bParts.filter((part) => { 96 | return part.length > 0; 97 | }); 98 | } 99 | 100 | if (aParts.length !== bParts.length) { 101 | hilog.info(0x0000, 'mainTag', 'Number of parts mismatch in line %{public}d: %{public}d vs %{public}d', i, 102 | aParts.length, bParts.length); 103 | return false; 104 | } 105 | 106 | for (let j = 0; j < aParts.length; j++) { 107 | let aPart: string = aParts[j]; 108 | let bPart: string = bParts[j]; 109 | 110 | let aFloat: number = parseFloat(aPart); 111 | let bFloat: number = parseFloat(bPart); 112 | if (!isNaN(aFloat) && !isNaN(bFloat)) { 113 | // fp 114 | // either one within error is okay 115 | if ((options!.relativeTolerance !== null && options!.relativeTolerance !== undefined) || 116 | (options!.absoluteTolerance !== null && options!.absoluteTolerance !== undefined)) { 117 | // check relative error 118 | let relativePass: boolean = false; 119 | if (options!.relativeTolerance !== null && options!.relativeTolerance !== undefined) { 120 | relativePass = true; 121 | if (Math.abs(aFloat - bFloat) / aFloat > options!.relativeTolerance!) { 122 | // handle --skipreltol 123 | if (options!.skipRelativeTolerance !== null && options!.skipRelativeTolerance !== undefined) { 124 | skippedRelativeTolerance += 1; 125 | if (skippedRelativeTolerance > options!.skipRelativeTolerance) { 126 | relativePass = true; 127 | } 128 | } else { 129 | relativePass = false; 130 | } 131 | } 132 | } 133 | 134 | // check absolute error 135 | let absolutePass: boolean = false; 136 | if (options!.absoluteTolerance !== null && options!.absoluteTolerance !== undefined) { 137 | absolutePass = true; 138 | if (Math.abs(aFloat - bFloat) > options!.absoluteTolerance!) { 139 | absolutePass = false; 140 | } 141 | } 142 | 143 | if (!relativePass && !absolutePass) { 144 | hilog.info(0x0000, 'mainTag', 145 | 'Relative/absolute tolerance violated: %{public}s vs %{public}s from %{public}s and %{public}s', 146 | aFloat.toString(), bFloat.toString(), aLine, bLine); 147 | return false; 148 | } 149 | } 150 | } else if (aPart !== bPart) { 151 | hilog.info(0x0000, 'mainTag', 'Part mismatch: %{public}s vs %{public}s', aPart, bPart); 152 | return false; 153 | } 154 | } 155 | } 156 | 157 | return true; 158 | } 159 | -------------------------------------------------------------------------------- /entry/src/main/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "entry", 4 | "type": "entry", 5 | "description": "$string:module_desc", 6 | "mainElement": "EntryAbility", 7 | "deviceTypes": [ 8 | "phone", 9 | "2in1" 10 | ], 11 | "deliveryWithInstall": true, 12 | "installationFree": false, 13 | "pages": "$profile:main_pages", 14 | "abilities": [ 15 | { 16 | "name": "EntryAbility", 17 | "srcEntry": "./ets/entryability/EntryAbility.ets", 18 | "description": "$string:EntryAbility_desc", 19 | "icon": "$media:layered_image", 20 | "label": "$string:EntryAbility_label", 21 | "startWindowIcon": "$media:startIcon", 22 | "startWindowBackground": "$color:start_window_background", 23 | "exported": true, 24 | "skills": [ 25 | { 26 | "entities": [ 27 | "entity.system.home" 28 | ], 29 | "actions": [ 30 | "action.system.home" 31 | ] 32 | } 33 | ] 34 | } 35 | ], 36 | "compressNativeLibs": true 37 | } 38 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/element/color.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": [ 3 | { 4 | "name": "start_window_background", 5 | "value": "#FFFFFF" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "module description" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "Run SPEC CPU 2017 on OpenHarmony/HarmonyOS NEXT" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "SPEC CPU 2017" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/SPECCPU2017Harmony/81724b97190de4ca60e6cd36db8e485f043be0ab/entry/src/main/resources/base/media/background.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/SPECCPU2017Harmony/81724b97190de4ca60e6cd36db8e485f043be0ab/entry/src/main/resources/base/media/foreground.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/layered_image.json: -------------------------------------------------------------------------------- 1 | { 2 | "layered-image": 3 | { 4 | "background" : "$media:background", 5 | "foreground" : "$media:foreground" 6 | } 7 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/startIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiegec/SPECCPU2017Harmony/81724b97190de4ca60e6cd36db8e485f043be0ab/entry/src/main/resources/base/media/startIcon.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/profile/main_pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": [ 3 | "pages/Index" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /entry/src/main/resources/rawfile/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip -------------------------------------------------------------------------------- /entry/src/mock/mock-config.json5: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/test/Ability.test.ets: -------------------------------------------------------------------------------- 1 | import { hilog } from '@kit.PerformanceAnalysisKit'; 2 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 3 | 4 | export default function abilityTest() { 5 | describe('ActsAbilityTest', () => { 6 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 7 | beforeAll(() => { 8 | // Presets an action, which is performed only once before all test cases of the test suite start. 9 | // This API supports only one parameter: preset action function. 10 | }) 11 | beforeEach(() => { 12 | // Presets an action, which is performed before each unit test case starts. 13 | // The number of execution times is the same as the number of test cases defined by **it**. 14 | // This API supports only one parameter: preset action function. 15 | }) 16 | afterEach(() => { 17 | // Presets a clear action, which is performed after each unit test case ends. 18 | // The number of execution times is the same as the number of test cases defined by **it**. 19 | // This API supports only one parameter: clear action function. 20 | }) 21 | afterAll(() => { 22 | // Presets a clear action, which is performed after all test cases of the test suite end. 23 | // This API supports only one parameter: clear action function. 24 | }) 25 | it('assertContain', 0, () => { 26 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 27 | hilog.info(0x0000, 'mainTag', '%{public}s', 'it begin'); 28 | let a = 'abc'; 29 | let b = 'b'; 30 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 31 | expect(a).assertContain(b); 32 | expect(a).assertEqual(a); 33 | }) 34 | }) 35 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import abilityTest from './Ability.test'; 2 | 3 | export default function testsuite() { 4 | abilityTest(); 5 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "entry_test", 4 | "type": "feature", 5 | "deviceTypes": [ 6 | "phone" 7 | ], 8 | "deliveryWithInstall": true, 9 | "installationFree": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /entry/src/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import localUnitTest from './LocalUnit.test'; 2 | 3 | export default function testsuite() { 4 | localUnitTest(); 5 | } -------------------------------------------------------------------------------- /entry/src/test/LocalUnit.test.ets: -------------------------------------------------------------------------------- 1 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 2 | 3 | export default function localUnitTest() { 4 | describe('localUnitTest', () => { 5 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 6 | beforeAll(() => { 7 | // Presets an action, which is performed only once before all test cases of the test suite start. 8 | // This API supports only one parameter: preset action function. 9 | }); 10 | beforeEach(() => { 11 | // Presets an action, which is performed before each unit test case starts. 12 | // The number of execution times is the same as the number of test cases defined by **it**. 13 | // This API supports only one parameter: preset action function. 14 | }); 15 | afterEach(() => { 16 | // Presets a clear action, which is performed after each unit test case ends. 17 | // The number of execution times is the same as the number of test cases defined by **it**. 18 | // This API supports only one parameter: clear action function. 19 | }); 20 | afterAll(() => { 21 | // Presets a clear action, which is performed after all test cases of the test suite end. 22 | // This API supports only one parameter: clear action function. 23 | }); 24 | it('assertContain', 0, () => { 25 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 26 | let a = 'abc'; 27 | let b = 'b'; 28 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 29 | expect(a).assertContain(b); 30 | expect(a).assertEqual(a); 31 | }); 32 | }); 33 | } -------------------------------------------------------------------------------- /generate.perl: -------------------------------------------------------------------------------- 1 | # enable -flto 2 | $enable_lto = 1; 3 | 4 | sub add_target { 5 | $target = $_[0]; 6 | # drop trailing '*' 7 | foreach my $source (@sources) 8 | { 9 | $source =~ s{\*$}{}; 10 | } 11 | @additional_sources = (); 12 | if ($target eq "diffwrf_521") { 13 | # add missing sources due to split module folder 14 | @additional_sources = ("module_cam_shr_const_mod.F90", "module_cam_shr_kind_mod.F90", "module_gfs_machine.F90", "module_gfs_physcons.F90", "ESMF_Fraction.F90"); 15 | } 16 | print(FH "add_library(", $target, " SHARED ", (join " ", @sources) , " ", (join " ", @additional_sources), ")\n"); 17 | 18 | # add more flags 19 | $bench_flags = $bench_flags . " -march=armv8-a+sve -O3"; 20 | $bench_flags = $bench_flags . " -DSPEC -DSPEC_LP64 -DSPEC_LINUX -DSPEC_LINUX_AARCH64 -DSPEC_NO_USE_STDIO_PTR -DSPEC_NO_USE_STDIO_BASE -DSPEC_NO_ISFINITE"; 21 | if ($target ne "502.gcc_r" and $target ne "507.cactuBSSN_r" and $target ne "510.parest_r" and $target ne "521.wrf_r" and $target ne "526.blender_r" and $target ne "527.cam4_r" and $enable_lto) { 22 | # -flto miscompiles for 502.gcc_r 23 | # -flto incompatible llvm version for 507.cactuBSSN_r 24 | # -flto ICE for 510.parest_r 25 | # -flto too slow for 521.wrf_r 26 | # -flto too slow for 526.blender_r 27 | # -flto too slow for 527.cam4_r 28 | $bench_flags = $bench_flags . " -flto"; 29 | } 30 | if ($target ne "503.bwaves_r" and $target ne "507.cactuBSSN_r" and $target ne "521.wrf_r" and $target ne "diffwrf_521" and $target ne "527.cam4_r" and $target ne "cam4_validate_527" and $target ne "548.exchange2_r" and $target ne "549.fotonik3d_r" and $target ne "554.roms_r") { 31 | # flang does not support -Wno-error and -fcommon 32 | $bench_flags = $bench_flags . " -Wno-error=format-security -Wno-error=reserved-user-defined-literal -fcommon"; 33 | } 34 | if ($target eq "521.wrf_r") { 35 | $bench_cflags = $bench_cflags . " -DSPEC_CASE_FLAG"; 36 | # fix crash due to little endian 37 | $bench_fflags = $bench_fflags . " -fconvert=big-endian"; 38 | } 39 | if ($target eq "527.cam4_r") { 40 | $bench_cflags = $bench_cflags . " -DSPEC_CASE_FLAG"; 41 | } 42 | if ($target eq "554.roms_r") { 43 | # fix compilation 44 | $bench_flags = $bench_flags . " -DNDEBUG"; 45 | } 46 | 47 | # convert -I flags to target_include_directories 48 | for $flag (split(" ", ($bench_flags . " " . $bench_cflags . " " . $bench_cxxflags . " " . $bench_fflags . " " . $bench_fppflags))) { 49 | if ((rindex $flag, "-I", 0) == 0) { 50 | print(FH "target_include_directories(", $target, " PRIVATE ", substr($flag, 2, length($flag)), ")\n"); 51 | } 52 | } 53 | 54 | # drop unwanted preprocessor flags 55 | $bench_fppflags =~ s{-w -m literal-single.pm -m c-comment.pm}{}; 56 | $bench_fppflags =~ s{-w -m literal.pm}{}; 57 | 58 | # handle symbol interposition 59 | $bench_cflags = $bench_cflags . " -fvisibility=protected"; 60 | $bench_cxxflags = $bench_cxxflags . " -fvisibility=protected"; 61 | 62 | # set flags for each language 63 | $bench_cflags = $bench_cflags . " " . $bench_flags; 64 | $bench_cxxflags = $bench_cxxflags . " " . $bench_flags; 65 | $bench_fflags = $bench_fflags . " " . $bench_fppflags . " " . $bench_flags; 66 | 67 | print(FH "target_compile_options(", $target, " PRIVATE\n\t\$<\$:", $bench_cflags, ">\n\t\$<\$:", $bench_cxxflags, ">\n\t\$<\$:", $bench_fflags, ">)\n"); 68 | 69 | # handle same fortran source in multiple targets in 521.wrf_r 70 | # https://stackoverflow.com/questions/73036890/cmake-multiple-version-of-fortran-mod-files 71 | print(FH "set_target_properties(", $target, " PROPERTIES Fortran_MODULE_DIRECTORY \${CMAKE_CURRENT_BINARY_DIR}/", $target, ")\n"); 72 | print(FH "target_include_directories(", $target, " PUBLIC \${CMAKE_CURRENT_BINARY_DIR}/", $target, ")\n"); 73 | } 74 | 75 | for $benchmark ("500.perlbench_r", "502.gcc_r", "505.mcf_r", "520.omnetpp_r", "523.xalancbmk_r", "525.x264_r", "531.deepsjeng_r", "541.leela_r", "548.exchange2_r", "557.xz_r", "503.bwaves_r", "507.cactuBSSN_r", "508.namd_r", "510.parest_r", "511.povray_r", "519.lbm_r", "521.wrf_r", "526.blender_r", "527.cam4_r", "538.imagick_r", "544.nab_r", "549.fotonik3d_r", "554.roms_r") { 76 | $bench_flags = $bench_cflags = $bench_cxxflags = $bench_fflags = $bench_fppflags = ""; 77 | require "./benchspec/CPU/" . $benchmark . "/Spec/object.pm"; 78 | mkdir("entry/src/main/cpp/" . $benchmark); 79 | system("cp -arv ./benchspec/CPU/" . $benchmark . "/src/* entry/src/main/cpp/" . $benchmark . "/"); 80 | open(FH, '>', "entry/src/main/cpp/" . $benchmark . "/CMakeLists.txt") or die $!; 81 | if ($benchmark eq "511.povray_r") { 82 | @sources = @{%sources{"povray_r"}}; 83 | add_target("511.povray_r"); 84 | 85 | @sources = @{%sources{"imagevalidate_511"}}; 86 | add_target("imagevalidate_511"); 87 | } elsif ($benchmark eq "521.wrf_r") { 88 | @sources = @{%sources{"wrf_r"}}; 89 | add_target("521.wrf_r"); 90 | 91 | @sources = @{%sources{"diffwrf_521"}}; 92 | add_target("diffwrf_521"); 93 | } elsif ($benchmark eq "525.x264_r") { 94 | @sources = @{%sources{"x264_r"}}; 95 | add_target("525.x264_r"); 96 | 97 | @sources = @{%sources{"ldecod_r"}}; 98 | add_target("ldecod_r"); 99 | 100 | @sources = @{%sources{"imagevalidate_525"}}; 101 | add_target("imagevalidate_525"); 102 | } elsif ($benchmark eq "526.blender_r") { 103 | @sources = @{%sources{"blender_r"}}; 104 | add_target("526.blender_r"); 105 | 106 | @sources = @{%sources{"imagevalidate_526"}}; 107 | add_target("imagevalidate_526"); 108 | } elsif ($benchmark eq "527.cam4_r") { 109 | @sources = @{%sources{"cam4_r"}}; 110 | add_target("527.cam4_r"); 111 | 112 | @sources = @{%sources{"cam4_validate_527"}}; 113 | add_target("cam4_validate_527"); 114 | } elsif ($benchmark eq "538.imagick_r") { 115 | @sources = @{%sources{"imagick_r"}}; 116 | add_target("538.imagick_r"); 117 | 118 | @sources = @{%sources{"imagevalidate_538"}}; 119 | add_target("imagevalidate_538"); 120 | } else { 121 | add_target($benchmark); 122 | } 123 | 124 | if ($benchmark eq "549.fotonik3d_r") { 125 | # extract OBJ.dat.xz for input 126 | system("xz -d -k ./benchspec/CPU/549.fotonik3d_r/data/refrate/input/OBJ.dat.xz"); 127 | } 128 | 129 | # zip inputs 130 | system("rm -rf tmp"); 131 | system("mkdir -p tmp/input tmp/output tmp/compare"); 132 | system("cp -rv ./benchspec/CPU/" . $benchmark . "/data/all/input/* ./benchspec/CPU/" . $benchmark . "/data/refrate/input/* tmp/input/"); 133 | system("cp -rv ./benchspec/CPU/" . $benchmark . "/data/refrate/output/* tmp/output/"); 134 | system("cp -rv ./benchspec/CPU/" . $benchmark . "/data/refrate/compare/* tmp/compare/"); 135 | system("rm -f entry/src/main/resources/rawfile/" . $benchmark . ".zip"); 136 | system("cd tmp && zip -r ../entry/src/main/resources/rawfile/" . $benchmark . ".zip *"); 137 | system("rm -rf tmp"); 138 | } 139 | 140 | # patch code 141 | # fix compilation 142 | system("sed -i '1s;^;#include \\n;' entry/src/main/cpp/500.perlbench_r/perlio.c"); 143 | system("sed -i 's/__linux__/__nonexistent__/' entry/src/main/cpp/510.parest_r/source/base/utilities.cc"); 144 | system("sed -i 's/#if defined __FreeBSD__/#include \\n#if 1/' entry/src/main/cpp/520.omnetpp_r/simulator/platdep/platmisc.h"); 145 | system("sed -i 's/#if defined.* && !defined.*/#if 0/' entry/src/main/cpp/521.wrf_r/netcdf/include/ncfortran.h"); 146 | system("sed -i '1s/^/# define rindex(X,Y) strrchr(X,Y)\\n/' entry/src/main/cpp/521.wrf_r/misc.c"); 147 | system("sed -i '1s/^/# define rindex(X,Y) strrchr(X,Y)\\n/' entry/src/main/cpp/521.wrf_r/type.c"); 148 | system("sed -i '1s/^/# define rindex(X,Y) strrchr(X,Y)\\n/' entry/src/main/cpp/521.wrf_r/reg_parse.c"); 149 | system("sed -i 's/^#ifdef\$/#ifdef SPEC/' entry/src/main/cpp/527.cam4_r/ESMF_AlarmMod.F90"); 150 | system("sed -i 's/#if defined.* && !defined.*/#if 0/' entry/src/main/cpp/527.cam4_r/netcdf/include/ncfortran.h"); 151 | -------------------------------------------------------------------------------- /hvigor/hvigor-config.json5: -------------------------------------------------------------------------------- 1 | { 2 | "modelVersion": "5.0.1", 3 | "dependencies": { 4 | "@ohos/hvigor-ohos-arkui-x-plugin": "4.2.4" 5 | }, 6 | "execution": { 7 | // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ 8 | // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ 9 | // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ 10 | // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ 11 | // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ 12 | }, 13 | "logging": { 14 | // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ 15 | }, 16 | "debugging": { 17 | // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ 18 | }, 19 | "nodeOptions": { 20 | // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ 21 | // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ 22 | } 23 | } -------------------------------------------------------------------------------- /hvigorfile.ts: -------------------------------------------------------------------------------- 1 | // Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. 2 | export { AppTasksForArkUIX } from '@ohos/hvigor-ohos-arkui-x-plugin'; 3 | -------------------------------------------------------------------------------- /oh-package-lock.json5: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "stableOrder": true 4 | }, 5 | "lockfileVersion": 3, 6 | "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", 7 | "specifiers": { 8 | "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", 9 | "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19" 10 | }, 11 | "packages": { 12 | "@ohos/hamock@1.0.0": { 13 | "name": "@ohos/hamock", 14 | "version": "1.0.0", 15 | "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", 16 | "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har", 17 | "registryType": "ohpm" 18 | }, 19 | "@ohos/hypium@1.0.19": { 20 | "name": "@ohos/hypium", 21 | "version": "1.0.19", 22 | "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==", 23 | "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har", 24 | "registryType": "ohpm" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "modelVersion": "5.0.1", 3 | "description": "Please describe the basic information.", 4 | "dependencies": { 5 | }, 6 | "devDependencies": { 7 | "@ohos/hypium": "1.0.19", 8 | "@ohos/hamock": "1.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # push and install the hap 3 | # assume deveco studio is downloaded from: 4 | # https://developer.huawei.com/consumer/cn/download/ 5 | # and extracted to /Applications/DevEco-Studio.app 6 | set -x -e 7 | export TOOL_HOME=/Applications/DevEco-Studio.app/Contents 8 | export PATH=$TOOL_HOME/sdk/default/openharmony/toolchains:$PATH 9 | hdc file send $1 /data/local/tmp 10 | hdc shell bm install -p /data/local/tmp/$(basename $1) 11 | hdc shell aa start -a EntryAbility -b $(jq ".app.bundleName" AppScope/app.json5) 12 | -------------------------------------------------------------------------------- /results/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarking results 2 | 3 | Record the results of running benchmarks using this application. All numbers provided are estimates. 4 | 5 | Due to fluctuations in performance, we offer two types of benchmark runs: 6 | 7 | 1. [Full Run](./full/): Executes all benchmarks sequentially, resulting in less favorable thermal conditions. 8 | 2. [Best Run](./best/): Allows each benchmark to be run individually, ensuring optimal thermal conditions. 9 | 10 | For integer benchmarks, the best run is slightly faster than the full run. For floating-point benchmarks, however, the best run is over 20% faster than the full run, likely due to the increased heat generation. 11 | 12 | Note: Placing the device in a refrigerator is strictly prohibited. 13 | 14 | The C/C++ code is compiled using the current Clang version (15.0.4) from the HarmonyOS SDK. The Fortran code is compiled with the latest Flang-20 version from the LLVM APT repository. The following optimization flags are used: 15 | 16 | - some benchmarks are built without -flto: -O3 -march=armv8.a+sve 17 | - 502.gcc_r: LTO leads to crashes 18 | - 507.cactuBSSN_r: LTO fails due to different Clang and Flang versions 19 | - 510.parest_r: internal exception in LTO 20 | - 521.wrf_r: LTO is quite slow 21 | - 526.blender_r: LTO is quite slow 22 | - 527.cam4_r: LTO is quite slow 23 | - others: -O3 -flto -march=armv8.a+sve 24 | -------------------------------------------------------------------------------- /results/best/HBN-AL80.csv: -------------------------------------------------------------------------------- 1 | benchmark,time,ratio 2 | 500.perlbench_r,425,3.75 3 | 502.gcc_r,264,5.36 4 | 505.mcf_r,386,4.19 5 | 520.omnetpp_r,495,2.65 6 | 523.xalancbmk_r,314,3.36 7 | 525.x264_r,151,11.60 8 | 531.deepsjeng_r,362,3.17 9 | 541.leela_r,645,2.57 10 | 548.exchange2_r,230,11.39 11 | 557.xz_r,540,2.00 12 | int_rate,3812,4.18 13 | 503.bwaves_r,310,32.35 14 | 507.cactuBSSN_r,185,6.84 15 | 508.namd_r,209,4.55 16 | 510.parest_r,479,5.46 17 | 511.povray_r,441,5.29 18 | 519.lbm_r,205,5.14 19 | 521.wrf_r,275,8.15 20 | 526.blender_r,340,4.48 21 | 527.cam4_r,1099,1.59 22 | 538.imagick_r,450,5.53 23 | 544.nab_r,253,6.65 24 | 549.fotonik3d_r,436,8.94 25 | 554.roms_r,292,5.44 26 | fp_rate,4974,6.08 27 | -------------------------------------------------------------------------------- /results/compute.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import sys 3 | import statistics 4 | 5 | int_rate = [ 6 | "500.perlbench_r", 7 | "502.gcc_r", 8 | "505.mcf_r", 9 | "520.omnetpp_r", 10 | "523.xalancbmk_r", 11 | "525.x264_r", 12 | "531.deepsjeng_r", 13 | "541.leela_r", 14 | "548.exchange2_r", 15 | "557.xz_r", 16 | ] 17 | 18 | fp_rate = [ 19 | "503.bwaves_r", 20 | "507.cactuBSSN_r", 21 | "508.namd_r", 22 | "510.parest_r", 23 | "511.povray_r", 24 | "519.lbm_r", 25 | "521.wrf_r", 26 | "526.blender_r", 27 | "527.cam4_r", 28 | "538.imagick_r", 29 | "544.nab_r", 30 | "549.fotonik3d_r", 31 | "554.roms_r", 32 | ] 33 | 34 | reftime = { 35 | # int rate 36 | "500.perlbench_r": 1592, 37 | "502.gcc_r": 1416, 38 | "505.mcf_r": 1616, 39 | "520.omnetpp_r": 1312, 40 | "523.xalancbmk_r": 1056, 41 | "525.x264_r": 1751, 42 | "531.deepsjeng_r": 1146, 43 | "541.leela_r": 1656, 44 | "548.exchange2_r": 2620, 45 | "557.xz_r": 1080, 46 | # fp rate 47 | "503.bwaves_r": 10028, 48 | "507.cactuBSSN_r": 1266, 49 | "508.namd_r": 950, 50 | "510.parest_r": 2616, 51 | "511.povray_r": 2335, 52 | "519.lbm_r": 1054, 53 | "521.wrf_r": 2240, 54 | "526.blender_r": 1523, 55 | "527.cam4_r": 1749, 56 | "538.imagick_r": 2487, 57 | "544.nab_r": 1683, 58 | "549.fotonik3d_r": 3897, 59 | "554.roms_r": 1589, 60 | } 61 | 62 | with open(sys.argv[1], newline="") as csvfile: 63 | reader = csv.DictReader(csvfile) 64 | scores = {} 65 | for row in reader: 66 | if row["benchmark"] in int_rate or row["benchmark"] in fp_rate: 67 | scores[row["benchmark"]] = { 68 | "time": float(row["time"]), 69 | "ratio": reftime[row["benchmark"]] / float(row["time"]), 70 | } 71 | 72 | with open(sys.argv[1], "w", newline="") as csvfile: 73 | fieldnames = ["benchmark", "time", "ratio"] 74 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 75 | 76 | writer.writeheader() 77 | 78 | for name, rate in [("int_rate", int_rate), ("fp_rate", fp_rate)]: 79 | sum_time = 0 80 | for benchmark in rate: 81 | if benchmark in scores: 82 | sum_time += scores[benchmark]["time"] 83 | writer.writerow( 84 | { 85 | "benchmark": benchmark, 86 | "time": round(scores[benchmark]["time"]), 87 | "ratio": "{:.2f}".format(scores[benchmark]["ratio"]), 88 | } 89 | ) 90 | 91 | ratios = [] 92 | for benchmark in rate: 93 | if benchmark in scores: 94 | ratios.append(scores[benchmark]["ratio"]) 95 | 96 | if len(ratios) == 0: 97 | continue 98 | 99 | writer.writerow( 100 | { 101 | "benchmark": name, 102 | "time": round(sum_time), 103 | "ratio": "{:.2f}".format(statistics.geometric_mean(ratios)), 104 | } 105 | ) 106 | -------------------------------------------------------------------------------- /results/full/HBN-AL80-001.csv: -------------------------------------------------------------------------------- 1 | benchmark,time,ratio 2 | 500.perlbench_r,432,3.69 3 | 502.gcc_r,279,5.08 4 | 505.mcf_r,416,3.88 5 | 520.omnetpp_r,515,2.55 6 | 523.xalancbmk_r,332,3.18 7 | 525.x264_r,168,10.42 8 | 531.deepsjeng_r,380,3.02 9 | 541.leela_r,686,2.41 10 | 548.exchange2_r,248,10.56 11 | 557.xz_r,557,1.94 12 | int_rate,4013,3.95 13 | 503.bwaves_r,316,31.73 14 | 507.cactuBSSN_r,199,6.36 15 | 508.namd_r,231,4.11 16 | 510.parest_r,527,4.96 17 | 511.povray_r,463,5.04 18 | 519.lbm_r,318,3.31 19 | 521.wrf_r,431,5.20 20 | 526.blender_r,421,3.62 21 | 527.cam4_r,1372,1.27 22 | 538.imagick_r,505,4.92 23 | 544.nab_r,279,6.03 24 | 549.fotonik3d_r,550,7.09 25 | 554.roms_r,454,3.50 26 | fp_rate,6066,5.00 27 | -------------------------------------------------------------------------------- /results/full/HBN-AL80-002.csv: -------------------------------------------------------------------------------- 1 | benchmark,time,ratio 2 | 500.perlbench_r,424,3.75 3 | 502.gcc_r,275,5.15 4 | 505.mcf_r,410,3.94 5 | 520.omnetpp_r,516,2.54 6 | 523.xalancbmk_r,329,3.21 7 | 525.x264_r,168,10.42 8 | 531.deepsjeng_r,383,2.99 9 | 541.leela_r,687,2.41 10 | 548.exchange2_r,248,10.56 11 | 557.xz_r,556,1.94 12 | int_rate,3996,3.96 13 | 503.bwaves_r,299,33.54 14 | 507.cactuBSSN_r,195,6.49 15 | 508.namd_r,219,4.34 16 | 510.parest_r,500,5.23 17 | 511.povray_r,445,5.25 18 | 519.lbm_r,224,4.71 19 | 521.wrf_r,304,7.37 20 | 526.blender_r,411,3.71 21 | 527.cam4_r,1112,1.57 22 | 538.imagick_r,475,5.24 23 | 544.nab_r,274,6.14 24 | 549.fotonik3d_r,494,7.89 25 | 554.roms_r,384,4.14 26 | fp_rate,5336,5.61 27 | -------------------------------------------------------------------------------- /results/template.csv: -------------------------------------------------------------------------------- 1 | benchmark,time,ratio 2 | 500.perlbench_r,1592,1.00 3 | 502.gcc_r,1416,1.00 4 | 505.mcf_r,1616,1.00 5 | 520.omnetpp_r,1312,1.00 6 | 523.xalancbmk_r,1056,1.00 7 | 525.x264_r,1751,1.00 8 | 531.deepsjeng_r,1146,1.00 9 | 541.leela_r,1656,1.00 10 | 548.exchange2_r,2620,1.00 11 | 557.xz_r,1080,1.00 12 | int_rate,15245,1.00 13 | 503.bwaves_r,10028,1.00 14 | 507.cactuBSSN_r,1266,1.00 15 | 508.namd_r,950,1.00 16 | 510.parest_r,2616,1.00 17 | 511.povray_r,2335,1.00 18 | 519.lbm_r,1054,1.00 19 | 521.wrf_r,2240,1.00 20 | 526.blender_r,1523,1.00 21 | 527.cam4_r,1749,1.00 22 | 538.imagick_r,2487,1.00 23 | 544.nab_r,1683,1.00 24 | 549.fotonik3d_r,3897,1.00 25 | 554.roms_r,1589,1.00 26 | fp_rate,33417,1.00 27 | --------------------------------------------------------------------------------