diff --git a/test/wasmBenchmarker/benchmark.py b/test/wasmBenchmarker/benchmark.py index 818b835ab..60fd3b4b3 100644 --- a/test/wasmBenchmarker/benchmark.py +++ b/test/wasmBenchmarker/benchmark.py @@ -38,7 +38,8 @@ "prime": 48611, "quick_sort": 0, "red-black": 4000000, - "salesman": 840 + "salesman": 840, + "simdMandelbrotCount": 775007 } # https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/simple.html#simple gameTests = ["mandelbrot", "nbody", "gregory", "fannkuch", "k_nucleotide"] @@ -111,8 +112,10 @@ def compile_tests(path, only_game=False, compile_anyway=False, run=None): print("target files are found; compilation skipped") continue + extraFlags = "-mavx -msimd128" if file.startswith("simd") else "" + print("compiling " + name) - bob_the_stringbuilder = "./emsdk/upstream/emscripten/emcc " + path + "/" + file + " --no-entry -s WASM=1 -s EXPORTED_FUNCTIONS=_runtime -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o " + path + "/wasm/" + name + ".wasm" + bob_the_stringbuilder = "./emsdk/upstream/emscripten/emcc " + path + "/" + file + " " + extraFlags + " --no-entry -s WASM=1 -s EXPORTED_FUNCTIONS=_runtime -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o " + path + "/wasm/" + name + ".wasm" os.system(bob_the_stringbuilder) return test_names diff --git a/test/wasmBenchmarker/ctests/simdMandelbrotCount.c b/test/wasmBenchmarker/ctests/simdMandelbrotCount.c new file mode 100644 index 000000000..6aa2eebce --- /dev/null +++ b/test/wasmBenchmarker/ctests/simdMandelbrotCount.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023-present Samsung Electronics Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include // SIMD header + +#define WIDTH 1600 +#define HIGHT 1400 +#define N 20 +#define REAL_AXIS_SHIFT -1.8 // ~ horizontal shift +#define IMAGINARY_AXIS_SHIFT -1.0 // ~ vertical shift +#define ZOOM 0.0015 + +#define getNthBit(b, n) ((b & (0b00000001 << (7 - n))) > 0) + +#define setNthBitZero(b, n) b = b & (0b11111111 - (0b00000001 << (7 - n))) + +#define setNthBitOne(b, n) b = b | (0b00000001 << (7 - n)) + +#define SQUARE(num) _mm_mul_ps(num, num) + +#define ABS_COMPLEX(z_real, z_complex) _mm_sqrt_ps(_mm_add_ps(SQUARE(z_real), SQUARE(z_imaginary))) + +typedef uint8_t byte; + +byte areInMandelbrotSet(__m128 c_real, __m128 c_imaginary); + +uint32_t runtime(); + +int main() { + if (WIDTH % 4 != 0) { + return 1; + } + printf("%u\n", runtime()); + return 0; +} + +byte areInMandelbrotSet(__m128 c_real, __m128 c_imaginary) +{ + byte result = 0b11110000; + __m128 z_real = _mm_set1_ps(0); + __m128 z_imaginary = _mm_set1_ps(0); + for (size_t i = 0; i < N; i++) { + __m128 cmp_result = _mm_cmpgt_ps(ABS_COMPLEX(z_real, z_imaginary), _mm_set1_ps(2)); + for (size_t j = 0; j < 4; j++) { + if (getNthBit(result, j) == 1 && ((float*)&cmp_result)[j] != 0) { + setNthBitZero(result, j); + } + } + __m128 next_z_real = _mm_add_ps(_mm_sub_ps(SQUARE(z_real), SQUARE(z_imaginary)), c_real); + __m128 next_z_imaginary = _mm_add_ps(_mm_mul_ps(_mm_mul_ps(z_real, z_imaginary), _mm_set1_ps(2)), c_imaginary); + z_real = next_z_real; + z_imaginary = next_z_imaginary; + if (result == 0b00000000) { + break; + } + } + return result; +} + +uint32_t runtime() { + uint32_t setSize = 0; + for (int i = 0; i < HIGHT; i++) { + for (int j = 0; j < WIDTH; j+=4) { + __m128 real = _mm_add_ps(_mm_mul_ps(_mm_set_ps(j+3, j+2, j+1, j), _mm_set1_ps(ZOOM)), _mm_set1_ps(REAL_AXIS_SHIFT)); + __m128 imaginary = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(i), _mm_set1_ps(ZOOM)), _mm_set1_ps(IMAGINARY_AXIS_SHIFT)); + byte pixels = areInMandelbrotSet(real, imaginary); + for (int i = 0; i < 4; i++) { + if (getNthBit(pixels, i)) { + setSize++; + } + } + } + } + return setSize; +}