Skip to content

Commit

Permalink
Add Mandelbrot SIMD test to the benchmark tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GorogPeter committed Sep 11, 2023
1 parent 583cb15 commit 6614277
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 5 deletions.
18 changes: 13 additions & 5 deletions test/wasmBenchmarker/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@
"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"]

simdTests = ["simdMandelbrotCount"]

def prepare_arg_pars():
parser = argparse.ArgumentParser()
parser.add_argument('--test-dir', metavar='PATH', help='path to the test files written in c', nargs='?',
Expand All @@ -58,6 +61,7 @@ def prepare_arg_pars():
parser.add_argument('--iterations', metavar='NUMBER', help='how many times run the tests', nargs='?',
const='10', default=10, type=int)
parser.add_argument('--compile-anyway', help='compile the tests even if they are compiled', action='store_true')
parser.add_argument('--enable-simd', help='run SIMD tests too', action='store_true')
return parser.parse_args()


Expand Down Expand Up @@ -98,7 +102,7 @@ def get_emcc():
return emcc_path


def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, run=None):
def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, simd=False, run=None):
if not os.path.exists(emcc_path):
print("invalid path for emcc: " + emcc_path)
exit(1)
Expand All @@ -118,7 +122,9 @@ def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, run=No
for file in test_list:
name = file.split('.')[0]

if (name not in gameTests and only_game) or (run is not None and name != run):
if (name not in gameTests and only_game) or \
(run is not None and name != run) or \
(name in simdTests and not simd):
continue

test_names.append(name)
Expand All @@ -127,8 +133,10 @@ def compile_tests(emcc_path, path, only_game=False, compile_anyway=False, run=No
print("target files are found; compilation skipped")
continue

extraFlags = "-mavx -msimd128" if file.startswith("simd") else ""

print("compiling " + name)
bob_the_stringbuilder = emcc_path + " " + 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 = emcc_path + " " + path + "/" + file + " " + extraFlags + " --no-entry -s WASM=1 -s EXPORTED_FUNCTIONS=_runtime -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o " + path + "/wasm/" + name + ".wasm"
print(bob_the_stringbuilder)
os.system(bob_the_stringbuilder)

Expand Down Expand Up @@ -217,7 +225,7 @@ def main():

check_programs(args.engines)
emcc_path = get_emcc()
test_names = compile_tests(emcc_path, args.test_dir, args.only_game, args.compile_anyway, args.run)
test_names = compile_tests(emcc_path, args.test_dir, args.only_game, args.compile_anyway, args.enable_simd, args.run)
generate_report(
run_tests(args.test_dir, test_names, args.engines, args.iterations),
args.report)
Expand Down
91 changes: 91 additions & 0 deletions test/wasmBenchmarker/ctests/simdMandelbrotCount.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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 <stdio.h>
#include <stdbool.h>
#include <stdint.h>

#include <immintrin.h> // SIMD header

#define WIDTH 1600 // WIDTH has to be a multiple of four!
#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 clearNthBit(b, n) b = b & (0b11111111 - (0b00000001 << (7 - n)))

#define setNthBit(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) {
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) {
clearNthBit(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) {
return result;
}
}
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;
}


int main() {
printf("%u\n", runtime());
return 0;
}

0 comments on commit 6614277

Please sign in to comment.