From 0d842a5930e2ea60af68821d20965ddfd0ee8030 Mon Sep 17 00:00:00 2001 From: Richard Yan Date: Wed, 29 Jan 2025 21:22:41 -0800 Subject: [PATCH] more renaming and cleanup --- Makefile | 12 +- ci/blackbox.sh | 310 - ci/regression.sh | 326 - ci/toolchain_prebuilt.sh | 128 - ci/trace_csv.py | 245 - ci/travis_run.py | 68 - {tests/regression => kernels}/Makefile | 0 .../bad_apple/.gitignore | 0 .../regression => kernels}/bad_apple/Makefile | 0 .../regression => kernels}/bad_apple/common.h | 0 .../bad_apple/display.py | 0 .../bad_apple/display.py.bak | 0 .../bad_apple/kernel.cpp | 0 {tests/regression => kernels}/common.mk | 0 .../flash_attention/.gitignore | 0 .../flash_attention/Makefile | 0 .../flash_attention/common.h | 0 .../flash_attention/flash_impl.hpp | 0 .../flash_attention/half.hpp | 0 .../flash_attention/kernel.cpp | 0 .../flash_attention/kernel.gemmini.cpp | 0 .../kernel.gemmini.warpspec.cpp | 0 {tests/regression => kernels}/idle/.gitignore | 0 {tests/regression => kernels}/idle/Makefile | 0 {tests/regression => kernels}/idle/common.h | 0 {tests/regression => kernels}/idle/hello.c | 0 {tests/regression => kernels}/idle/kernel.cpp | 0 .../rickroll/.gitignore | 0 .../regression => kernels}/rickroll/Makefile | 0 .../regression => kernels}/rickroll/common.h | 0 .../rickroll/display_color.py | 0 .../rickroll/kernel.cpp | 0 .../sgemm_gemmini/.gitignore | 0 .../sgemm_gemmini/Makefile | 0 .../regression => kernels}/sgemm_gemmini/args | 0 .../sgemm_gemmini/common.h | 0 .../sgemm_gemmini/compile_ampere.sh | 0 .../sgemm_gemmini/compile_hopper.sh | 0 .../sgemm_gemmini/input.a | 0 .../sgemm_gemmini/input.b | 0 .../sgemm_gemmini/kernel.cpp | 0 .../sgemm_gemmini_dma/.gitignore | 0 .../sgemm_gemmini_dma/Makefile | 0 .../sgemm_gemmini_dma/args/1024 | Bin .../sgemm_gemmini_dma/args/128 | Bin .../sgemm_gemmini_dma/args/256 | Bin .../sgemm_gemmini_dma/args/512 | Bin .../sgemm_gemmini_dma/common.h | 0 .../sgemm_gemmini_dma/compile_ampere.sh | 0 .../sgemm_gemmini_dma/compile_debug.sh | 0 .../sgemm_gemmini_dma/compile_hopper.sh | 0 .../sgemm_gemmini_dma/generate_operands.py | 0 .../sgemm_gemmini_dma/input.a/1024 | Bin .../sgemm_gemmini_dma/input.a/128 | Bin .../sgemm_gemmini_dma/input.a/256 | Bin .../sgemm_gemmini_dma/input.a/512 | Bin .../sgemm_gemmini_dma/input.b/1024 | Bin .../sgemm_gemmini_dma/input.b/128 | Bin .../sgemm_gemmini_dma/input.b/256 | Bin .../sgemm_gemmini_dma/input.b/512 | Bin .../sgemm_gemmini_dma/kernel.activation.cpp | 0 .../sgemm_gemmini_dma/kernel.cpp | 0 .../sgemm_gemmini_duo/.gitignore | 0 .../sgemm_gemmini_duo/Makefile | 0 .../sgemm_gemmini_duo/common.h | 0 .../sgemm_gemmini_duo/kernel.cpp | 0 .../sgemm_gemmini_duo/kernel.serialized.cpp | 0 .../sgemm_tcore/.gitignore | 0 .../sgemm_tcore/Makefile | 0 .../sgemm_tcore/args.bin | 0 .../sgemm_tcore/args.m1024n1024k1024.bin | Bin .../sgemm_tcore/args.m256n256k256.bin | Bin .../sgemm_tcore/args.m512n512k512.bin | Bin .../sgemm_tcore/common.h | 0 .../sgemm_tcore/half.hpp | 0 .../sgemm_tcore/input.a.bin | 0 ....fp16.m1024n1024k1024.col.swizzle_fp16.bin | Bin ...d01.fp16.m256n256k256.col.swizzle_fp16.bin | Bin ...d01.fp16.m512n512k512.col.swizzle_fp16.bin | Bin .../sgemm_tcore/input.b.bin | 0 ....fp16.m1024n1024k1024.row.swizzle_fp16.bin | Bin ...d01.fp16.m256n256k256.row.swizzle_fp16.bin | Bin ...d01.fp16.m512n512k512.row.swizzle_fp16.bin | Bin .../sgemm_tcore/input.c.bin | 0 .../input.c.zero.fp32.m64n64k64.row.bin | Bin .../sgemm_tcore/kernel.4warps.cpp | 0 .../sgemm_tcore/kernel.activation.cpp | 0 .../sgemm_tcore/kernel.cpp | 0 .../sgemm_tcore/kernel.warpspecial.cpp | 0 .../sgemm_tcore/kernel.warpspecial_dma.cpp | 0 .../sgemm_tcore/sgemm_impl.hpp | 0 .../sgemm_tcore/switch_args_input.sh | 0 .../sgemm_wg/.gitignore | 0 .../regression => kernels}/sgemm_wg/Makefile | 0 .../regression => kernels}/sgemm_wg/common.h | 0 .../sgemm_wg/kernel.cpp | 0 .../regression => kernels}/unaligned/Makefile | 0 .../.gitignore => kernels/unaligned/args.bin | 0 .../regression => kernels}/unaligned/common.h | 0 .../README => kernels/unaligned/input.a.bin | 0 .../README => kernels/unaligned/input.b.bin | 0 .../README => kernels/unaligned/input.c.bin | 0 .../unaligned/kernel.cpp | 0 .../unaligned/kernel.minimal.cpp | 0 .../regression => kernels}/vecaddx/Makefile | 0 kernels/vecaddx/args.bin | Bin 0 -> 40 bytes .../regression => kernels}/vecaddx/common.h | 0 kernels/vecaddx/input.a.bin | Bin 0 -> 32768 bytes kernels/vecaddx/input.b.bin | Bin 0 -> 32768 bytes .../README => kernels/vecaddx/input.c.bin | 0 .../regression => kernels}/vecaddx/kernel.cpp | 0 tests/opencl/sfilter/README => lib/.gitignore | 0 {kernel => lib}/Makefile | 0 .../gemmini}/include/accumulator.h | 0 {gemmini => lib/gemmini}/include/character.h | 0 {gemmini => lib/gemmini}/include/gemmini.h | 0 .../gemmini}/include/gemmini_counter.h | 0 {gemmini => lib/gemmini}/include/gemmini_nn.h | 0 .../include/gemmini_params.dim16fp16.h | 0 .../include/gemmini_params.dim8fp32.h | 0 .../gemmini}/include/gemmini_params.h | 0 .../gemmini}/include/gemmini_testutils.h | 0 {gemmini => lib/gemmini}/include/translator.h | 0 .../gemmini}/rocc-software/.gitignore | 0 .../gemmini}/rocc-software/CONTRIBUTING.md | 0 .../gemmini}/rocc-software/LICENSE | 0 .../gemmini}/rocc-software/README.md | 0 .../rocc-software/src/riscv_test_rocc.h | 0 .../gemmini}/rocc-software/src/xcustom.h | 0 {kernel => lib}/include/VX_config.h | 0 {kernel => lib}/include/VX_types.h | 0 {kernel => lib}/include/gemmini_mmio.h | 0 {kernel => lib}/include/vx_intrinsics.h | 0 {kernel => lib}/include/vx_print.h | 0 {kernel => lib}/include/vx_spawn.h | 0 {kernel => lib}/linker/vx_link32.ld | 0 {kernel => lib}/linker/vx_link64.ld | 0 {kernel => lib}/src/tinyprintf.c | 0 {kernel => lib}/src/tinyprintf.h | 0 {kernel => lib}/src/vx_perf.c | 0 {kernel => lib}/src/vx_print.S | 0 {kernel => lib}/src/vx_print.c | 0 {kernel => lib}/src/vx_serial.S | 0 {kernel => lib}/src/vx_spawn.c | 0 {kernel => lib}/src/vx_start.S | 0 {kernel => lib}/src/vx_syscalls.c | 0 {kernel => lib}/tohost.S | 0 {ci => scripts}/toolchain_env.sh | 0 {ci => scripts}/toolchain_install.sh | 0 tests/.gitignore | 7 - tests/Makefile | 19 - tests/opencl/Makefile | 107 - tests/opencl/bfs/CLHelper.h | 859 - tests/opencl/bfs/Makefile | 7 - tests/opencl/bfs/graph4096.txt | 28677 ---------------- tests/opencl/bfs/kernel.cl | 53 - tests/opencl/bfs/kernel.pocl | Bin 40973 -> 0 bytes tests/opencl/bfs/main.cc | 297 - tests/opencl/bfs/run | 1 - tests/opencl/bfs/timer.cc | 78 - tests/opencl/bfs/timer.h | 101 - tests/opencl/bfs/util.h | 72 - tests/opencl/blackscholes/Makefile | 9 - tests/opencl/blackscholes/cmd_arg_reader.cpp | 152 - tests/opencl/blackscholes/cmd_arg_reader.h | 488 - tests/opencl/blackscholes/exception.h | 151 - tests/opencl/blackscholes/kernel.cl | 101 - tests/opencl/blackscholes/main.cpp | 248 - tests/opencl/blackscholes/oclBlackScholes.pdf | Bin 206856 -> 0 bytes .../blackscholes/oclBlackScholes_common.h | 50 - .../blackscholes/oclBlackScholes_gold.cpp | 92 - .../blackscholes/oclBlackScholes_launcher.cpp | 151 - tests/opencl/blackscholes/oclUtils.cpp | 806 - tests/opencl/blackscholes/oclUtils.h | 198 - tests/opencl/blackscholes/shrQATest.h | 238 - tests/opencl/blackscholes/shrUtils.cpp | 1954 -- tests/opencl/blackscholes/shrUtils.h | 642 - tests/opencl/common.mk | 120 - tests/opencl/convolution/Makefile | 7 - tests/opencl/convolution/kernel.cl | 32 - tests/opencl/convolution/main.cc | 285 - tests/opencl/dotproduct/DotProduct.cl | 29 - tests/opencl/dotproduct/Makefile | 7 - tests/opencl/dotproduct/cmd_arg_reader.cpp | 152 - tests/opencl/dotproduct/cmd_arg_reader.h | 488 - tests/opencl/dotproduct/exception.h | 151 - tests/opencl/dotproduct/kernel.cl | 22 - tests/opencl/dotproduct/main.cc | 267 - tests/opencl/dotproduct/oclUtils.cpp | 806 - tests/opencl/dotproduct/oclUtils.h | 198 - tests/opencl/dotproduct/shrQATest.h | 238 - tests/opencl/dotproduct/shrUtils.cpp | 1954 -- tests/opencl/dotproduct/shrUtils.h | 642 - tests/opencl/flops/.depend | 8 - tests/opencl/flops/.gitignore | 6 - tests/opencl/flops/Makefile | 7 - tests/opencl/flops/kernel.cl | 13 - tests/opencl/flops/main.cc | 237 - tests/opencl/guassian/Makefile | 7 - tests/opencl/guassian/OriginalParallel.c | 241 - tests/opencl/guassian/README.txt | 60 - tests/opencl/guassian/clutils.cpp | 1457 - tests/opencl/guassian/clutils.h | 281 - tests/opencl/guassian/gaussianElim.h | 40 - tests/opencl/guassian/gettimeofday.cpp | 74 - tests/opencl/guassian/gettimeofday.h | 17 - tests/opencl/guassian/kernel.cl | 49 - tests/opencl/guassian/main.cc | 420 - tests/opencl/guassian/matrix4.txt | 11 - tests/opencl/guassian/run | 1 - tests/opencl/guassian/utils.cpp | 204 - tests/opencl/guassian/utils.h | 84 - tests/opencl/kmeans/.gitignore | 2 - tests/opencl/kmeans/Makefile | 7 - tests/opencl/kmeans/cluster.c | 155 - tests/opencl/kmeans/getopt.c | 1184 - tests/opencl/kmeans/getopt.h | 191 - tests/opencl/kmeans/kernel.cl | 61 - tests/opencl/kmeans/kmeans.h | 65 - tests/opencl/kmeans/kmeans_clustering.c | 177 - tests/opencl/kmeans/main.cc | 401 - tests/opencl/kmeans/read_input.c | 340 - tests/opencl/kmeans/rmse.c | 94 - tests/opencl/lbm/120_120_150_ldc.of | 18150 ---------- tests/opencl/lbm/Makefile | 9 - tests/opencl/lbm/args.c | 617 - tests/opencl/lbm/gpu_info.c | 55 - tests/opencl/lbm/gpu_info.h | 28 - tests/opencl/lbm/kernel.cl | 424 - tests/opencl/lbm/layout_config.h | 69 - tests/opencl/lbm/lbm.c | 356 - tests/opencl/lbm/lbm.h | 41 - tests/opencl/lbm/lbm_macros.h | 177 - tests/opencl/lbm/main.cc | 260 - tests/opencl/lbm/main.h | 31 - tests/opencl/lbm/ocl.c | 40 - tests/opencl/lbm/ocl.h | 33 - tests/opencl/lbm/parboil.h | 348 - tests/opencl/lbm/parboil_opencl.c | 1409 - tests/opencl/nearn/Makefile | 7 - tests/opencl/nearn/README.txt | 33 - tests/opencl/nearn/cane4_0.db | 10691 ------ tests/opencl/nearn/cane4_1.db | 10691 ------ tests/opencl/nearn/cane4_2.db | 10691 ------ tests/opencl/nearn/cane4_3.db | 10691 ------ tests/opencl/nearn/clutils.cpp | 1457 - tests/opencl/nearn/clutils.h | 281 - tests/opencl/nearn/filelist.txt | 2 - tests/opencl/nearn/inputgen/Makefile | 5 - tests/opencl/nearn/inputgen/gen_dataset.sh | 12 - .../nearn/inputgen/gen_dataset_multifile.sh | 13 - tests/opencl/nearn/inputgen/hurricanegen.c | 105 - tests/opencl/nearn/ipoint.h | 29 - tests/opencl/nearn/kernel.cl | 22 - tests/opencl/nearn/main.cc | 361 - tests/opencl/nearn/nearestNeighbor.h | 50 - tests/opencl/nearn/run | 1 - tests/opencl/nearn/utils.cpp | 204 - tests/opencl/nearn/utils.h | 84 - tests/opencl/oclprintf/Makefile | 7 - tests/opencl/oclprintf/kernel.cl | 6 - tests/opencl/oclprintf/main.cc | 173 - tests/opencl/psort/Makefile | 7 - tests/opencl/psort/kernel.cl | 35 - tests/opencl/psort/main.cc | 241 - tests/opencl/saxpy/Makefile | 7 - tests/opencl/saxpy/kernel.cl | 5 - tests/opencl/saxpy/main.cc | 269 - tests/opencl/sfilter/Makefile | 7 - tests/opencl/sfilter/kernel.cl | 23 - tests/opencl/sfilter/main.cc | 306 - tests/opencl/sgemm/Makefile | 7 - tests/opencl/sgemm/README | 0 tests/opencl/sgemm/common.h | 8 - tests/opencl/sgemm/kernel.cl | 20 - tests/opencl/sgemm/main.cc | 304 - tests/opencl/sharedmem/.depend | 8 - tests/opencl/sharedmem/.gitignore | 5 - tests/opencl/sharedmem/Makefile | 7 - tests/opencl/sharedmem/README | 0 tests/opencl/sharedmem/kernel.cl | 13 - tests/opencl/sharedmem/main.cc | 237 - tests/opencl/smemcoherence/.depend | 8 - tests/opencl/smemcoherence/.gitignore | 5 - tests/opencl/smemcoherence/Makefile | 7 - tests/opencl/smemcoherence/README | 0 tests/opencl/smemcoherence/kernel.cl | 33 - tests/opencl/smemcoherence/main.cc | 238 - tests/opencl/spmv/1138_bus.mtx | 2610 -- tests/opencl/spmv/DESCRIPTION | 3 - tests/opencl/spmv/Makefile | 9 - tests/opencl/spmv/args.c | 617 - tests/opencl/spmv/convert_dataset.c | 352 - tests/opencl/spmv/convert_dataset.h | 17 - tests/opencl/spmv/file.c | 78 - tests/opencl/spmv/file.h | 26 - tests/opencl/spmv/gpu_info.c | 55 - tests/opencl/spmv/gpu_info.h | 28 - tests/opencl/spmv/input/1138_bus.mtx | 2610 -- tests/opencl/spmv/input/1138_bus.mtx.bin | Bin 40431 -> 0 bytes tests/opencl/spmv/input/DESCRIPTION | 3 - tests/opencl/spmv/input/vector.bin | Bin 4552 -> 0 bytes tests/opencl/spmv/kernel.cl | 36 - tests/opencl/spmv/main.cc | 313 - tests/opencl/spmv/mmio.c | 509 - tests/opencl/spmv/mmio.h | 135 - tests/opencl/spmv/ocl.c | 50 - tests/opencl/spmv/ocl.h | 29 - tests/opencl/spmv/parboil.h | 348 - tests/opencl/spmv/parboil_opencl.c | 1390 - tests/opencl/spmv/perf_util.c | 670 - tests/opencl/spmv/perf_util.h | 184 - tests/opencl/spmv/perfmon.c | 281 - tests/opencl/spmv/perfmon.h | 20 - tests/opencl/spmv/stub.cc | 46 - tests/opencl/spmv/vector.bin | Bin 4552 -> 0 bytes tests/opencl/stencil/128x128x32.bin | Bin 2097152 -> 0 bytes tests/opencl/stencil/Makefile | 9 - tests/opencl/stencil/args.c | 617 - tests/opencl/stencil/file.c | 78 - tests/opencl/stencil/file.h | 18 - tests/opencl/stencil/gpu_info.c | 55 - tests/opencl/stencil/gpu_info.h | 20 - tests/opencl/stencil/kernel.cl | 28 - tests/opencl/stencil/main.cc | 266 - tests/opencl/stencil/ocl.c | 50 - tests/opencl/stencil/ocl.h | 21 - tests/opencl/stencil/parboil.h | 348 - tests/opencl/stencil/parboil_opencl.c | 1390 - tests/opencl/transpose/.gitignore | 1 - tests/opencl/transpose/Makefile | 9 - tests/opencl/transpose/cmd_arg_reader.cpp | 152 - tests/opencl/transpose/cmd_arg_reader.h | 488 - tests/opencl/transpose/exception.h | 151 - tests/opencl/transpose/kernel.cl | 108 - tests/opencl/transpose/main.cc | 390 - tests/opencl/transpose/oclUtils.cpp | 806 - tests/opencl/transpose/oclUtils.h | 198 - tests/opencl/transpose/shrQATest.h | 238 - tests/opencl/transpose/shrUtils.cpp | 1950 -- tests/opencl/transpose/shrUtils.h | 642 - tests/opencl/transpose/transpose_gold.cpp | 38 - tests/opencl/vecadd/.gitignore | 1 - tests/opencl/vecadd/Makefile | 7 - tests/opencl/vecadd/README | 0 tests/opencl/vecadd/kernel.cl | 7 - tests/opencl/vecadd/main.cc | 241 - tests/regression/common.mk.muon | 145 - 348 files changed, 6 insertions(+), 136287 deletions(-) delete mode 100755 ci/blackbox.sh delete mode 100755 ci/regression.sh delete mode 100755 ci/toolchain_prebuilt.sh delete mode 100755 ci/trace_csv.py delete mode 100755 ci/travis_run.py rename {tests/regression => kernels}/Makefile (100%) rename {tests/regression => kernels}/bad_apple/.gitignore (100%) rename {tests/regression => kernels}/bad_apple/Makefile (100%) rename {tests/regression => kernels}/bad_apple/common.h (100%) rename {tests/regression => kernels}/bad_apple/display.py (100%) rename {tests/regression => kernels}/bad_apple/display.py.bak (100%) rename {tests/regression => kernels}/bad_apple/kernel.cpp (100%) rename {tests/regression => kernels}/common.mk (100%) rename {tests/regression => kernels}/flash_attention/.gitignore (100%) rename {tests/regression => kernels}/flash_attention/Makefile (100%) rename {tests/regression => kernels}/flash_attention/common.h (100%) rename {tests/regression => kernels}/flash_attention/flash_impl.hpp (100%) rename {tests/regression => kernels}/flash_attention/half.hpp (100%) rename {tests/regression => kernels}/flash_attention/kernel.cpp (100%) rename {tests/regression => kernels}/flash_attention/kernel.gemmini.cpp (100%) rename {tests/regression => kernels}/flash_attention/kernel.gemmini.warpspec.cpp (100%) rename {tests/regression => kernels}/idle/.gitignore (100%) rename {tests/regression => kernels}/idle/Makefile (100%) rename {tests/regression => kernels}/idle/common.h (100%) rename {tests/regression => kernels}/idle/hello.c (100%) rename {tests/regression => kernels}/idle/kernel.cpp (100%) rename {tests/regression => kernels}/rickroll/.gitignore (100%) rename {tests/regression => kernels}/rickroll/Makefile (100%) rename {tests/regression => kernels}/rickroll/common.h (100%) rename {tests/regression => kernels}/rickroll/display_color.py (100%) rename {tests/regression => kernels}/rickroll/kernel.cpp (100%) rename {tests/regression => kernels}/sgemm_gemmini/.gitignore (100%) rename {tests/regression => kernels}/sgemm_gemmini/Makefile (100%) rename {tests/regression => kernels}/sgemm_gemmini/args (100%) rename {tests/regression => kernels}/sgemm_gemmini/common.h (100%) rename {tests/regression => kernels}/sgemm_gemmini/compile_ampere.sh (100%) rename {tests/regression => kernels}/sgemm_gemmini/compile_hopper.sh (100%) rename {tests/regression => kernels}/sgemm_gemmini/input.a (100%) rename {tests/regression => kernels}/sgemm_gemmini/input.b (100%) rename {tests/regression => kernels}/sgemm_gemmini/kernel.cpp (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/.gitignore (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/Makefile (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/args/1024 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/args/128 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/args/256 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/args/512 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/common.h (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/compile_ampere.sh (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/compile_debug.sh (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/compile_hopper.sh (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/generate_operands.py (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.a/1024 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.a/128 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.a/256 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.a/512 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.b/1024 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.b/128 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.b/256 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/input.b/512 (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/kernel.activation.cpp (100%) rename {tests/regression => kernels}/sgemm_gemmini_dma/kernel.cpp (100%) rename {tests/regression => kernels}/sgemm_gemmini_duo/.gitignore (100%) rename {tests/regression => kernels}/sgemm_gemmini_duo/Makefile (100%) rename {tests/regression => kernels}/sgemm_gemmini_duo/common.h (100%) rename {tests/regression => kernels}/sgemm_gemmini_duo/kernel.cpp (100%) rename {tests/regression => kernels}/sgemm_gemmini_duo/kernel.serialized.cpp (100%) rename {tests/regression => kernels}/sgemm_tcore/.gitignore (100%) rename {tests/regression => kernels}/sgemm_tcore/Makefile (100%) rename {tests/regression => kernels}/sgemm_tcore/args.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/args.m1024n1024k1024.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/args.m256n256k256.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/args.m512n512k512.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/common.h (100%) rename {tests/regression => kernels}/sgemm_tcore/half.hpp (100%) rename {tests/regression => kernels}/sgemm_tcore/input.a.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.a.rand01.fp16.m1024n1024k1024.col.swizzle_fp16.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.a.rand01.fp16.m256n256k256.col.swizzle_fp16.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.a.rand01.fp16.m512n512k512.col.swizzle_fp16.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.b.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.b.rand01.fp16.m1024n1024k1024.row.swizzle_fp16.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.b.rand01.fp16.m256n256k256.row.swizzle_fp16.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.b.rand01.fp16.m512n512k512.row.swizzle_fp16.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.c.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/input.c.zero.fp32.m64n64k64.row.bin (100%) rename {tests/regression => kernels}/sgemm_tcore/kernel.4warps.cpp (100%) rename {tests/regression => kernels}/sgemm_tcore/kernel.activation.cpp (100%) rename {tests/regression => kernels}/sgemm_tcore/kernel.cpp (100%) rename {tests/regression => kernels}/sgemm_tcore/kernel.warpspecial.cpp (100%) rename {tests/regression => kernels}/sgemm_tcore/kernel.warpspecial_dma.cpp (100%) rename {tests/regression => kernels}/sgemm_tcore/sgemm_impl.hpp (100%) rename {tests/regression => kernels}/sgemm_tcore/switch_args_input.sh (100%) rename {tests/regression => kernels}/sgemm_wg/.gitignore (100%) rename {tests/regression => kernels}/sgemm_wg/Makefile (100%) rename {tests/regression => kernels}/sgemm_wg/common.h (100%) rename {tests/regression => kernels}/sgemm_wg/kernel.cpp (100%) rename {tests/regression => kernels}/unaligned/Makefile (100%) rename kernel/.gitignore => kernels/unaligned/args.bin (100%) rename {tests/regression => kernels}/unaligned/common.h (100%) rename tests/opencl/bfs/README => kernels/unaligned/input.a.bin (100%) rename tests/opencl/flops/README => kernels/unaligned/input.b.bin (100%) rename tests/opencl/kmeans/README => kernels/unaligned/input.c.bin (100%) rename {tests/regression => kernels}/unaligned/kernel.cpp (100%) rename {tests/regression => kernels}/unaligned/kernel.minimal.cpp (100%) rename {tests/regression => kernels}/vecaddx/Makefile (100%) create mode 100644 kernels/vecaddx/args.bin rename {tests/regression => kernels}/vecaddx/common.h (100%) create mode 100644 kernels/vecaddx/input.a.bin create mode 100644 kernels/vecaddx/input.b.bin rename tests/opencl/saxpy/README => kernels/vecaddx/input.c.bin (100%) rename {tests/regression => kernels}/vecaddx/kernel.cpp (100%) rename tests/opencl/sfilter/README => lib/.gitignore (100%) rename {kernel => lib}/Makefile (100%) rename {gemmini => lib/gemmini}/include/accumulator.h (100%) rename {gemmini => lib/gemmini}/include/character.h (100%) rename {gemmini => lib/gemmini}/include/gemmini.h (100%) rename {gemmini => lib/gemmini}/include/gemmini_counter.h (100%) rename {gemmini => lib/gemmini}/include/gemmini_nn.h (100%) rename {gemmini => lib/gemmini}/include/gemmini_params.dim16fp16.h (100%) rename {gemmini => lib/gemmini}/include/gemmini_params.dim8fp32.h (100%) rename {gemmini => lib/gemmini}/include/gemmini_params.h (100%) rename {gemmini => lib/gemmini}/include/gemmini_testutils.h (100%) rename {gemmini => lib/gemmini}/include/translator.h (100%) rename {gemmini => lib/gemmini}/rocc-software/.gitignore (100%) rename {gemmini => lib/gemmini}/rocc-software/CONTRIBUTING.md (100%) rename {gemmini => lib/gemmini}/rocc-software/LICENSE (100%) rename {gemmini => lib/gemmini}/rocc-software/README.md (100%) rename {gemmini => lib/gemmini}/rocc-software/src/riscv_test_rocc.h (100%) rename {gemmini => lib/gemmini}/rocc-software/src/xcustom.h (100%) rename {kernel => lib}/include/VX_config.h (100%) rename {kernel => lib}/include/VX_types.h (100%) rename {kernel => lib}/include/gemmini_mmio.h (100%) rename {kernel => lib}/include/vx_intrinsics.h (100%) rename {kernel => lib}/include/vx_print.h (100%) rename {kernel => lib}/include/vx_spawn.h (100%) rename {kernel => lib}/linker/vx_link32.ld (100%) rename {kernel => lib}/linker/vx_link64.ld (100%) rename {kernel => lib}/src/tinyprintf.c (100%) rename {kernel => lib}/src/tinyprintf.h (100%) rename {kernel => lib}/src/vx_perf.c (100%) rename {kernel => lib}/src/vx_print.S (100%) rename {kernel => lib}/src/vx_print.c (100%) rename {kernel => lib}/src/vx_serial.S (100%) rename {kernel => lib}/src/vx_spawn.c (100%) rename {kernel => lib}/src/vx_start.S (100%) rename {kernel => lib}/src/vx_syscalls.c (100%) rename {kernel => lib}/tohost.S (100%) rename {ci => scripts}/toolchain_env.sh (100%) rename {ci => scripts}/toolchain_install.sh (100%) delete mode 100644 tests/.gitignore delete mode 100644 tests/Makefile delete mode 100644 tests/opencl/Makefile delete mode 100755 tests/opencl/bfs/CLHelper.h delete mode 100644 tests/opencl/bfs/Makefile delete mode 100755 tests/opencl/bfs/graph4096.txt delete mode 100755 tests/opencl/bfs/kernel.cl delete mode 100644 tests/opencl/bfs/kernel.pocl delete mode 100755 tests/opencl/bfs/main.cc delete mode 100755 tests/opencl/bfs/run delete mode 100755 tests/opencl/bfs/timer.cc delete mode 100755 tests/opencl/bfs/timer.h delete mode 100755 tests/opencl/bfs/util.h delete mode 100644 tests/opencl/blackscholes/Makefile delete mode 100644 tests/opencl/blackscholes/cmd_arg_reader.cpp delete mode 100644 tests/opencl/blackscholes/cmd_arg_reader.h delete mode 100644 tests/opencl/blackscholes/exception.h delete mode 100644 tests/opencl/blackscholes/kernel.cl delete mode 100644 tests/opencl/blackscholes/main.cpp delete mode 100644 tests/opencl/blackscholes/oclBlackScholes.pdf delete mode 100644 tests/opencl/blackscholes/oclBlackScholes_common.h delete mode 100644 tests/opencl/blackscholes/oclBlackScholes_gold.cpp delete mode 100644 tests/opencl/blackscholes/oclBlackScholes_launcher.cpp delete mode 100644 tests/opencl/blackscholes/oclUtils.cpp delete mode 100644 tests/opencl/blackscholes/oclUtils.h delete mode 100644 tests/opencl/blackscholes/shrQATest.h delete mode 100644 tests/opencl/blackscholes/shrUtils.cpp delete mode 100644 tests/opencl/blackscholes/shrUtils.h delete mode 100644 tests/opencl/common.mk delete mode 100644 tests/opencl/convolution/Makefile delete mode 100644 tests/opencl/convolution/kernel.cl delete mode 100644 tests/opencl/convolution/main.cc delete mode 100644 tests/opencl/dotproduct/DotProduct.cl delete mode 100644 tests/opencl/dotproduct/Makefile delete mode 100644 tests/opencl/dotproduct/cmd_arg_reader.cpp delete mode 100644 tests/opencl/dotproduct/cmd_arg_reader.h delete mode 100644 tests/opencl/dotproduct/exception.h delete mode 100644 tests/opencl/dotproduct/kernel.cl delete mode 100644 tests/opencl/dotproduct/main.cc delete mode 100644 tests/opencl/dotproduct/oclUtils.cpp delete mode 100644 tests/opencl/dotproduct/oclUtils.h delete mode 100644 tests/opencl/dotproduct/shrQATest.h delete mode 100644 tests/opencl/dotproduct/shrUtils.cpp delete mode 100644 tests/opencl/dotproduct/shrUtils.h delete mode 100644 tests/opencl/flops/.depend delete mode 100644 tests/opencl/flops/.gitignore delete mode 100644 tests/opencl/flops/Makefile delete mode 100644 tests/opencl/flops/kernel.cl delete mode 100644 tests/opencl/flops/main.cc delete mode 100644 tests/opencl/guassian/Makefile delete mode 100755 tests/opencl/guassian/OriginalParallel.c delete mode 100755 tests/opencl/guassian/README.txt delete mode 100755 tests/opencl/guassian/clutils.cpp delete mode 100755 tests/opencl/guassian/clutils.h delete mode 100755 tests/opencl/guassian/gaussianElim.h delete mode 100755 tests/opencl/guassian/gettimeofday.cpp delete mode 100755 tests/opencl/guassian/gettimeofday.h delete mode 100755 tests/opencl/guassian/kernel.cl delete mode 100755 tests/opencl/guassian/main.cc delete mode 100755 tests/opencl/guassian/matrix4.txt delete mode 100755 tests/opencl/guassian/run delete mode 100755 tests/opencl/guassian/utils.cpp delete mode 100755 tests/opencl/guassian/utils.h delete mode 100644 tests/opencl/kmeans/.gitignore delete mode 100644 tests/opencl/kmeans/Makefile delete mode 100755 tests/opencl/kmeans/cluster.c delete mode 100755 tests/opencl/kmeans/getopt.c delete mode 100755 tests/opencl/kmeans/getopt.h delete mode 100755 tests/opencl/kmeans/kernel.cl delete mode 100755 tests/opencl/kmeans/kmeans.h delete mode 100755 tests/opencl/kmeans/kmeans_clustering.c delete mode 100755 tests/opencl/kmeans/main.cc delete mode 100755 tests/opencl/kmeans/read_input.c delete mode 100755 tests/opencl/kmeans/rmse.c delete mode 100644 tests/opencl/lbm/120_120_150_ldc.of delete mode 100644 tests/opencl/lbm/Makefile delete mode 100644 tests/opencl/lbm/args.c delete mode 100644 tests/opencl/lbm/gpu_info.c delete mode 100644 tests/opencl/lbm/gpu_info.h delete mode 100644 tests/opencl/lbm/kernel.cl delete mode 100644 tests/opencl/lbm/layout_config.h delete mode 100644 tests/opencl/lbm/lbm.c delete mode 100644 tests/opencl/lbm/lbm.h delete mode 100644 tests/opencl/lbm/lbm_macros.h delete mode 100644 tests/opencl/lbm/main.cc delete mode 100644 tests/opencl/lbm/main.h delete mode 100644 tests/opencl/lbm/ocl.c delete mode 100644 tests/opencl/lbm/ocl.h delete mode 100644 tests/opencl/lbm/parboil.h delete mode 100644 tests/opencl/lbm/parboil_opencl.c delete mode 100644 tests/opencl/nearn/Makefile delete mode 100755 tests/opencl/nearn/README.txt delete mode 100755 tests/opencl/nearn/cane4_0.db delete mode 100755 tests/opencl/nearn/cane4_1.db delete mode 100755 tests/opencl/nearn/cane4_2.db delete mode 100755 tests/opencl/nearn/cane4_3.db delete mode 100755 tests/opencl/nearn/clutils.cpp delete mode 100755 tests/opencl/nearn/clutils.h delete mode 100755 tests/opencl/nearn/filelist.txt delete mode 100644 tests/opencl/nearn/inputgen/Makefile delete mode 100644 tests/opencl/nearn/inputgen/gen_dataset.sh delete mode 100644 tests/opencl/nearn/inputgen/gen_dataset_multifile.sh delete mode 100644 tests/opencl/nearn/inputgen/hurricanegen.c delete mode 100755 tests/opencl/nearn/ipoint.h delete mode 100755 tests/opencl/nearn/kernel.cl delete mode 100755 tests/opencl/nearn/main.cc delete mode 100755 tests/opencl/nearn/nearestNeighbor.h delete mode 100755 tests/opencl/nearn/run delete mode 100755 tests/opencl/nearn/utils.cpp delete mode 100755 tests/opencl/nearn/utils.h delete mode 100644 tests/opencl/oclprintf/Makefile delete mode 100644 tests/opencl/oclprintf/kernel.cl delete mode 100644 tests/opencl/oclprintf/main.cc delete mode 100644 tests/opencl/psort/Makefile delete mode 100644 tests/opencl/psort/kernel.cl delete mode 100644 tests/opencl/psort/main.cc delete mode 100644 tests/opencl/saxpy/Makefile delete mode 100644 tests/opencl/saxpy/kernel.cl delete mode 100644 tests/opencl/saxpy/main.cc delete mode 100644 tests/opencl/sfilter/Makefile delete mode 100644 tests/opencl/sfilter/kernel.cl delete mode 100644 tests/opencl/sfilter/main.cc delete mode 100644 tests/opencl/sgemm/Makefile delete mode 100644 tests/opencl/sgemm/README delete mode 100644 tests/opencl/sgemm/common.h delete mode 100644 tests/opencl/sgemm/kernel.cl delete mode 100644 tests/opencl/sgemm/main.cc delete mode 100644 tests/opencl/sharedmem/.depend delete mode 100644 tests/opencl/sharedmem/.gitignore delete mode 100644 tests/opencl/sharedmem/Makefile delete mode 100644 tests/opencl/sharedmem/README delete mode 100644 tests/opencl/sharedmem/kernel.cl delete mode 100644 tests/opencl/sharedmem/main.cc delete mode 100644 tests/opencl/smemcoherence/.depend delete mode 100644 tests/opencl/smemcoherence/.gitignore delete mode 100644 tests/opencl/smemcoherence/Makefile delete mode 100644 tests/opencl/smemcoherence/README delete mode 100644 tests/opencl/smemcoherence/kernel.cl delete mode 100644 tests/opencl/smemcoherence/main.cc delete mode 100755 tests/opencl/spmv/1138_bus.mtx delete mode 100755 tests/opencl/spmv/DESCRIPTION delete mode 100644 tests/opencl/spmv/Makefile delete mode 100644 tests/opencl/spmv/args.c delete mode 100644 tests/opencl/spmv/convert_dataset.c delete mode 100644 tests/opencl/spmv/convert_dataset.h delete mode 100644 tests/opencl/spmv/file.c delete mode 100644 tests/opencl/spmv/file.h delete mode 100644 tests/opencl/spmv/gpu_info.c delete mode 100644 tests/opencl/spmv/gpu_info.h delete mode 100755 tests/opencl/spmv/input/1138_bus.mtx delete mode 100755 tests/opencl/spmv/input/1138_bus.mtx.bin delete mode 100755 tests/opencl/spmv/input/DESCRIPTION delete mode 100644 tests/opencl/spmv/input/vector.bin delete mode 100644 tests/opencl/spmv/kernel.cl delete mode 100644 tests/opencl/spmv/main.cc delete mode 100644 tests/opencl/spmv/mmio.c delete mode 100644 tests/opencl/spmv/mmio.h delete mode 100644 tests/opencl/spmv/ocl.c delete mode 100644 tests/opencl/spmv/ocl.h delete mode 100644 tests/opencl/spmv/parboil.h delete mode 100644 tests/opencl/spmv/parboil_opencl.c delete mode 100644 tests/opencl/spmv/perf_util.c delete mode 100644 tests/opencl/spmv/perf_util.h delete mode 100644 tests/opencl/spmv/perfmon.c delete mode 100644 tests/opencl/spmv/perfmon.h delete mode 100644 tests/opencl/spmv/stub.cc delete mode 100644 tests/opencl/spmv/vector.bin delete mode 100644 tests/opencl/stencil/128x128x32.bin delete mode 100644 tests/opencl/stencil/Makefile delete mode 100644 tests/opencl/stencil/args.c delete mode 100644 tests/opencl/stencil/file.c delete mode 100644 tests/opencl/stencil/file.h delete mode 100644 tests/opencl/stencil/gpu_info.c delete mode 100644 tests/opencl/stencil/gpu_info.h delete mode 100644 tests/opencl/stencil/kernel.cl delete mode 100644 tests/opencl/stencil/main.cc delete mode 100644 tests/opencl/stencil/ocl.c delete mode 100644 tests/opencl/stencil/ocl.h delete mode 100644 tests/opencl/stencil/parboil.h delete mode 100644 tests/opencl/stencil/parboil_opencl.c delete mode 100644 tests/opencl/transpose/.gitignore delete mode 100644 tests/opencl/transpose/Makefile delete mode 100644 tests/opencl/transpose/cmd_arg_reader.cpp delete mode 100644 tests/opencl/transpose/cmd_arg_reader.h delete mode 100644 tests/opencl/transpose/exception.h delete mode 100644 tests/opencl/transpose/kernel.cl delete mode 100644 tests/opencl/transpose/main.cc delete mode 100644 tests/opencl/transpose/oclUtils.cpp delete mode 100644 tests/opencl/transpose/oclUtils.h delete mode 100644 tests/opencl/transpose/shrQATest.h delete mode 100644 tests/opencl/transpose/shrUtils.cpp delete mode 100644 tests/opencl/transpose/shrUtils.h delete mode 100644 tests/opencl/transpose/transpose_gold.cpp delete mode 100644 tests/opencl/vecadd/.gitignore delete mode 100644 tests/opencl/vecadd/Makefile delete mode 100644 tests/opencl/vecadd/README delete mode 100644 tests/opencl/vecadd/kernel.cl delete mode 100644 tests/opencl/vecadd/main.cc delete mode 100644 tests/regression/common.mk.muon diff --git a/Makefile b/Makefile index 4498d56b..aeec6f9d 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ all: - $(MAKE) -C kernel - $(MAKE) -C tests + $(MAKE) -C lib + $(MAKE) -C kernels clean: - $(MAKE) -C kernel clean - $(MAKE) -C tests clean + $(MAKE) -C lib clean + $(MAKE) -C kernels clean clean-all: - $(MAKE) -C kernel clean - $(MAKE) -C tests clean-all + $(MAKE) -C lib clean + $(MAKE) -C kernels clean-all diff --git a/ci/blackbox.sh b/ci/blackbox.sh deleted file mode 100755 index d5deacec..00000000 --- a/ci/blackbox.sh +++ /dev/null @@ -1,310 +0,0 @@ -#!/bin/sh - -# Copyright © 2019-2023 -# -# 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. - -show_usage() -{ - echo "Vortex BlackBox Test Driver v1.0" - echo "Usage: $0 [[--clusters=#n] [--cores=#n] [--warps=#n] [--threads=#n] [--l2cache] [--l3cache] [[--driver=#name] [--app=#app] [--args=#args] [--debug=#level] [--scope] [--perf=#class] [--rebuild=#n] [--log=logfile] [--help]]" -} - -show_help() -{ - show_usage - echo " where" - echo "--driver: simx, rtlsim, oape, xrt" - echo "--app: any subfolder test under regression or opencl" - echo "--class: 0=disable, 1=pipeline, 2=memsys" - echo "--rebuild: 0=disable, 1=force, 2=auto, 3=temp" -} - -SCRIPT_DIR=$(dirname "$0") -VORTEX_HOME=$SCRIPT_DIR/.. - -DRIVER=simx -APP=sgemm -CLUSTERS=1 -CORES=1 -WARPS=4 -THREADS=4 -L2= -L3= -DEBUG=0 -DEBUG_LEVEL=0 -SCOPE=0 -HAS_ARGS=0 -PERF_CLASS=0 -REBUILD=2 -TEMPBUILD=0 -LOGFILE=run.log - -for i in "$@" -do -case $i in - --driver=*) - DRIVER=${i#*=} - shift - ;; - --app=*) - APP=${i#*=} - shift - ;; - --clusters=*) - CLUSTERS=${i#*=} - shift - ;; - --cores=*) - CORES=${i#*=} - shift - ;; - --warps=*) - WARPS=${i#*=} - shift - ;; - --threads=*) - THREADS=${i#*=} - shift - ;; - --l2cache) - L2=-DL2_ENABLE - shift - ;; - --l3cache) - L3=-DL3_ENABLE - shift - ;; - --debug=*) - DEBUG_LEVEL=${i#*=} - DEBUG=1 - shift - ;; - --scope) - SCOPE=1 - CORES=1 - shift - ;; - --perf=*) - PERF_FLAG=-DPERF_ENABLE - PERF_CLASS=${i#*=} - shift - ;; - --args=*) - ARGS=${i#*=} - HAS_ARGS=1 - shift - ;; - --rebuild=*) - REBUILD=${i#*=} - shift - ;; - --log=*) - LOGFILE=${i#*=} - shift - ;; - --help) - show_help - exit 0 - ;; - *) - show_usage - exit -1 - ;; -esac -done - -if [ $REBUILD -eq 3 ]; -then - REBUILD=1 - TEMPBUILD=1 -fi - -case $DRIVER in - simx) - DRIVER_PATH=$VORTEX_HOME/runtime/simx - ;; - rtlsim) - DRIVER_PATH=$VORTEX_HOME/runtime/rtlsim - ;; - opae) - DRIVER_PATH=$VORTEX_HOME/runtime/opae - ;; - xrt) - DRIVER_PATH=$VORTEX_HOME/runtime/xrt - ;; - *) - echo "invalid driver: $DRIVER" - exit -1 - ;; -esac - -if [ -d "$VORTEX_HOME/tests/opencl/$APP" ]; -then - APP_PATH=$VORTEX_HOME/tests/opencl/$APP -elif [ -d "$VORTEX_HOME/tests/regression/$APP" ]; -then - APP_PATH=$VORTEX_HOME/tests/regression/$APP -else - echo "Application folder not found: $APP" - exit -1 -fi - -CONFIGS="-DNUM_CLUSTERS=$CLUSTERS -DNUM_CORES=$CORES -DNUM_WARPS=$WARPS -DNUM_THREADS=$THREADS $L2 $L3 $PERF_FLAG $CONFIGS" - -echo "CONFIGS=$CONFIGS" - -if [ $REBUILD -ne 0 ] -then - BLACKBOX_CACHE=blackbox.$DRIVER.cache - if [ -f "$BLACKBOX_CACHE" ] - then - LAST_CONFIGS=`cat $BLACKBOX_CACHE` - fi - - if [ $REBUILD -eq 1 ] || [ "$CONFIGS+$DEBUG+$SCOPE" != "$LAST_CONFIGS" ]; - then - make -C $DRIVER_PATH clean > /dev/null - echo "$CONFIGS+$DEBUG+$SCOPE" > $BLACKBOX_CACHE - fi -fi - -# export performance monitor class identifier -export PERF_CLASS=$PERF_CLASS - -status=0 - -# ensure config update -make -C $VORTEX_HOME/hw config > /dev/null - -# ensure the stub driver is present -make -C $VORTEX_HOME/runtime/stub > /dev/null - -if [ $DEBUG -ne 0 ] -then - # running application - if [ $TEMPBUILD -eq 1 ] - then - # setup temp directory - TEMPDIR=$(mktemp -d) - mkdir -p "$TEMPDIR/$DRIVER" - - # driver initialization - if [ $SCOPE -eq 1 ] - then - echo "running: DESTDIR=$TEMPDIR/$DRIVER DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" - DESTDIR="$TEMPDIR/$DRIVER" DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - else - echo "running: DESTDIR=$TEMPDIR/$DRIVER DEBUG=$DEBUG_LEVEL CONFIGS=$CONFIGS make -C $DRIVER_PATH" - DESTDIR="$TEMPDIR/$DRIVER" DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - fi - - # running application - if [ $HAS_ARGS -eq 1 ] - then - echo "running: VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" - VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 - status=$? - else - echo "running: VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" - VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 - status=$? - fi - - # cleanup temp directory - trap "rm -rf $TEMPDIR" EXIT - else - # driver initialization - if [ $SCOPE -eq 1 ] - then - echo "running: DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" - DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - else - echo "running: DEBUG=$DEBUG_LEVEL CONFIGS=$CONFIGS make -C $DRIVER_PATH" - DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - fi - - # running application - if [ $HAS_ARGS -eq 1 ] - then - echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" - OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 - status=$? - else - echo "running: make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" - make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 - status=$? - fi - fi - - if [ -f "$APP_PATH/trace.vcd" ] - then - mv -f $APP_PATH/trace.vcd . - fi -else - if [ $TEMPBUILD -eq 1 ] - then - # setup temp directory - TEMPDIR=$(mktemp -d) - mkdir -p "$TEMPDIR/$DRIVER" - - # driver initialization - if [ $SCOPE -eq 1 ] - then - echo "running: DESTDIR=$TEMPDIR/$DRIVER SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" - DESTDIR="$TEMPDIR/$DRIVER" SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - else - echo "running: DESTDIR=$TEMPDIR/$DRIVER CONFIGS=$CONFIGS make -C $DRIVER_PATH" - DESTDIR="$TEMPDIR/$DRIVER" CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - fi - - # running application - if [ $HAS_ARGS -eq 1 ] - then - echo "running: VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER" - VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER - status=$? - else - echo "running: VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER" - VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER - status=$? - fi - - # cleanup temp directory - trap "rm -rf $TEMPDIR" EXIT - else - - # driver initialization - if [ $SCOPE -eq 1 ] - then - echo "running: SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" - SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - else - echo "running: CONFIGS=$CONFIGS make -C $DRIVER_PATH" - CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - fi - - # running application - if [ $HAS_ARGS -eq 1 ] - then - echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER" - OPTS=$ARGS make -C $APP_PATH run-$DRIVER - status=$? - else - echo "running: make -C $APP_PATH run-$DRIVER" - make -C $APP_PATH run-$DRIVER - status=$? - fi - fi -fi - -exit $status diff --git a/ci/regression.sh b/ci/regression.sh deleted file mode 100755 index 41ce8332..00000000 --- a/ci/regression.sh +++ /dev/null @@ -1,326 +0,0 @@ -#!/bin/bash - -# Copyright © 2019-2023 -# -# 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. - -# exit when any command fails -set -e - -# clear blackbox cache -rm -f blackbox.*.cache - -unittest() -{ -make -C tests/unittest run -make -C hw/unittest > /dev/null -} - -isa() -{ -echo "begin isa tests..." - -make -C tests/riscv/isa run-simx -make -C tests/riscv/isa run-rtlsim - -make -C sim/rtlsim clean && CONFIGS="-DDPI_DISABLE" make -C sim/rtlsim > /dev/null -make -C tests/riscv/isa run-rtlsim - -make -C sim/rtlsim clean && CONFIGS="-DFPU_FPNEW" make -C sim/rtlsim > /dev/null -make -C tests/riscv/isa run-rtlsim-32f - -make -C sim/rtlsim clean && CONFIGS="-DFPU_DPI" make -C sim/rtlsim > /dev/null -make -C tests/riscv/isa run-rtlsim-32f - -make -C sim/rtlsim clean && CONFIGS="-DFPU_DSP" make -C sim/rtlsim > /dev/null -make -C tests/riscv/isa run-rtlsim-32f - -if [ "$XLEN" == "64" ] -then - make -C sim/rtlsim clean && CONFIGS="-DFPU_FPNEW" make -C sim/rtlsim > /dev/null - make -C tests/riscv/isa run-rtlsim-64f - - make -C sim/rtlsim clean && CONFIGS="-DEXT_D_ENABLE -DFPU_FPNEW" make -C sim/rtlsim > /dev/null - make -C tests/riscv/isa run-rtlsim-64d || true - - make -C sim/rtlsim clean && CONFIGS="-DFPU_DPI" make -C sim/rtlsim > /dev/null - make -C tests/riscv/isa run-rtlsim-64f - - make -C sim/rtlsim clean && CONFIGS="-DFPU_DSP" make -C sim/rtlsim > /dev/null - make -C tests/riscv/isa run-rtlsim-64fx -fi - -# restore default prebuilt configuration -make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null - -echo "isa tests done!" -} - -regression() -{ -echo "begin regression tests..." - -make -C tests/kernel run-simx -make -C tests/kernel run-rtlsim - -make -C tests/regression run-simx -make -C tests/regression run-rtlsim - -# test FPU hardware implementations -CONFIGS="-DFPU_DPI" ./ci/blackbox.sh --driver=rtlsim --app=dogfood -CONFIGS="-DFPU_DSP" ./ci/blackbox.sh --driver=rtlsim --app=dogfood -CONFIGS="-DFPU_FPNEW" ./ci/blackbox.sh --driver=rtlsim --app=dogfood - -# test local barrier -./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -t19" -./ci/blackbox.sh --driver=rtlsim --app=dogfood --args="-n1 -t19" - -# test global barrier -CONFIGS="-DGBAR_ENABLE" ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -t20" --cores=2 -CONFIGS="-DGBAR_ENABLE" ./ci/blackbox.sh --driver=rtlsim --app=dogfood --args="-n1 -t20" --cores=2 - -# test FPU core - -echo "regression tests done!" -} - -opencl() -{ -echo "begin opencl tests..." - -make -C tests/opencl run-simx -make -C tests/opencl run-rtlsim - -echo "opencl tests done!" -} - -cluster() -{ -echo "begin clustering tests..." - -# warp/threads configurations -./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=1 --threads=1 --app=diverge -./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=2 --app=diverge -./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=8 --app=diverge -./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=8 --threads=2 --app=diverge -./ci/blackbox.sh --driver=simx --cores=1 --warps=1 --threads=1 --app=diverge -./ci/blackbox.sh --driver=simx --cores=1 --warps=8 --threads=16 --app=diverge - -# cores clustering -./ci/blackbox.sh --driver=rtlsim --cores=1 --clusters=1 --app=diverge --args="-n1" -./ci/blackbox.sh --driver=rtlsim --cores=4 --clusters=1 --app=diverge --args="-n1" -./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=diverge --args="-n1" -./ci/blackbox.sh --driver=simx --cores=4 --clusters=1 --app=diverge --args="-n1" -./ci/blackbox.sh --driver=simx --cores=4 --clusters=2 --app=diverge --args="-n1" - -# L2/L3 -./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=diverge --args="-n1" -./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l3cache --app=diverge --args="-n1" -./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=io_addr --args="-n1" -./ci/blackbox.sh --driver=simx --cores=4 --clusters=2 --l2cache --app=diverge --args="-n1" -./ci/blackbox.sh --driver=simx --cores=4 --clusters=4 --l2cache --l3cache --app=diverge --args="-n1" - -echo "clustering tests done!" -} - -debug() -{ -echo "begin debugging tests..." - -# test CSV trace generation -make -C sim/simx clean && DEBUG=3 make -C sim/simx > /dev/null -make -C sim/rtlsim clean && DEBUG=3 CONFIGS="-DGPR_RESET" make -C sim/rtlsim > /dev/null -make -C tests/riscv/isa run-simx-32im > run_simx.log -make -C tests/riscv/isa run-rtlsim-32im > run_rtlsim.log -./ci/trace_csv.py -trtlsim run_rtlsim.log -otrace_rtlsim.csv -./ci/trace_csv.py -tsimx run_simx.log -otrace_simx.csv -diff trace_rtlsim.csv trace_simx.csv -# restore default prebuilt configuration -make -C sim/simx clean && make -C sim/simx > /dev/null -make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null - -./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --perf=1 --app=demo --args="-n1" -./ci/blackbox.sh --driver=simx --cores=2 --clusters=2 --l2cache --perf=1 --app=demo --args="-n1" -./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --debug=1 --app=demo --args="-n1" -./ci/blackbox.sh --driver=simx --cores=2 --clusters=2 --l2cache --debug=1 --app=demo --args="-n1" -./ci/blackbox.sh --driver=opae --cores=1 --scope --app=basic --args="-t0 -n1" - -echo "debugging tests done!" -} - -config() -{ -echo "begin configuration tests..." - -# disable DPI -CONFIGS="-DDPI_DISABLE -DFPU_FPNEW" ./ci/blackbox.sh --driver=rtlsim --app=dogfood -CONFIGS="-DDPI_DISABLE -DFPU_FPNEW" ./ci/blackbox.sh --driver=opae --app=dogfood - -# issue width -CONFIGS="-DISSUE_WIDTH=1" ./ci/blackbox.sh --driver=rtlsim --app=diverge -CONFIGS="-DISSUE_WIDTH=2" ./ci/blackbox.sh --driver=rtlsim --app=diverge -CONFIGS="-DISSUE_WIDTH=1" ./ci/blackbox.sh --driver=simx --app=diverge -CONFIGS="-DISSUE_WIDTH=2" ./ci/blackbox.sh --driver=simx --app=diverge - -# dispatch size -CONFIGS="-DNUM_ALU_BLOCK=1 -DNUM_ALU_LANES=1" ./ci/blackbox.sh --driver=rtlsim --app=diverge -CONFIGS="-DNUM_ALU_BLOCK=2 -DNUM_ALU_LANES=2" ./ci/blackbox.sh --driver=rtlsim --app=diverge -CONFIGS="-DNUM_ALU_BLOCK=1 -DNUM_ALU_LANES=1" ./ci/blackbox.sh --driver=simx --app=diverge -CONFIGS="-DNUM_ALU_BLOCK=2 -DNUM_ALU_LANES=2" ./ci/blackbox.sh --driver=simx --app=diverge - -# FPU scaling -CONFIGS="-DNUM_ALU_BLOCK=4 -DNUM_FPU_LANES=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemm -CONFIGS="-DNUM_ALU_BLOCK=2 -DNUM_FPU_LANES=4" ./ci/blackbox.sh --driver=rtlsim --app=sgemm -CONFIGS="-DNUM_ALU_BLOCK=4 -DNUM_FPU_LANES=4" ./ci/blackbox.sh --driver=rtlsim --app=sgemm - -# custom program startup address -make -C tests/regression/dogfood clean-all -STARTUP_ADDR=0x40000000 make -C tests/regression/dogfood -CONFIGS="-DSTARTUP_ADDR=0x40000000" ./ci/blackbox.sh --driver=simx --app=dogfood -CONFIGS="-DSTARTUP_ADDR=0x40000000" ./ci/blackbox.sh --driver=rtlsim --app=dogfood -make -C tests/regression/dogfood clean-all -make -C tests/regression/dogfood - -# disabling M extension -CONFIGS="-DEXT_M_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=no_mf_ext - -# disabling F extension -CONFIGS="-DEXT_F_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=no_mf_ext -CONFIGS="-DEXT_F_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=no_mf_ext --perf=1 -CONFIGS="-DEXT_F_DISABLE" ./ci/blackbox.sh --driver=simx --cores=1 --app=no_mf_ext --perf=1 - -# disable shared memory -CONFIGS="-DSM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=no_smem -CONFIGS="-DSM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=no_smem --perf=1 -CONFIGS="-DSM_DISABLE" ./ci/blackbox.sh --driver=simx --cores=1 --app=no_smem --perf=1 - -# disable L1 cache -CONFIGS="-DL1_DISABLE -DSM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemm -CONFIGS="-DDCACHE_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemm - -# multiple L1 caches per cluster -CONFIGS="-DNUM_DCACHES=2 -DNUM_ICACHES=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemm --cores=8 --warps=1 --threads=2 - -# test AXI bus -AXI_BUS=1 ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=demo - -# adjust l1 block size to match l2 -CONFIGS="-DL1_LINE_SIZE=64" ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=io_addr --args="-n1" - -# test cache banking -CONFIGS="-DSMEM_NUM_BANKS=4 -DDCACHE_NUM_BANKS=1" ./ci/blackbox.sh --driver=rtlsim --app=sgemm -CONFIGS="-DSMEM_NUM_BANKS=2 -DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemm -CONFIGS="-DSMEM_NUM_BANKS=2 -DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=simx --app=sgemm -CONFIGS="-DDCACHE_NUM_BANKS=1" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemm -CONFIGS="-DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemm -CONFIGS="-DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=simx --cores=1 --app=sgemm - -# test 128-bit MEM block -CONFIGS="-DMEM_BLOCK_SIZE=16" ./ci/blackbox.sh --driver=opae --cores=1 --app=demo - -# test single-bank DRAM -CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1" ./ci/blackbox.sh --driver=opae --cores=1 --app=demo - -# test 27-bit DRAM address -CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27" ./ci/blackbox.sh --driver=opae --cores=1 --app=demo - -echo "configuration tests done!" -} - -stress0() -{ -echo "begin stress0 tests..." - -# test verilator reset values -CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --l3cache --app=dogfood -CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --l3cache --app=io_addr -CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=opae --app=printf - -echo "stress0 tests done!" -} - -stress1() -{ -echo "begin stress1 tests..." - -./ci/blackbox.sh --driver=rtlsim --app=sgemm --args="-n128" --l2cache - -echo "stress1 tests done!" -} - -synthesis() -{ -echo "begin synthesis tests..." - -PREFIX=build_base make -C hw/syn/yosys clean -PREFIX=build_base CONFIGS="-DDPI_DISABLE -DEXT_F_DISABLE" make -C hw/syn/yosys elaborate - -echo "synthesis tests done!" -} - -show_usage() -{ - echo "Vortex Regression Test" - echo "Usage: $0 [--unittest] [--isa] [--regression] [--opencl] [--cluster] [--debug] [--config] [--stress[#n]] [--synthesis] [--all] [--h|--help]" -} - -start=$SECONDS - -while [ "$1" != "" ]; do - case $1 in - --unittest ) unittest - ;; - --isa ) isa - ;; - --regression ) regression - ;; - --opencl ) opencl - ;; - --cluster ) cluster - ;; - --debug ) debug - ;; - --config ) config - ;; - --stress0 ) stress0 - ;; - --stress1 ) stress1 - ;; - --stress ) stress0 - stress1 - ;; - --synthesis ) synthesis - ;; - --all ) unittest - isa - regression - opencl - cluster - debug - config - stress0 - stress1 - synthesis - ;; - -h | --help ) show_usage - exit - ;; - * ) show_usage - exit 1 - esac - shift -done - -echo "Regression completed!" - -duration=$(( SECONDS - start )) -awk -v t=$duration 'BEGIN{t=int(t*1000); printf "Elapsed Time: %d:%02d:%02d\n", t/3600000, t/60000%60, t/1000%60}' diff --git a/ci/toolchain_prebuilt.sh b/ci/toolchain_prebuilt.sh deleted file mode 100755 index d819858a..00000000 --- a/ci/toolchain_prebuilt.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash - -# Copyright © 2019-2023 -# -# 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. - -# exit when any command fails -set -e - -TOOLDIR=${TOOLDIR:=/opt} -OSDIR=${OSDIR:=ubuntu/bionic} - -riscv() -{ - echo "prebuilt riscv-gnu-toolchain..." - tar -C $TOOLDIR -cvjf riscv-gnu-toolchain.tar.bz2 riscv-gnu-toolchain - split -b 50M riscv-gnu-toolchain.tar.bz2 "riscv-gnu-toolchain.tar.bz2.part" - mv riscv-gnu-toolchain.tar.bz2.part* ./riscv-gnu-toolchain/$OSDIR - rm riscv-gnu-toolchain.tar.bz2 -} - -riscv64() -{ - echo "prebuilt riscv64-gnu-toolchain..." - tar -C $TOOLDIR -cvjf riscv64-gnu-toolchain.tar.bz2 riscv64-gnu-toolchain - split -b 50M riscv64-gnu-toolchain.tar.bz2 "riscv64-gnu-toolchain.tar.bz2.part" - mv riscv64-gnu-toolchain.tar.bz2.part* ./riscv64-gnu-toolchain/$OSDIR - rm riscv64-gnu-toolchain.tar.bz2 -} - -llvm-vortex() -{ - echo "prebuilt llvm-vortex..." - tar -C $TOOLDIR -cvjf llvm-vortex.tar.bz2 llvm-vortex - split -b 50M llvm-vortex.tar.bz2 "llvm-vortex.tar.bz2.part" - mv llvm-vortex.tar.bz2.part* ./llvm-vortex/$OSDIR - rm llvm-vortex.tar.bz2 -} - -llvm-pocl() -{ - echo "prebuilt llvm-pocl..." - tar -C $TOOLDIR -cvjf llvm-pocl.tar.bz2 llvm-pocl - split -b 50M llvm-pocl.tar.bz2 "llvm-pocl.tar.bz2.part" - mv llvm-pocl.tar.bz2.part* ./llvm-pocl/$OSDIR - rm llvm-pocl.tar.bz2 -} - -pocl() -{ - echo "prebuilt pocl..." - tar -C $TOOLDIR -cvjf pocl.tar.bz2 pocl - mv pocl.tar.bz2 ./pocl/$OSDIR -} - -verilator() -{ - echo "prebuilt verilator..." - tar -C $TOOLDIR -cvjf verilator.tar.bz2 verilator - mv verilator.tar.bz2 ./verilator/$OSDIR -} - -sv2v() -{ - echo "prebuilt sv2v..." - tar -C $TOOLDIR -cvjf sv2v.tar.bz2 sv2v - mv sv2v.tar.bz2 ./sv2v/$OSDIR -} - -yosys() -{ - echo "prebuilt yosys..." - tar -C $TOOLDIR -cvjf yosys.tar.bz2 yosys - split -b 50M yosys.tar.bz2 "yosys.tar.bz2.part" - mv yosys.tar.bz2.part* ./yosys/$OSDIR - rm yosys.tar.bz2 -} - -show_usage() -{ - echo "Setup Pre-built Vortex Toolchain" - echo "Usage: $0 [[--riscv] [--llvm-vortex] [--llvm-pocl] [--pocl] [--verilator] [--sv2v] [-yosys] [--all] [-h|--help]]" -} - -while [ "$1" != "" ]; do - case $1 in - --pocl ) pocl - ;; - --verilator ) verilator - ;; - --riscv ) riscv - ;; - --riscv64 ) riscv64 - ;; - --llvm-vortex ) llvm-vortex - ;; - --llvm-pocl ) llvm-pocl - ;; - --sv2v ) sv2v - ;; - --yosys ) yosys - ;; - --all ) riscv - riscv64 - llvm-vortex - llvm-pocl - pocl - verilator - sv2v - yosys - ;; - -h | --help ) show_usage - exit - ;; - * ) show_usage - exit 1 - esac - shift -done diff --git a/ci/trace_csv.py b/ci/trace_csv.py deleted file mode 100755 index 2fe7e712..00000000 --- a/ci/trace_csv.py +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright © 2019-2023 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import argparse -import csv -import re - -def parse_args(): - parser = argparse.ArgumentParser(description='CPU trace log to CSV format converter.') - parser.add_argument('-t', '--type', default='simx', help='log type (rtlsim or simx)') - parser.add_argument('-o', '--csv', default='trace.csv', help='Output CSV file') - parser.add_argument('log', help='Input log file') - return parser.parse_args() - -def parse_simx(log_filename): - pc_pattern = r"PC=(0x[0-9a-fA-F]+)" - instr_pattern = r"Instr (0x[0-9a-fA-F]+):" - opcode_pattern = r"Instr 0x[0-9a-fA-F]+: ([0-9a-zA-Z_\.]+)" - core_id_pattern = r"cid=(\d+)" - warp_id_pattern = r"wid=(\d+)" - tmask_pattern = r"tmask=(\d+)" - operands_pattern = r"Src\d+ Reg: (.+)" - destination_pattern = r"Dest Reg: (.+)" - uuid_pattern = r"#(\d+)" - entries = [] - with open(log_filename, 'r') as log_file: - instr_data = None - for lineno, line in enumerate(log_file, start=1): - if line.startswith("DEBUG Fetch:"): - if instr_data: - entries.append(instr_data) - instr_data = {} - instr_data["lineno"] = lineno - instr_data["PC"] = re.search(pc_pattern, line).group(1) - instr_data["core_id"] = re.search(core_id_pattern, line).group(1) - instr_data["warp_id"] = re.search(warp_id_pattern, line).group(1) - instr_data["tmask"] = re.search(tmask_pattern, line).group(1) - instr_data["uuid"] = re.search(uuid_pattern, line).group(1) - elif line.startswith("DEBUG Instr"): - instr_data["instr"] = re.search(instr_pattern, line).group(1) - instr_data["opcode"] = re.search(opcode_pattern, line).group(1) - elif line.startswith("DEBUG Src"): - src_reg = re.search(operands_pattern, line).group(1) - instr_data["operands"] = (instr_data["operands"] + ', ' + src_reg) if 'operands' in instr_data else src_reg - elif line.startswith("DEBUG Dest"): - instr_data["destination"] = re.search(destination_pattern, line).group(1) - if instr_data: - entries.append(instr_data) - return entries - -def reverse_binary(bin_str): - return bin_str[::-1] - -def bin_to_array(bin_str): - return [int(bit) for bit in bin_str] - -def append_reg(text, value, sep): - if sep: - text += ", " - ivalue = int(value) - if (ivalue >= 32): - text += "f" + str(ivalue % 32) - else: - text += "x" + value - sep = True - return text, sep - -def append_imm(text, value, sep): - if sep: - text += ", " - text += value - sep = True - return text, sep - -def append_value(text, reg, value, tmask_arr, sep): - text, sep = append_reg(text, reg, sep) - text += "={" - for i in range(len(tmask_arr)): - if i != 0: - text += ", " - if tmask_arr[i]: - text += value[i] - else: - text +="-" - text += "}" - return text, sep - -def parse_rtlsim(log_filename): - line_pattern = r"\d+: core(\d+)-(decode|issue|commit)" - pc_pattern = r"PC=(0x[0-9a-fA-F]+)" - instr_pattern = r"instr=(0x[0-9a-fA-F]+)" - ex_pattern = r"ex=([a-zA-Z]+)" - op_pattern = r"op=([\?0-9a-zA-Z_\.]+)" - warp_id_pattern = r"wid=(\d+)" - tmask_pattern = r"tmask=(\d+)" - wb_pattern = r"wb=(\d)" - opds_pattern = r"opds=(\d+)" - use_imm_pattern = r"use_imm=(\d)" - imm_pattern = r"imm=(0x[0-9a-fA-F]+)" - rd_pattern = r"rd=(\d+)" - rs1_pattern = r"rs1=(\d+)" - rs2_pattern = r"rs2=(\d+)" - rs3_pattern = r"rs3=(\d+)" - rs1_data_pattern = r"rs1_data=\{(.+?)\}" - rs2_data_pattern = r"rs2_data=\{(.+?)\}" - rs3_data_pattern = r"rs3_data=\{(.+?)\}" - rd_data_pattern = r"data=\{(.+?)\}" - eop_pattern = r"eop=(\d)" - uuid_pattern = r"#(\d+)" - entries = [] - with open(log_filename, 'r') as log_file: - instr_data = {} - for lineno, line in enumerate(log_file, start=1): - line_match = re.search(line_pattern, line) - if line_match: - PC = re.search(pc_pattern, line).group(1) - warp_id = re.search(warp_id_pattern, line).group(1) - tmask = re.search(tmask_pattern, line).group(1) - uuid = re.search(uuid_pattern, line).group(1) - core_id = line_match.group(1) - stage = line_match.group(2) - if stage == "decode": - trace = {} - trace["uuid"] = uuid - trace["PC"] = PC - trace["core_id"] = core_id - trace["warp_id"] = warp_id - trace["tmask"] = reverse_binary(tmask) - trace["instr"] = re.search(instr_pattern, line).group(1) - trace["opcode"] = re.search(op_pattern, line).group(1) - trace["opds"] = bin_to_array(re.search(opds_pattern, line).group(1)) - trace["rd"] = re.search(rd_pattern, line).group(1) - trace["rs1"] = re.search(rs1_pattern, line).group(1) - trace["rs2"] = re.search(rs2_pattern, line).group(1) - trace["rs3"] = re.search(rs3_pattern, line).group(1) - trace["use_imm"] = re.search(use_imm_pattern, line).group(1) == "1" - trace["imm"] = re.search(imm_pattern, line).group(1) - instr_data[uuid] = trace - elif stage == "issue": - if uuid in instr_data: - trace = instr_data[uuid] - trace["lineno"] = lineno - opds = trace["opds"] - if opds[1]: - trace["rs1_data"] = re.search(rs1_data_pattern, line).group(1).split(', ')[::-1] - if opds[2]: - trace["rs2_data"] = re.search(rs2_data_pattern, line).group(1).split(', ')[::-1] - if opds[3]: - trace["rs3_data"] = re.search(rs3_data_pattern, line).group(1).split(', ')[::-1] - trace["issued"] = True - instr_data[uuid] = trace - elif stage == "commit": - if uuid in instr_data: - trace = instr_data[uuid] - if "issued" in trace: - opds = trace["opds"] - dst_tmask_arr = bin_to_array(tmask)[::-1] - wb = re.search(wb_pattern, line).group(1) == "1" - if wb: - rd_data = re.search(rd_data_pattern, line).group(1).split(', ')[::-1] - if 'rd_data' in trace: - merged_rd_data = trace['rd_data'] - for i in range(len(dst_tmask_arr)): - if dst_tmask_arr[i] == 1: - merged_rd_data[i] = rd_data[i] - trace['rd_data'] = merged_rd_data - else: - trace['rd_data'] = rd_data - instr_data[uuid] = trace - eop = re.search(eop_pattern, line).group(1) == "1" - if eop: - tmask_arr = bin_to_array(trace["tmask"]) - destination = '' - if wb: - destination, sep = append_value(destination, trace["rd"], trace['rd_data'], tmask_arr, False) - del trace['rd_data'] - trace["destination"] = destination - operands = '' - sep = False - if opds[1]: - operands, sep = append_value(operands, trace["rs1"], trace["rs1_data"], tmask_arr, sep) - del trace["rs1_data"] - if opds[2]: - operands, sep = append_value(operands, trace["rs2"], trace["rs2_data"], tmask_arr, sep) - del trace["rs2_data"] - if opds[3]: - operands, sep = append_value(operands, trace["rs3"], trace["rs3_data"], tmask_arr, sep) - del trace["rs3_data"] - trace["operands"] = operands - del trace["opds"] - del trace["rd"] - del trace["rs1"] - del trace["rs2"] - del trace["rs3"] - del trace["use_imm"] - del trace["imm"] - del trace["issued"] - del instr_data[uuid] - entries.append(trace) - return entries - -def write_csv(log_filename, csv_filename, log_type): - entries = None - - # parse log file - if log_type == "rtlsim": - entries = parse_rtlsim(log_filename) - elif log_type == "simx": - entries = parse_simx(log_filename) - else: - print('Error: invalid log type') - sys.exit() - - # sort entries by uuid - entries.sort(key=lambda x: (int(x['core_id']), int(x['warp_id']), int(x['lineno']))) - for entry in entries: - del entry['lineno'] - - # write to CSV - with open(csv_filename, 'w', newline='') as csv_file: - fieldnames = ["uuid", "PC", "opcode", "instr", "core_id", "warp_id", "tmask", "operands", "destination"] - writer = csv.DictWriter(csv_file, fieldnames=fieldnames) - writer.writeheader() - for entry in entries: - writer.writerow(entry) - -def main(): - args = parse_args() - write_csv(args.log, args.csv, args.type) - -if __name__ == "__main__": - main() diff --git a/ci/travis_run.py b/ci/travis_run.py deleted file mode 100755 index 021e3ff2..00000000 --- a/ci/travis_run.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2019-2023 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import time -import threading -import subprocess - -# This script executes a long-running command while outputing "still running ..." periodically -# to notify Travis build system that the program has not hanged - -PING_INTERVAL=300 # 5 minutes - -def monitor(stop): - wait_time = 0 - while True: - time.sleep(PING_INTERVAL) - wait_time += PING_INTERVAL - print(" + still running (" + str(wait_time) + "s) ...") - sys.stdout.flush() - if stop(): - break - -def execute(command): - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - while True: - output = process.stdout.readline() - if output: - line = output.decode('utf-8').rstrip() - print(">>> " + line) - process.stdout.flush() - ret = process.poll() - if ret is not None: - return ret - return -1 - -def main(argv): - - # start monitoring thread - stop_monitor = False - t = threading.Thread(target = monitor, args =(lambda : stop_monitor, )) - t.start() - - # execute command - exitcode = execute(argv) - print(" + exitcode="+str(exitcode)) - sys.stdout.flush() - - # terminate monitoring thread - stop_monitor = True - t.join() - - sys.exit(exitcode) - -if __name__ == "__main__": - main(sys.argv[1:]) \ No newline at end of file diff --git a/tests/regression/Makefile b/kernels/Makefile similarity index 100% rename from tests/regression/Makefile rename to kernels/Makefile diff --git a/tests/regression/bad_apple/.gitignore b/kernels/bad_apple/.gitignore similarity index 100% rename from tests/regression/bad_apple/.gitignore rename to kernels/bad_apple/.gitignore diff --git a/tests/regression/bad_apple/Makefile b/kernels/bad_apple/Makefile similarity index 100% rename from tests/regression/bad_apple/Makefile rename to kernels/bad_apple/Makefile diff --git a/tests/regression/bad_apple/common.h b/kernels/bad_apple/common.h similarity index 100% rename from tests/regression/bad_apple/common.h rename to kernels/bad_apple/common.h diff --git a/tests/regression/bad_apple/display.py b/kernels/bad_apple/display.py similarity index 100% rename from tests/regression/bad_apple/display.py rename to kernels/bad_apple/display.py diff --git a/tests/regression/bad_apple/display.py.bak b/kernels/bad_apple/display.py.bak similarity index 100% rename from tests/regression/bad_apple/display.py.bak rename to kernels/bad_apple/display.py.bak diff --git a/tests/regression/bad_apple/kernel.cpp b/kernels/bad_apple/kernel.cpp similarity index 100% rename from tests/regression/bad_apple/kernel.cpp rename to kernels/bad_apple/kernel.cpp diff --git a/tests/regression/common.mk b/kernels/common.mk similarity index 100% rename from tests/regression/common.mk rename to kernels/common.mk diff --git a/tests/regression/flash_attention/.gitignore b/kernels/flash_attention/.gitignore similarity index 100% rename from tests/regression/flash_attention/.gitignore rename to kernels/flash_attention/.gitignore diff --git a/tests/regression/flash_attention/Makefile b/kernels/flash_attention/Makefile similarity index 100% rename from tests/regression/flash_attention/Makefile rename to kernels/flash_attention/Makefile diff --git a/tests/regression/flash_attention/common.h b/kernels/flash_attention/common.h similarity index 100% rename from tests/regression/flash_attention/common.h rename to kernels/flash_attention/common.h diff --git a/tests/regression/flash_attention/flash_impl.hpp b/kernels/flash_attention/flash_impl.hpp similarity index 100% rename from tests/regression/flash_attention/flash_impl.hpp rename to kernels/flash_attention/flash_impl.hpp diff --git a/tests/regression/flash_attention/half.hpp b/kernels/flash_attention/half.hpp similarity index 100% rename from tests/regression/flash_attention/half.hpp rename to kernels/flash_attention/half.hpp diff --git a/tests/regression/flash_attention/kernel.cpp b/kernels/flash_attention/kernel.cpp similarity index 100% rename from tests/regression/flash_attention/kernel.cpp rename to kernels/flash_attention/kernel.cpp diff --git a/tests/regression/flash_attention/kernel.gemmini.cpp b/kernels/flash_attention/kernel.gemmini.cpp similarity index 100% rename from tests/regression/flash_attention/kernel.gemmini.cpp rename to kernels/flash_attention/kernel.gemmini.cpp diff --git a/tests/regression/flash_attention/kernel.gemmini.warpspec.cpp b/kernels/flash_attention/kernel.gemmini.warpspec.cpp similarity index 100% rename from tests/regression/flash_attention/kernel.gemmini.warpspec.cpp rename to kernels/flash_attention/kernel.gemmini.warpspec.cpp diff --git a/tests/regression/idle/.gitignore b/kernels/idle/.gitignore similarity index 100% rename from tests/regression/idle/.gitignore rename to kernels/idle/.gitignore diff --git a/tests/regression/idle/Makefile b/kernels/idle/Makefile similarity index 100% rename from tests/regression/idle/Makefile rename to kernels/idle/Makefile diff --git a/tests/regression/idle/common.h b/kernels/idle/common.h similarity index 100% rename from tests/regression/idle/common.h rename to kernels/idle/common.h diff --git a/tests/regression/idle/hello.c b/kernels/idle/hello.c similarity index 100% rename from tests/regression/idle/hello.c rename to kernels/idle/hello.c diff --git a/tests/regression/idle/kernel.cpp b/kernels/idle/kernel.cpp similarity index 100% rename from tests/regression/idle/kernel.cpp rename to kernels/idle/kernel.cpp diff --git a/tests/regression/rickroll/.gitignore b/kernels/rickroll/.gitignore similarity index 100% rename from tests/regression/rickroll/.gitignore rename to kernels/rickroll/.gitignore diff --git a/tests/regression/rickroll/Makefile b/kernels/rickroll/Makefile similarity index 100% rename from tests/regression/rickroll/Makefile rename to kernels/rickroll/Makefile diff --git a/tests/regression/rickroll/common.h b/kernels/rickroll/common.h similarity index 100% rename from tests/regression/rickroll/common.h rename to kernels/rickroll/common.h diff --git a/tests/regression/rickroll/display_color.py b/kernels/rickroll/display_color.py similarity index 100% rename from tests/regression/rickroll/display_color.py rename to kernels/rickroll/display_color.py diff --git a/tests/regression/rickroll/kernel.cpp b/kernels/rickroll/kernel.cpp similarity index 100% rename from tests/regression/rickroll/kernel.cpp rename to kernels/rickroll/kernel.cpp diff --git a/tests/regression/sgemm_gemmini/.gitignore b/kernels/sgemm_gemmini/.gitignore similarity index 100% rename from tests/regression/sgemm_gemmini/.gitignore rename to kernels/sgemm_gemmini/.gitignore diff --git a/tests/regression/sgemm_gemmini/Makefile b/kernels/sgemm_gemmini/Makefile similarity index 100% rename from tests/regression/sgemm_gemmini/Makefile rename to kernels/sgemm_gemmini/Makefile diff --git a/tests/regression/sgemm_gemmini/args b/kernels/sgemm_gemmini/args similarity index 100% rename from tests/regression/sgemm_gemmini/args rename to kernels/sgemm_gemmini/args diff --git a/tests/regression/sgemm_gemmini/common.h b/kernels/sgemm_gemmini/common.h similarity index 100% rename from tests/regression/sgemm_gemmini/common.h rename to kernels/sgemm_gemmini/common.h diff --git a/tests/regression/sgemm_gemmini/compile_ampere.sh b/kernels/sgemm_gemmini/compile_ampere.sh similarity index 100% rename from tests/regression/sgemm_gemmini/compile_ampere.sh rename to kernels/sgemm_gemmini/compile_ampere.sh diff --git a/tests/regression/sgemm_gemmini/compile_hopper.sh b/kernels/sgemm_gemmini/compile_hopper.sh similarity index 100% rename from tests/regression/sgemm_gemmini/compile_hopper.sh rename to kernels/sgemm_gemmini/compile_hopper.sh diff --git a/tests/regression/sgemm_gemmini/input.a b/kernels/sgemm_gemmini/input.a similarity index 100% rename from tests/regression/sgemm_gemmini/input.a rename to kernels/sgemm_gemmini/input.a diff --git a/tests/regression/sgemm_gemmini/input.b b/kernels/sgemm_gemmini/input.b similarity index 100% rename from tests/regression/sgemm_gemmini/input.b rename to kernels/sgemm_gemmini/input.b diff --git a/tests/regression/sgemm_gemmini/kernel.cpp b/kernels/sgemm_gemmini/kernel.cpp similarity index 100% rename from tests/regression/sgemm_gemmini/kernel.cpp rename to kernels/sgemm_gemmini/kernel.cpp diff --git a/tests/regression/sgemm_gemmini_dma/.gitignore b/kernels/sgemm_gemmini_dma/.gitignore similarity index 100% rename from tests/regression/sgemm_gemmini_dma/.gitignore rename to kernels/sgemm_gemmini_dma/.gitignore diff --git a/tests/regression/sgemm_gemmini_dma/Makefile b/kernels/sgemm_gemmini_dma/Makefile similarity index 100% rename from tests/regression/sgemm_gemmini_dma/Makefile rename to kernels/sgemm_gemmini_dma/Makefile diff --git a/tests/regression/sgemm_gemmini_dma/args/1024 b/kernels/sgemm_gemmini_dma/args/1024 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/args/1024 rename to kernels/sgemm_gemmini_dma/args/1024 diff --git a/tests/regression/sgemm_gemmini_dma/args/128 b/kernels/sgemm_gemmini_dma/args/128 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/args/128 rename to kernels/sgemm_gemmini_dma/args/128 diff --git a/tests/regression/sgemm_gemmini_dma/args/256 b/kernels/sgemm_gemmini_dma/args/256 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/args/256 rename to kernels/sgemm_gemmini_dma/args/256 diff --git a/tests/regression/sgemm_gemmini_dma/args/512 b/kernels/sgemm_gemmini_dma/args/512 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/args/512 rename to kernels/sgemm_gemmini_dma/args/512 diff --git a/tests/regression/sgemm_gemmini_dma/common.h b/kernels/sgemm_gemmini_dma/common.h similarity index 100% rename from tests/regression/sgemm_gemmini_dma/common.h rename to kernels/sgemm_gemmini_dma/common.h diff --git a/tests/regression/sgemm_gemmini_dma/compile_ampere.sh b/kernels/sgemm_gemmini_dma/compile_ampere.sh similarity index 100% rename from tests/regression/sgemm_gemmini_dma/compile_ampere.sh rename to kernels/sgemm_gemmini_dma/compile_ampere.sh diff --git a/tests/regression/sgemm_gemmini_dma/compile_debug.sh b/kernels/sgemm_gemmini_dma/compile_debug.sh similarity index 100% rename from tests/regression/sgemm_gemmini_dma/compile_debug.sh rename to kernels/sgemm_gemmini_dma/compile_debug.sh diff --git a/tests/regression/sgemm_gemmini_dma/compile_hopper.sh b/kernels/sgemm_gemmini_dma/compile_hopper.sh similarity index 100% rename from tests/regression/sgemm_gemmini_dma/compile_hopper.sh rename to kernels/sgemm_gemmini_dma/compile_hopper.sh diff --git a/tests/regression/sgemm_gemmini_dma/generate_operands.py b/kernels/sgemm_gemmini_dma/generate_operands.py similarity index 100% rename from tests/regression/sgemm_gemmini_dma/generate_operands.py rename to kernels/sgemm_gemmini_dma/generate_operands.py diff --git a/tests/regression/sgemm_gemmini_dma/input.a/1024 b/kernels/sgemm_gemmini_dma/input.a/1024 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.a/1024 rename to kernels/sgemm_gemmini_dma/input.a/1024 diff --git a/tests/regression/sgemm_gemmini_dma/input.a/128 b/kernels/sgemm_gemmini_dma/input.a/128 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.a/128 rename to kernels/sgemm_gemmini_dma/input.a/128 diff --git a/tests/regression/sgemm_gemmini_dma/input.a/256 b/kernels/sgemm_gemmini_dma/input.a/256 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.a/256 rename to kernels/sgemm_gemmini_dma/input.a/256 diff --git a/tests/regression/sgemm_gemmini_dma/input.a/512 b/kernels/sgemm_gemmini_dma/input.a/512 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.a/512 rename to kernels/sgemm_gemmini_dma/input.a/512 diff --git a/tests/regression/sgemm_gemmini_dma/input.b/1024 b/kernels/sgemm_gemmini_dma/input.b/1024 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.b/1024 rename to kernels/sgemm_gemmini_dma/input.b/1024 diff --git a/tests/regression/sgemm_gemmini_dma/input.b/128 b/kernels/sgemm_gemmini_dma/input.b/128 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.b/128 rename to kernels/sgemm_gemmini_dma/input.b/128 diff --git a/tests/regression/sgemm_gemmini_dma/input.b/256 b/kernels/sgemm_gemmini_dma/input.b/256 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.b/256 rename to kernels/sgemm_gemmini_dma/input.b/256 diff --git a/tests/regression/sgemm_gemmini_dma/input.b/512 b/kernels/sgemm_gemmini_dma/input.b/512 similarity index 100% rename from tests/regression/sgemm_gemmini_dma/input.b/512 rename to kernels/sgemm_gemmini_dma/input.b/512 diff --git a/tests/regression/sgemm_gemmini_dma/kernel.activation.cpp b/kernels/sgemm_gemmini_dma/kernel.activation.cpp similarity index 100% rename from tests/regression/sgemm_gemmini_dma/kernel.activation.cpp rename to kernels/sgemm_gemmini_dma/kernel.activation.cpp diff --git a/tests/regression/sgemm_gemmini_dma/kernel.cpp b/kernels/sgemm_gemmini_dma/kernel.cpp similarity index 100% rename from tests/regression/sgemm_gemmini_dma/kernel.cpp rename to kernels/sgemm_gemmini_dma/kernel.cpp diff --git a/tests/regression/sgemm_gemmini_duo/.gitignore b/kernels/sgemm_gemmini_duo/.gitignore similarity index 100% rename from tests/regression/sgemm_gemmini_duo/.gitignore rename to kernels/sgemm_gemmini_duo/.gitignore diff --git a/tests/regression/sgemm_gemmini_duo/Makefile b/kernels/sgemm_gemmini_duo/Makefile similarity index 100% rename from tests/regression/sgemm_gemmini_duo/Makefile rename to kernels/sgemm_gemmini_duo/Makefile diff --git a/tests/regression/sgemm_gemmini_duo/common.h b/kernels/sgemm_gemmini_duo/common.h similarity index 100% rename from tests/regression/sgemm_gemmini_duo/common.h rename to kernels/sgemm_gemmini_duo/common.h diff --git a/tests/regression/sgemm_gemmini_duo/kernel.cpp b/kernels/sgemm_gemmini_duo/kernel.cpp similarity index 100% rename from tests/regression/sgemm_gemmini_duo/kernel.cpp rename to kernels/sgemm_gemmini_duo/kernel.cpp diff --git a/tests/regression/sgemm_gemmini_duo/kernel.serialized.cpp b/kernels/sgemm_gemmini_duo/kernel.serialized.cpp similarity index 100% rename from tests/regression/sgemm_gemmini_duo/kernel.serialized.cpp rename to kernels/sgemm_gemmini_duo/kernel.serialized.cpp diff --git a/tests/regression/sgemm_tcore/.gitignore b/kernels/sgemm_tcore/.gitignore similarity index 100% rename from tests/regression/sgemm_tcore/.gitignore rename to kernels/sgemm_tcore/.gitignore diff --git a/tests/regression/sgemm_tcore/Makefile b/kernels/sgemm_tcore/Makefile similarity index 100% rename from tests/regression/sgemm_tcore/Makefile rename to kernels/sgemm_tcore/Makefile diff --git a/tests/regression/sgemm_tcore/args.bin b/kernels/sgemm_tcore/args.bin similarity index 100% rename from tests/regression/sgemm_tcore/args.bin rename to kernels/sgemm_tcore/args.bin diff --git a/tests/regression/sgemm_tcore/args.m1024n1024k1024.bin b/kernels/sgemm_tcore/args.m1024n1024k1024.bin similarity index 100% rename from tests/regression/sgemm_tcore/args.m1024n1024k1024.bin rename to kernels/sgemm_tcore/args.m1024n1024k1024.bin diff --git a/tests/regression/sgemm_tcore/args.m256n256k256.bin b/kernels/sgemm_tcore/args.m256n256k256.bin similarity index 100% rename from tests/regression/sgemm_tcore/args.m256n256k256.bin rename to kernels/sgemm_tcore/args.m256n256k256.bin diff --git a/tests/regression/sgemm_tcore/args.m512n512k512.bin b/kernels/sgemm_tcore/args.m512n512k512.bin similarity index 100% rename from tests/regression/sgemm_tcore/args.m512n512k512.bin rename to kernels/sgemm_tcore/args.m512n512k512.bin diff --git a/tests/regression/sgemm_tcore/common.h b/kernels/sgemm_tcore/common.h similarity index 100% rename from tests/regression/sgemm_tcore/common.h rename to kernels/sgemm_tcore/common.h diff --git a/tests/regression/sgemm_tcore/half.hpp b/kernels/sgemm_tcore/half.hpp similarity index 100% rename from tests/regression/sgemm_tcore/half.hpp rename to kernels/sgemm_tcore/half.hpp diff --git a/tests/regression/sgemm_tcore/input.a.bin b/kernels/sgemm_tcore/input.a.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.a.bin rename to kernels/sgemm_tcore/input.a.bin diff --git a/tests/regression/sgemm_tcore/input.a.rand01.fp16.m1024n1024k1024.col.swizzle_fp16.bin b/kernels/sgemm_tcore/input.a.rand01.fp16.m1024n1024k1024.col.swizzle_fp16.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.a.rand01.fp16.m1024n1024k1024.col.swizzle_fp16.bin rename to kernels/sgemm_tcore/input.a.rand01.fp16.m1024n1024k1024.col.swizzle_fp16.bin diff --git a/tests/regression/sgemm_tcore/input.a.rand01.fp16.m256n256k256.col.swizzle_fp16.bin b/kernels/sgemm_tcore/input.a.rand01.fp16.m256n256k256.col.swizzle_fp16.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.a.rand01.fp16.m256n256k256.col.swizzle_fp16.bin rename to kernels/sgemm_tcore/input.a.rand01.fp16.m256n256k256.col.swizzle_fp16.bin diff --git a/tests/regression/sgemm_tcore/input.a.rand01.fp16.m512n512k512.col.swizzle_fp16.bin b/kernels/sgemm_tcore/input.a.rand01.fp16.m512n512k512.col.swizzle_fp16.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.a.rand01.fp16.m512n512k512.col.swizzle_fp16.bin rename to kernels/sgemm_tcore/input.a.rand01.fp16.m512n512k512.col.swizzle_fp16.bin diff --git a/tests/regression/sgemm_tcore/input.b.bin b/kernels/sgemm_tcore/input.b.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.b.bin rename to kernels/sgemm_tcore/input.b.bin diff --git a/tests/regression/sgemm_tcore/input.b.rand01.fp16.m1024n1024k1024.row.swizzle_fp16.bin b/kernels/sgemm_tcore/input.b.rand01.fp16.m1024n1024k1024.row.swizzle_fp16.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.b.rand01.fp16.m1024n1024k1024.row.swizzle_fp16.bin rename to kernels/sgemm_tcore/input.b.rand01.fp16.m1024n1024k1024.row.swizzle_fp16.bin diff --git a/tests/regression/sgemm_tcore/input.b.rand01.fp16.m256n256k256.row.swizzle_fp16.bin b/kernels/sgemm_tcore/input.b.rand01.fp16.m256n256k256.row.swizzle_fp16.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.b.rand01.fp16.m256n256k256.row.swizzle_fp16.bin rename to kernels/sgemm_tcore/input.b.rand01.fp16.m256n256k256.row.swizzle_fp16.bin diff --git a/tests/regression/sgemm_tcore/input.b.rand01.fp16.m512n512k512.row.swizzle_fp16.bin b/kernels/sgemm_tcore/input.b.rand01.fp16.m512n512k512.row.swizzle_fp16.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.b.rand01.fp16.m512n512k512.row.swizzle_fp16.bin rename to kernels/sgemm_tcore/input.b.rand01.fp16.m512n512k512.row.swizzle_fp16.bin diff --git a/tests/regression/sgemm_tcore/input.c.bin b/kernels/sgemm_tcore/input.c.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.c.bin rename to kernels/sgemm_tcore/input.c.bin diff --git a/tests/regression/sgemm_tcore/input.c.zero.fp32.m64n64k64.row.bin b/kernels/sgemm_tcore/input.c.zero.fp32.m64n64k64.row.bin similarity index 100% rename from tests/regression/sgemm_tcore/input.c.zero.fp32.m64n64k64.row.bin rename to kernels/sgemm_tcore/input.c.zero.fp32.m64n64k64.row.bin diff --git a/tests/regression/sgemm_tcore/kernel.4warps.cpp b/kernels/sgemm_tcore/kernel.4warps.cpp similarity index 100% rename from tests/regression/sgemm_tcore/kernel.4warps.cpp rename to kernels/sgemm_tcore/kernel.4warps.cpp diff --git a/tests/regression/sgemm_tcore/kernel.activation.cpp b/kernels/sgemm_tcore/kernel.activation.cpp similarity index 100% rename from tests/regression/sgemm_tcore/kernel.activation.cpp rename to kernels/sgemm_tcore/kernel.activation.cpp diff --git a/tests/regression/sgemm_tcore/kernel.cpp b/kernels/sgemm_tcore/kernel.cpp similarity index 100% rename from tests/regression/sgemm_tcore/kernel.cpp rename to kernels/sgemm_tcore/kernel.cpp diff --git a/tests/regression/sgemm_tcore/kernel.warpspecial.cpp b/kernels/sgemm_tcore/kernel.warpspecial.cpp similarity index 100% rename from tests/regression/sgemm_tcore/kernel.warpspecial.cpp rename to kernels/sgemm_tcore/kernel.warpspecial.cpp diff --git a/tests/regression/sgemm_tcore/kernel.warpspecial_dma.cpp b/kernels/sgemm_tcore/kernel.warpspecial_dma.cpp similarity index 100% rename from tests/regression/sgemm_tcore/kernel.warpspecial_dma.cpp rename to kernels/sgemm_tcore/kernel.warpspecial_dma.cpp diff --git a/tests/regression/sgemm_tcore/sgemm_impl.hpp b/kernels/sgemm_tcore/sgemm_impl.hpp similarity index 100% rename from tests/regression/sgemm_tcore/sgemm_impl.hpp rename to kernels/sgemm_tcore/sgemm_impl.hpp diff --git a/tests/regression/sgemm_tcore/switch_args_input.sh b/kernels/sgemm_tcore/switch_args_input.sh similarity index 100% rename from tests/regression/sgemm_tcore/switch_args_input.sh rename to kernels/sgemm_tcore/switch_args_input.sh diff --git a/tests/regression/sgemm_wg/.gitignore b/kernels/sgemm_wg/.gitignore similarity index 100% rename from tests/regression/sgemm_wg/.gitignore rename to kernels/sgemm_wg/.gitignore diff --git a/tests/regression/sgemm_wg/Makefile b/kernels/sgemm_wg/Makefile similarity index 100% rename from tests/regression/sgemm_wg/Makefile rename to kernels/sgemm_wg/Makefile diff --git a/tests/regression/sgemm_wg/common.h b/kernels/sgemm_wg/common.h similarity index 100% rename from tests/regression/sgemm_wg/common.h rename to kernels/sgemm_wg/common.h diff --git a/tests/regression/sgemm_wg/kernel.cpp b/kernels/sgemm_wg/kernel.cpp similarity index 100% rename from tests/regression/sgemm_wg/kernel.cpp rename to kernels/sgemm_wg/kernel.cpp diff --git a/tests/regression/unaligned/Makefile b/kernels/unaligned/Makefile similarity index 100% rename from tests/regression/unaligned/Makefile rename to kernels/unaligned/Makefile diff --git a/kernel/.gitignore b/kernels/unaligned/args.bin similarity index 100% rename from kernel/.gitignore rename to kernels/unaligned/args.bin diff --git a/tests/regression/unaligned/common.h b/kernels/unaligned/common.h similarity index 100% rename from tests/regression/unaligned/common.h rename to kernels/unaligned/common.h diff --git a/tests/opencl/bfs/README b/kernels/unaligned/input.a.bin similarity index 100% rename from tests/opencl/bfs/README rename to kernels/unaligned/input.a.bin diff --git a/tests/opencl/flops/README b/kernels/unaligned/input.b.bin similarity index 100% rename from tests/opencl/flops/README rename to kernels/unaligned/input.b.bin diff --git a/tests/opencl/kmeans/README b/kernels/unaligned/input.c.bin similarity index 100% rename from tests/opencl/kmeans/README rename to kernels/unaligned/input.c.bin diff --git a/tests/regression/unaligned/kernel.cpp b/kernels/unaligned/kernel.cpp similarity index 100% rename from tests/regression/unaligned/kernel.cpp rename to kernels/unaligned/kernel.cpp diff --git a/tests/regression/unaligned/kernel.minimal.cpp b/kernels/unaligned/kernel.minimal.cpp similarity index 100% rename from tests/regression/unaligned/kernel.minimal.cpp rename to kernels/unaligned/kernel.minimal.cpp diff --git a/tests/regression/vecaddx/Makefile b/kernels/vecaddx/Makefile similarity index 100% rename from tests/regression/vecaddx/Makefile rename to kernels/vecaddx/Makefile diff --git a/kernels/vecaddx/args.bin b/kernels/vecaddx/args.bin new file mode 100644 index 0000000000000000000000000000000000000000..dae91e7956de06dbee33997cef53875806dd77c8 GIT binary patch literal 40 bcmZo*U|?u~Vju+q3&11;!$K&107L@-Pc;LA literal 0 HcmV?d00001 diff --git a/tests/regression/vecaddx/common.h b/kernels/vecaddx/common.h similarity index 100% rename from tests/regression/vecaddx/common.h rename to kernels/vecaddx/common.h diff --git a/kernels/vecaddx/input.a.bin b/kernels/vecaddx/input.a.bin new file mode 100644 index 0000000000000000000000000000000000000000..66035f64c4af4ebfc28e7b554552171221b9aa91 GIT binary patch literal 32768 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 NHxSFdMQnk>{eRu~DXstj literal 0 HcmV?d00001 diff --git a/kernels/vecaddx/input.b.bin b/kernels/vecaddx/input.b.bin new file mode 100644 index 0000000000000000000000000000000000000000..5b6ff306622fbaf27bd739fdf855245b03cc795f GIT binary patch literal 32768 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 QOpcvOdW$n~qw}i&0cv@jKL7v# literal 0 HcmV?d00001 diff --git a/tests/opencl/saxpy/README b/kernels/vecaddx/input.c.bin similarity index 100% rename from tests/opencl/saxpy/README rename to kernels/vecaddx/input.c.bin diff --git a/tests/regression/vecaddx/kernel.cpp b/kernels/vecaddx/kernel.cpp similarity index 100% rename from tests/regression/vecaddx/kernel.cpp rename to kernels/vecaddx/kernel.cpp diff --git a/tests/opencl/sfilter/README b/lib/.gitignore similarity index 100% rename from tests/opencl/sfilter/README rename to lib/.gitignore diff --git a/kernel/Makefile b/lib/Makefile similarity index 100% rename from kernel/Makefile rename to lib/Makefile diff --git a/gemmini/include/accumulator.h b/lib/gemmini/include/accumulator.h similarity index 100% rename from gemmini/include/accumulator.h rename to lib/gemmini/include/accumulator.h diff --git a/gemmini/include/character.h b/lib/gemmini/include/character.h similarity index 100% rename from gemmini/include/character.h rename to lib/gemmini/include/character.h diff --git a/gemmini/include/gemmini.h b/lib/gemmini/include/gemmini.h similarity index 100% rename from gemmini/include/gemmini.h rename to lib/gemmini/include/gemmini.h diff --git a/gemmini/include/gemmini_counter.h b/lib/gemmini/include/gemmini_counter.h similarity index 100% rename from gemmini/include/gemmini_counter.h rename to lib/gemmini/include/gemmini_counter.h diff --git a/gemmini/include/gemmini_nn.h b/lib/gemmini/include/gemmini_nn.h similarity index 100% rename from gemmini/include/gemmini_nn.h rename to lib/gemmini/include/gemmini_nn.h diff --git a/gemmini/include/gemmini_params.dim16fp16.h b/lib/gemmini/include/gemmini_params.dim16fp16.h similarity index 100% rename from gemmini/include/gemmini_params.dim16fp16.h rename to lib/gemmini/include/gemmini_params.dim16fp16.h diff --git a/gemmini/include/gemmini_params.dim8fp32.h b/lib/gemmini/include/gemmini_params.dim8fp32.h similarity index 100% rename from gemmini/include/gemmini_params.dim8fp32.h rename to lib/gemmini/include/gemmini_params.dim8fp32.h diff --git a/gemmini/include/gemmini_params.h b/lib/gemmini/include/gemmini_params.h similarity index 100% rename from gemmini/include/gemmini_params.h rename to lib/gemmini/include/gemmini_params.h diff --git a/gemmini/include/gemmini_testutils.h b/lib/gemmini/include/gemmini_testutils.h similarity index 100% rename from gemmini/include/gemmini_testutils.h rename to lib/gemmini/include/gemmini_testutils.h diff --git a/gemmini/include/translator.h b/lib/gemmini/include/translator.h similarity index 100% rename from gemmini/include/translator.h rename to lib/gemmini/include/translator.h diff --git a/gemmini/rocc-software/.gitignore b/lib/gemmini/rocc-software/.gitignore similarity index 100% rename from gemmini/rocc-software/.gitignore rename to lib/gemmini/rocc-software/.gitignore diff --git a/gemmini/rocc-software/CONTRIBUTING.md b/lib/gemmini/rocc-software/CONTRIBUTING.md similarity index 100% rename from gemmini/rocc-software/CONTRIBUTING.md rename to lib/gemmini/rocc-software/CONTRIBUTING.md diff --git a/gemmini/rocc-software/LICENSE b/lib/gemmini/rocc-software/LICENSE similarity index 100% rename from gemmini/rocc-software/LICENSE rename to lib/gemmini/rocc-software/LICENSE diff --git a/gemmini/rocc-software/README.md b/lib/gemmini/rocc-software/README.md similarity index 100% rename from gemmini/rocc-software/README.md rename to lib/gemmini/rocc-software/README.md diff --git a/gemmini/rocc-software/src/riscv_test_rocc.h b/lib/gemmini/rocc-software/src/riscv_test_rocc.h similarity index 100% rename from gemmini/rocc-software/src/riscv_test_rocc.h rename to lib/gemmini/rocc-software/src/riscv_test_rocc.h diff --git a/gemmini/rocc-software/src/xcustom.h b/lib/gemmini/rocc-software/src/xcustom.h similarity index 100% rename from gemmini/rocc-software/src/xcustom.h rename to lib/gemmini/rocc-software/src/xcustom.h diff --git a/kernel/include/VX_config.h b/lib/include/VX_config.h similarity index 100% rename from kernel/include/VX_config.h rename to lib/include/VX_config.h diff --git a/kernel/include/VX_types.h b/lib/include/VX_types.h similarity index 100% rename from kernel/include/VX_types.h rename to lib/include/VX_types.h diff --git a/kernel/include/gemmini_mmio.h b/lib/include/gemmini_mmio.h similarity index 100% rename from kernel/include/gemmini_mmio.h rename to lib/include/gemmini_mmio.h diff --git a/kernel/include/vx_intrinsics.h b/lib/include/vx_intrinsics.h similarity index 100% rename from kernel/include/vx_intrinsics.h rename to lib/include/vx_intrinsics.h diff --git a/kernel/include/vx_print.h b/lib/include/vx_print.h similarity index 100% rename from kernel/include/vx_print.h rename to lib/include/vx_print.h diff --git a/kernel/include/vx_spawn.h b/lib/include/vx_spawn.h similarity index 100% rename from kernel/include/vx_spawn.h rename to lib/include/vx_spawn.h diff --git a/kernel/linker/vx_link32.ld b/lib/linker/vx_link32.ld similarity index 100% rename from kernel/linker/vx_link32.ld rename to lib/linker/vx_link32.ld diff --git a/kernel/linker/vx_link64.ld b/lib/linker/vx_link64.ld similarity index 100% rename from kernel/linker/vx_link64.ld rename to lib/linker/vx_link64.ld diff --git a/kernel/src/tinyprintf.c b/lib/src/tinyprintf.c similarity index 100% rename from kernel/src/tinyprintf.c rename to lib/src/tinyprintf.c diff --git a/kernel/src/tinyprintf.h b/lib/src/tinyprintf.h similarity index 100% rename from kernel/src/tinyprintf.h rename to lib/src/tinyprintf.h diff --git a/kernel/src/vx_perf.c b/lib/src/vx_perf.c similarity index 100% rename from kernel/src/vx_perf.c rename to lib/src/vx_perf.c diff --git a/kernel/src/vx_print.S b/lib/src/vx_print.S similarity index 100% rename from kernel/src/vx_print.S rename to lib/src/vx_print.S diff --git a/kernel/src/vx_print.c b/lib/src/vx_print.c similarity index 100% rename from kernel/src/vx_print.c rename to lib/src/vx_print.c diff --git a/kernel/src/vx_serial.S b/lib/src/vx_serial.S similarity index 100% rename from kernel/src/vx_serial.S rename to lib/src/vx_serial.S diff --git a/kernel/src/vx_spawn.c b/lib/src/vx_spawn.c similarity index 100% rename from kernel/src/vx_spawn.c rename to lib/src/vx_spawn.c diff --git a/kernel/src/vx_start.S b/lib/src/vx_start.S similarity index 100% rename from kernel/src/vx_start.S rename to lib/src/vx_start.S diff --git a/kernel/src/vx_syscalls.c b/lib/src/vx_syscalls.c similarity index 100% rename from kernel/src/vx_syscalls.c rename to lib/src/vx_syscalls.c diff --git a/kernel/tohost.S b/lib/tohost.S similarity index 100% rename from kernel/tohost.S rename to lib/tohost.S diff --git a/ci/toolchain_env.sh b/scripts/toolchain_env.sh similarity index 100% rename from ci/toolchain_env.sh rename to scripts/toolchain_env.sh diff --git a/ci/toolchain_install.sh b/scripts/toolchain_install.sh similarity index 100% rename from ci/toolchain_install.sh rename to scripts/toolchain_install.sh diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 30ca0fa4..00000000 --- a/tests/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -**/*.log -.depend -*.bin -*.dump -*.elf -*.o -*.ll diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index ab8328df..00000000 --- a/tests/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -all: regression # opencl - -regression: - $(MAKE) -C regression - -opencl: -ifneq ($(XLEN),64) - $(MAKE) -C opencl -endif - -clean: - $(MAKE) -C regression clean - $(MAKE) -C opencl clean - -clean-all: - $(MAKE) -C regression clean-all - # $(MAKE) -C opencl clean-all - -.PHONY: all regression opencl diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile deleted file mode 100644 index 5635643e..00000000 --- a/tests/opencl/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -all: - $(MAKE) -C vecadd - $(MAKE) -C sgemm - $(MAKE) -C psort - $(MAKE) -C saxpy - $(MAKE) -C sfilter - $(MAKE) -C nearn - $(MAKE) -C guassian - $(MAKE) -C dotproduct - $(MAKE) -C kmeans - $(MAKE) -C spmv - $(MAKE) -C stencil - $(MAKE) -C lbm - $(MAKE) -C oclprintf - $(MAKE) -C blackscholes - $(MAKE) -C transpose - $(MAKE) -C convolution - -run-simx: - $(MAKE) -C vecadd run-simx - $(MAKE) -C sgemm run-simx - $(MAKE) -C psort run-simx - $(MAKE) -C saxpy run-simx - $(MAKE) -C sfilter run-simx - $(MAKE) -C nearn run-simx - $(MAKE) -C guassian run-simx - $(MAKE) -C dotproduct run-simx - $(MAKE) -C kmeans run-simx - $(MAKE) -C spmv run-simx - $(MAKE) -C stencil run-simx - $(MAKE) -C lbm run-simx - $(MAKE) -C oclprintf run-simx - $(MAKE) -C blackscholes run-simx - $(MAKE) -C transpose run-simx - $(MAKE) -C convolution run-simx - -run-rtlsim: - $(MAKE) -C vecadd run-rtlsim - $(MAKE) -C sgemm run-rtlsim - $(MAKE) -C psort run-rtlsim - $(MAKE) -C saxpy run-rtlsim - $(MAKE) -C sfilter run-rtlsim - $(MAKE) -C nearn run-rtlsim - $(MAKE) -C guassian run-rtlsim - $(MAKE) -C dotproduct run-rtlsim - $(MAKE) -C kmeans run-rtlsim - $(MAKE) -C spmv run-rtlsim - $(MAKE) -C transpose run-rtlsim - $(MAKE) -C stencil run-rtlsim - $(MAKE) -C lbm run-rtlsim - $(MAKE) -C oclprintf run-rtlsim - $(MAKE) -C blackscholes run-rtlsim - $(MAKE) -C convolution run-rtlsim - -run-opae: - $(MAKE) -C vecadd run-opae - $(MAKE) -C sgemm run-opae - $(MAKE) -C psort run-opae - $(MAKE) -C saxpy run-opae - $(MAKE) -C sfilter run-opae - $(MAKE) -C nearn run-opae - $(MAKE) -C guassian run-opae - $(MAKE) -C dotproduct run-opae - $(MAKE) -C kmeans run-opae - $(MAKE) -C spmv run-opae - $(MAKE) -C transpose run-opae - $(MAKE) -C stencil run-opae - $(MAKE) -C lbm run-opae - $(MAKE) -C oclprintf run-opae - $(MAKE) -C blackscholes run-opae - $(MAKE) -C convolution run-opae - -clean: - $(MAKE) -C vecadd clean - $(MAKE) -C sgemm clean - $(MAKE) -C psort clean - $(MAKE) -C saxpy clean - $(MAKE) -C sfilter clean - $(MAKE) -C nearn clean - $(MAKE) -C guassian clean - $(MAKE) -C dotproduct clean - $(MAKE) -C kmeans clean - $(MAKE) -C spmv clean - $(MAKE) -C transpose clean - $(MAKE) -C stencil clean - $(MAKE) -C lbm clean - $(MAKE) -C oclprintf clean - $(MAKE) -C blackscholes clean - $(MAKE) -C convolution clean - -clean-all: - $(MAKE) -C vecadd clean-all - $(MAKE) -C sgemm clean-all - $(MAKE) -C psort clean-all - $(MAKE) -C saxpy clean-all - $(MAKE) -C sfilter clean-all - $(MAKE) -C nearn clean-all - $(MAKE) -C guassian clean-all - $(MAKE) -C dotproduct clean-all - $(MAKE) -C kmeans clean-all - $(MAKE) -C spmv clean-all - $(MAKE) -C transpose clean-all - $(MAKE) -C stencil clean-all - $(MAKE) -C lbm clean-all - $(MAKE) -C oclprintf clean-all - $(MAKE) -C blackscholes clean-all - $(MAKE) -C convolution clean-all \ No newline at end of file diff --git a/tests/opencl/bfs/CLHelper.h b/tests/opencl/bfs/CLHelper.h deleted file mode 100755 index 6ac9c609..00000000 --- a/tests/opencl/bfs/CLHelper.h +++ /dev/null @@ -1,859 +0,0 @@ -//------------------------------------------ -//--cambine:helper function for OpenCL -//--programmer: Jianbin Fang -//--date: 27/12/2010 -//------------------------------------------ -#ifndef _CL_HELPER_ -#define _CL_HELPER_ - -#include -#include -#include -#include -#include - - -using std::string; -using std::ifstream; -using std::cerr; -using std::endl; -using std::cout; -//#pragma OPENCL EXTENSION cl_nv_compiler_options:enable -#define WORK_DIM 2 // work-items dimensions - -struct oclHandleStruct { - cl_context context; - cl_device_id *devices; - cl_command_queue queue; - cl_program program; - cl_int cl_status; - std::string error_str; - std::vector kernel; -}; - -struct oclHandleStruct oclHandles; - -char kernel_file[100] = "Kernels.cl"; -int total_kernels = 2; -string kernel_names[2] = {"BFS_1", "BFS_2"}; -int work_group_size = 512; -int device_id_inused = 0; // deviced id used (default : 0) - -int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - -/* - * Converts the contents of a file into a string - */ -string FileToString(const string fileName) { - ifstream f(fileName.c_str(), ifstream::in | ifstream::binary); - - try { - size_t size; - char *str; - string s; - - if (f.is_open()) { - size_t fileSize; - f.seekg(0, ifstream::end); - size = fileSize = f.tellg(); - f.seekg(0, ifstream::beg); - - str = new char[size + 1]; - if (!str) - throw(string("Could not allocate memory")); - - f.read(str, fileSize); - f.close(); - str[size] = '\0'; - - s = str; - delete[] str; - return s; - } - } catch (std::string msg) { - cerr << "Exception caught in FileToString(): " << msg << endl; - if (f.is_open()) - f.close(); - } catch (...) { - cerr << "Exception caught in FileToString()" << endl; - if (f.is_open()) - f.close(); - } - string errorMsg = "FileToString()::Error: Unable to open file " + fileName; - throw(errorMsg); -} -//--------------------------------------- -// Read command line parameters -// -void _clCmdParams(int argc, char *argv[]) { - for (int i = 0; i < argc; ++i) { - switch (argv[i][1]) { - case 'g': //--g stands for size of work group - if (++i < argc) { - sscanf(argv[i], "%u", &work_group_size); - } else { - std::cerr << "Could not read argument after option " << argv[i - 1] - << std::endl; - throw; - } - break; - case 'd': //--d stands for device id used in computaion - if (++i < argc) { - sscanf(argv[i], "%u", &device_id_inused); - } else { - std::cerr << "Could not read argument after option " << argv[i - 1] - << std::endl; - throw; - } - break; - default:; - } - } -} - -//--------------------------------------- -// Initlize CL objects -//--description: there are 5 steps to initialize all the OpenCL objects needed -//--revised on 04/01/2011: get the number of devices and -// devices have no relationship with context -void _clInit() { - printf("_clInit()\n"); - - int DEVICE_ID_INUSED = device_id_inused; - cl_int resultCL; - - oclHandles.context = NULL; - oclHandles.devices = NULL; - oclHandles.queue = NULL; - oclHandles.program = NULL; - - cl_uint deviceListSize; - - //----------------------------------------------- - //--cambine-1: find the available platforms and select one - - cl_uint numPlatforms = 1; - cl_platform_id targetPlatform = NULL; - - cl_platform_id *allPlatforms = - (cl_platform_id *)malloc(numPlatforms * sizeof(cl_platform_id)); - - resultCL = clGetPlatformIDs(numPlatforms, allPlatforms, NULL); - if (resultCL != CL_SUCCESS) - throw(string("InitCL()::Error: Getting platform ids (clGetPlatformIDs)")); - - // Select the target platform. Default: first platform - targetPlatform = allPlatforms[0]; - - /*for (int i = 0; i < numPlatforms; i++) -{ -char pbuff[128]; -resultCL = clGetPlatformInfo( allPlatforms[i], - CL_PLATFORM_VENDOR, - sizeof(pbuff), - pbuff, - NULL); -if (resultCL != CL_SUCCESS) -throw (string("InitCL()::Error: Getting platform info (clGetPlatformInfo)")); - - //printf("vedor is %s\n",pbuff); - -} -free(allPlatforms);*/ - - //----------------------------------------------- - //--cambine-2: create an OpenCL context - /*cl_context_properties cprops[3] = { CL_CONTEXT_PLATFORM, - (cl_context_properties)targetPlatform, 0 }; - oclHandles.context = clCreateContextFromType(cprops, - CL_DEVICE_TYPE_GPU, - NULL, - NULL, - &resultCL); - - if ((resultCL != CL_SUCCESS) || (oclHandles.context == NULL)) - throw (string("InitCL()::Error: Creating Context - (clCreateContextFromType)")); - - //----------------------------------------------- - //--cambine-3: detect OpenCL devices - // First, get the size of device list - oclHandles.cl_status = clGetDeviceIDs(targetPlatform, CL_DEVICE_TYPE_GPU, 0, - NULL, &deviceListSize); - if(oclHandles.cl_status!=CL_SUCCESS){ - throw(string("exception in _clInit -> clGetDeviceIDs")); - } - if (deviceListSize == 0) - throw(string("InitCL()::Error: No devices found.")); - - printf("OK1()\n"); - - //std::cout<<"device number:"< clGetDeviceIDs-2")); - } - - oclHandles.context = clCreateContext(NULL, deviceListSize, oclHandles.devices, - NULL, NULL, &resultCL); - if ((resultCL != CL_SUCCESS) || (oclHandles.context == NULL)) - throw(string("InitCL()::Error: Creating Context (clCreateContext)")); - - //----------------------------------------------- - //--cambine-4: Create an OpenCL command queue - oclHandles.queue = clCreateCommandQueue( - oclHandles.context, oclHandles.devices[DEVICE_ID_INUSED], 0, &resultCL); - //printf("resultCL=%d, queue=0x%x\n", resultCL, oclHandles.queue); - - if ((resultCL != CL_SUCCESS) || (oclHandles.queue == NULL)) - throw(string("InitCL()::Creating Command Queue. (clCreateCommandQueue)")); - //----------------------------------------------- - //--cambine-5: Load CL file, build CL program object, create CL kernel object - /*std::string source_str = FileToString(kernel_file); - const char * source = source_str.c_str(); - size_t sourceSize[] = { source_str.length() };*/ - - //oclHandles.program = clCreateProgramWithBuiltInKernels( - // oclHandles.context, 1, &oclHandles.devices[DEVICE_ID_INUSED], - // "BFS_1;BFS_2", &resultCL); - /*oclHandles.program = clCreateProgramWithSource(oclHandles.context, - 1, - &source, - sourceSize, - &resultCL);*/ - // read kernel binary from file - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - std::abort(); - - oclHandles.program = clCreateProgramWithBinary( - oclHandles.context, 1, &oclHandles.devices[DEVICE_ID_INUSED], &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &resultCL); - free(kernel_bin); - - if ((resultCL != CL_SUCCESS) || (oclHandles.program == NULL)) - throw(string("InitCL()::Error: Loading Binary into cl_program. " - "(clCreateProgramWithBinary)")); - - // insert debug information - // std::string options= "-cl-nv-verbose"; //Doesn't work on AMD machines - // options += " -cl-nv-opt-level=3"; - resultCL = clBuildProgram(oclHandles.program, deviceListSize, - oclHandles.devices, NULL, NULL, NULL); - if ((resultCL != CL_SUCCESS) || (oclHandles.program == NULL)) { - cerr << "InitCL()::Error: In clBuildProgram" << endl; - - size_t length; - resultCL = clGetProgramBuildInfo(oclHandles.program, - oclHandles.devices[DEVICE_ID_INUSED], - CL_PROGRAM_BUILD_LOG, 0, NULL, &length); - if (resultCL != CL_SUCCESS) - throw(string("InitCL()::Error: Getting Program build " - "info(clGetProgramBuildInfo)")); - - char *buffer = (char *)malloc(length); - resultCL = clGetProgramBuildInfo( - oclHandles.program, oclHandles.devices[DEVICE_ID_INUSED], - CL_PROGRAM_BUILD_LOG, length, buffer, NULL); - if (resultCL != CL_SUCCESS) - throw(string("InitCL()::Error: Getting Program build " - "info(clGetProgramBuildInfo)")); - - cerr << buffer << endl; - free(buffer); - - throw(string("InitCL()::Error: Building Program (clBuildProgram)")); - } - -// get program information in intermediate representation -#ifdef PTX_MSG - size_t binary_sizes[deviceListSize]; - char *binaries[deviceListSize]; - // figure out number of devices and the sizes of the binary for each device. - oclHandles.cl_status = - clGetProgramInfo(oclHandles.program, CL_PROGRAM_BINARY_SIZES, - sizeof(size_t) * deviceListSize, &binary_sizes, NULL); - if (oclHandles.cl_status != CL_SUCCESS) { - throw(string("--cambine:exception in _InitCL -> clGetProgramInfo-2")); - } - - std::cout << "--cambine:" << binary_sizes << std::endl; - // copy over all of the generated binaries. - for (int i = 0; i < deviceListSize; i++) - binaries[i] = (char *)malloc(sizeof(char) * (binary_sizes[i] + 1)); - oclHandles.cl_status = - clGetProgramInfo(oclHandles.program, CL_PROGRAM_BINARIES, - sizeof(char *) * deviceListSize, binaries, NULL); - if (oclHandles.cl_status != CL_SUCCESS) { - throw(string("--cambine:exception in _InitCL -> clGetProgramInfo-3")); - } - for (int i = 0; i < deviceListSize; i++) - binaries[i][binary_sizes[i]] = '\0'; - std::cout << "--cambine:writing ptd information..." << std::endl; - FILE *ptx_file = fopen("cl.ptx", "w"); - if (ptx_file == NULL) { - throw(string("exceptions in allocate ptx file.")); - } - fprintf(ptx_file, "%s", binaries[DEVICE_ID_INUSED]); - fclose(ptx_file); - std::cout << "--cambine:writing ptd information done." << std::endl; - for (int i = 0; i < deviceListSize; i++) - free(binaries[i]); -#endif - - for (int nKernel = 0; nKernel < total_kernels; nKernel++) { - /* get a kernel object handle for a kernel with the given name */ - cl_kernel kernel = clCreateKernel( - oclHandles.program, (kernel_names[nKernel]).c_str(), &resultCL); - - if ((resultCL != CL_SUCCESS) || (kernel == NULL)) { - string errorMsg = "InitCL()::Error: Creating Kernel (clCreateKernel) \"" + - kernel_names[nKernel] + "\""; - throw(errorMsg); - } - - oclHandles.kernel.push_back(kernel); - } -// get resource alocation information -#ifdef RES_MSG - char *build_log; - size_t ret_val_size; - oclHandles.cl_status = clGetProgramBuildInfo( - oclHandles.program, oclHandles.devices[DEVICE_ID_INUSED], - CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - if (oclHandles.cl_status != CL_SUCCESS) { - throw(string("exceptions in _InitCL -> getting resource information")); - } - - build_log = (char *)malloc(ret_val_size + 1); - oclHandles.cl_status = clGetProgramBuildInfo( - oclHandles.program, oclHandles.devices[DEVICE_ID_INUSED], - CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); - if (oclHandles.cl_status != CL_SUCCESS) { - throw(string( - "exceptions in _InitCL -> getting resources allocation information-2")); - } - build_log[ret_val_size] = '\0'; - std::cout << "--cambine:" << build_log << std::endl; - free(build_log); -#endif -} - -//--------------------------------------- -// release CL objects -void _clRelease() { - char errorFlag = false; - - for (int nKernel = 0; nKernel < oclHandles.kernel.size(); nKernel++) { - if (oclHandles.kernel[nKernel] != NULL) { - cl_int resultCL = clReleaseKernel(oclHandles.kernel[nKernel]); - if (resultCL != CL_SUCCESS) { - cerr << "ReleaseCL()::Error: In clReleaseKernel" << endl; - errorFlag = true; - } - oclHandles.kernel[nKernel] = NULL; - printf("clReleaseKernel()\n"); - } - } - - if (oclHandles.program != NULL) { - cl_int resultCL = clReleaseProgram(oclHandles.program); - if (resultCL != CL_SUCCESS) { - cerr << "ReleaseCL()::Error: In clReleaseProgram" << endl; - errorFlag = true; - } - oclHandles.program = NULL; - printf("clReleaseProgram()\n"); - } - - if (oclHandles.queue != NULL) { - cl_int resultCL = clReleaseCommandQueue(oclHandles.queue); - if (resultCL != CL_SUCCESS) { - cerr << "ReleaseCL()::Error: In clReleaseCommandQueue" << endl; - errorFlag = true; - } - oclHandles.queue = NULL; - printf("clReleaseCommandQueue()\n"); - } - - if (oclHandles.context != NULL) { - cl_int resultCL = clReleaseContext(oclHandles.context); - if (resultCL != CL_SUCCESS) { - cerr << "ReleaseCL()::Error: In clReleaseContext" << endl; - errorFlag = true; - } - oclHandles.context = NULL; - printf("clReleaseContext()\n"); - } - - if (oclHandles.devices != NULL) { - cl_int resultCL = clReleaseDevice(oclHandles.devices[0]); - if (resultCL != CL_SUCCESS) { - cerr << "ReleaseCL()::Error: In clReleaseDevice" << endl; - errorFlag = true; - } - free(oclHandles.devices); - printf("clReleaseDevice()\n"); - } - - if (errorFlag) - throw(string("ReleaseCL()::Error encountered.")); -} -//-------------------------------------------------------- -//--cambine:create buffer and then copy data from host to device -cl_mem _clCreateAndCpyMem(int size, void *h_mem_source) throw(string) { - cl_mem d_mem; - d_mem = clCreateBuffer(oclHandles.context, - CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, size, - h_mem_source, &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clCreateAndCpyMem()")); -#endif - return d_mem; -} -//------------------------------------------------------- -//--cambine: create read only buffer for devices -//--date: 17/01/2011 -cl_mem _clMallocRW(int size, void *h_mem_ptr) throw(string) { - cl_mem d_mem; - d_mem = clCreateBuffer(oclHandles.context, - CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, size, - h_mem_ptr, &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clMallocRW")); -#endif - return d_mem; -} -//------------------------------------------------------- -//--cambine: create read and write buffer for devices -//--date: 17/01/2011 -cl_mem _clMalloc(int size, void *h_mem_ptr) throw(string) { - cl_mem d_mem; - d_mem = clCreateBuffer(oclHandles.context, - CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR, size, - h_mem_ptr, &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clMalloc")); -#endif - return d_mem; -} - -//------------------------------------------------------- -//--cambine: transfer data from host to device -//--date: 17/01/2011 -void _clMemcpyH2D(cl_mem d_mem, int size, const void *h_mem_ptr) throw(string) { - oclHandles.cl_status = clEnqueueWriteBuffer( - oclHandles.queue, d_mem, CL_TRUE, 0, size, h_mem_ptr, 0, NULL, NULL); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clMemcpyH2D")); -#endif -} -//-------------------------------------------------------- -//--cambine:create buffer and then copy data from host to device with pinned -// memory -cl_mem _clCreateAndCpyPinnedMem(int size, float *h_mem_source) throw(string) { - cl_mem d_mem, d_mem_pinned; - float *h_mem_pinned = NULL; - d_mem_pinned = clCreateBuffer(oclHandles.context, - CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, size, - NULL, &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clCreateAndCpyMem()->d_mem_pinned")); -#endif - //------------ - d_mem = clCreateBuffer(oclHandles.context, CL_MEM_READ_ONLY, size, NULL, - &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clCreateAndCpyMem() -> d_mem ")); -#endif - //---------- - h_mem_pinned = (cl_float *)clEnqueueMapBuffer( - oclHandles.queue, d_mem_pinned, CL_TRUE, CL_MAP_WRITE, 0, size, 0, NULL, - NULL, &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clCreateAndCpyMem() -> clEnqueueMapBuffer")); -#endif - int element_number = size / sizeof(float); -#pragma omp parallel for - for (int i = 0; i < element_number; i++) { - h_mem_pinned[i] = h_mem_source[i]; - } - //---------- - oclHandles.cl_status = clEnqueueWriteBuffer( - oclHandles.queue, d_mem, CL_TRUE, 0, size, h_mem_pinned, 0, NULL, NULL); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clCreateAndCpyMem() -> clEnqueueWriteBuffer")); -#endif - - return d_mem; -} - -//-------------------------------------------------------- -//--cambine:create write only buffer on device -cl_mem _clMallocWO(int size) throw(string) { - cl_mem d_mem; - d_mem = clCreateBuffer(oclHandles.context, CL_MEM_WRITE_ONLY, size, 0, - &oclHandles.cl_status); -#ifdef ERRMSG - if (oclHandles.cl_status != CL_SUCCESS) - throw(string("excpetion in _clCreateMem()")); -#endif - return d_mem; -} - -//-------------------------------------------------------- -// transfer data from device to host -void _clMemcpyD2H(cl_mem d_mem, int size, void *h_mem) throw(string) { - oclHandles.cl_status = clEnqueueReadBuffer(oclHandles.queue, d_mem, CL_TRUE, - 0, size, h_mem, 0, 0, 0); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clCpyMemD2H -> "; - switch (oclHandles.cl_status) { - case CL_INVALID_COMMAND_QUEUE: - oclHandles.error_str += "CL_INVALID_COMMAND_QUEUE"; - break; - case CL_INVALID_CONTEXT: - oclHandles.error_str += "CL_INVALID_CONTEXT"; - break; - case CL_INVALID_MEM_OBJECT: - oclHandles.error_str += "CL_INVALID_MEM_OBJECT"; - break; - case CL_INVALID_VALUE: - oclHandles.error_str += "CL_INVALID_VALUE"; - break; - case CL_INVALID_EVENT_WAIT_LIST: - oclHandles.error_str += "CL_INVALID_EVENT_WAIT_LIST"; - break; - case CL_MEM_OBJECT_ALLOCATION_FAILURE: - oclHandles.error_str += "CL_MEM_OBJECT_ALLOCATION_FAILURE"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unknown reason"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) - throw(oclHandles.error_str); -#endif -} - -//-------------------------------------------------------- -// set kernel arguments -void _clSetArgs(int kernel_id, int arg_idx, void *d_mem, - int size = 0) throw(string) { - if (!size) { - oclHandles.cl_status = clSetKernelArg(oclHandles.kernel[kernel_id], arg_idx, - sizeof(d_mem), &d_mem); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clSetKernelArg() "; - switch (oclHandles.cl_status) { - case CL_INVALID_KERNEL: - oclHandles.error_str += "CL_INVALID_KERNEL"; - break; - case CL_INVALID_ARG_INDEX: - oclHandles.error_str += "CL_INVALID_ARG_INDEX"; - break; - case CL_INVALID_ARG_VALUE: - oclHandles.error_str += "CL_INVALID_ARG_VALUE"; - break; - case CL_INVALID_MEM_OBJECT: - oclHandles.error_str += "CL_INVALID_MEM_OBJECT"; - break; - case CL_INVALID_SAMPLER: - oclHandles.error_str += "CL_INVALID_SAMPLER"; - break; - case CL_INVALID_ARG_SIZE: - oclHandles.error_str += "CL_INVALID_ARG_SIZE"; - break; - case CL_OUT_OF_RESOURCES: - oclHandles.error_str += "CL_OUT_OF_RESOURCES"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unknown reason"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) - throw(oclHandles.error_str); -#endif - } else { - oclHandles.cl_status = - clSetKernelArg(oclHandles.kernel[kernel_id], arg_idx, size, d_mem); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clSetKernelArg() "; - switch (oclHandles.cl_status) { - case CL_INVALID_KERNEL: - oclHandles.error_str += "CL_INVALID_KERNEL"; - break; - case CL_INVALID_ARG_INDEX: - oclHandles.error_str += "CL_INVALID_ARG_INDEX"; - break; - case CL_INVALID_ARG_VALUE: - oclHandles.error_str += "CL_INVALID_ARG_VALUE"; - break; - case CL_INVALID_MEM_OBJECT: - oclHandles.error_str += "CL_INVALID_MEM_OBJECT"; - break; - case CL_INVALID_SAMPLER: - oclHandles.error_str += "CL_INVALID_SAMPLER"; - break; - case CL_INVALID_ARG_SIZE: - oclHandles.error_str += "CL_INVALID_ARG_SIZE"; - break; - case CL_OUT_OF_RESOURCES: - oclHandles.error_str += "CL_OUT_OF_RESOURCES"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unknown reason"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) - throw(oclHandles.error_str); -#endif - } -} -void _clFinish() throw(string) { - oclHandles.cl_status = clFinish(oclHandles.queue); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clFinish"; - switch (oclHandles.cl_status) { - case CL_INVALID_COMMAND_QUEUE: - oclHandles.error_str += "CL_INVALID_COMMAND_QUEUE"; - break; - case CL_OUT_OF_RESOURCES: - oclHandles.error_str += "CL_OUT_OF_RESOURCES"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unknown reasons"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) { - throw(oclHandles.error_str); - } -#endif -} -//-------------------------------------------------------- -//--cambine:enqueue kernel -void _clInvokeKernel(int kernel_id, int work_items, - int work_group_size) throw(string) { - cl_uint work_dim = WORK_DIM; - //cl_event e[1]; - if (work_items % work_group_size != 0) // process situations that work_items - // cannot be divided by work_group_size - work_items = - work_items + (work_group_size - (work_items % work_group_size)); - size_t local_work_size[] = {work_group_size, 1}; - size_t global_work_size[] = {work_items, 1}; - oclHandles.cl_status = clEnqueueNDRangeKernel( - oclHandles.queue, oclHandles.kernel[kernel_id], work_dim, 0, - global_work_size, local_work_size, 0, 0, NULL); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clInvokeKernel() -> "; - switch (oclHandles.cl_status) { - case CL_INVALID_PROGRAM_EXECUTABLE: - oclHandles.error_str += "CL_INVALID_PROGRAM_EXECUTABLE"; - break; - case CL_INVALID_COMMAND_QUEUE: - oclHandles.error_str += "CL_INVALID_COMMAND_QUEUE"; - break; - case CL_INVALID_KERNEL: - oclHandles.error_str += "CL_INVALID_KERNEL"; - break; - case CL_INVALID_CONTEXT: - oclHandles.error_str += "CL_INVALID_CONTEXT"; - break; - case CL_INVALID_KERNEL_ARGS: - oclHandles.error_str += "CL_INVALID_KERNEL_ARGS"; - break; - case CL_INVALID_WORK_DIMENSION: - oclHandles.error_str += "CL_INVALID_WORK_DIMENSION"; - break; - case CL_INVALID_GLOBAL_WORK_SIZE: - oclHandles.error_str += "CL_INVALID_GLOBAL_WORK_SIZE"; - break; - case CL_INVALID_WORK_GROUP_SIZE: - oclHandles.error_str += "CL_INVALID_WORK_GROUP_SIZE"; - break; - case CL_INVALID_WORK_ITEM_SIZE: - oclHandles.error_str += "CL_INVALID_WORK_ITEM_SIZE"; - break; - case CL_INVALID_GLOBAL_OFFSET: - oclHandles.error_str += "CL_INVALID_GLOBAL_OFFSET"; - break; - case CL_OUT_OF_RESOURCES: - oclHandles.error_str += "CL_OUT_OF_RESOURCES"; - break; - case CL_MEM_OBJECT_ALLOCATION_FAILURE: - oclHandles.error_str += "CL_MEM_OBJECT_ALLOCATION_FAILURE"; - break; - case CL_INVALID_EVENT_WAIT_LIST: - oclHandles.error_str += "CL_INVALID_EVENT_WAIT_LIST"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unkown reseason"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) - throw(oclHandles.error_str); -#endif - //_clFinish(); - // oclHandles.cl_status = clWaitForEvents(1, &e[0]); - // #ifdef ERRMSG - // if (oclHandles.cl_status!= CL_SUCCESS) - // throw(string("excpetion in _clEnqueueNDRange() -> clWaitForEvents")); - // #endif -} -void _clInvokeKernel2D(int kernel_id, int range_x, int range_y, int group_x, - int group_y) throw(string) { - cl_uint work_dim = WORK_DIM; - size_t local_work_size[] = {group_x, group_y}; - size_t global_work_size[] = {range_x, range_y}; - //cl_event e[1]; - /*if(work_items%work_group_size != 0) //process situations that work_items - cannot be divided by work_group_size - work_items = work_items + (work_group_size-(work_items%work_group_size));*/ - oclHandles.cl_status = clEnqueueNDRangeKernel( - oclHandles.queue, oclHandles.kernel[kernel_id], work_dim, 0, - global_work_size, local_work_size, 0, 0, NULL); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clInvokeKernel() -> "; - switch (oclHandles.cl_status) { - case CL_INVALID_PROGRAM_EXECUTABLE: - oclHandles.error_str += "CL_INVALID_PROGRAM_EXECUTABLE"; - break; - case CL_INVALID_COMMAND_QUEUE: - oclHandles.error_str += "CL_INVALID_COMMAND_QUEUE"; - break; - case CL_INVALID_KERNEL: - oclHandles.error_str += "CL_INVALID_KERNEL"; - break; - case CL_INVALID_CONTEXT: - oclHandles.error_str += "CL_INVALID_CONTEXT"; - break; - case CL_INVALID_KERNEL_ARGS: - oclHandles.error_str += "CL_INVALID_KERNEL_ARGS"; - break; - case CL_INVALID_WORK_DIMENSION: - oclHandles.error_str += "CL_INVALID_WORK_DIMENSION"; - break; - case CL_INVALID_GLOBAL_WORK_SIZE: - oclHandles.error_str += "CL_INVALID_GLOBAL_WORK_SIZE"; - break; - case CL_INVALID_WORK_GROUP_SIZE: - oclHandles.error_str += "CL_INVALID_WORK_GROUP_SIZE"; - break; - case CL_INVALID_WORK_ITEM_SIZE: - oclHandles.error_str += "CL_INVALID_WORK_ITEM_SIZE"; - break; - case CL_INVALID_GLOBAL_OFFSET: - oclHandles.error_str += "CL_INVALID_GLOBAL_OFFSET"; - break; - case CL_OUT_OF_RESOURCES: - oclHandles.error_str += "CL_OUT_OF_RESOURCES"; - break; - case CL_MEM_OBJECT_ALLOCATION_FAILURE: - oclHandles.error_str += "CL_MEM_OBJECT_ALLOCATION_FAILURE"; - break; - case CL_INVALID_EVENT_WAIT_LIST: - oclHandles.error_str += "CL_INVALID_EVENT_WAIT_LIST"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unkown reseason"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) - throw(oclHandles.error_str); -#endif - //_clFinish(); - /*oclHandles.cl_status = clWaitForEvents(1, &e[0]); - - #ifdef ERRMSG - - if (oclHandles.cl_status!= CL_SUCCESS) - - throw(string("excpetion in _clEnqueueNDRange() -> clWaitForEvents")); - - #endif*/ -} - -//-------------------------------------------------------- -// release OpenCL objects -void _clFree(cl_mem ob) throw(string) { - if (ob != NULL) - oclHandles.cl_status = clReleaseMemObject(ob); -#ifdef ERRMSG - oclHandles.error_str = "excpetion in _clFree() ->"; - switch (oclHandles.cl_status) { - case CL_INVALID_MEM_OBJECT: - oclHandles.error_str += "CL_INVALID_MEM_OBJECT"; - break; - case CL_OUT_OF_RESOURCES: - oclHandles.error_str += "CL_OUT_OF_RESOURCES"; - break; - case CL_OUT_OF_HOST_MEMORY: - oclHandles.error_str += "CL_OUT_OF_HOST_MEMORY"; - break; - default: - oclHandles.error_str += "Unkown reseason"; - break; - } - if (oclHandles.cl_status != CL_SUCCESS) - throw(oclHandles.error_str); -#endif -} -#endif //_CL_HELPER_ diff --git a/tests/opencl/bfs/Makefile b/tests/opencl/bfs/Makefile deleted file mode 100644 index 7cb3bd9a..00000000 --- a/tests/opencl/bfs/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = bfs - -SRCS = main.cc - -OPTS ?= - -include ../common.mk diff --git a/tests/opencl/bfs/graph4096.txt b/tests/opencl/bfs/graph4096.txt deleted file mode 100755 index 56743261..00000000 --- a/tests/opencl/bfs/graph4096.txt +++ /dev/null @@ -1,28677 +0,0 @@ -4096 -0 10 -10 6 -16 2 -18 5 -23 7 -30 7 -37 4 -41 4 -45 3 -48 5 -53 7 -60 4 -64 4 -68 6 -74 7 -81 5 -86 11 -97 5 -102 5 -107 8 -115 4 -119 4 -123 6 -129 4 -133 5 -138 7 -145 4 -149 2 -151 12 -163 3 -166 6 -172 6 -178 7 -185 5 -190 11 -201 4 -205 6 -211 9 -220 3 -223 4 -227 5 -232 4 -236 5 -241 6 -247 10 -257 4 -261 5 -266 7 -273 5 -278 4 -282 8 -290 5 -295 8 -303 9 -312 4 -316 5 -321 5 -326 3 -329 8 -337 5 -342 10 -352 6 -358 4 -362 5 -367 5 -372 10 -382 6 -388 8 -396 8 -404 5 -409 5 -414 5 -419 8 -427 6 -433 8 -441 9 -450 5 -455 10 -465 5 -470 11 -481 5 -486 7 -493 8 -501 9 -510 4 -514 10 -524 9 -533 5 -538 5 -543 7 -550 3 -553 3 -556 2 -558 6 -564 8 -572 3 -575 4 -579 5 -584 11 -595 8 -603 7 -610 5 -615 7 -622 4 -626 7 -633 6 -639 5 -644 4 -648 5 -653 4 -657 8 -665 8 -673 10 -683 2 -685 5 -690 5 -695 6 -701 3 -704 5 -709 9 -718 10 -728 7 -735 7 -742 9 -751 3 -754 4 -758 9 -767 6 -773 10 -783 7 -790 4 -794 8 -802 4 -806 5 -811 5 -816 8 -824 7 -831 8 -839 10 -849 5 -854 5 -859 4 -863 4 -867 7 -874 9 -883 2 -885 10 -895 8 -903 5 -908 6 -914 5 -919 11 -930 2 -932 6 -938 2 -940 4 -944 6 -950 6 -956 5 -961 4 -965 3 -968 4 -972 1 -973 10 -983 7 -990 4 -994 6 -1000 9 -1009 6 -1015 10 -1025 7 -1032 7 -1039 5 -1044 5 -1049 9 -1058 4 -1062 5 -1067 4 -1071 6 -1077 6 -1083 7 -1090 9 -1099 2 -1101 4 -1105 3 -1108 9 -1117 7 -1124 4 -1128 9 -1137 9 -1146 4 -1150 11 -1161 6 -1167 8 -1175 6 -1181 7 -1188 8 -1196 4 -1200 7 -1207 8 -1215 10 -1225 3 -1228 6 -1234 3 -1237 4 -1241 5 -1246 3 -1249 1 -1250 4 -1254 6 -1260 4 -1264 11 -1275 7 -1282 9 -1291 8 -1299 5 -1304 6 -1310 8 -1318 9 -1327 6 -1333 7 -1340 10 -1350 7 -1357 8 -1365 10 -1375 6 -1381 2 -1383 10 -1393 5 -1398 8 -1406 9 -1415 4 -1419 5 -1424 3 -1427 4 -1431 4 -1435 9 -1444 6 -1450 9 -1459 6 -1465 4 -1469 6 -1475 9 -1484 8 -1492 7 -1499 9 -1508 2 -1510 3 -1513 8 -1521 6 -1527 5 -1532 9 -1541 6 -1547 5 -1552 9 -1561 12 -1573 2 -1575 3 -1578 7 -1585 6 -1591 5 -1596 10 -1606 9 -1615 9 -1624 1 -1625 4 -1629 6 -1635 2 -1637 14 -1651 2 -1653 4 -1657 4 -1661 5 -1666 7 -1673 6 -1679 3 -1682 13 -1695 5 -1700 7 -1707 8 -1715 3 -1718 5 -1723 6 -1729 7 -1736 6 -1742 7 -1749 2 -1751 7 -1758 5 -1763 4 -1767 4 -1771 6 -1777 2 -1779 3 -1782 9 -1791 7 -1798 4 -1802 8 -1810 7 -1817 6 -1823 6 -1829 4 -1833 7 -1840 8 -1848 2 -1850 14 -1864 9 -1873 6 -1879 6 -1885 6 -1891 2 -1893 8 -1901 5 -1906 8 -1914 4 -1918 4 -1922 3 -1925 8 -1933 4 -1937 4 -1941 6 -1947 3 -1950 8 -1958 7 -1965 6 -1971 4 -1975 5 -1980 6 -1986 4 -1990 6 -1996 10 -2006 5 -2011 5 -2016 5 -2021 7 -2028 5 -2033 6 -2039 7 -2046 4 -2050 6 -2056 16 -2072 6 -2078 11 -2089 11 -2100 3 -2103 5 -2108 8 -2116 4 -2120 7 -2127 2 -2129 10 -2139 6 -2145 7 -2152 8 -2160 6 -2166 5 -2171 5 -2176 2 -2178 4 -2182 5 -2187 5 -2192 1 -2193 7 -2200 8 -2208 7 -2215 8 -2223 8 -2231 5 -2236 9 -2245 3 -2248 5 -2253 6 -2259 2 -2261 4 -2265 4 -2269 8 -2277 5 -2282 8 -2290 6 -2296 6 -2302 4 -2306 5 -2311 7 -2318 5 -2323 4 -2327 8 -2335 12 -2347 1 -2348 5 -2353 8 -2361 3 -2364 6 -2370 4 -2374 7 -2381 4 -2385 8 -2393 4 -2397 2 -2399 5 -2404 5 -2409 6 -2415 6 -2421 5 -2426 8 -2434 5 -2439 6 -2445 6 -2451 6 -2457 2 -2459 4 -2463 3 -2466 6 -2472 5 -2477 5 -2482 10 -2492 6 -2498 4 -2502 9 -2511 4 -2515 4 -2519 6 -2525 9 -2534 7 -2541 6 -2547 4 -2551 6 -2557 5 -2562 3 -2565 6 -2571 6 -2577 7 -2584 4 -2588 10 -2598 8 -2606 6 -2612 6 -2618 4 -2622 7 -2629 7 -2636 6 -2642 2 -2644 4 -2648 12 -2660 6 -2666 13 -2679 11 -2690 9 -2699 2 -2701 5 -2706 6 -2712 6 -2718 3 -2721 7 -2728 3 -2731 6 -2737 11 -2748 2 -2750 7 -2757 4 -2761 5 -2766 4 -2770 6 -2776 4 -2780 6 -2786 5 -2791 6 -2797 4 -2801 9 -2810 7 -2817 6 -2823 8 -2831 8 -2839 13 -2852 7 -2859 6 -2865 6 -2871 4 -2875 7 -2882 9 -2891 11 -2902 5 -2907 9 -2916 4 -2920 5 -2925 3 -2928 4 -2932 4 -2936 5 -2941 2 -2943 9 -2952 3 -2955 13 -2968 4 -2972 5 -2977 4 -2981 8 -2989 10 -2999 5 -3004 8 -3012 5 -3017 4 -3021 4 -3025 11 -3036 5 -3041 6 -3047 7 -3054 5 -3059 5 -3064 6 -3070 9 -3079 2 -3081 4 -3085 5 -3090 11 -3101 5 -3106 3 -3109 5 -3114 5 -3119 6 -3125 8 -3133 6 -3139 4 -3143 5 -3148 7 -3155 6 -3161 8 -3169 5 -3174 4 -3178 6 -3184 6 -3190 6 -3196 5 -3201 4 -3205 6 -3211 8 -3219 7 -3226 6 -3232 3 -3235 5 -3240 7 -3247 6 -3253 11 -3264 6 -3270 4 -3274 3 -3277 1 -3278 2 -3280 8 -3288 7 -3295 8 -3303 8 -3311 5 -3316 9 -3325 9 -3334 7 -3341 3 -3344 7 -3351 8 -3359 5 -3364 1 -3365 4 -3369 2 -3371 5 -3376 7 -3383 8 -3391 2 -3393 5 -3398 5 -3403 12 -3415 4 -3419 6 -3425 5 -3430 4 -3434 8 -3442 6 -3448 4 -3452 3 -3455 7 -3462 4 -3466 6 -3472 5 -3477 7 -3484 8 -3492 6 -3498 6 -3504 11 -3515 6 -3521 2 -3523 10 -3533 3 -3536 7 -3543 8 -3551 4 -3555 11 -3566 5 -3571 8 -3579 6 -3585 8 -3593 6 -3599 5 -3604 7 -3611 2 -3613 5 -3618 2 -3620 4 -3624 10 -3634 4 -3638 8 -3646 5 -3651 4 -3655 6 -3661 5 -3666 11 -3677 10 -3687 4 -3691 6 -3697 2 -3699 6 -3705 6 -3711 4 -3715 7 -3722 4 -3726 6 -3732 9 -3741 4 -3745 6 -3751 7 -3758 10 -3768 3 -3771 12 -3783 2 -3785 7 -3792 4 -3796 8 -3804 8 -3812 4 -3816 5 -3821 10 -3831 6 -3837 6 -3843 5 -3848 6 -3854 7 -3861 6 -3867 3 -3870 5 -3875 5 -3880 7 -3887 12 -3899 9 -3908 4 -3912 6 -3918 3 -3921 6 -3927 4 -3931 8 -3939 6 -3945 9 -3954 11 -3965 10 -3975 7 -3982 7 -3989 8 -3997 8 -4005 6 -4011 3 -4014 6 -4020 10 -4030 5 -4035 9 -4044 6 -4050 3 -4053 7 -4060 2 -4062 4 -4066 3 -4069 4 -4073 7 -4080 11 -4091 3 -4094 6 -4100 7 -4107 4 -4111 7 -4118 7 -4125 7 -4132 9 -4141 6 -4147 5 -4152 3 -4155 9 -4164 8 -4172 5 -4177 5 -4182 7 -4189 7 -4196 7 -4203 7 -4210 4 -4214 6 -4220 3 -4223 4 -4227 3 -4230 4 -4234 4 -4238 8 -4246 5 -4251 5 -4256 3 -4259 7 -4266 5 -4271 3 -4274 4 -4278 6 -4284 5 -4289 4 -4293 9 -4302 9 -4311 5 -4316 5 -4321 6 -4327 5 -4332 9 -4341 5 -4346 5 -4351 4 -4355 5 -4360 8 -4368 6 -4374 15 -4389 7 -4396 2 -4398 7 -4405 7 -4412 9 -4421 4 -4425 8 -4433 6 -4439 6 -4445 5 -4450 6 -4456 7 -4463 5 -4468 4 -4472 9 -4481 4 -4485 7 -4492 9 -4501 3 -4504 15 -4519 8 -4527 10 -4537 5 -4542 2 -4544 6 -4550 3 -4553 5 -4558 5 -4563 8 -4571 9 -4580 8 -4588 7 -4595 10 -4605 9 -4614 10 -4624 7 -4631 3 -4634 5 -4639 6 -4645 5 -4650 5 -4655 10 -4665 10 -4675 9 -4684 3 -4687 6 -4693 7 -4700 5 -4705 9 -4714 6 -4720 7 -4727 6 -4733 8 -4741 12 -4753 7 -4760 5 -4765 9 -4774 4 -4778 5 -4783 5 -4788 9 -4797 7 -4804 6 -4810 5 -4815 9 -4824 3 -4827 5 -4832 5 -4837 3 -4840 7 -4847 3 -4850 4 -4854 7 -4861 9 -4870 7 -4877 8 -4885 6 -4891 6 -4897 5 -4902 10 -4912 4 -4916 4 -4920 4 -4924 3 -4927 5 -4932 7 -4939 4 -4943 3 -4946 5 -4951 5 -4956 3 -4959 3 -4962 1 -4963 6 -4969 4 -4973 10 -4983 4 -4987 7 -4994 4 -4998 4 -5002 4 -5006 6 -5012 7 -5019 7 -5026 8 -5034 12 -5046 7 -5053 5 -5058 7 -5065 8 -5073 3 -5076 6 -5082 5 -5087 3 -5090 6 -5096 3 -5099 4 -5103 4 -5107 6 -5113 7 -5120 5 -5125 3 -5128 2 -5130 5 -5135 6 -5141 6 -5147 2 -5149 7 -5156 9 -5165 8 -5173 6 -5179 4 -5183 6 -5189 6 -5195 8 -5203 3 -5206 9 -5215 3 -5218 6 -5224 13 -5237 9 -5246 6 -5252 7 -5259 11 -5270 5 -5275 9 -5284 6 -5290 4 -5294 6 -5300 9 -5309 7 -5316 4 -5320 5 -5325 3 -5328 1 -5329 4 -5333 4 -5337 3 -5340 3 -5343 2 -5345 4 -5349 7 -5356 5 -5361 11 -5372 6 -5378 8 -5386 7 -5393 5 -5398 2 -5400 9 -5409 8 -5417 2 -5419 5 -5424 3 -5427 9 -5436 6 -5442 7 -5449 5 -5454 7 -5461 6 -5467 4 -5471 4 -5475 8 -5483 3 -5486 4 -5490 13 -5503 7 -5510 6 -5516 2 -5518 6 -5524 8 -5532 8 -5540 7 -5547 9 -5556 4 -5560 4 -5564 7 -5571 2 -5573 10 -5583 2 -5585 8 -5593 4 -5597 7 -5604 8 -5612 8 -5620 5 -5625 3 -5628 6 -5634 5 -5639 9 -5648 6 -5654 6 -5660 3 -5663 9 -5672 9 -5681 7 -5688 8 -5696 6 -5702 7 -5709 2 -5711 8 -5719 4 -5723 6 -5729 3 -5732 9 -5741 7 -5748 6 -5754 8 -5762 6 -5768 4 -5772 6 -5778 8 -5786 3 -5789 10 -5799 10 -5809 5 -5814 9 -5823 5 -5828 10 -5838 9 -5847 7 -5854 5 -5859 4 -5863 7 -5870 4 -5874 5 -5879 6 -5885 8 -5893 8 -5901 7 -5908 4 -5912 2 -5914 6 -5920 5 -5925 7 -5932 6 -5938 3 -5941 6 -5947 7 -5954 5 -5959 8 -5967 5 -5972 7 -5979 6 -5985 4 -5989 5 -5994 5 -5999 3 -6002 2 -6004 5 -6009 7 -6016 11 -6027 7 -6034 6 -6040 3 -6043 6 -6049 11 -6060 10 -6070 2 -6072 9 -6081 5 -6086 2 -6088 4 -6092 7 -6099 6 -6105 5 -6110 5 -6115 5 -6120 3 -6123 3 -6126 5 -6131 7 -6138 5 -6143 11 -6154 4 -6158 8 -6166 8 -6174 9 -6183 4 -6187 6 -6193 5 -6198 4 -6202 6 -6208 5 -6213 6 -6219 8 -6227 6 -6233 6 -6239 5 -6244 4 -6248 4 -6252 4 -6256 6 -6262 7 -6269 4 -6273 6 -6279 11 -6290 5 -6295 9 -6304 2 -6306 8 -6314 4 -6318 3 -6321 2 -6323 9 -6332 9 -6341 2 -6343 8 -6351 9 -6360 5 -6365 4 -6369 5 -6374 3 -6377 6 -6383 12 -6395 7 -6402 3 -6405 9 -6414 7 -6421 7 -6428 5 -6433 6 -6439 5 -6444 6 -6450 2 -6452 6 -6458 3 -6461 9 -6470 6 -6476 7 -6483 11 -6494 9 -6503 5 -6508 8 -6516 4 -6520 7 -6527 5 -6532 2 -6534 4 -6538 4 -6542 7 -6549 5 -6554 6 -6560 3 -6563 4 -6567 7 -6574 5 -6579 6 -6585 5 -6590 7 -6597 11 -6608 8 -6616 5 -6621 16 -6637 5 -6642 12 -6654 7 -6661 6 -6667 10 -6677 5 -6682 7 -6689 1 -6690 6 -6696 8 -6704 5 -6709 10 -6719 5 -6724 3 -6727 6 -6733 5 -6738 2 -6740 4 -6744 5 -6749 12 -6761 5 -6766 10 -6776 8 -6784 7 -6791 6 -6797 6 -6803 3 -6806 5 -6811 6 -6817 2 -6819 11 -6830 7 -6837 7 -6844 8 -6852 6 -6858 8 -6866 6 -6872 4 -6876 3 -6879 7 -6886 8 -6894 6 -6900 6 -6906 3 -6909 8 -6917 5 -6922 7 -6929 4 -6933 6 -6939 7 -6946 5 -6951 5 -6956 5 -6961 9 -6970 8 -6978 5 -6983 8 -6991 5 -6996 6 -7002 7 -7009 3 -7012 8 -7020 10 -7030 3 -7033 6 -7039 6 -7045 8 -7053 5 -7058 7 -7065 5 -7070 4 -7074 9 -7083 10 -7093 6 -7099 5 -7104 4 -7108 12 -7120 8 -7128 2 -7130 3 -7133 2 -7135 11 -7146 12 -7158 6 -7164 9 -7173 12 -7185 8 -7193 5 -7198 4 -7202 7 -7209 3 -7212 4 -7216 8 -7224 3 -7227 4 -7231 5 -7236 7 -7243 5 -7248 7 -7255 3 -7258 10 -7268 8 -7276 3 -7279 8 -7287 11 -7298 2 -7300 8 -7308 6 -7314 6 -7320 9 -7329 4 -7333 11 -7344 6 -7350 4 -7354 5 -7359 4 -7363 9 -7372 1 -7373 10 -7383 4 -7387 8 -7395 7 -7402 8 -7410 9 -7419 4 -7423 3 -7426 6 -7432 5 -7437 7 -7444 9 -7453 8 -7461 6 -7467 10 -7477 8 -7485 13 -7498 4 -7502 6 -7508 7 -7515 10 -7525 7 -7532 4 -7536 3 -7539 3 -7542 10 -7552 5 -7557 6 -7563 6 -7569 3 -7572 7 -7579 9 -7588 5 -7593 8 -7601 7 -7608 7 -7615 7 -7622 5 -7627 5 -7632 6 -7638 7 -7645 6 -7651 6 -7657 10 -7667 6 -7673 4 -7677 5 -7682 8 -7690 6 -7696 8 -7704 9 -7713 2 -7715 3 -7718 9 -7727 4 -7731 4 -7735 6 -7741 6 -7747 9 -7756 6 -7762 3 -7765 4 -7769 12 -7781 4 -7785 4 -7789 6 -7795 7 -7802 3 -7805 1 -7806 7 -7813 2 -7815 4 -7819 3 -7822 5 -7827 9 -7836 8 -7844 9 -7853 8 -7861 6 -7867 2 -7869 4 -7873 8 -7881 5 -7886 9 -7895 3 -7898 10 -7908 2 -7910 8 -7918 6 -7924 7 -7931 4 -7935 7 -7942 3 -7945 6 -7951 8 -7959 6 -7965 11 -7976 6 -7982 9 -7991 4 -7995 2 -7997 7 -8004 5 -8009 5 -8014 7 -8021 8 -8029 7 -8036 4 -8040 4 -8044 11 -8055 11 -8066 6 -8072 6 -8078 9 -8087 3 -8090 6 -8096 9 -8105 6 -8111 4 -8115 6 -8121 4 -8125 4 -8129 5 -8134 8 -8142 10 -8152 5 -8157 4 -8161 6 -8167 7 -8174 6 -8180 3 -8183 6 -8189 5 -8194 10 -8204 4 -8208 6 -8214 5 -8219 3 -8222 5 -8227 8 -8235 8 -8243 4 -8247 4 -8251 4 -8255 11 -8266 10 -8276 6 -8282 6 -8288 8 -8296 3 -8299 4 -8303 6 -8309 5 -8314 9 -8323 3 -8326 3 -8329 9 -8338 6 -8344 7 -8351 5 -8356 4 -8360 7 -8367 11 -8378 4 -8382 6 -8388 9 -8397 8 -8405 8 -8413 4 -8417 6 -8423 9 -8432 1 -8433 3 -8436 7 -8443 5 -8448 4 -8452 6 -8458 3 -8461 4 -8465 4 -8469 5 -8474 5 -8479 4 -8483 5 -8488 5 -8493 3 -8496 7 -8503 5 -8508 9 -8517 6 -8523 3 -8526 3 -8529 6 -8535 4 -8539 7 -8546 8 -8554 7 -8561 4 -8565 5 -8570 6 -8576 6 -8582 6 -8588 6 -8594 6 -8600 6 -8606 4 -8610 3 -8613 5 -8618 4 -8622 8 -8630 2 -8632 8 -8640 5 -8645 6 -8651 4 -8655 5 -8660 4 -8664 7 -8671 3 -8674 7 -8681 3 -8684 5 -8689 7 -8696 3 -8699 5 -8704 5 -8709 5 -8714 6 -8720 9 -8729 5 -8734 6 -8740 2 -8742 4 -8746 9 -8755 5 -8760 8 -8768 4 -8772 10 -8782 5 -8787 7 -8794 7 -8801 3 -8804 4 -8808 5 -8813 10 -8823 4 -8827 8 -8835 8 -8843 5 -8848 4 -8852 4 -8856 5 -8861 7 -8868 10 -8878 5 -8883 3 -8886 2 -8888 4 -8892 8 -8900 5 -8905 3 -8908 4 -8912 7 -8919 12 -8931 9 -8940 6 -8946 5 -8951 5 -8956 7 -8963 12 -8975 10 -8985 8 -8993 9 -9002 10 -9012 6 -9018 11 -9029 5 -9034 4 -9038 9 -9047 6 -9053 12 -9065 6 -9071 6 -9077 2 -9079 1 -9080 6 -9086 3 -9089 6 -9095 8 -9103 5 -9108 6 -9114 10 -9124 2 -9126 10 -9136 5 -9141 4 -9145 4 -9149 4 -9153 4 -9157 8 -9165 7 -9172 12 -9184 2 -9186 5 -9191 6 -9197 4 -9201 4 -9205 5 -9210 5 -9215 5 -9220 14 -9234 5 -9239 4 -9243 5 -9248 3 -9251 3 -9254 7 -9261 5 -9266 6 -9272 7 -9279 6 -9285 5 -9290 6 -9296 4 -9300 7 -9307 8 -9315 5 -9320 2 -9322 4 -9326 7 -9333 9 -9342 7 -9349 4 -9353 7 -9360 3 -9363 2 -9365 3 -9368 7 -9375 5 -9380 4 -9384 4 -9388 4 -9392 3 -9395 3 -9398 5 -9403 9 -9412 7 -9419 4 -9423 5 -9428 3 -9431 6 -9437 6 -9443 2 -9445 7 -9452 4 -9456 9 -9465 4 -9469 5 -9474 6 -9480 4 -9484 12 -9496 6 -9502 7 -9509 8 -9517 6 -9523 1 -9524 5 -9529 5 -9534 5 -9539 5 -9544 4 -9548 3 -9551 11 -9562 4 -9566 6 -9572 4 -9576 6 -9582 5 -9587 4 -9591 3 -9594 3 -9597 3 -9600 9 -9609 6 -9615 4 -9619 7 -9626 5 -9631 4 -9635 4 -9639 8 -9647 6 -9653 9 -9662 5 -9667 7 -9674 6 -9680 8 -9688 2 -9690 6 -9696 4 -9700 5 -9705 8 -9713 6 -9719 4 -9723 9 -9732 9 -9741 9 -9750 2 -9752 3 -9755 6 -9761 8 -9769 4 -9773 7 -9780 3 -9783 5 -9788 4 -9792 1 -9793 8 -9801 6 -9807 11 -9818 4 -9822 8 -9830 5 -9835 8 -9843 6 -9849 6 -9855 8 -9863 9 -9872 7 -9879 2 -9881 5 -9886 6 -9892 5 -9897 4 -9901 14 -9915 5 -9920 5 -9925 8 -9933 10 -9943 5 -9948 5 -9953 5 -9958 5 -9963 5 -9968 7 -9975 3 -9978 4 -9982 6 -9988 5 -9993 6 -9999 11 -10010 7 -10017 5 -10022 4 -10026 6 -10032 7 -10039 5 -10044 6 -10050 4 -10054 7 -10061 9 -10070 7 -10077 4 -10081 6 -10087 3 -10090 5 -10095 6 -10101 4 -10105 13 -10118 5 -10123 4 -10127 10 -10137 8 -10145 6 -10151 9 -10160 3 -10163 2 -10165 12 -10177 10 -10187 9 -10196 3 -10199 11 -10210 13 -10223 5 -10228 7 -10235 6 -10241 5 -10246 2 -10248 3 -10251 6 -10257 9 -10266 6 -10272 6 -10278 8 -10286 7 -10293 2 -10295 3 -10298 9 -10307 5 -10312 5 -10317 6 -10323 5 -10328 9 -10337 6 -10343 7 -10350 9 -10359 7 -10366 5 -10371 7 -10378 9 -10387 4 -10391 7 -10398 6 -10404 2 -10406 4 -10410 10 -10420 9 -10429 10 -10439 4 -10443 4 -10447 4 -10451 3 -10454 6 -10460 5 -10465 8 -10473 6 -10479 6 -10485 6 -10491 7 -10498 7 -10505 11 -10516 6 -10522 9 -10531 4 -10535 5 -10540 7 -10547 6 -10553 3 -10556 5 -10561 4 -10565 11 -10576 6 -10582 7 -10589 3 -10592 4 -10596 5 -10601 8 -10609 3 -10612 7 -10619 9 -10628 5 -10633 3 -10636 11 -10647 5 -10652 5 -10657 8 -10665 5 -10670 8 -10678 5 -10683 2 -10685 9 -10694 7 -10701 6 -10707 5 -10712 5 -10717 7 -10724 5 -10729 3 -10732 3 -10735 7 -10742 5 -10747 4 -10751 9 -10760 7 -10767 11 -10778 9 -10787 5 -10792 6 -10798 6 -10804 5 -10809 5 -10814 6 -10820 5 -10825 5 -10830 11 -10841 6 -10847 5 -10852 5 -10857 7 -10864 5 -10869 12 -10881 7 -10888 7 -10895 4 -10899 2 -10901 5 -10906 6 -10912 9 -10921 2 -10923 7 -10930 5 -10935 4 -10939 7 -10946 10 -10956 10 -10966 4 -10970 7 -10977 6 -10983 7 -10990 6 -10996 2 -10998 3 -11001 5 -11006 4 -11010 6 -11016 5 -11021 5 -11026 6 -11032 6 -11038 3 -11041 9 -11050 7 -11057 5 -11062 2 -11064 5 -11069 5 -11074 8 -11082 9 -11091 4 -11095 6 -11101 6 -11107 9 -11116 5 -11121 5 -11126 4 -11130 2 -11132 7 -11139 4 -11143 6 -11149 7 -11156 3 -11159 5 -11164 4 -11168 1 -11169 8 -11177 7 -11184 5 -11189 6 -11195 2 -11197 7 -11204 4 -11208 8 -11216 4 -11220 5 -11225 8 -11233 9 -11242 3 -11245 5 -11250 11 -11261 6 -11267 4 -11271 9 -11280 11 -11291 4 -11295 5 -11300 6 -11306 9 -11315 1 -11316 5 -11321 7 -11328 4 -11332 3 -11335 3 -11338 5 -11343 5 -11348 7 -11355 2 -11357 5 -11362 5 -11367 9 -11376 7 -11383 6 -11389 9 -11398 8 -11406 9 -11415 5 -11420 16 -11436 1 -11437 8 -11445 7 -11452 6 -11458 11 -11469 7 -11476 5 -11481 11 -11492 3 -11495 3 -11498 5 -11503 3 -11506 7 -11513 7 -11520 5 -11525 7 -11532 5 -11537 11 -11548 3 -11551 2 -11553 6 -11559 7 -11566 6 -11572 6 -11578 8 -11586 7 -11593 7 -11600 6 -11606 7 -11613 9 -11622 10 -11632 7 -11639 10 -11649 8 -11657 6 -11663 7 -11670 5 -11675 11 -11686 10 -11696 13 -11709 6 -11715 6 -11721 12 -11733 5 -11738 3 -11741 4 -11745 6 -11751 6 -11757 13 -11770 6 -11776 6 -11782 5 -11787 2 -11789 6 -11795 5 -11800 4 -11804 7 -11811 8 -11819 3 -11822 7 -11829 7 -11836 7 -11843 9 -11852 2 -11854 2 -11856 7 -11863 5 -11868 6 -11874 4 -11878 7 -11885 2 -11887 4 -11891 4 -11895 3 -11898 5 -11903 6 -11909 3 -11912 7 -11919 6 -11925 8 -11933 2 -11935 9 -11944 5 -11949 6 -11955 5 -11960 3 -11963 13 -11976 8 -11984 6 -11990 3 -11993 4 -11997 3 -12000 7 -12007 6 -12013 9 -12022 4 -12026 11 -12037 4 -12041 6 -12047 6 -12053 9 -12062 4 -12066 3 -12069 6 -12075 7 -12082 3 -12085 5 -12090 8 -12098 6 -12104 4 -12108 8 -12116 4 -12120 11 -12131 6 -12137 7 -12144 3 -12147 8 -12155 8 -12163 3 -12166 6 -12172 5 -12177 3 -12180 5 -12185 6 -12191 3 -12194 7 -12201 8 -12209 3 -12212 2 -12214 5 -12219 4 -12223 2 -12225 8 -12233 4 -12237 5 -12242 3 -12245 5 -12250 6 -12256 5 -12261 8 -12269 4 -12273 6 -12279 4 -12283 7 -12290 5 -12295 8 -12303 5 -12308 3 -12311 6 -12317 6 -12323 4 -12327 7 -12334 7 -12341 1 -12342 8 -12350 4 -12354 4 -12358 6 -12364 5 -12369 13 -12382 3 -12385 7 -12392 4 -12396 7 -12403 10 -12413 8 -12421 9 -12430 9 -12439 6 -12445 6 -12451 10 -12461 6 -12467 8 -12475 3 -12478 9 -12487 11 -12498 4 -12502 6 -12508 4 -12512 4 -12516 4 -12520 5 -12525 8 -12533 4 -12537 5 -12542 5 -12547 6 -12553 4 -12557 8 -12565 8 -12573 6 -12579 5 -12584 5 -12589 6 -12595 4 -12599 4 -12603 2 -12605 8 -12613 4 -12617 5 -12622 4 -12626 6 -12632 5 -12637 12 -12649 5 -12654 6 -12660 9 -12669 5 -12674 5 -12679 7 -12686 6 -12692 5 -12697 4 -12701 6 -12707 5 -12712 5 -12717 6 -12723 5 -12728 8 -12736 10 -12746 6 -12752 7 -12759 6 -12765 4 -12769 6 -12775 6 -12781 13 -12794 6 -12800 11 -12811 4 -12815 8 -12823 7 -12830 7 -12837 6 -12843 6 -12849 7 -12856 5 -12861 10 -12871 10 -12881 8 -12889 9 -12898 4 -12902 6 -12908 9 -12917 8 -12925 9 -12934 4 -12938 4 -12942 7 -12949 2 -12951 7 -12958 1 -12959 9 -12968 8 -12976 8 -12984 1 -12985 4 -12989 4 -12993 4 -12997 8 -13005 4 -13009 4 -13013 8 -13021 9 -13030 6 -13036 8 -13044 3 -13047 8 -13055 5 -13060 7 -13067 8 -13075 7 -13082 2 -13084 5 -13089 9 -13098 5 -13103 7 -13110 6 -13116 6 -13122 6 -13128 6 -13134 7 -13141 5 -13146 8 -13154 12 -13166 4 -13170 6 -13176 4 -13180 6 -13186 5 -13191 3 -13194 6 -13200 9 -13209 4 -13213 5 -13218 8 -13226 6 -13232 3 -13235 8 -13243 7 -13250 8 -13258 5 -13263 5 -13268 4 -13272 7 -13279 3 -13282 11 -13293 7 -13300 6 -13306 5 -13311 5 -13316 6 -13322 9 -13331 2 -13333 6 -13339 7 -13346 7 -13353 6 -13359 6 -13365 5 -13370 4 -13374 6 -13380 9 -13389 11 -13400 5 -13405 8 -13413 4 -13417 4 -13421 9 -13430 4 -13434 9 -13443 3 -13446 7 -13453 6 -13459 6 -13465 1 -13466 7 -13473 7 -13480 6 -13486 5 -13491 7 -13498 3 -13501 6 -13507 5 -13512 4 -13516 8 -13524 2 -13526 4 -13530 5 -13535 3 -13538 5 -13543 5 -13548 5 -13553 3 -13556 4 -13560 7 -13567 4 -13571 4 -13575 8 -13583 9 -13592 6 -13598 7 -13605 1 -13606 9 -13615 9 -13624 10 -13634 4 -13638 3 -13641 9 -13650 8 -13658 5 -13663 7 -13670 4 -13674 12 -13686 2 -13688 3 -13691 5 -13696 5 -13701 10 -13711 4 -13715 4 -13719 7 -13726 5 -13731 4 -13735 9 -13744 7 -13751 5 -13756 4 -13760 8 -13768 8 -13776 9 -13785 7 -13792 7 -13799 6 -13805 6 -13811 7 -13818 11 -13829 7 -13836 6 -13842 5 -13847 6 -13853 7 -13860 10 -13870 4 -13874 3 -13877 4 -13881 4 -13885 6 -13891 6 -13897 8 -13905 10 -13915 9 -13924 6 -13930 2 -13932 4 -13936 6 -13942 10 -13952 8 -13960 4 -13964 12 -13976 6 -13982 5 -13987 6 -13993 5 -13998 3 -14001 7 -14008 7 -14015 10 -14025 3 -14028 6 -14034 6 -14040 2 -14042 3 -14045 5 -14050 6 -14056 4 -14060 7 -14067 9 -14076 1 -14077 6 -14083 5 -14088 4 -14092 7 -14099 9 -14108 2 -14110 14 -14124 7 -14131 4 -14135 7 -14142 8 -14150 3 -14153 5 -14158 7 -14165 11 -14176 6 -14182 8 -14190 5 -14195 8 -14203 6 -14209 5 -14214 5 -14219 2 -14221 4 -14225 3 -14228 4 -14232 5 -14237 5 -14242 5 -14247 3 -14250 9 -14259 7 -14266 4 -14270 6 -14276 6 -14282 3 -14285 2 -14287 8 -14295 6 -14301 6 -14307 2 -14309 7 -14316 6 -14322 5 -14327 9 -14336 3 -14339 6 -14345 7 -14352 2 -14354 7 -14361 6 -14367 8 -14375 6 -14381 6 -14387 2 -14389 3 -14392 4 -14396 5 -14401 3 -14404 6 -14410 7 -14417 4 -14421 4 -14425 5 -14430 4 -14434 11 -14445 8 -14453 5 -14458 5 -14463 8 -14471 3 -14474 5 -14479 5 -14484 15 -14499 6 -14505 7 -14512 5 -14517 5 -14522 2 -14524 3 -14527 2 -14529 9 -14538 9 -14547 6 -14553 4 -14557 11 -14568 6 -14574 7 -14581 5 -14586 2 -14588 3 -14591 8 -14599 3 -14602 5 -14607 5 -14612 6 -14618 2 -14620 4 -14624 3 -14627 9 -14636 5 -14641 2 -14643 12 -14655 7 -14662 4 -14666 8 -14674 4 -14678 9 -14687 5 -14692 6 -14698 9 -14707 3 -14710 9 -14719 4 -14723 5 -14728 5 -14733 2 -14735 5 -14740 4 -14744 11 -14755 7 -14762 7 -14769 12 -14781 4 -14785 8 -14793 8 -14801 5 -14806 4 -14810 4 -14814 6 -14820 8 -14828 9 -14837 4 -14841 4 -14845 6 -14851 3 -14854 6 -14860 9 -14869 7 -14876 8 -14884 7 -14891 6 -14897 6 -14903 5 -14908 6 -14914 8 -14922 5 -14927 3 -14930 7 -14937 4 -14941 8 -14949 8 -14957 7 -14964 7 -14971 7 -14978 7 -14985 8 -14993 6 -14999 6 -15005 10 -15015 5 -15020 4 -15024 8 -15032 7 -15039 3 -15042 6 -15048 7 -15055 5 -15060 9 -15069 13 -15082 6 -15088 5 -15093 4 -15097 5 -15102 6 -15108 6 -15114 6 -15120 10 -15130 7 -15137 9 -15146 5 -15151 8 -15159 9 -15168 10 -15178 10 -15188 4 -15192 4 -15196 4 -15200 7 -15207 6 -15213 12 -15225 3 -15228 7 -15235 3 -15238 6 -15244 8 -15252 5 -15257 10 -15267 7 -15274 6 -15280 2 -15282 5 -15287 2 -15289 4 -15293 3 -15296 5 -15301 8 -15309 9 -15318 4 -15322 3 -15325 4 -15329 5 -15334 3 -15337 5 -15342 2 -15344 4 -15348 11 -15359 3 -15362 8 -15370 7 -15377 4 -15381 7 -15388 7 -15395 5 -15400 6 -15406 9 -15415 4 -15419 10 -15429 9 -15438 4 -15442 2 -15444 6 -15450 6 -15456 12 -15468 7 -15475 5 -15480 6 -15486 3 -15489 5 -15494 6 -15500 5 -15505 3 -15508 3 -15511 1 -15512 10 -15522 8 -15530 6 -15536 4 -15540 3 -15543 8 -15551 5 -15556 4 -15560 9 -15569 10 -15579 6 -15585 11 -15596 10 -15606 9 -15615 12 -15627 9 -15636 4 -15640 4 -15644 4 -15648 11 -15659 4 -15663 5 -15668 4 -15672 5 -15677 5 -15682 1 -15683 3 -15686 4 -15690 7 -15697 7 -15704 6 -15710 6 -15716 4 -15720 4 -15724 10 -15734 7 -15741 5 -15746 8 -15754 5 -15759 5 -15764 4 -15768 6 -15774 8 -15782 2 -15784 6 -15790 5 -15795 4 -15799 5 -15804 5 -15809 9 -15818 6 -15824 6 -15830 3 -15833 10 -15843 7 -15850 4 -15854 5 -15859 6 -15865 9 -15874 4 -15878 4 -15882 5 -15887 7 -15894 5 -15899 6 -15905 8 -15913 8 -15921 4 -15925 6 -15931 10 -15941 7 -15948 4 -15952 5 -15957 7 -15964 10 -15974 1 -15975 1 -15976 6 -15982 2 -15984 11 -15995 6 -16001 3 -16004 4 -16008 5 -16013 6 -16019 6 -16025 11 -16036 4 -16040 3 -16043 4 -16047 4 -16051 4 -16055 6 -16061 3 -16064 4 -16068 3 -16071 7 -16078 10 -16088 11 -16099 5 -16104 7 -16111 8 -16119 8 -16127 6 -16133 3 -16136 3 -16139 8 -16147 4 -16151 4 -16155 11 -16166 6 -16172 4 -16176 12 -16188 5 -16193 2 -16195 2 -16197 2 -16199 7 -16206 1 -16207 8 -16215 7 -16222 4 -16226 6 -16232 6 -16238 7 -16245 8 -16253 6 -16259 6 -16265 4 -16269 5 -16274 5 -16279 7 -16286 3 -16289 9 -16298 4 -16302 5 -16307 7 -16314 6 -16320 5 -16325 4 -16329 8 -16337 6 -16343 5 -16348 7 -16355 3 -16358 3 -16361 4 -16365 6 -16371 4 -16375 9 -16384 4 -16388 5 -16393 3 -16396 7 -16403 5 -16408 9 -16417 9 -16426 7 -16433 7 -16440 9 -16449 3 -16452 5 -16457 1 -16458 10 -16468 10 -16478 9 -16487 4 -16491 6 -16497 9 -16506 11 -16517 7 -16524 9 -16533 6 -16539 9 -16548 8 -16556 8 -16564 5 -16569 8 -16577 4 -16581 4 -16585 5 -16590 5 -16595 9 -16604 7 -16611 8 -16619 3 -16622 12 -16634 13 -16647 3 -16650 2 -16652 4 -16656 7 -16663 7 -16670 4 -16674 3 -16677 6 -16683 6 -16689 6 -16695 5 -16700 10 -16710 3 -16713 7 -16720 6 -16726 6 -16732 6 -16738 12 -16750 5 -16755 3 -16758 4 -16762 4 -16766 10 -16776 6 -16782 10 -16792 5 -16797 5 -16802 4 -16806 4 -16810 7 -16817 2 -16819 6 -16825 7 -16832 8 -16840 9 -16849 5 -16854 3 -16857 10 -16867 6 -16873 8 -16881 7 -16888 8 -16896 10 -16906 9 -16915 6 -16921 3 -16924 7 -16931 5 -16936 6 -16942 7 -16949 11 -16960 3 -16963 8 -16971 6 -16977 8 -16985 4 -16989 8 -16997 8 -17005 5 -17010 3 -17013 6 -17019 5 -17024 4 -17028 7 -17035 2 -17037 7 -17044 3 -17047 5 -17052 5 -17057 3 -17060 8 -17068 6 -17074 8 -17082 4 -17086 6 -17092 9 -17101 5 -17106 4 -17110 6 -17116 6 -17122 7 -17129 8 -17137 7 -17144 7 -17151 9 -17160 6 -17166 3 -17169 3 -17172 4 -17176 5 -17181 4 -17185 4 -17189 4 -17193 7 -17200 14 -17214 6 -17220 4 -17224 5 -17229 5 -17234 8 -17242 10 -17252 8 -17260 4 -17264 6 -17270 12 -17282 7 -17289 9 -17298 10 -17308 6 -17314 5 -17319 5 -17324 4 -17328 4 -17332 7 -17339 4 -17343 8 -17351 4 -17355 7 -17362 8 -17370 5 -17375 4 -17379 5 -17384 4 -17388 8 -17396 5 -17401 5 -17406 6 -17412 4 -17416 6 -17422 6 -17428 9 -17437 7 -17444 8 -17452 4 -17456 3 -17459 4 -17463 9 -17472 5 -17477 8 -17485 5 -17490 6 -17496 6 -17502 8 -17510 6 -17516 8 -17524 5 -17529 8 -17537 5 -17542 6 -17548 7 -17555 5 -17560 4 -17564 5 -17569 6 -17575 4 -17579 4 -17583 3 -17586 4 -17590 13 -17603 4 -17607 8 -17615 2 -17617 19 -17636 7 -17643 3 -17646 6 -17652 7 -17659 6 -17665 3 -17668 5 -17673 7 -17680 5 -17685 7 -17692 8 -17700 4 -17704 5 -17709 2 -17711 4 -17715 5 -17720 11 -17731 5 -17736 11 -17747 6 -17753 3 -17756 5 -17761 5 -17766 13 -17779 4 -17783 5 -17788 8 -17796 5 -17801 10 -17811 6 -17817 9 -17826 3 -17829 7 -17836 7 -17843 4 -17847 3 -17850 6 -17856 6 -17862 8 -17870 3 -17873 5 -17878 4 -17882 7 -17889 5 -17894 11 -17905 6 -17911 4 -17915 5 -17920 7 -17927 3 -17930 9 -17939 7 -17946 9 -17955 4 -17959 7 -17966 5 -17971 5 -17976 5 -17981 18 -17999 8 -18007 3 -18010 6 -18016 7 -18023 3 -18026 8 -18034 7 -18041 8 -18049 5 -18054 4 -18058 10 -18068 2 -18070 9 -18079 5 -18084 5 -18089 6 -18095 4 -18099 3 -18102 11 -18113 5 -18118 6 -18124 4 -18128 2 -18130 9 -18139 5 -18144 11 -18155 7 -18162 3 -18165 5 -18170 4 -18174 4 -18178 5 -18183 6 -18189 6 -18195 6 -18201 6 -18207 9 -18216 4 -18220 9 -18229 3 -18232 5 -18237 6 -18243 7 -18250 8 -18258 4 -18262 11 -18273 5 -18278 7 -18285 3 -18288 3 -18291 7 -18298 6 -18304 4 -18308 2 -18310 2 -18312 10 -18322 5 -18327 6 -18333 3 -18336 9 -18345 3 -18348 5 -18353 9 -18362 6 -18368 5 -18373 6 -18379 5 -18384 10 -18394 6 -18400 3 -18403 4 -18407 7 -18414 5 -18419 6 -18425 6 -18431 5 -18436 4 -18440 5 -18445 8 -18453 11 -18464 10 -18474 10 -18484 5 -18489 3 -18492 9 -18501 9 -18510 3 -18513 8 -18521 7 -18528 4 -18532 3 -18535 5 -18540 7 -18547 6 -18553 3 -18556 7 -18563 7 -18570 8 -18578 4 -18582 3 -18585 12 -18597 6 -18603 8 -18611 7 -18618 5 -18623 4 -18627 5 -18632 10 -18642 5 -18647 5 -18652 4 -18656 7 -18663 9 -18672 8 -18680 5 -18685 5 -18690 3 -18693 7 -18700 8 -18708 6 -18714 10 -18724 6 -18730 7 -18737 2 -18739 4 -18743 9 -18752 6 -18758 5 -18763 8 -18771 3 -18774 13 -18787 8 -18795 9 -18804 5 -18809 4 -18813 5 -18818 5 -18823 5 -18828 4 -18832 8 -18840 2 -18842 7 -18849 6 -18855 8 -18863 8 -18871 6 -18877 5 -18882 9 -18891 5 -18896 11 -18907 8 -18915 3 -18918 5 -18923 8 -18931 7 -18938 6 -18944 5 -18949 2 -18951 4 -18955 7 -18962 6 -18968 5 -18973 5 -18978 5 -18983 10 -18993 6 -18999 9 -19008 9 -19017 5 -19022 6 -19028 4 -19032 7 -19039 5 -19044 4 -19048 7 -19055 7 -19062 2 -19064 12 -19076 6 -19082 5 -19087 3 -19090 8 -19098 3 -19101 5 -19106 7 -19113 3 -19116 5 -19121 4 -19125 6 -19131 4 -19135 5 -19140 8 -19148 5 -19153 7 -19160 9 -19169 4 -19173 8 -19181 2 -19183 5 -19188 6 -19194 5 -19199 7 -19206 1 -19207 3 -19210 2 -19212 6 -19218 7 -19225 3 -19228 4 -19232 8 -19240 6 -19246 10 -19256 5 -19261 8 -19269 9 -19278 9 -19287 3 -19290 6 -19296 3 -19299 2 -19301 9 -19310 3 -19313 8 -19321 4 -19325 6 -19331 7 -19338 8 -19346 5 -19351 10 -19361 2 -19363 6 -19369 4 -19373 5 -19378 8 -19386 10 -19396 4 -19400 8 -19408 7 -19415 5 -19420 7 -19427 6 -19433 5 -19438 6 -19444 5 -19449 6 -19455 7 -19462 5 -19467 4 -19471 8 -19479 2 -19481 6 -19487 4 -19491 3 -19494 4 -19498 3 -19501 2 -19503 7 -19510 6 -19516 2 -19518 8 -19526 9 -19535 8 -19543 2 -19545 3 -19548 10 -19558 4 -19562 7 -19569 5 -19574 5 -19579 5 -19584 6 -19590 3 -19593 6 -19599 6 -19605 4 -19609 6 -19615 8 -19623 5 -19628 7 -19635 6 -19641 6 -19647 4 -19651 8 -19659 6 -19665 4 -19669 3 -19672 9 -19681 6 -19687 6 -19693 4 -19697 6 -19703 8 -19711 6 -19717 6 -19723 7 -19730 3 -19733 5 -19738 4 -19742 5 -19747 5 -19752 11 -19763 8 -19771 6 -19777 9 -19786 6 -19792 11 -19803 4 -19807 8 -19815 6 -19821 8 -19829 7 -19836 9 -19845 3 -19848 5 -19853 5 -19858 10 -19868 3 -19871 4 -19875 10 -19885 5 -19890 8 -19898 5 -19903 5 -19908 5 -19913 4 -19917 6 -19923 4 -19927 5 -19932 6 -19938 3 -19941 8 -19949 7 -19956 6 -19962 7 -19969 4 -19973 6 -19979 4 -19983 10 -19993 8 -20001 16 -20017 5 -20022 6 -20028 11 -20039 6 -20045 6 -20051 8 -20059 5 -20064 4 -20068 9 -20077 9 -20086 10 -20096 9 -20105 6 -20111 4 -20115 5 -20120 3 -20123 7 -20130 9 -20139 4 -20143 2 -20145 7 -20152 7 -20159 6 -20165 7 -20172 10 -20182 6 -20188 2 -20190 5 -20195 7 -20202 6 -20208 6 -20214 5 -20219 3 -20222 2 -20224 4 -20228 7 -20235 4 -20239 5 -20244 8 -20252 3 -20255 6 -20261 9 -20270 9 -20279 2 -20281 8 -20289 2 -20291 3 -20294 3 -20297 3 -20300 4 -20304 7 -20311 7 -20318 6 -20324 4 -20328 4 -20332 4 -20336 10 -20346 7 -20353 3 -20356 5 -20361 3 -20364 6 -20370 4 -20374 4 -20378 3 -20381 5 -20386 5 -20391 4 -20395 5 -20400 4 -20404 5 -20409 1 -20410 5 -20415 2 -20417 5 -20422 7 -20429 4 -20433 2 -20435 6 -20441 5 -20446 4 -20450 7 -20457 8 -20465 2 -20467 10 -20477 5 -20482 5 -20487 8 -20495 11 -20506 5 -20511 4 -20515 3 -20518 6 -20524 12 -20536 3 -20539 12 -20551 8 -20559 4 -20563 10 -20573 8 -20581 3 -20584 7 -20591 6 -20597 4 -20601 10 -20611 7 -20618 5 -20623 4 -20627 5 -20632 8 -20640 6 -20646 3 -20649 9 -20658 2 -20660 7 -20667 4 -20671 5 -20676 7 -20683 8 -20691 4 -20695 6 -20701 4 -20705 8 -20713 8 -20721 4 -20725 5 -20730 7 -20737 4 -20741 5 -20746 4 -20750 2 -20752 8 -20760 8 -20768 10 -20778 7 -20785 7 -20792 10 -20802 3 -20805 3 -20808 10 -20818 4 -20822 6 -20828 7 -20835 4 -20839 8 -20847 5 -20852 12 -20864 2 -20866 7 -20873 3 -20876 5 -20881 3 -20884 8 -20892 4 -20896 7 -20903 5 -20908 4 -20912 10 -20922 5 -20927 10 -20937 10 -20947 6 -20953 3 -20956 6 -20962 4 -20966 5 -20971 8 -20979 4 -20983 7 -20990 5 -20995 10 -21005 7 -21012 10 -21022 3 -21025 7 -21032 5 -21037 12 -21049 8 -21057 4 -21061 5 -21066 2 -21068 10 -21078 3 -21081 4 -21085 5 -21090 4 -21094 9 -21103 4 -21107 7 -21114 7 -21121 6 -21127 1 -21128 9 -21137 7 -21144 10 -21154 4 -21158 5 -21163 6 -21169 5 -21174 4 -21178 4 -21182 5 -21187 6 -21193 11 -21204 7 -21211 7 -21218 10 -21228 5 -21233 13 -21246 10 -21256 3 -21259 5 -21264 9 -21273 6 -21279 11 -21290 8 -21298 3 -21301 3 -21304 12 -21316 7 -21323 5 -21328 6 -21334 4 -21338 7 -21345 7 -21352 6 -21358 3 -21361 8 -21369 6 -21375 5 -21380 5 -21385 6 -21391 6 -21397 6 -21403 6 -21409 9 -21418 6 -21424 12 -21436 5 -21441 3 -21444 7 -21451 9 -21460 9 -21469 10 -21479 5 -21484 5 -21489 8 -21497 6 -21503 4 -21507 2 -21509 5 -21514 4 -21518 4 -21522 6 -21528 11 -21539 6 -21545 6 -21551 6 -21557 11 -21568 3 -21571 4 -21575 3 -21578 6 -21584 7 -21591 3 -21594 8 -21602 7 -21609 9 -21618 4 -21622 7 -21629 8 -21637 8 -21645 4 -21649 4 -21653 2 -21655 6 -21661 6 -21667 5 -21672 5 -21677 8 -21685 6 -21691 6 -21697 4 -21701 4 -21705 3 -21708 12 -21720 6 -21726 9 -21735 5 -21740 6 -21746 5 -21751 6 -21757 12 -21769 5 -21774 6 -21780 4 -21784 8 -21792 3 -21795 3 -21798 6 -21804 7 -21811 5 -21816 11 -21827 7 -21834 3 -21837 6 -21843 9 -21852 8 -21860 6 -21866 4 -21870 5 -21875 6 -21881 9 -21890 3 -21893 5 -21898 4 -21902 5 -21907 8 -21915 6 -21921 3 -21924 5 -21929 6 -21935 5 -21940 5 -21945 7 -21952 7 -21959 4 -21963 8 -21971 4 -21975 6 -21981 3 -21984 9 -21993 6 -21999 5 -22004 6 -22010 9 -22019 8 -22027 2 -22029 7 -22036 3 -22039 5 -22044 3 -22047 7 -22054 10 -22064 3 -22067 2 -22069 5 -22074 6 -22080 4 -22084 5 -22089 7 -22096 4 -22100 8 -22108 4 -22112 10 -22122 4 -22126 6 -22132 3 -22135 4 -22139 9 -22148 5 -22153 4 -22157 5 -22162 5 -22167 8 -22175 5 -22180 4 -22184 5 -22189 4 -22193 4 -22197 5 -22202 10 -22212 8 -22220 5 -22225 4 -22229 8 -22237 8 -22245 8 -22253 2 -22255 4 -22259 9 -22268 10 -22278 3 -22281 9 -22290 4 -22294 4 -22298 7 -22305 6 -22311 4 -22315 7 -22322 3 -22325 6 -22331 3 -22334 5 -22339 9 -22348 4 -22352 5 -22357 6 -22363 5 -22368 4 -22372 5 -22377 7 -22384 2 -22386 7 -22393 8 -22401 7 -22408 9 -22417 8 -22425 3 -22428 4 -22432 7 -22439 6 -22445 4 -22449 9 -22458 6 -22464 5 -22469 7 -22476 10 -22486 5 -22491 5 -22496 10 -22506 8 -22514 8 -22522 8 -22530 8 -22538 5 -22543 9 -22552 2 -22554 2 -22556 6 -22562 7 -22569 9 -22578 3 -22581 7 -22588 8 -22596 3 -22599 6 -22605 3 -22608 4 -22612 6 -22618 13 -22631 7 -22638 5 -22643 8 -22651 8 -22659 9 -22668 7 -22675 2 -22677 12 -22689 14 -22703 10 -22713 4 -22717 7 -22724 3 -22727 5 -22732 9 -22741 9 -22750 11 -22761 4 -22765 5 -22770 12 -22782 4 -22786 8 -22794 4 -22798 7 -22805 6 -22811 4 -22815 8 -22823 4 -22827 7 -22834 2 -22836 7 -22843 9 -22852 2 -22854 10 -22864 6 -22870 7 -22877 8 -22885 7 -22892 2 -22894 4 -22898 9 -22907 7 -22914 8 -22922 7 -22929 5 -22934 5 -22939 4 -22943 7 -22950 8 -22958 3 -22961 7 -22968 5 -22973 4 -22977 5 -22982 7 -22989 4 -22993 4 -22997 7 -23004 4 -23008 5 -23013 7 -23020 6 -23026 3 -23029 7 -23036 9 -23045 3 -23048 3 -23051 5 -23056 5 -23061 5 -23066 6 -23072 7 -23079 4 -23083 4 -23087 9 -23096 4 -23100 6 -23106 5 -23111 6 -23117 7 -23124 5 -23129 5 -23134 3 -23137 2 -23139 8 -23147 13 -23160 6 -23166 4 -23170 5 -23175 4 -23179 3 -23182 6 -23188 6 -23194 5 -23199 4 -23203 6 -23209 4 -23213 12 -23225 4 -23229 7 -23236 10 -23246 9 -23255 6 -23261 9 -23270 9 -23279 8 -23287 3 -23290 7 -23297 5 -23302 3 -23305 2 -23307 7 -23314 7 -23321 6 -23327 10 -23337 4 -23341 9 -23350 6 -23356 6 -23362 7 -23369 12 -23381 4 -23385 5 -23390 3 -23393 10 -23403 10 -23413 4 -23417 6 -23423 3 -23426 9 -23435 6 -23441 7 -23448 5 -23453 6 -23459 5 -23464 3 -23467 8 -23475 2 -23477 10 -23487 3 -23490 4 -23494 5 -23499 8 -23507 4 -23511 7 -23518 8 -23526 4 -23530 6 -23536 8 -23544 6 -23550 7 -23557 3 -23560 7 -23567 2 -23569 6 -23575 9 -23584 12 -23596 5 -23601 8 -23609 7 -23616 6 -23622 6 -23628 4 -23632 10 -23642 8 -23650 7 -23657 1 -23658 8 -23666 8 -23674 4 -23678 8 -23686 6 -23692 9 -23701 8 -23709 7 -23716 9 -23725 8 -23733 9 -23742 5 -23747 4 -23751 5 -23756 10 -23766 6 -23772 4 -23776 6 -23782 3 -23785 6 -23791 7 -23798 9 -23807 9 -23816 13 -23829 10 -23839 6 -23845 3 -23848 6 -23854 7 -23861 6 -23867 4 -23871 11 -23882 12 -23894 3 -23897 2 -23899 8 -23907 3 -23910 8 -23918 7 -23925 6 -23931 5 -23936 6 -23942 11 -23953 6 -23959 4 -23963 4 -23967 5 -23972 7 -23979 8 -23987 5 -23992 5 -23997 6 -24003 4 -24007 8 -24015 9 -24024 5 -24029 4 -24033 3 -24036 4 -24040 2 -24042 7 -24049 2 -24051 6 -24057 1 -24058 9 -24067 8 -24075 6 -24081 3 -24084 9 -24093 6 -24099 8 -24107 9 -24116 6 -24122 5 -24127 4 -24131 8 -24139 6 -24145 7 -24152 3 -24155 8 -24163 5 -24168 6 -24174 6 -24180 4 -24184 8 -24192 5 -24197 5 -24202 6 -24208 7 -24215 5 -24220 3 -24223 11 -24234 12 -24246 12 -24258 3 -24261 9 -24270 6 -24276 5 -24281 5 -24286 8 -24294 4 -24298 8 -24306 5 -24311 7 -24318 3 -24321 8 -24329 5 -24334 3 -24337 7 -24344 7 -24351 5 -24356 7 -24363 4 -24367 6 -24373 3 -24376 8 -24384 3 -24387 7 -24394 10 -24404 3 -24407 5 -24412 6 -24418 4 -24422 4 -24426 2 -24428 3 -24431 9 -24440 8 -24448 7 -24455 5 -24460 11 -24471 7 -24478 7 -24485 5 -24490 10 -24500 4 -24504 7 -24511 6 -24517 13 -24530 10 -24540 7 -24547 8 -24555 4 -24559 2 -24561 9 -24570 2 -24572 4 - -0 - -24576 -2539 2 -1187 5 -3911 2 -585 8 -1498 10 -1681 2 -2115 7 -2424 1 -3708 7 -196 1 -1852 10 -3555 8 -2134 1 -1064 9 -1293 8 -944 9 -2413 3 -1678 2 -839 9 -297 1 -174 7 -2217 9 -51 8 -3195 6 -3215 5 -332 3 -2077 7 -1214 2 -2367 10 -1947 10 -2350 6 -3441 1 -3246 7 -1999 1 -2037 5 -2227 8 -101 7 -3340 9 -3713 7 -3013 4 -1001 3 -444 6 -3306 2 -4043 1 -1361 1 -3916 6 -365 4 -1485 8 -251 8 -234 2 -4042 2 -870 7 -3803 9 -3874 4 -1058 5 -831 3 -2331 6 -1328 1 -2525 4 -255 3 -381 1 -2521 1 -3946 5 -2449 4 -285 2 -3848 4 -2669 9 -3949 3 -1050 4 -2855 9 -1974 3 -349 7 -2874 6 -192 6 -3442 4 -265 1 -2281 4 -403 6 -2359 5 -319 8 -39 1 -3893 3 -1176 1 -3154 10 -866 9 -2670 9 -3934 6 -3799 5 -393 8 -2722 10 -2107 4 -185 3 -69 1 -1958 4 -1613 2 -1908 10 -3867 5 -2950 2 -3397 10 -3737 1 -1074 9 -234 2 -2795 8 -1452 8 -1437 2 -768 7 -3400 1 -1212 6 -2675 7 -989 4 -1338 6 -764 5 -216 3 -2186 3 -2210 9 -2194 1 -1703 3 -2668 5 -3684 3 -3636 6 -3939 5 -3718 2 -3954 10 -4009 10 -703 8 -2990 8 -2162 4 -3980 1 -1245 8 -2488 1 -2391 3 -3774 9 -3238 5 -1534 4 -3440 3 -2611 6 -2878 7 -1931 8 -3668 9 -3139 10 -3822 10 -2184 3 -82 6 -3317 1 -1702 3 -4087 10 -519 3 -1944 1 -3830 9 -3563 10 -2150 5 -3735 9 -1158 2 -3265 9 -2571 6 -2587 4 -2073 3 -405 6 -3865 3 -42 4 -2358 9 -2632 1 -1629 5 -2968 10 -3160 8 -1934 7 -1108 3 -2324 9 -1923 4 -2536 10 -3112 3 -3817 1 -4008 3 -2118 10 -1034 6 -3094 8 -3868 9 -2484 6 -3791 7 -1456 5 -2643 5 -462 9 -1481 8 -1788 10 -811 5 -1441 10 -2258 6 -3559 5 -2816 2 -3886 1 -428 9 -2442 8 -873 2 -3460 2 -989 7 -2897 9 -1464 7 -1525 4 -685 7 -3906 4 -678 7 -1824 2 -2256 8 -1016 9 -3705 1 -3368 10 -136 1 -1154 8 -2478 10 -3323 2 -104 10 -932 7 -3100 8 -2465 5 -491 9 -1735 3 -1031 3 -2790 1 -1423 5 -2939 6 -1829 9 -1241 3 -386 4 -1934 8 -2883 9 -14 1 -686 2 -992 5 -3564 8 -551 10 -2074 3 -2344 1 -3593 9 -1103 6 -2668 6 -696 5 -4019 4 -1708 1 -2519 3 -3455 8 -28 4 -3639 8 -1977 7 -2429 5 -3549 7 -468 10 -2801 10 -848 7 -959 9 -2410 6 -3898 9 -2059 3 -1938 9 -3544 1 -3513 9 -1136 1 -302 4 -1589 7 -305 1 -3199 2 -847 4 -3900 6 -2632 6 -2193 6 -442 7 -3972 1 -3426 4 -1500 3 -1723 5 -2849 1 -2498 4 -3104 4 -3131 5 -1198 2 -1492 10 -2112 6 -1202 2 -2284 10 -1672 10 -3115 3 -2934 4 -990 4 -434 8 -3372 6 -1974 6 -2729 9 -3517 3 -2286 6 -1761 1 -3637 3 -3058 4 -1178 2 -985 4 -3 8 -939 6 -445 3 -1807 9 -2728 7 -1861 5 -2716 5 -3316 3 -2836 5 -174 3 -1190 4 -1061 9 -2375 6 -3599 9 -1048 3 -3021 8 -1421 5 -2090 10 -1289 6 -971 1 -3560 4 -1817 2 -3691 1 -2572 6 -1938 9 -576 6 -3178 3 -3265 6 -3747 6 -1332 1 -2812 9 -3574 5 -2033 7 -1103 4 -2806 4 -2506 5 -686 3 -3917 3 -350 5 -2609 6 -1906 7 -3969 10 -3419 10 -3338 10 -1448 9 -1050 3 -1080 5 -3620 4 -1286 10 -2202 5 -4079 7 -3722 3 -1210 7 -3678 2 -1323 7 -2341 7 -320 2 -3506 7 -649 4 -2993 5 -1165 6 -1384 9 -335 7 -2002 2 -302 7 -1502 1 -4049 9 -2628 3 -259 2 -2500 1 -2022 9 -541 9 -2910 2 -4089 6 -3356 1 -2474 9 -1941 2 -1025 2 -3026 10 -2314 6 -2102 6 -1122 7 -1833 10 -1692 1 -1372 3 -1302 4 -3883 10 -2310 9 -3151 9 -2447 2 -1205 5 -276 2 -2431 8 -611 3 -512 8 -1134 10 -758 2 -2418 6 -276 10 -2592 1 -1655 8 -2181 1 -3243 10 -2191 3 -455 4 -1130 5 -2880 8 -740 1 -635 6 -932 9 -3178 8 -1032 9 -89 6 -414 1 -730 9 -16 1 -3631 9 -1411 6 -2356 5 -2474 5 -3025 4 -3876 8 -2897 7 -957 5 -2621 6 -1568 8 -2610 8 -3253 7 -1169 1 -3292 4 -1035 2 -1417 5 -3613 10 -1063 5 -1779 7 -360 2 -208 3 -1014 7 -894 8 -2599 7 -4076 3 -3329 6 -2497 10 -1110 5 -803 8 -3322 10 -3100 7 -1921 8 -3077 2 -1052 7 -2808 5 -3802 9 -2708 9 -3412 1 -690 9 -2266 3 -112 3 -765 4 -3276 3 -3823 5 -181 9 -457 1 -299 6 -934 5 -3422 7 -3718 4 -1793 6 -3672 8 -2858 2 -3801 3 -1693 8 -3711 4 -2917 1 -291 6 -3209 1 -334 10 -3287 6 -626 5 -915 3 -2886 6 -236 3 -1390 10 -2523 8 -1386 10 -3340 2 -4047 7 -303 8 -230 2 -2390 8 -1983 5 -2897 2 -3922 3 -954 3 -3004 4 -3912 10 -393 1 -1768 3 -2783 2 -1522 6 -4055 8 -3429 6 -3884 2 -25 6 -3606 3 -3813 7 -2176 9 -2774 10 -2829 1 -2858 7 -3722 8 -1468 6 -1208 5 -3466 7 -446 2 -1824 4 -4056 8 -1036 5 -985 4 -2979 3 -3919 6 -479 3 -3896 5 -128 3 -2928 9 -1208 1 -1356 10 -928 10 -787 5 -3418 6 -421 8 -1985 3 -2218 3 -3452 1 -2255 3 -405 7 -3265 4 -2763 4 -641 10 -3202 1 -3754 8 -1949 3 -3120 10 -2017 9 -1932 9 -2302 9 -2060 9 -773 5 -3294 1 -2044 2 -2277 10 -3755 10 -3620 6 -69 6 -2237 4 -3696 3 -2141 7 -1698 7 -2629 7 -2951 1 -1211 8 -3830 3 -1858 3 -2153 10 -2512 9 -3088 10 -3996 3 -423 8 -584 7 -383 10 -2355 1 -2140 5 -954 4 -99 4 -1575 4 -2552 2 -405 4 -1175 10 -1124 10 -3839 8 -1711 6 -3475 8 -1104 5 -2724 4 -1185 4 -1081 9 -2892 8 -1177 10 -2260 8 -1362 1 -1979 3 -2161 4 -3940 7 -694 3 -254 1 -966 6 -3083 5 -920 6 -3555 6 -1233 6 -947 6 -3804 6 -1611 2 -951 1 -3524 10 -94 4 -3332 5 -3542 10 -152 7 -289 1 -539 9 -566 10 -3745 8 -2949 10 -2114 8 -2206 1 -364 5 -3081 4 -2286 9 -3450 1 -2703 10 -5 7 -1851 3 -2618 6 -1958 1 -550 3 -2220 3 -375 7 -3322 10 -3901 10 -2296 4 -732 1 -3721 8 -3064 1 -3315 5 -2066 10 -2566 7 -593 10 -36 10 -1177 2 -2225 9 -1485 8 -392 6 -3144 7 -2170 5 -2052 5 -1235 7 -801 2 -3439 1 -2565 9 -3646 7 -893 3 -1991 3 -2220 1 -1540 5 -1493 4 -3384 5 -1115 4 -488 6 -568 8 -1240 3 -4030 2 -3376 2 -3660 1 -2790 5 -3528 8 -1131 10 -1932 7 -2690 10 -3852 7 -2833 3 -785 1 -705 10 -2183 9 -3411 6 -2966 6 -2765 1 -3756 1 -199 4 -817 3 -3221 1 -1154 9 -1610 9 -1224 6 -3511 6 -3245 5 -75 3 -1353 8 -2848 7 -2353 4 -268 10 -374 8 -2591 9 -2501 8 -953 5 -2335 3 -1304 1 -407 1 -1556 9 -2965 3 -1263 7 -2258 4 -138 3 -1237 5 -1719 6 -1272 6 -1867 6 -3052 9 -2829 10 -515 10 -1874 9 -1699 8 -3351 2 -1303 10 -2853 9 -866 6 -3533 1 -895 2 -2287 9 -1954 9 -3352 9 -3760 2 -1026 9 -2074 6 -1529 4 -868 2 -3551 9 -3603 8 -1589 3 -2230 3 -1141 7 -3914 8 -3396 3 -1997 6 -898 10 -3176 8 -3063 7 -2957 5 -194 10 -2959 2 -1616 9 -686 1 -921 9 -2578 10 -3986 4 -2293 3 -2529 6 -722 7 -1783 3 -594 1 -2188 7 -1317 6 -992 1 -2754 3 -3113 7 -205 4 -3815 5 -3076 8 -1205 9 -1703 4 -3901 4 -1627 8 -2490 6 -524 4 -4031 10 -3070 1 -4004 9 -652 8 -891 8 -765 2 -248 9 -836 4 -2567 7 -1083 8 -1743 7 -3716 7 -2978 9 -2097 6 -3205 10 -310 4 -907 4 -2378 6 -85 3 -1268 1 -1250 4 -1745 4 -3608 4 -948 6 -3799 2 -552 4 -2391 9 -758 7 -2703 6 -2951 6 -2674 5 -3839 2 -1778 4 -3064 8 -2392 7 -1312 9 -798 6 -391 5 -3602 3 -1346 7 -2819 7 -3549 2 -476 8 -1661 5 -2335 8 -963 5 -3882 4 -2778 6 -521 9 -353 4 -1534 2 -3229 1 -2011 3 -3422 8 -757 9 -2851 1 -180 10 -584 10 -3797 4 -2092 8 -237 10 -2797 7 -3207 10 -3546 9 -1225 9 -282 3 -1545 2 -2111 7 -3439 1 -2231 5 -1814 3 -36 1 -1513 4 -1803 10 -2642 3 -2749 4 -3608 7 -2702 4 -1331 8 -3867 6 -883 3 -2695 6 -3879 1 -2200 10 -1720 4 -2801 5 -1463 1 -250 2 -3074 8 -1938 8 -115 3 -1161 5 -835 10 -962 7 -2543 10 -1828 7 -1488 7 -3860 1 -1497 2 -413 1 -3003 7 -3593 9 -3711 7 -1680 2 -2586 7 -3164 4 -1227 1 -2124 9 -2302 10 -541 7 -1123 7 -1261 10 -2938 9 -3420 3 -1604 3 -3772 10 -3921 10 -3518 4 -194 3 -456 2 -3212 4 -3898 5 -1158 7 -186 3 -449 3 -620 7 -330 8 -3579 1 -1214 2 -1598 2 -160 2 -3430 4 -2579 5 -2321 6 -3585 7 -1710 5 -4037 2 -3234 6 -3245 5 -3139 2 -2571 4 -536 9 -358 3 -378 8 -383 8 -1575 5 -432 5 -2731 1 -2298 2 -2600 1 -1525 5 -2324 9 -2883 4 -473 4 -934 3 -641 7 -3351 7 -1225 4 -1535 3 -2448 7 -3853 3 -1055 1 -2545 5 -3337 2 -1247 1 -2846 4 -681 2 -1495 2 -3803 4 -1023 7 -2533 8 -338 10 -3061 5 -2127 9 -1459 6 -99 7 -3569 7 -1724 8 -2816 4 -351 7 -2074 7 -193 5 -3012 7 -2078 6 -3269 10 -2182 1 -3485 10 -685 8 -2592 5 -2970 10 -170 1 -1314 7 -1342 7 -3914 8 -761 1 -3823 3 -2388 1 -3280 10 -2773 6 -3930 3 -1338 3 -895 8 -1576 3 -1445 8 -221 8 -415 6 -2915 1 -3712 2 -2374 6 -146 2 -333 10 -1369 1 -2909 10 -1699 4 -2560 8 -982 4 -716 3 -3109 4 -2823 5 -1810 2 -2582 8 -3314 3 -1875 4 -3040 1 -3229 7 -2454 6 -2690 4 -2880 4 -203 2 -3240 9 -639 6 -3636 10 -4025 5 -3986 3 -3159 8 -2873 1 -1798 1 -3724 2 -1942 6 -3947 2 -1767 8 -2916 3 -1358 8 -3242 4 -1710 2 -3440 9 -2958 4 -427 3 -1003 1 -2351 7 -2339 10 -3991 2 -3758 1 -3229 3 -2572 5 -297 4 -1987 4 -1033 4 -2941 10 -1582 1 -1775 7 -1510 1 -1216 8 -2154 6 -2178 5 -2009 10 -1887 8 -1090 10 -1213 9 -867 5 -1604 4 -3968 3 -2542 1 -156 1 -2056 6 -2008 4 -1882 1 -3508 5 -3603 10 -195 7 -226 7 -1070 8 -1523 3 -3067 10 -2665 6 -639 3 -3369 6 -3750 7 -1326 10 -3019 2 -261 2 -3191 7 -1692 9 -1403 1 -3822 8 -3 7 -1215 5 -2335 4 -52 3 -2325 8 -1872 2 -3000 4 -399 9 -962 4 -3591 5 -3366 9 -1774 8 -2512 10 -2805 7 -1001 4 -3962 8 -318 9 -2789 7 -3299 4 -1140 10 -1234 9 -1301 10 -2402 2 -2978 4 -494 1 -2857 9 -2856 8 -1970 1 -3511 8 -2335 6 -907 5 -730 5 -2194 2 -1785 10 -134 10 -4045 9 -872 5 -2925 5 -353 10 -3690 9 -3147 9 -2525 9 -1087 6 -2143 9 -1301 8 -76 9 -412 7 -2266 6 -2772 1 -1253 5 -2786 2 -186 10 -354 2 -3073 6 -1807 6 -2720 10 -496 5 -1936 9 -4044 9 -333 4 -3080 3 -2030 5 -831 8 -1824 10 -16 3 -3371 3 -3971 6 -1671 8 -183 10 -716 9 -144 3 -824 3 -1499 2 -288 7 -379 9 -2076 3 -1418 10 -3787 1 -549 2 -1904 1 -939 4 -1841 3 -2637 1 -1448 7 -420 1 -382 6 -2592 1 -2591 2 -1298 2 -2238 9 -3599 1 -2705 9 -3938 7 -2700 10 -2881 10 -3331 7 -1130 2 -3909 10 -2516 6 -1695 2 -196 7 -3700 1 -2510 7 -1838 8 -3886 8 -4041 7 -3904 4 -3272 8 -426 3 -3851 9 -1539 1 -2457 2 -2890 10 -968 9 -13 6 -613 3 -282 7 -1110 2 -2559 7 -1913 5 -153 5 -515 2 -2026 6 -2985 8 -144 3 -3929 4 -121 10 -478 6 -713 4 -1204 3 -2721 9 -171 7 -659 5 -3872 5 -719 4 -1651 4 -2765 3 -1370 10 -191 7 -3359 4 -3869 4 -900 6 -2104 2 -0 1 -3350 1 -2890 9 -305 7 -1997 7 -2885 8 -2138 9 -3940 2 -3704 8 -1379 9 -908 3 -1249 9 -1286 1 -1632 1 -2438 4 -2000 5 -1237 3 -1797 6 -3789 8 -111 4 -668 1 -3502 2 -1338 5 -1617 7 -4067 4 -2203 1 -2924 7 -2009 2 -1903 4 -3918 6 -1857 3 -1062 8 -2212 10 -1847 4 -671 8 -3686 1 -1788 1 -1578 10 -3501 1 -2554 1 -164 2 -2886 10 -1318 10 -570 5 -2649 10 -2581 4 -1103 4 -3748 7 -2504 5 -123 4 -3156 5 -1737 10 -1594 3 -667 3 -3426 7 -2117 10 -1626 9 -73 3 -933 7 -3979 9 -2199 3 -1885 2 -2168 2 -1276 8 -2458 7 -591 3 -1502 3 -2454 1 -471 2 -2918 1 -3221 4 -1135 8 -3922 4 -239 6 -723 6 -3865 8 -1145 2 -2640 7 -812 1 -3977 6 -2318 3 -558 8 -1479 7 -1248 9 -377 1 -2986 9 -3356 2 -2964 9 -2967 6 -3212 9 -2455 6 -3254 1 -933 1 -3326 3 -464 10 -4003 4 -3246 5 -2883 6 -3568 7 -3578 7 -3045 4 -1516 4 -3131 3 -2759 2 -2942 6 -1211 3 -3201 1 -333 1 -2319 6 -2033 10 -3489 6 -704 5 -1242 7 -1327 1 -1596 6 -19 3 -552 6 -4031 7 -4060 9 -3793 7 -978 3 -3817 1 -2194 4 -3677 6 -1684 10 -227 7 -2985 8 -2105 6 -3677 2 -1486 2 -3993 5 -1698 5 -3903 9 -2048 4 -568 10 -2101 2 -1272 4 -1358 10 -3457 10 -1460 7 -3763 3 -1066 8 -2459 2 -1117 5 -712 6 -4018 1 -425 8 -3698 5 -3277 2 -2648 8 -226 7 -1201 7 -158 8 -503 2 -1517 10 -803 9 -1582 4 -637 9 -3550 9 -2803 7 -2130 1 -2199 6 -1682 10 -3393 8 -352 8 -1107 2 -1994 8 -1894 7 -3787 2 -2311 9 -2262 3 -3517 1 -3867 9 -1868 2 -856 10 -4029 8 -2769 5 -253 1 -832 4 -3702 2 -468 9 -1984 8 -2524 1 -767 4 -2701 3 -4086 4 -660 4 -171 7 -221 7 -218 7 -2965 2 -3286 8 -1200 10 -3434 4 -1969 8 -1625 4 -501 10 -1701 9 -2440 7 -3201 1 -1870 8 -3934 4 -3252 9 -2169 2 -3959 5 -2629 4 -2557 10 -557 9 -817 3 -745 9 -3575 10 -651 10 -2591 5 -2432 1 -1689 9 -1173 7 -1743 5 -1163 3 -1320 3 -79 2 -1370 2 -2077 8 -3964 9 -1021 1 -1484 9 -1551 6 -3956 3 -2222 7 -3843 5 -347 10 -841 5 -3810 1 -3443 9 -9 2 -2063 9 -17 2 -3938 3 -1839 4 -1233 2 -2308 1 -2941 10 -1598 2 -1287 1 -79 3 -1377 4 -3143 7 -3366 2 -2660 2 -2225 10 -2731 3 -1070 5 -3581 7 -135 10 -1704 7 -1314 1 -1309 5 -3273 8 -3207 5 -4037 7 -1014 2 -3825 6 -2835 7 -3363 4 -3895 6 -2554 8 -1121 9 -3166 5 -211 6 -3249 2 -1744 10 -3165 10 -1191 2 -1054 10 -3828 10 -3761 3 -2625 4 -765 8 -3157 8 -3575 2 -3196 8 -577 10 -1460 7 -1447 5 -2756 6 -1208 7 -1100 5 -857 4 -1808 7 -4018 9 -2670 6 -3445 10 -3564 10 -3854 8 -3476 10 -2565 6 -1536 3 -3436 9 -2842 7 -423 3 -2912 7 -271 7 -1992 6 -883 5 -1287 6 -3277 1 -3560 9 -2265 3 -900 8 -2009 7 -2644 3 -1288 5 -2997 2 -329 2 -2344 4 -1900 5 -532 9 -2821 2 -3858 7 -1644 7 -2114 8 -848 10 -2820 6 -126 9 -2006 6 -2471 10 -3260 2 -2660 5 -3745 6 -1105 9 -3301 3 -2592 6 -3313 1 -1388 3 -2828 10 -138 2 -3765 6 -1882 3 -1552 10 -2130 8 -2421 1 -9 8 -1084 1 -1615 8 -2619 7 -1831 6 -3940 9 -1596 9 -1127 9 -1718 1 -814 5 -2365 9 -1654 4 -279 10 -3360 9 -4025 6 -224 1 -2529 2 -2277 10 -286 3 -1781 3 -2429 3 -98 1 -1214 4 -3920 2 -2300 6 -1818 10 -2490 1 -2674 10 -2767 4 -3042 9 -3007 1 -3082 6 -1264 6 -738 3 -2078 6 -3111 6 -10 3 -2939 3 -2420 9 -3298 6 -472 10 -3383 6 -3041 1 -557 2 -2520 5 -3695 4 -1487 10 -3723 3 -317 10 -3442 10 -574 8 -2151 7 -3178 1 -1727 9 -62 2 -3282 10 -564 6 -1492 6 -948 3 -3745 3 -3866 6 -749 6 -1150 2 -691 4 -1023 4 -2960 4 -173 2 -1170 5 -3284 7 -808 6 -4088 1 -2320 6 -1876 1 -1171 9 -3202 5 -1899 9 -3775 8 -1090 6 -881 1 -2486 9 -1102 10 -3164 2 -3261 7 -1200 3 -3738 10 -1250 3 -3947 10 -1409 3 -2226 5 -2599 8 -1847 3 -14 1 -587 8 -2833 8 -3511 8 -2348 5 -3814 3 -734 6 -1469 3 -3521 6 -1980 7 -2075 3 -675 3 -2818 3 -3436 7 -1169 10 -3998 8 -3268 4 -373 6 -2090 1 -1641 5 -1220 9 -502 3 -1103 1 -1907 6 -956 4 -112 10 -1229 6 -3587 4 -3008 10 -3458 5 -1991 3 -3781 9 -1335 1 -244 7 -1054 3 -1566 1 -1325 5 -3153 3 -4069 10 -318 1 -3883 6 -2088 9 -446 1 -2397 2 -2999 5 -3668 9 -2764 8 -1962 4 -2531 3 -348 4 -2445 2 -1730 2 -4070 9 -3439 9 -1430 7 -2819 7 -2225 4 -553 2 -2429 9 -1763 2 -503 4 -2692 7 -2899 1 -67 10 -3106 5 -2896 9 -66 2 -2111 3 -4061 7 -1103 8 -3469 3 -612 4 -1922 7 -300 8 -3712 10 -1386 9 -3626 4 -2924 3 -3897 4 -1149 5 -2435 6 -480 7 -2695 6 -1772 5 -1140 8 -2930 8 -2593 3 -252 10 -574 7 -648 2 -321 10 -3347 1 -391 7 -2755 6 -2834 8 -3028 8 -1339 10 -943 2 -3139 3 -193 7 -3133 6 -932 8 -135 3 -1621 4 -1837 6 -409 1 -3328 9 -3938 4 -2062 9 -3383 5 -3584 9 -1646 9 -3074 3 -1945 1 -734 10 -2558 5 -2644 4 -2850 1 -12 2 -1033 7 -1612 8 -3555 2 -3520 4 -1176 4 -254 3 -3906 6 -2661 10 -489 8 -3828 10 -2171 6 -2611 10 -1502 7 -622 5 -1913 4 -2033 6 -187 7 -1307 8 -3612 7 -2677 3 -1813 6 -3700 2 -99 1 -3300 6 -3535 7 -931 1 -3119 5 -3010 4 -78 6 -2386 7 -3633 5 -1706 7 -647 9 -669 9 -3026 4 -2259 3 -3716 3 -1337 5 -1813 8 -580 4 -3163 10 -2789 5 -3971 2 -1466 8 -1120 2 -2384 7 -4079 8 -1253 4 -428 5 -2713 10 -3247 3 -1031 1 -1398 6 -2114 6 -3392 3 -308 4 -1008 3 -655 7 -3483 8 -3 1 -418 8 -2071 4 -1238 2 -168 4 -642 4 -1031 6 -915 5 -742 4 -2101 2 -1627 9 -1593 4 -419 5 -1763 9 -77 6 -3463 6 -2740 4 -4000 2 -1192 5 -1959 2 -3150 8 -528 8 -1751 7 -1639 2 -2363 7 -277 8 -3790 7 -688 8 -1667 8 -1870 1 -3122 5 -795 7 -2150 9 -61 7 -44 4 -1213 7 -2420 3 -1355 4 -430 7 -1115 3 -3473 3 -2992 2 -2787 9 -789 6 -79 8 -786 6 -305 4 -1054 6 -2507 3 -197 7 -1296 1 -3126 2 -3274 1 -2143 3 -45 1 -4077 8 -1909 7 -304 4 -2444 5 -2457 3 -1388 5 -4003 3 -3304 7 -1671 9 -2554 6 -3080 2 -1004 8 -1610 9 -475 9 -597 9 -1984 3 -2096 9 -3046 4 -2725 6 -1141 10 -3287 10 -2049 10 -296 4 -439 2 -1424 10 -1080 9 -2884 5 -2767 1 -1619 3 -645 3 -2259 6 -866 5 -3559 10 -2414 9 -127 4 -1380 1 -1180 5 -2342 9 -467 2 -1500 7 -616 7 -2511 7 -1714 9 -828 3 -3509 4 -1002 2 -1340 7 -1886 10 -1203 3 -2010 2 -3289 10 -3963 4 -992 2 -1669 6 -1405 1 -3342 2 -1421 7 -2761 7 -459 4 -2007 5 -2400 5 -1601 4 -3057 2 -1086 9 -3956 2 -786 7 -1401 4 -1036 2 -1095 1 -258 10 -864 10 -402 6 -3880 7 -3268 2 -3968 6 -177 9 -450 1 -3520 9 -272 1 -474 4 -2195 8 -3049 4 -14 8 -1920 10 -964 7 -2409 10 -454 5 -716 1 -60 2 -280 10 -4013 10 -1825 2 -1639 10 -2149 10 -3730 4 -1631 4 -1600 1 -707 2 -765 3 -924 6 -2011 3 -3304 3 -3267 10 -1280 10 -2467 3 -3621 7 -2970 10 -3119 8 -834 1 -504 7 -2209 5 -1593 8 -2914 1 -2123 6 -2951 8 -3075 4 -3518 6 -2102 6 -1899 9 -2574 9 -4077 3 -1850 7 -3734 4 -2330 1 -2680 3 -1216 2 -3915 4 -3361 5 -358 3 -1317 8 -794 9 -1513 2 -2065 4 -3161 2 -893 1 -4062 7 -2286 7 -245 2 -4088 9 -3214 4 -4020 1 -1723 5 -1462 2 -2652 6 -2549 3 -144 8 -2646 2 -685 4 -3242 3 -2633 5 -2625 5 -2366 5 -2019 3 -3369 5 -1350 7 -4 3 -2019 10 -663 9 -2373 1 -160 10 -185 4 -215 1 -1706 3 -2565 1 -1158 1 -78 10 -2433 5 -1543 4 -1704 8 -3098 8 -832 7 -61 7 -433 7 -705 2 -837 3 -1622 3 -1025 1 -4074 2 -1897 6 -3598 2 -2113 2 -3735 5 -1622 10 -3517 5 -3540 1 -3656 6 -1388 8 -1985 7 -2284 2 -1937 1 -2800 5 -151 10 -3823 7 -2937 10 -3100 1 -2566 4 -1157 4 -1848 6 -3122 3 -2065 10 -2890 1 -869 5 -2450 1 -634 7 -661 8 -726 3 -3599 1 -1099 3 -2725 1 -1513 1 -1176 1 -3474 9 -3643 5 -627 1 -2773 4 -2173 4 -544 10 -2950 5 -1047 1 -2535 3 -2821 10 -3929 10 -3770 6 -477 1 -765 5 -3666 9 -1929 7 -715 10 -1941 4 -1299 9 -1912 7 -375 6 -1481 9 -774 1 -1516 5 -577 3 -1373 2 -2822 6 -3694 10 -3338 2 -1915 2 -2461 2 -673 7 -3165 6 -2635 5 -1900 5 -1264 7 -1580 5 -1310 8 -2815 1 -2053 2 -2750 7 -1522 5 -1601 5 -953 10 -3764 3 -4033 4 -3763 1 -3167 6 -630 10 -232 10 -3228 7 -3190 7 -1512 8 -274 4 -1299 5 -377 5 -1327 8 -860 5 -1489 3 -13 7 -1350 10 -3046 4 -3254 3 -1946 8 -2996 1 -395 7 -3068 6 -58 5 -2429 9 -1987 9 -2124 4 -2714 3 -3312 2 -153 7 -2558 3 -3051 3 -223 8 -2167 1 -2974 7 -3793 10 -918 6 -479 6 -3151 3 -2875 1 -3343 8 -132 4 -2995 1 -3006 9 -180 10 -3996 4 -3742 3 -3899 10 -3751 6 -2976 3 -1914 9 -183 2 -3004 5 -579 3 -766 7 -3381 7 -2072 9 -1223 8 -1063 1 -3020 5 -3778 4 -4055 2 -1371 4 -3756 4 -588 3 -328 3 -147 3 -2082 10 -1860 10 -3077 8 -2936 10 -3445 9 -2795 7 -3513 5 -2763 7 -73 2 -1480 7 -1475 5 -966 7 -2178 7 -4075 8 -3541 5 -3507 3 -2097 4 -1313 2 -2648 10 -3037 3 -668 3 -3828 3 -1366 9 -899 5 -1948 10 -1540 3 -2020 1 -1136 4 -3771 3 -3581 3 -1604 9 -3648 9 -3838 9 -3980 1 -100 5 -3022 9 -2117 3 -1617 2 -1856 4 -8 4 -4057 6 -2708 6 -3392 1 -764 3 -3595 5 -2560 3 -3670 2 -456 6 -542 3 -2333 3 -1134 7 -3643 3 -2835 6 -1091 2 -1616 2 -1525 2 -2960 5 -1424 1 -762 10 -2380 1 -1932 3 -377 3 -703 2 -2384 3 -1916 7 -429 7 -1986 10 -1064 4 -3871 3 -947 10 -1510 7 -1722 5 -3972 6 -442 7 -2630 4 -3923 9 -701 4 -878 2 -2700 1 -609 10 -2911 4 -2702 4 -925 9 -2769 9 -268 6 -113 8 -923 8 -1044 2 -1163 6 -3896 8 -1770 6 -343 6 -785 8 -102 7 -3757 6 -2902 3 -2140 2 -2897 1 -1369 7 -853 4 -3715 3 -3842 10 -2289 2 -3955 8 -1795 5 -2428 6 -212 1 -348 5 -368 3 -2240 3 -956 4 -3489 8 -1081 3 -1098 7 -2015 5 -147 8 -4028 2 -1067 8 -187 9 -1350 6 -1201 1 -2986 1 -2236 10 -722 3 -1902 6 -2518 1 -11 1 -407 7 -718 3 -3125 6 -1605 9 -1577 2 -1349 5 -899 7 -3277 4 -188 6 -2315 9 -2535 8 -2148 8 -2422 9 -93 10 -3583 2 -147 8 -507 7 -1484 5 -2812 6 -1520 6 -1901 10 -475 8 -1402 4 -1454 3 -2988 10 -2328 10 -2863 5 -1956 5 -1655 8 -988 3 -421 3 -3287 9 -3223 7 -2255 3 -1825 5 -2010 6 -2240 7 -2655 1 -38 4 -968 10 -3451 10 -759 1 -1362 7 -421 5 -1943 8 -1099 3 -1756 10 -513 7 -3683 10 -2108 9 -1000 7 -1072 3 -2710 6 -3839 1 -3884 9 -2408 8 -3533 10 -2453 7 -1253 3 -130 5 -280 7 -3464 3 -1994 6 -105 6 -3473 2 -1407 1 -3019 9 -1820 7 -3278 9 -16 8 -81 1 -1135 10 -2509 7 -2685 4 -1252 3 -585 1 -526 8 -1689 4 -3582 9 -350 7 -2432 4 -683 2 -437 6 -2594 4 -1520 5 -4041 9 -612 9 -2342 1 -2657 7 -1893 3 -528 1 -657 3 -1296 9 -4046 9 -1828 4 -2444 3 -1655 7 -175 9 -648 6 -1541 5 -2987 10 -944 1 -3777 2 -691 1 -1904 6 -1786 8 -1663 6 -1423 7 -597 7 -480 3 -2398 2 -417 10 -2610 9 -3464 7 -593 6 -2428 6 -2220 10 -317 6 -1135 7 -2762 3 -1943 4 -1736 3 -975 1 -14 6 -3681 6 -633 6 -2505 4 -3971 5 -2618 10 -3902 10 -618 2 -3249 9 -495 4 -4030 3 -86 7 -3327 2 -28 6 -94 4 -1717 5 -783 8 -2521 10 -4018 8 -2156 5 -1331 10 -958 2 -3362 3 -3351 2 -381 7 -114 1 -1805 7 -1903 2 -2663 9 -2542 3 -283 1 -3931 7 -1115 3 -563 3 -2584 8 -1400 6 -3584 5 -2605 10 -3338 8 -4029 5 -1157 1 -1828 3 -1982 2 -2276 6 -1531 4 -626 6 -181 7 -3734 5 -140 1 -2835 1 -3805 7 -3094 8 -2553 10 -1948 1 -69 1 -732 5 -786 2 -2152 4 -3992 10 -2884 9 -611 8 -2053 1 -3132 1 -159 6 -3376 4 -3846 2 -2703 1 -2660 4 -583 8 -3563 3 -3421 5 -2081 8 -1372 8 -3802 7 -3927 2 -1332 1 -401 10 -3164 10 -640 6 -665 6 -3261 4 -1292 4 -2037 10 -297 8 -607 7 -2218 8 -3101 1 -298 5 -709 3 -472 3 -1995 1 -1475 7 -3289 2 -1152 10 -188 1 -2554 3 -2655 8 -388 5 -386 3 -3997 5 -933 9 -2941 1 -4047 3 -85 8 -3850 5 -1757 3 -3920 3 -1611 4 -1817 6 -2138 1 -2944 4 -244 3 -3902 4 -93 8 -1614 9 -1851 3 -621 9 -3211 9 -503 4 -3034 3 -2328 6 -4021 9 -1839 6 -221 8 -908 9 -2417 7 -819 7 -590 8 -1940 1 -1652 1 -3750 3 -191 3 -2247 8 -167 3 -1034 5 -34 9 -295 5 -1149 7 -1762 6 -1853 1 -2450 5 -1682 3 -369 7 -3726 1 -613 4 -3931 5 -2214 3 -303 7 -1091 2 -642 5 -1675 8 -743 4 -1176 5 -2579 1 -2473 5 -3862 3 -3672 1 -1129 8 -1191 6 -3790 3 -2537 10 -1950 3 -2653 6 -3653 3 -1212 4 -1082 10 -147 5 -1468 5 -730 6 -2640 1 -335 7 -2568 8 -2719 1 -689 3 -686 3 -2145 6 -50 8 -2911 8 -3260 5 -3244 5 -3703 1 -577 8 -2192 6 -1459 7 -759 10 -2185 10 -895 6 -3981 4 -1420 3 -2161 5 -2529 7 -2943 10 -778 3 -828 10 -4087 7 -2416 8 -692 2 -3985 6 -395 6 -3628 10 -3951 7 -3089 8 -2571 2 -2867 2 -982 5 -1022 1 -442 4 -2390 2 -3345 1 -308 2 -3818 7 -3433 6 -3896 1 -694 6 -3157 2 -2557 7 -2151 9 -2786 1 -751 8 -371 7 -4051 2 -1717 5 -439 4 -2833 3 -3278 8 -1070 4 -459 2 -2349 3 -46 7 -588 4 -539 3 -3371 6 -1310 8 -2531 5 -2075 1 -2766 2 -3242 8 -3066 4 -2900 10 -3021 3 -7 6 -3311 6 -2171 8 -3750 1 -1550 1 -756 1 -1849 1 -2649 6 -1134 10 -2693 2 -52 3 -2004 3 -1782 10 -3076 2 -1586 7 -3650 9 -1705 5 -3287 9 -2025 8 -1077 9 -2233 3 -1816 2 -1850 7 -273 1 -3458 9 -2606 6 -83 2 -2657 10 -2486 4 -4052 7 -2874 10 -520 4 -2485 6 -2587 7 -3806 7 -4024 4 -3391 10 -2760 6 -3009 2 -144 3 -1414 5 -3565 8 -3128 9 -3192 7 -3333 8 -318 1 -3937 7 -2027 2 -951 10 -2610 9 -1260 10 -3343 9 -3218 6 -3079 9 -1587 3 -1032 5 -658 8 -868 10 -1085 10 -749 5 -4028 6 -1029 3 -3979 10 -4001 9 -1181 8 -1281 6 -320 5 -68 4 -4085 2 -1857 3 -3240 1 -1193 2 -525 5 -3535 7 -2438 6 -1771 9 -2812 1 -3815 8 -144 2 -366 6 -1847 2 -1434 3 -3170 6 -76 1 -3522 7 -3703 1 -2016 10 -1516 1 -1804 2 -1727 8 -2682 6 -2672 5 -687 1 -442 2 -314 4 -2553 3 -2489 5 -1319 9 -2001 2 -2297 1 -935 8 -3378 6 -2472 4 -1358 4 -1640 4 -1958 10 -1719 7 -32 9 -3620 10 -2455 9 -1186 8 -3283 8 -1937 2 -2787 3 -2208 6 -1680 8 -3348 5 -886 5 -213 10 -3651 6 -2328 5 -3140 1 -783 1 -3679 2 -486 3 -3997 6 -2420 2 -3116 7 -2596 6 -651 1 -594 8 -1197 5 -1954 5 -2844 1 -2550 5 -311 2 -3818 4 -3099 7 -4072 10 -4085 9 -1618 9 -2572 6 -3031 8 -43 10 -224 9 -1515 2 -1248 2 -3187 6 -2950 8 -3835 5 -2238 4 -4030 2 -2980 10 -2152 8 -1105 5 -1238 5 -3564 10 -1892 3 -1019 10 -1351 8 -2964 9 -2191 9 -4058 7 -1366 7 -1843 10 -2136 7 -210 2 -1870 3 -2307 8 -1405 4 -2098 2 -420 3 -3166 9 -3400 1 -2946 9 -1210 6 -850 6 -906 3 -256 10 -2817 7 -2319 10 -1367 8 -717 5 -149 4 -1035 4 -964 3 -1747 2 -3494 1 -3187 1 -1071 8 -2716 1 -319 4 -3392 7 -851 2 -1355 4 -1907 2 -385 8 -958 1 -933 2 -4004 7 -306 9 -637 4 -2620 10 -131 8 -3138 7 -3146 5 -3665 10 -342 1 -2361 7 -3332 7 -1153 4 -1208 3 -3453 5 -2285 2 -1692 9 -1565 9 -3932 5 -1129 2 -1282 4 -1323 7 -194 6 -1363 1 -1288 3 -4087 2 -3244 2 -1408 4 -3278 9 -3000 8 -84 3 -3788 6 -3777 9 -352 6 -3082 2 -3815 8 -401 3 -278 7 -1410 6 -736 4 -1051 2 -2683 8 -2580 3 -2862 5 -769 5 -3626 5 -4006 7 -618 5 -1977 1 -771 7 -4026 8 -3212 4 -1323 5 -2699 8 -3683 7 -4081 10 -4042 10 -2115 5 -2221 1 -1006 6 -3965 7 -1466 5 -2782 7 -3883 10 -465 3 -3280 1 -1152 10 -557 9 -1061 10 -1181 1 -1449 3 -2154 9 -3221 10 -108 6 -1115 10 -2308 6 -287 8 -1775 5 -1918 5 -978 6 -1054 9 -848 9 -1469 8 -729 4 -2086 4 -2710 6 -3468 2 -2673 3 -676 9 -3198 4 -985 1 -3647 8 -1025 7 -1461 5 -3741 7 -3780 10 -2885 8 -37 9 -3114 1 -1704 4 -2775 3 -3515 7 -2277 9 -2176 1 -3196 7 -3231 10 -2693 4 -2855 8 -1774 1 -3426 6 -1097 9 -2088 8 -178 1 -405 4 -3199 9 -2633 8 -1241 1 -3782 8 -3637 2 -2732 9 -1295 10 -2952 8 -585 2 -1605 6 -1753 6 -3015 5 -184 5 -872 3 -4030 4 -1418 5 -2318 7 -3813 7 -2012 6 -574 7 -2574 10 -2898 2 -1492 3 -3735 7 -2882 9 -1446 10 -1671 10 -1146 3 -2947 5 -3150 8 -2796 4 -872 8 -3915 10 -2135 5 -1806 4 -3748 9 -3824 10 -3866 4 -2236 9 -3597 7 -3421 7 -608 9 -227 10 -1735 10 -674 10 -2621 8 -2742 8 -2056 7 -3717 3 -2211 10 -2546 2 -2210 6 -2756 5 -268 3 -2698 2 -276 4 -424 4 -3217 3 -221 2 -660 7 -1626 4 -2158 10 -324 7 -609 3 -3056 1 -2207 8 -1253 7 -1224 3 -2636 9 -3560 6 -3137 7 -3178 5 -3879 3 -2797 5 -2394 9 -550 8 -3610 2 -384 7 -1668 7 -3456 4 -1876 5 -1874 1 -1244 8 -3161 6 -1389 6 -1097 7 -743 3 -3599 9 -2129 2 -3620 7 -858 3 -3993 4 -1686 6 -2561 3 -3456 7 -656 6 -3245 1 -734 5 -849 1 -897 2 -2861 1 -1711 8 -1549 3 -1081 3 -1208 6 -4063 3 -66 8 -2047 7 -2031 6 -704 3 -1293 5 -2441 8 -2816 9 -3667 10 -709 10 -1702 8 -3080 9 -389 7 -1949 1 -3887 7 -1712 2 -3273 10 -3876 2 -1662 6 -117 10 -923 6 -193 2 -3301 10 -3128 6 -2148 5 -2265 6 -3990 7 -2615 3 -3310 7 -2775 5 -3110 10 -2657 9 -1001 7 -1065 1 -1793 7 -533 9 -2986 6 -2089 9 -26 3 -2384 5 -3568 8 -969 2 -3062 3 -2330 6 -661 8 -956 7 -1684 3 -448 4 -2293 1 -2192 8 -3401 1 -1961 2 -869 3 -132 9 -902 9 -3533 6 -2493 5 -2162 2 -1644 7 -2240 1 -2152 6 -1617 9 -1023 5 -1934 10 -3861 3 -2532 1 -2440 2 -3584 6 -1317 1 -1939 8 -931 7 -125 4 -2073 4 -1806 3 -2377 2 -2070 3 -532 2 -741 10 -1092 6 -2350 1 -455 5 -2687 1 -2664 4 -3497 4 -1812 6 -1456 1 -394 8 -3347 3 -937 10 -3880 2 -1317 9 -3140 4 -300 8 -397 1 -2059 5 -2476 9 -1608 1 -3288 5 -2640 2 -1757 3 -2641 6 -2603 5 -2545 2 -3159 9 -3387 7 -3987 8 -1645 5 -2049 1 -2995 1 -1532 1 -2478 3 -2599 7 -3035 2 -768 6 -525 2 -3308 10 -246 9 -1723 5 -2727 9 -518 9 -1222 5 -677 2 -1196 2 -1824 3 -3310 4 -1129 5 -2665 2 -2004 6 -862 2 -1190 2 -2075 5 -2657 9 -2618 7 -3337 7 -3113 9 -1970 4 -1988 1 -863 8 -2625 10 -147 9 -1395 6 -2187 2 -1039 5 -1843 6 -1805 10 -1913 1 -2793 9 -2420 3 -1987 7 -1233 8 -3491 4 -3761 6 -2967 2 -443 3 -1502 6 -1586 10 -99 9 -2373 7 -3045 2 -945 7 -1145 2 -658 8 -682 2 -2717 2 -3663 1 -3178 1 -1558 10 -3148 3 -1159 2 -968 8 -3862 8 -2476 6 -63 9 -142 7 -2412 3 -2505 3 -4079 7 -3113 9 -1160 8 -1234 5 -2604 6 -3123 4 -366 3 -2954 1 -2298 9 -3526 7 -3071 2 -1579 2 -3108 10 -341 10 -3385 8 -3201 2 -4024 3 -3989 1 -2840 3 -803 10 -1698 8 -1100 10 -2982 9 -1657 7 -3584 8 -3626 3 -1983 1 -1765 10 -3843 4 -3101 10 -2972 8 -1692 9 -1874 4 -188 2 -1425 10 -2366 2 -3314 1 -2063 9 -2354 1 -2565 4 -1190 10 -3072 7 -945 6 -2670 10 -102 3 -3070 7 -1750 5 -506 8 -3060 2 -3108 9 -40 10 -1995 4 -2963 2 -217 6 -1585 5 -661 5 -769 4 -3476 9 -1583 7 -128 4 -1154 1 -3485 3 -276 2 -2850 4 -4026 9 -1551 8 -3113 3 -1887 5 -1895 7 -653 4 -960 4 -4060 9 -2873 8 -1374 3 -2762 2 -2336 5 -2954 4 -3048 7 -3791 9 -2818 3 -2544 9 -2364 6 -1081 8 -1369 3 -2397 9 -3635 8 -3219 2 -1811 4 -1532 2 -2492 4 -229 9 -1725 8 -1608 8 -257 2 -486 9 -2756 5 -212 8 -3191 9 -1855 4 -3752 8 -2958 4 -1134 3 -3533 3 -1951 10 -2131 4 -2610 9 -2919 4 -3949 2 -3292 2 -1456 1 -2276 4 -3196 5 -3501 8 -1020 10 -1175 5 -3252 3 -3757 5 -2920 4 -1755 9 -410 3 -605 7 -1207 8 -2536 5 -3803 4 -972 9 -259 6 -2712 3 -1886 6 -1610 10 -3107 5 -100 10 -1551 1 -2627 8 -876 6 -979 1 -3767 7 -1682 4 -3011 10 -1346 3 -4060 2 -749 2 -985 4 -1607 7 -2158 9 -219 10 -1320 10 -989 8 -2288 9 -4002 9 -3639 3 -2251 6 -108 8 -3571 5 -1871 4 -1798 8 -3303 9 -830 10 -204 5 -2710 4 -690 1 -871 2 -3513 7 -1718 6 -1493 8 -2766 2 -2847 7 -3304 4 -1122 5 -4016 9 -3035 3 -3626 7 -1202 3 -2422 2 -2267 9 -2837 2 -1253 10 -2135 4 -2592 7 -895 1 -497 7 -258 8 -2515 9 -3309 7 -1945 10 -279 7 -807 7 -750 4 -2745 7 -3154 2 -1091 1 -55 6 -3749 2 -2469 8 -1771 1 -434 8 -935 8 -3013 3 -241 10 -343 3 -3839 7 -2967 4 -2877 9 -729 1 -2844 2 -1627 1 -1805 6 -355 3 -3715 3 -3513 3 -294 4 -3911 8 -1748 6 -3890 10 -1027 1 -3646 7 -1210 8 -3549 3 -882 4 -2439 8 -3578 7 -606 3 -3881 6 -2532 6 -1396 8 -3425 10 -778 8 -3003 10 -1838 10 -1596 5 -416 8 -2314 4 -2755 9 -2133 6 -3384 1 -3039 10 -2575 8 -93 7 -134 10 -2137 3 -1431 2 -1299 6 -1745 8 -943 5 -496 2 -394 1 -0 8 -693 5 -3931 3 -3976 10 -3829 10 -3181 7 -1338 5 -3057 10 -2894 9 -2043 1 -3121 10 -2248 10 -1188 8 -265 8 -3422 3 -3565 4 -649 9 -2980 1 -2923 4 -3570 8 -357 3 -442 4 -1470 4 -2726 10 -4003 8 -1331 5 -3786 7 -2368 3 -3113 8 -902 3 -426 8 -1570 10 -1944 2 -4049 7 -3548 1 -728 5 -1047 7 -3482 10 -2645 2 -928 9 -1986 1 -209 3 -2623 2 -3860 4 -1380 8 -4026 7 -3918 5 -1051 10 -3944 3 -3250 2 -694 10 -402 6 -1707 7 -4037 10 -1283 5 -1261 1 -104 10 -2859 1 -1262 7 -3877 8 -466 8 -122 1 -3346 9 -3570 8 -1921 8 -3987 3 -1670 10 -2598 2 -3718 10 -2091 5 -3745 9 -1009 5 -2823 3 -2506 3 -2945 4 -1941 1 -2372 4 -833 7 -2509 4 -3358 1 -401 7 -3688 8 -3441 4 -306 9 -3991 7 -1636 5 -789 9 -3662 6 -728 2 -3376 3 -2619 7 -3994 8 -3485 1 -1844 4 -2819 3 -1027 9 -1267 7 -2068 4 -1659 6 -1878 4 -3620 8 -778 3 -3801 8 -1354 1 -1967 5 -3829 7 -1123 5 -3990 9 -3199 3 -2923 3 -1366 1 -3516 10 -1228 4 -1367 4 -3435 7 -1213 4 -564 7 -3668 7 -1730 5 -2317 6 -1688 4 -1647 1 -3429 6 -1080 4 -721 1 -1795 8 -3204 9 -3529 8 -581 3 -1833 6 -2435 2 -3641 4 -3085 9 -1569 6 -2799 6 -1389 7 -418 7 -3103 6 -2438 6 -3126 5 -501 9 -2675 9 -750 1 -504 3 -372 10 -1741 4 -3746 6 -4075 10 -2654 8 -622 10 -633 5 -2107 10 -869 3 -66 3 -1724 8 -2734 7 -3801 2 -414 8 -2164 1 -2812 2 -396 9 -2526 7 -3088 1 -277 4 -3455 4 -2535 8 -3039 6 -2670 3 -762 3 -2842 4 -3746 1 -1691 4 -429 4 -3319 2 -192 3 -3180 4 -3633 10 -1232 10 -2420 2 -622 8 -1721 1 -3665 8 -2476 1 -2432 5 -2419 7 -1778 6 -2852 8 -3101 5 -948 2 -1896 6 -311 7 -3321 8 -1686 3 -3126 2 -2589 5 -3920 6 -3499 3 -404 2 -1581 6 -3045 4 -3363 4 -481 5 -3439 8 -2868 8 -2306 2 -1331 1 -1352 4 -797 3 -2136 7 -2222 5 -1796 10 -1541 3 -144 7 -3522 1 -3608 5 -3480 2 -423 9 -1621 1 -3896 3 -614 8 -610 10 -975 6 -287 5 -1651 6 -4087 7 -1979 10 -1406 3 -2786 2 -2682 8 -901 6 -2356 1 -1623 9 -1311 10 -3431 6 -873 7 -2216 4 -3918 1 -3801 4 -2766 8 -4005 10 -767 1 -1933 2 -1532 3 -79 5 -2101 3 -2366 8 -412 6 -2925 9 -3375 3 -1773 4 -4009 8 -3572 8 -1512 5 -1188 2 -3942 7 -3366 6 -1544 6 -3548 10 -340 1 -678 6 -3557 6 -922 6 -3996 5 -1672 7 -1910 5 -1099 2 -3570 9 -4029 2 -3950 6 -1599 10 -1841 9 -3785 5 -3981 6 -3063 9 -986 9 -347 10 -1832 5 -2273 1 -2509 8 -2470 5 -2067 10 -719 6 -1269 8 -2941 1 -4031 7 -3032 3 -2822 5 -916 7 -1781 4 -2107 1 -3950 2 -2227 7 -3153 4 -610 5 -913 3 -403 6 -340 7 -3573 10 -1325 9 -881 7 -3903 4 -799 9 -1249 8 -2114 3 -3648 1 -4076 4 -3782 10 -68 6 -3936 9 -2202 9 -3932 4 -1467 4 -2978 5 -476 4 -222 9 -2747 1 -1227 9 -1823 8 -2387 10 -1440 4 -2887 10 -943 4 -875 5 -1401 1 -1615 10 -3520 2 -2384 10 -2884 8 -3669 5 -2387 9 -164 6 -172 3 -2510 2 -2926 9 -3235 6 -1881 5 -1950 7 -3728 6 -1128 1 -417 6 -836 6 -149 7 -1300 6 -3946 8 -86 10 -3291 8 -1233 3 -3856 1 -3118 1 -1761 1 -430 5 -938 6 -297 4 -1548 1 -2995 4 -1048 3 -3783 5 -3499 7 -3868 2 -2272 10 -4007 10 -3906 10 -309 3 -1660 10 -2925 3 -2792 7 -773 4 -3786 1 -3468 5 -2748 1 -1680 6 -978 7 -815 5 -1632 6 -291 9 -3937 1 -1277 1 -4071 2 -3781 5 -1858 3 -399 6 -1108 8 -3145 6 -2173 9 -3652 6 -1588 4 -1241 7 -2724 5 -2344 6 -279 2 -2602 8 -588 9 -3281 5 -742 2 -3824 3 -2506 9 -60 4 -2815 4 -3679 1 -2121 7 -755 9 -3033 1 -1025 3 -1265 10 -1513 2 -1802 3 -2800 9 -1695 1 -229 10 -466 1 -126 8 -4027 5 -943 7 -4066 8 -2329 5 -3925 2 -3970 6 -553 4 -3589 3 -1504 10 -939 2 -829 8 -3608 4 -3197 9 -1613 4 -2219 3 -2744 10 -296 7 -3970 6 -3902 5 -1915 2 -3423 4 -3305 9 -3303 9 -1819 5 -3765 3 -509 6 -1146 9 -2902 6 -4035 4 -950 9 -1946 7 -3092 3 -397 3 -2952 4 -870 7 -3611 6 -2213 10 -2894 3 -540 8 -1944 3 -1879 8 -2040 4 -1552 10 -2498 2 -823 4 -452 8 -3351 1 -3025 7 -3241 5 -2244 7 -3168 4 -2072 6 -195 5 -880 6 -1257 7 -3455 2 -504 7 -1848 2 -2660 4 -2317 8 -1884 3 -225 4 -1809 10 -552 5 -1112 5 -340 8 -3021 2 -3084 3 -2140 6 -519 8 -1879 2 -2878 5 -1785 10 -1589 2 -1259 2 -3609 5 -2048 10 -2345 10 -670 8 -3944 6 -1773 9 -1612 7 -4076 4 -2856 9 -332 9 -2127 8 -1091 2 -3606 6 -751 3 -4036 9 -3866 9 -1326 3 -1120 9 -3361 8 -417 6 -1075 2 -1459 6 -1269 5 -3602 5 -2276 1 -678 3 -3846 9 -206 3 -1592 5 -1677 4 -2752 4 -2158 1 -2350 6 -2931 8 -2294 1 -1215 1 -363 3 -1423 3 -1526 10 -199 1 -3893 7 -3443 1 -2004 1 -1796 3 -292 9 -3030 5 -1002 7 -1657 4 -717 4 -1567 3 -663 8 -4037 10 -1253 9 -2510 4 -1699 4 -2198 6 -202 8 -777 10 -3846 3 -2196 5 -2910 2 -2246 9 -3640 9 -1491 5 -1503 10 -1670 4 -344 7 -3988 9 -1347 2 -502 10 -2808 3 -3885 5 -2786 2 -267 3 -3512 3 -3211 10 -491 9 -2175 7 -2833 3 -3513 6 -3403 9 -973 10 -1560 3 -734 4 -533 2 -1839 1 -1926 4 -2975 1 -2156 3 -3377 2 -2299 4 -666 3 -3981 2 -2857 6 -627 6 -34 7 -3789 7 -2067 3 -751 6 -2819 9 -1311 9 -1113 5 -2389 1 -2600 9 -1820 6 -1090 9 -3392 3 -2987 2 -2031 2 -2522 2 -4004 1 -151 2 -3816 3 -2188 6 -2184 7 -540 2 -2076 6 -3861 10 -3289 2 -1024 6 -2344 1 -1880 4 -1704 3 -395 2 -3616 3 -3136 4 -2388 5 -3016 3 -3086 8 -2745 3 -2143 7 -1009 9 -3566 9 -155 8 -330 4 -3616 3 -2777 5 -34 7 -3824 2 -58 3 -1069 9 -1959 6 -1326 10 -121 1 -39 2 -708 8 -433 3 -2002 3 -1537 9 -459 1 -2062 1 -2212 1 -1689 2 -301 8 -785 9 -1777 4 -2689 4 -2614 5 -3668 7 -3096 8 -433 3 -3618 1 -902 10 -760 3 -1181 10 -570 1 -3705 6 -2119 1 -2040 7 -75 9 -945 8 -1652 2 -261 4 -1925 5 -400 1 -1630 4 -3873 6 -3964 3 -3633 10 -2434 6 -3058 9 -437 2 -1939 4 -1577 1 -585 5 -3775 1 -3825 3 -3629 7 -98 3 -593 10 -2123 9 -2668 9 -1845 8 -440 6 -3140 4 -1397 8 -2796 6 -1974 10 -2409 7 -1383 6 -3167 9 -3146 2 -3175 1 -2007 2 -4083 2 -782 9 -2423 7 -41 5 -2687 9 -1083 5 -2213 6 -1865 10 -1077 2 -770 4 -3067 1 -2747 3 -3136 5 -2861 7 -2093 4 -3547 4 -3509 10 -3388 2 -3252 6 -2245 10 -2690 1 -915 7 -2760 2 -2304 10 -1416 3 -1226 10 -2056 7 -371 4 -1700 4 -1080 3 -722 8 -1133 4 -1915 7 -22 8 -368 2 -1223 5 -513 3 -216 5 -923 10 -4081 6 -1186 7 -2072 10 -335 2 -3573 6 -1543 8 -1825 3 -110 10 -2327 1 -1010 6 -1954 4 -3420 2 -1862 4 -3075 10 -2937 9 -3747 3 -322 2 -2944 9 -3751 6 -2462 10 -3596 9 -686 8 -2853 1 -2072 1 -2941 9 -513 10 -3508 4 -419 3 -1327 2 -1594 10 -3150 7 -3013 1 -3214 3 -2671 5 -3782 10 -3802 1 -3958 10 -3795 6 -1522 6 -1401 4 -220 6 -2269 10 -3654 3 -755 1 -1803 6 -3780 2 -194 4 -4057 1 -2433 1 -856 7 -3131 5 -3963 6 -1949 6 -1643 7 -3594 6 -342 10 -3132 8 -1849 3 -2588 5 -3774 9 -186 9 -2446 4 -162 3 -1681 8 -320 1 -473 5 -1648 8 -809 5 -1421 6 -1656 7 -2678 4 -3269 2 -2563 7 -669 4 -921 2 -3819 10 -1546 6 -2286 9 -381 3 -3492 5 -1230 3 -195 4 -3236 9 -631 6 -1848 8 -2904 2 -3668 2 -1794 8 -3286 1 -3144 4 -1830 7 -1039 8 -3926 6 -3408 5 -605 1 -3806 10 -2356 3 -2266 1 -1520 5 -702 8 -380 3 -122 7 -1726 4 -1139 4 -3062 3 -2496 7 -3760 10 -211 6 -2970 4 -1211 3 -2315 9 -2739 6 -1137 9 -1725 6 -3946 4 -3446 10 -1218 10 -3736 5 -3246 1 -3816 7 -3051 6 -340 3 -3934 8 -2177 8 -963 4 -1978 9 -1076 5 -3329 7 -2824 6 -900 7 -1077 7 -591 5 -809 5 -1175 2 -598 2 -3882 2 -1753 1 -3796 1 -2958 7 -2551 5 -2574 7 -2240 1 -578 1 -2462 10 -2082 9 -4043 2 -489 4 -2008 7 -3176 4 -2675 9 -3178 2 -1655 7 -3293 3 -433 6 -3353 2 -2230 7 -179 5 -2290 5 -69 9 -2822 4 -908 1 -1488 3 -103 1 -1803 10 -3633 5 -1447 5 -1165 2 -414 5 -3311 5 -1882 8 -3396 10 -2937 9 -1823 2 -1895 2 -3746 9 -1409 3 -677 4 -266 6 -2961 3 -3229 2 -284 10 -510 5 -1385 4 -1105 9 -1481 10 -2218 7 -3113 9 -1185 10 -481 4 -3427 4 -859 5 -3885 8 -2238 5 -1933 10 -3188 7 -3824 2 -3712 2 -3336 7 -1127 8 -3648 5 -2894 9 -1370 4 -2276 2 -2952 6 -3528 10 -3977 6 -3714 3 -255 3 -1946 4 -2867 10 -978 8 -3391 1 -3137 6 -3584 6 -3170 1 -1441 6 -3988 2 -68 1 -2842 1 -2574 5 -525 10 -2742 6 -873 7 -3436 9 -836 2 -1320 4 -298 4 -3559 1 -3008 2 -2519 5 -649 2 -3098 6 -1217 9 -430 4 -508 3 -3641 8 -2941 8 -1172 7 -3938 8 -987 10 -2640 7 -2175 7 -1589 1 -3858 6 -1799 7 -2386 5 -2921 5 -229 9 -1875 8 -3662 5 -3382 5 -1457 8 -2667 1 -1020 4 -1529 8 -2273 3 -3537 9 -2486 3 -3058 8 -3500 4 -3907 2 -4023 8 -2301 5 -875 10 -853 4 -1284 10 -1577 7 -568 2 -3351 9 -3747 8 -1624 8 -3734 1 -1924 2 -453 5 -2140 10 -2486 6 -886 4 -1088 4 -1911 8 -1722 3 -260 6 -1655 1 -1627 10 -575 4 -2477 5 -3718 5 -1236 2 -1886 10 -608 1 -2025 10 -442 8 -664 3 -3810 7 -802 6 -1433 1 -1700 8 -1823 7 -3167 3 -679 6 -2025 9 -3808 7 -1765 9 -2703 1 -2508 6 -1762 5 -1219 4 -2483 10 -3182 7 -3739 2 -1473 6 -1270 1 -3942 2 -3869 10 -650 9 -713 1 -2696 6 -2817 7 -2214 9 -3339 8 -3379 2 -444 1 -837 9 -3325 6 -3605 7 -133 9 -3903 5 -129 7 -919 9 -67 2 -1519 6 -2093 2 -863 9 -2481 10 -2267 4 -388 1 -4034 5 -2236 2 -2963 8 -2563 10 -2641 10 -1925 7 -435 10 -946 2 -1408 3 -1672 9 -1064 10 -690 3 -1566 6 -3434 1 -2659 9 -3511 9 -157 1 -1768 6 -3980 2 -3126 4 -1763 7 -1494 1 -956 9 -1267 4 -1485 1 -368 10 -3108 5 -1683 9 -2098 5 -2746 6 -612 3 -1994 5 -3867 5 -2411 9 -3485 4 -3200 6 -807 3 -2942 5 -3652 6 -3093 5 -1102 9 -3343 5 -1669 7 -366 3 -2797 6 -1969 3 -3297 4 -2688 10 -3444 6 -1576 8 -2409 4 -19 5 -76 4 -241 8 -126 2 -342 5 -2267 8 -322 3 -1458 3 -771 5 -355 7 -1012 6 -1410 2 -225 4 -625 1 -1537 5 -3643 4 -4017 7 -1681 10 -18 7 -988 9 -531 6 -3340 1 -3715 5 -552 4 -481 5 -2289 9 -2799 2 -1854 9 -3959 4 -3941 7 -697 4 -3044 5 -3879 10 -823 2 -482 7 -766 5 -1611 2 -1186 1 -1063 5 -3696 4 -3997 4 -1121 2 -1532 4 -3565 2 -3844 8 -3642 2 -2298 8 -3612 4 -3319 6 -2730 3 -1361 9 -2790 3 -2653 10 -3237 4 -2719 2 -88 5 -894 1 -4048 3 -645 4 -2641 7 -970 9 -3808 3 -3216 3 -343 1 -2582 9 -3595 5 -2230 10 -2953 10 -2343 8 -2333 5 -2659 3 -3320 10 -2310 9 -3659 1 -2166 6 -1147 7 -3420 6 -3912 1 -2932 6 -4095 5 -815 3 -671 10 -1709 10 -437 3 -2612 7 -948 10 -582 8 -600 3 -2057 10 -1943 1 -3193 6 -1005 5 -2603 2 -1975 6 -1551 7 -861 9 -805 4 -2556 8 -2980 8 -1150 9 -2859 8 -3236 10 -2504 7 -3151 2 -2432 10 -1337 8 -3581 5 -2099 6 -2249 1 -2755 9 -3959 9 -2478 4 -1950 2 -696 9 -783 8 -3474 10 -1250 4 -1640 4 -406 8 -1045 2 -2403 10 -465 1 -2555 10 -867 6 -932 5 -782 8 -991 1 -3450 4 -2163 7 -4014 5 -2548 10 -2088 9 -2206 8 -2695 2 -2360 8 -3681 2 -1849 7 -2659 4 -688 9 -375 8 -1702 10 -110 1 -2464 1 -3988 5 -1309 4 -316 7 -3777 2 -304 6 -3448 1 -3484 3 -414 2 -2171 3 -2190 5 -1234 6 -85 5 -4036 8 -2928 8 -832 9 -800 10 -799 9 -598 9 -3154 3 -3829 10 -2183 9 -303 6 -2100 3 -3751 2 -1404 2 -2872 3 -3529 10 -3178 3 -3184 5 -2229 4 -2452 1 -4064 3 -2624 4 -1858 5 -4038 9 -2116 3 -3140 5 -1762 2 -1278 7 -3472 5 -3779 9 -3487 8 -1745 1 -904 3 -1487 9 -1532 8 -1159 2 -2898 1 -1408 10 -2516 10 -2320 1 -3764 3 -2506 7 -1887 2 -1457 6 -2111 3 -1434 8 -328 9 -302 7 -3819 6 -1137 3 -2846 9 -1432 1 -3129 8 -2929 5 -1912 5 -1461 10 -3630 5 -620 3 -3217 5 -3176 10 -2691 5 -923 9 -130 6 -3075 8 -3104 2 -634 9 -1953 5 -840 10 -788 9 -2142 7 -788 10 -3641 10 -2398 10 -106 2 -2817 9 -2196 2 -1266 10 -4091 1 -2069 1 -751 6 -3077 5 -2497 6 -1919 8 -2524 6 -547 10 -3896 2 -3216 6 -2263 1 -74 8 -3736 4 -2958 7 -221 9 -2353 1 -3987 7 -3894 2 -3556 3 -1661 3 -1270 4 -3749 6 -3599 1 -2712 6 -1776 8 -1370 1 -1757 9 -3157 4 -2404 10 -779 4 -3029 2 -3154 8 -1503 2 -1166 8 -1657 9 -1727 9 -2278 2 -575 7 -3046 5 -2276 1 -763 3 -3781 5 -1355 6 -2091 4 -3323 9 -904 9 -2388 8 -261 6 -1099 2 -827 10 -1204 4 -728 5 -717 5 -1425 1 -1017 5 -3516 9 -1395 3 -1883 1 -3193 8 -1838 1 -1226 10 -1646 6 -2328 1 -2603 6 -32 5 -2660 6 -3992 7 -977 5 -3369 2 -211 1 -1526 5 -3302 10 -3332 3 -1422 3 -3467 5 -252 5 -4001 10 -3832 3 -647 5 -1311 8 -2676 7 -777 3 -1459 8 -3346 1 -3498 3 -4042 10 -2097 1 -928 8 -1523 6 -1179 8 -229 3 -111 3 -3898 5 -1932 9 -1413 1 -2283 7 -3192 3 -3533 7 -3581 1 -3549 4 -425 7 -2740 2 -2600 2 -4006 3 -1513 8 -4017 5 -3449 6 -3751 5 -3518 3 -771 2 -2254 5 -3596 4 -1826 9 -1265 4 -658 4 -1015 2 -3840 2 -186 3 -1904 4 -988 6 -2508 4 -3309 9 -1553 6 -1894 7 -4064 10 -2256 1 -1399 6 -3120 9 -3891 3 -2364 1 -3351 2 -3364 9 -3724 8 -3279 7 -809 10 -3446 1 -1057 3 -3114 9 -3952 5 -2817 3 -312 3 -437 10 -1690 10 -2620 2 -2785 7 -3914 2 -654 8 -2473 5 -570 10 -1857 8 -2927 3 -3633 8 -2586 10 -1979 9 -3221 10 -185 8 -3094 3 -10 3 -335 7 -3610 7 -3820 9 -3210 9 -788 9 -224 4 -2623 5 -2714 6 -1288 6 -597 7 -1995 9 -1699 7 -2072 6 -3344 6 -2649 5 -1779 6 -324 1 -1018 1 -2155 7 -869 7 -1636 2 -3612 5 -2360 5 -1043 10 -2716 10 -1962 7 -1923 8 -2994 10 -1160 3 -138 10 -1379 4 -942 1 -2718 5 -3565 5 -1245 5 -641 6 -1953 2 -1186 4 -126 4 -3651 1 -741 2 -4026 7 -1044 1 -3329 6 -335 3 -757 9 -1959 1 -970 10 -1374 6 -1372 3 -2080 6 -3134 5 -2353 9 -3 9 -2327 3 -3715 9 -2304 7 -3320 2 -3035 2 -954 6 -3934 10 -2073 2 -2233 2 -799 10 -1736 1 -3663 9 -985 4 -233 5 -3515 2 -993 6 -2173 6 -3041 6 -2718 7 -3604 5 -1238 3 -2604 4 -3032 8 -3675 8 -905 7 -3644 2 -1388 7 -3322 1 -3798 1 -3338 4 -1194 7 -2614 3 -1600 8 -2937 8 -1452 10 -893 4 -4077 9 -2633 10 -3024 2 -45 4 -2351 1 -44 7 -248 10 -2566 1 -2282 8 -2721 6 -489 9 -2994 10 -3121 7 -3316 1 -2512 2 -2221 7 -510 1 -3000 3 -2551 5 -3512 4 -3770 5 -472 6 -1555 1 -1540 8 -474 2 -3574 1 -3385 9 -1272 3 -3225 3 -1225 8 -748 4 -1122 1 -376 4 -1160 3 -1260 2 -2478 6 -3236 4 -1873 9 -2811 2 -2034 1 -2712 3 -3957 7 -1364 4 -1303 1 -3264 5 -224 10 -714 7 -2487 8 -2272 6 -1067 9 -1252 3 -242 4 -3523 5 -3954 5 -2360 7 -1939 8 -3576 5 -1035 2 -509 3 -1477 6 -3307 8 -3731 6 -2372 7 -736 5 -1469 1 -3459 1 -3949 7 -2502 5 -2273 7 -1007 8 -2756 7 -1486 1 -2849 4 -976 1 -2354 3 -348 5 -3211 4 -3659 9 -3949 2 -1305 10 -779 9 -1559 4 -1827 8 -3133 6 -534 2 -2501 5 -1378 6 -2656 10 -4060 10 -758 9 -2607 8 -535 8 -3398 6 -1572 6 -4092 2 -2856 2 -317 10 -1333 3 -2024 4 -2912 7 -1334 10 -2471 3 -1186 7 -1027 2 -1139 1 -3857 1 -118 6 -15 9 -309 5 -2691 10 -1855 7 -3243 9 -3972 5 -170 5 -783 6 -1648 10 -2250 1 -3008 10 -452 10 -119 2 -2175 8 -2432 2 -3369 9 -340 5 -1207 2 -521 3 -3438 10 -2126 8 -3333 3 -3293 7 -610 3 -1504 9 -3487 5 -3962 8 -834 7 -3231 1 -3834 5 -2801 7 -2515 3 -3627 4 -2839 4 -1796 10 -657 7 -9 7 -1298 1 -2113 1 -2261 4 -1215 4 -570 2 -2509 3 -499 8 -1675 2 -1159 8 -1633 6 -2181 5 -180 5 -496 3 -3674 9 -1866 10 -2576 4 -2640 10 -2986 7 -741 7 -34 2 -4050 10 -624 7 -2524 2 -3795 9 -1544 8 -3232 1 -2544 7 -3116 8 -1180 9 -3784 9 -2335 1 -2941 7 -2329 8 -637 5 -1408 5 -974 6 -747 10 -2873 9 -2754 10 -1682 2 -1962 3 -3132 7 -3578 5 -566 6 -1152 6 -2729 4 -3160 9 -1700 4 -1789 5 -2309 4 -1773 4 -371 2 -3821 6 -3587 7 -2523 3 -993 9 -2604 5 -3284 7 -3117 2 -3249 6 -1839 5 -1228 6 -1835 8 -3598 2 -1284 7 -3343 1 -659 6 -2633 4 -1227 8 -2996 9 -1224 3 -634 7 -3985 4 -262 1 -2655 9 -581 4 -3039 10 -2723 1 -1957 1 -2528 2 -244 5 -137 3 -4075 3 -3436 2 -4087 7 -3641 10 -2620 2 -3511 3 -464 5 -1857 4 -749 4 -2694 7 -3515 2 -3285 4 -2205 5 -1417 8 -1834 10 -3335 9 -2735 2 -2596 5 -4057 6 -3832 2 -3595 10 -126 8 -2982 1 -2578 1 -1442 6 -3415 5 -2849 8 -2145 9 -3870 3 -3082 1 -3210 10 -3737 1 -1449 7 -1304 3 -2853 7 -329 1 -1904 3 -3690 2 -3711 2 -2568 9 -846 4 -1446 2 -106 3 -3568 9 -1030 5 -2394 10 -773 1 -3241 8 -73 8 -2778 6 -119 2 -2873 4 -158 8 -2655 4 -2269 10 -573 1 -3776 8 -435 6 -1733 8 -2862 7 -3845 2 -3189 8 -3969 1 -3108 1 -1215 2 -511 2 -2863 5 -3713 2 -3127 4 -3081 6 -1419 10 -120 10 -2843 6 -3079 7 -382 7 -2755 8 -2196 9 -363 5 -3175 7 -3447 9 -4021 1 -2999 3 -2210 4 -245 8 -3486 6 -196 6 -4055 7 -4083 5 -727 7 -623 6 -1936 1 -590 3 -690 10 -1327 1 -2046 8 -521 9 -3709 8 -1357 8 -3306 4 -2909 9 -808 9 -2466 10 -2968 7 -792 3 -1565 10 -1199 3 -977 7 -2759 7 -2836 5 -1631 9 -844 7 -1675 9 -1770 6 -1131 5 -3687 1 -2869 7 -3020 9 -2215 10 -3912 10 -3568 5 -472 3 -3801 2 -2739 1 -179 5 -127 4 -1912 5 -198 3 -2111 5 -1162 7 -425 9 -731 1 -1410 10 -3101 9 -1103 5 -1485 7 -1555 8 -2825 9 -3312 8 -1881 1 -3349 1 -3721 2 -1049 5 -2363 8 -3727 2 -2794 10 -2658 5 -3487 1 -2979 10 -2119 10 -1466 3 -3963 2 -3181 1 -1866 8 -1646 3 -2777 2 -2483 8 -3825 9 -633 3 -3489 8 -2970 7 -1956 4 -3246 3 -298 5 -79 3 -2958 10 -1600 6 -3610 7 -1230 3 -2683 6 -2687 5 -4054 2 -699 7 -3400 10 -1956 4 -1907 4 -3961 3 -3709 4 -3893 8 -2588 8 -632 7 -3859 6 -1001 3 -1108 10 -3667 8 -1009 3 -3586 9 -3187 10 -1790 8 -2542 3 -352 6 -2829 2 -758 9 -3788 8 -1950 8 -1995 2 -3562 4 -1812 3 -3072 4 -973 7 -98 6 -2162 10 -2251 7 -1984 8 -1871 8 -2085 10 -3638 3 -2192 3 -718 2 -3932 2 -2416 7 -121 9 -1394 3 -1053 4 -3505 5 -1671 9 -3121 8 -1205 3 -2068 1 -628 6 -704 10 -515 6 -798 9 -3251 1 -374 8 -2594 8 -3858 4 -2619 5 -2191 7 -1986 10 -322 6 -2839 10 -2546 6 -1236 9 -1752 8 -3056 5 -373 9 -2983 8 -2264 6 -2325 8 -2959 3 -3631 7 -1979 3 -3088 5 -3082 2 -2863 2 -2681 8 -3473 7 -816 8 -85 10 -955 7 -591 9 -3790 6 -1168 3 -2321 9 -1923 2 -2731 3 -2146 8 -2847 1 -2206 9 -1113 2 -3631 7 -2177 7 -2281 3 -2262 5 -3129 2 -2149 4 -524 7 -2552 7 -290 1 -37 7 -1938 10 -1799 9 -4080 5 -783 5 -282 8 -68 9 -2637 2 -2539 9 -213 1 -475 2 -208 7 -421 9 -1530 6 -2418 5 -3953 6 -3985 1 -3000 10 -77 5 -149 3 -2218 4 -1826 1 -2212 2 -461 8 -4087 7 -2039 5 -1590 3 -577 8 -1191 5 -2466 4 -3361 5 -527 10 -3358 1 -2079 4 -2798 5 -3990 2 -2835 6 -2139 10 -2979 7 -2117 8 -3185 3 -642 6 -188 4 -654 2 -2128 1 -3288 4 -3134 10 -51 6 -3496 9 -2883 10 -1077 7 -3069 6 -1204 10 -1396 2 -2541 1 -2317 7 -4090 7 -3539 5 -3235 4 -1110 3 -1790 6 -1968 10 -1076 7 -2311 2 -3495 9 -835 1 -585 5 -2294 5 -2840 3 -1028 4 -652 7 -1619 6 -3608 10 -281 2 -637 4 -1123 8 -1155 6 -2604 6 -2203 3 -2420 7 -3215 7 -399 1 -1 9 -1436 6 -691 8 -550 6 -2629 1 -539 7 -1001 7 -3453 6 -2965 4 -2098 5 -1789 5 -3621 6 -3958 4 -1681 3 -759 2 -1172 3 -1126 7 -3477 3 -370 10 -1318 9 -98 6 -2313 2 -1291 6 -993 4 -3593 3 -128 6 -778 10 -1473 7 -615 2 -260 3 -3651 1 -3334 8 -4042 5 -657 9 -3542 7 -2233 7 -1956 4 -2133 8 -2782 4 -3889 5 -99 1 -2578 3 -451 10 -2484 9 -1947 4 -2212 2 -2284 6 -1371 2 -3921 5 -2002 3 -114 5 -4084 1 -346 10 -4070 2 -2330 10 -2200 10 -94 4 -3099 4 -1497 7 -1740 9 -80 3 -839 6 -2305 7 -928 7 -1369 3 -2532 8 -995 9 -1568 1 -1773 3 -378 4 -2271 5 -761 9 -519 7 -3151 2 -268 4 -3857 4 -71 5 -2831 10 -2903 3 -3173 4 -3630 6 -2258 5 -1272 7 -475 1 -407 2 -1433 2 -2624 8 -1492 10 -4013 6 -2006 5 -44 9 -3647 9 -3104 1 -3251 9 -4090 1 -4053 9 -2748 6 -553 4 -2964 8 -3234 4 -2097 4 -2762 10 -3947 7 -2941 3 -3343 9 -1872 1 -3647 2 -139 7 -175 4 -1573 1 -2708 3 -2525 4 -727 4 -1281 9 -2165 6 -3119 6 -131 5 -2162 7 -2469 3 -1384 6 -1382 6 -3262 10 -2898 2 -1168 10 -320 7 -1772 4 -473 3 -3529 8 -2740 2 -3866 10 -1730 9 -1447 8 -2700 1 -1340 1 -1161 4 -1811 4 -3582 5 -98 6 -3185 1 -1405 9 -3288 4 -1797 9 -360 7 -3764 6 -1722 4 -3924 4 -2621 9 -1187 6 -1487 10 -2761 9 -541 8 -2024 6 -192 9 -3758 6 -3311 9 -2768 8 -3336 7 -386 10 -1103 5 -2229 1 -519 2 -1819 4 -2215 8 -2053 1 -1345 4 -3518 1 -1189 7 -3789 8 -1794 9 -1995 3 -2693 9 -838 10 -1363 3 -773 9 -2361 8 -1417 3 -54 1 -2915 1 -3216 8 -3374 7 -1153 7 -564 9 -3772 6 -3009 4 -920 7 -677 10 -979 3 -2910 3 -1048 2 -3011 1 -2728 9 -2689 5 -1947 9 -3480 3 -875 6 -2501 6 -403 1 -622 6 -1937 7 -1144 1 -1928 2 -3868 5 -860 1 -2372 10 -2503 8 -1345 10 -3113 10 -3953 7 -1961 4 -812 5 -3080 1 -2311 7 -3193 7 -904 7 -3556 6 -2952 4 -739 8 -217 3 -2240 4 -489 6 -646 7 -2897 2 -4053 4 -973 3 -1981 7 -1990 4 -566 1 -3001 2 -3480 7 -2082 1 -2792 4 -3419 5 -3024 8 -1277 3 -1510 9 -2498 1 -3858 4 -1157 1 -1254 2 -161 4 -438 5 -3650 4 -3831 5 -4020 3 -1006 6 -2614 3 -1326 6 -1373 1 -3721 3 -1020 1 -3233 9 -1749 10 -3807 5 -84 4 -568 4 -491 1 -841 4 -1034 6 -51 4 -3602 10 -629 9 -3973 8 -1868 9 -1446 6 -2989 9 -744 10 -1532 2 -2925 10 -825 6 -386 3 -2393 4 -4035 6 -768 9 -2040 6 -2832 10 -2975 7 -568 8 -19 4 -3984 4 -34 7 -3284 8 -3156 3 -1019 9 -2933 10 -49 4 -4077 2 -1355 3 -2545 2 -1996 10 -2248 3 -1017 5 -4089 5 -783 1 -1172 3 -40 5 -123 1 -2792 1 -2268 9 -2753 3 -313 2 -948 4 -2304 8 -879 9 -1166 6 -841 6 -3261 10 -2327 2 -3126 7 -2692 10 -3446 6 -1215 4 -3609 8 -3941 5 -1542 1 -955 9 -2203 10 -3357 6 -1738 5 -1091 1 -3621 6 -3578 2 -4064 1 -3219 5 -1585 7 -1567 6 -1242 10 -1678 3 -2076 9 -3229 6 -2482 1 -2001 5 -1968 2 -4086 8 -1474 8 -1595 7 -3949 8 -389 7 -518 7 -3353 5 -1771 5 -176 4 -3143 7 -1062 1 -3723 6 -2526 9 -6 3 -916 3 -945 7 -2457 6 -1225 7 -1501 5 -312 2 -2929 8 -669 7 -1425 6 -2928 5 -3538 6 -1444 9 -3465 8 -3437 2 -167 1 -3190 5 -2577 8 -306 8 -4033 2 -2328 5 -779 5 -1500 7 -2871 2 -1743 4 -2576 9 -1528 9 -1617 3 -2812 3 -2018 9 -3726 10 -1503 8 -3606 9 -3525 6 -484 6 -983 6 -1851 5 -2362 9 -2500 8 -2253 10 -1238 2 -859 8 -3411 2 -2654 10 -2875 10 -3981 6 -296 3 -3343 10 -2490 7 -596 5 -1242 4 -917 3 -685 9 -3037 8 -4062 8 -3358 4 -2020 4 -3051 1 -706 6 -3352 6 -3930 2 -2514 4 -2324 2 -1957 4 -1550 9 -3652 3 -766 6 -3272 9 -2208 8 -2373 7 -1449 1 -4076 3 -3757 6 -2161 2 -1279 7 -2691 5 -3233 8 -238 2 -73 7 -3186 7 -2862 5 -2711 3 -824 2 -4048 8 -3774 6 -3607 8 -1511 8 -4085 7 -1144 6 -2260 4 -35 9 -3432 7 -991 5 -1808 9 -2489 2 -809 5 -3806 8 -1757 7 -834 1 -990 9 -1455 9 -470 10 -563 10 -2445 5 -984 1 -2935 6 -746 4 -1113 5 -3351 5 -1597 7 -231 1 -3145 9 -2295 4 -2004 6 -2916 10 -3419 2 -438 1 -3711 6 -1064 5 -2075 4 -523 5 -261 4 -2574 1 -2443 7 -2812 2 -151 7 -3046 3 -3699 5 -1677 8 -1185 7 -683 6 -3300 10 -2144 7 -2628 8 -491 7 -4084 4 -2199 1 -1684 7 -336 1 -650 3 -4048 10 -64 2 -1623 7 -2228 7 -3790 5 -1977 2 -119 9 -2063 9 -1127 5 -2145 8 -1158 4 -1100 5 -3564 7 -865 2 -580 1 -3794 10 -1621 6 -599 9 -3026 8 -3182 1 -943 4 -3462 4 -3390 1 -1672 1 -454 3 -1599 1 -3866 1 -1925 10 -3973 3 -894 5 -2404 5 -3911 2 -1974 4 -2769 2 -295 1 -2131 4 -297 6 -37 3 -1655 10 -1706 8 -1380 9 -69 9 -1261 1 -452 5 -285 7 -2702 4 -2808 6 -2288 4 -168 4 -2535 4 -1179 8 -31 6 -985 6 -427 5 -1793 1 -3950 2 -4050 6 -473 4 -3749 10 -858 2 -2783 6 -2865 5 -72 2 -317 2 -83 5 -2835 10 -2970 8 -2445 4 -1907 7 -3755 7 -3220 5 -1212 9 -1866 8 -2923 7 -3425 2 -2185 9 -2268 10 -1101 1 -2508 4 -2412 6 -2231 1 -1086 10 -721 8 -536 5 -3132 9 -1583 9 -2922 4 -1733 2 -2003 8 -2151 6 -3964 4 -2653 1 -3929 6 -3772 2 -3549 8 -1585 7 -2414 9 -1398 9 -835 10 -2111 1 -1921 6 -1625 10 -4035 9 -2153 5 -2544 8 -1419 7 -837 1 -3674 10 -374 2 -783 2 -3037 1 -2860 7 -3361 9 -2160 6 -3610 5 -3669 1 -1462 9 -2179 2 -3097 8 -2400 8 -1703 2 -2742 9 -1445 10 -3308 2 -2933 3 -3671 6 -2688 1 -591 7 -2597 7 -2615 1 -341 1 -3323 10 -3673 9 -643 3 -1500 10 -2765 9 -53 3 -973 2 -2733 7 -4044 8 -3912 4 -910 5 -2219 4 -13 4 -59 3 -3989 8 -1989 6 -2264 1 -1981 4 -3312 7 -593 10 -481 2 -3357 1 -3309 4 -75 7 -3573 3 -3416 1 -922 4 -1912 9 -305 6 -1347 2 -240 10 -1340 8 -271 3 -1489 9 -4017 9 -2196 10 -489 9 -2553 9 -3552 3 -2211 4 -1707 2 -2026 6 -150 1 -2019 1 -3302 6 -1103 3 -2928 8 -1932 8 -2849 9 -3964 3 -3316 2 -827 3 -2539 6 -3906 8 -3010 2 -2978 7 -2238 10 -3688 1 -2970 4 -10 5 -3763 1 -3845 8 -1236 8 -3027 1 -1103 3 -2121 3 -1697 1 -3316 1 -3389 6 -3338 5 -3791 5 -3895 6 -1110 1 -3670 1 -53 9 -3283 1 -487 10 -1793 10 -1809 8 -1611 2 -201 8 -1001 1 -356 1 -2754 3 -771 5 -3793 10 -72 5 -2873 9 -4020 5 -2492 5 -2004 8 -760 10 -3015 9 -3595 2 -1 9 -3636 8 -369 4 -1022 5 -2738 1 -1189 3 -1904 7 -2150 3 -518 1 -2067 6 -1944 6 -1358 4 -2897 4 -3545 2 -220 8 -1115 1 -1379 3 -1382 5 -3269 6 -3510 8 -379 8 -857 9 -3631 2 -1696 3 -2309 9 -1116 4 -3279 5 -2990 8 -3186 6 -2864 5 -4065 9 -2127 1 -1925 3 -1841 3 -686 9 -1404 1 -2371 1 -3340 4 -2080 10 -237 5 -442 4 -171 8 -1959 3 -2504 1 -474 8 -1761 7 -3057 3 -2051 3 -1657 7 -2597 3 -3463 5 -2334 2 -2562 4 -2527 4 -389 3 -1929 4 -2744 7 -2109 9 -1918 9 -3515 4 -2994 6 -17 9 -2022 7 -2678 8 -666 2 -2000 1 -4083 10 -1281 5 -2689 7 -1294 7 -941 7 -727 5 -697 2 -1586 5 -445 9 -3879 4 -727 7 -939 7 -3630 10 -3746 4 -2241 10 -2441 4 -1151 2 -3696 9 -2023 2 -3502 7 -2415 4 -3238 8 -2079 10 -2813 7 -2555 8 -2569 6 -3950 3 -3784 3 -3371 10 -3265 3 -702 3 -605 4 -1510 3 -59 5 -2396 2 -3647 6 -3203 4 -2946 9 -308 9 -2141 6 -512 3 -2231 3 -556 8 -378 3 -96 9 -3837 10 -3878 3 -1685 8 -3786 2 -2974 2 -1466 5 -1173 5 -432 10 -697 5 -1109 6 -3939 2 -2166 5 -1616 2 -1415 5 -1878 10 -126 8 -251 1 -2404 6 -3118 7 -4083 9 -453 10 -2851 4 -3353 1 -3906 9 -3452 2 -1691 2 -2531 9 -1595 5 -1039 10 -3183 9 -315 9 -3580 10 -181 6 -3034 1 -3822 10 -2217 7 -1096 1 -749 4 -2775 3 -3722 3 -4013 8 -1745 6 -3560 10 -3450 6 -2212 10 -3302 5 -262 6 -680 9 -169 10 -664 2 -367 2 -576 1 -430 2 -996 1 -525 6 -2879 9 -3893 10 -2596 2 -3926 9 -3063 10 -2092 1 -3535 2 -1753 1 -1747 4 -1647 3 -1658 9 -1391 9 -317 1 -1265 3 -2018 1 -1849 9 -2974 7 -3643 8 -1490 10 -2818 8 -1796 3 -1410 8 -3495 3 -1088 1 -1461 1 -3197 3 -3555 2 -1569 2 -508 7 -494 9 -1578 10 -1367 7 -2708 4 -378 7 -3221 2 -809 2 -2226 5 -629 2 -1460 3 -2908 6 -388 3 -340 3 -3437 3 -2596 2 -3018 1 -2073 8 -1027 5 -242 5 -1226 2 -547 10 -1672 10 -3843 7 -2941 2 -2178 4 -3964 2 -1038 1 -2925 2 -2741 9 -3659 9 -1679 9 -3098 9 -3096 4 -2846 4 -262 10 -2609 10 -763 9 -909 5 -41 6 -3771 6 -3756 1 -57 4 -2278 6 -204 4 -3135 4 -1058 3 -2430 7 -968 5 -276 8 -1055 3 -1567 8 -2034 7 -268 1 -3712 1 -3462 4 -2625 9 -95 5 -2386 1 -249 9 -3086 3 -470 5 -2357 7 -4042 9 -3577 10 -1269 3 -2582 2 -2707 3 -3259 5 -734 9 -2531 2 -2497 5 -3346 7 -1471 6 -3556 8 -3881 7 -1671 5 -3761 1 -2011 3 -2994 9 -223 2 -2469 9 -2715 2 -3925 3 -917 10 -3700 5 -30 3 -648 8 -2711 8 -3955 10 -3434 9 -1332 7 -2426 1 -3265 7 -1384 10 -2200 2 -1769 6 -1083 6 -3487 4 -193 2 -74 5 -3120 10 -941 3 -1060 1 -1519 5 -3053 6 -1646 1 -3081 8 -661 5 -2178 9 -3945 8 -3594 4 -1176 9 -1021 5 -3169 2 -1224 6 -930 2 -680 5 -2877 6 -1515 2 -2755 1 -2377 4 -1256 6 -2793 3 -2184 7 -2921 8 -108 4 -303 3 -1066 1 -409 3 -2237 7 -1752 2 -488 10 -2851 8 -3101 6 -2210 9 -1068 4 -3060 6 -2083 5 -1977 6 -3496 2 -3604 2 -3007 6 -220 5 -2910 3 -1332 9 -3795 5 -3497 1 -1609 2 -3805 7 -2249 3 -2971 2 -1280 1 -1194 8 -2004 8 -294 2 -665 9 -239 9 -1689 8 -771 2 -3960 2 -572 5 -65 7 -2085 7 -853 1 -3924 9 -3364 9 -3237 6 -944 8 -3086 5 -1720 1 -3034 6 -2514 6 -602 5 -4044 4 -3773 3 -142 7 -1902 1 -3840 6 -1561 3 -1389 5 -3355 2 -94 10 -2979 9 -3224 10 -2206 6 -1175 9 -1217 10 -1768 9 -3629 10 -1207 2 -1773 2 -2941 1 -1801 6 -2920 9 -3735 6 -2572 5 -946 7 -1615 2 -3680 9 -3007 9 -1459 1 -252 9 -737 8 -2263 3 -2456 6 -4026 5 -1026 5 -2208 8 -1939 8 -2444 5 -3747 9 -1262 10 -640 1 -534 5 -3660 3 -478 2 -1703 3 -431 8 -1659 10 -68 5 -190 2 -1733 7 -110 10 -3610 1 -2266 5 -905 5 -1865 6 -2530 5 -2071 5 -3889 2 -2860 5 -1433 3 -3908 6 -702 4 -1659 4 -67 10 -3952 5 -559 3 -3869 8 -1320 2 -3978 10 -366 7 -444 10 -1468 3 -3896 3 -2353 3 -211 8 -1387 5 -2750 6 -393 10 -2379 6 -402 7 -3495 3 -2281 7 -1455 4 -1900 1 -4067 3 -1552 1 -363 4 -44 1 -2135 5 -3643 4 -2082 4 -3434 10 -724 9 -3372 2 -795 3 -1808 3 -1346 4 -3392 9 -2935 4 -1442 7 -3227 1 -2113 3 -3294 10 -866 1 -3571 10 -2258 4 -4040 6 -2070 4 -722 4 -2599 7 -3078 4 -3663 10 -279 8 -2693 10 -177 10 -1750 3 -1413 1 -307 10 -120 7 -3970 8 -3789 2 -3036 8 -2813 10 -1443 9 -1426 1 -3281 10 -3566 1 -3280 5 -3835 1 -2545 4 -1627 4 -1230 10 -2529 1 -2831 2 -4071 7 -975 1 -2329 2 -1016 6 -1995 4 -1584 2 -3436 8 -540 2 -3267 9 -211 2 -657 9 -3683 4 -3075 5 -4041 5 -498 3 -3189 1 -1738 7 -1929 5 -776 7 -1280 1 -3997 4 -2958 2 -1564 10 -2375 4 -3536 6 -2832 5 -3732 9 -1368 5 -428 7 -2208 8 -3588 2 -278 5 -1875 5 -261 2 -3375 9 -3267 9 -1845 7 -780 9 -3185 5 -2191 2 -1078 2 -2833 9 -3954 7 -3592 4 -877 6 -486 10 -420 10 -1564 3 -3518 4 -3898 7 -3228 1 -972 7 -2566 4 -3063 3 -3849 2 -477 4 -112 9 -36 8 -3299 9 -1266 3 -552 1 -1731 10 -944 6 -1160 4 -2160 5 -1836 1 -3098 5 -1702 6 -2884 3 -1573 10 -1829 4 -2323 5 -1910 4 -982 1 -3032 2 -2733 2 -339 4 -411 1 -2426 10 -1185 8 -28 2 -334 1 -1027 4 -3008 4 -2466 6 -144 7 -3098 8 -3518 4 -541 2 -872 8 -2515 2 -2123 9 -793 2 -2938 1 -1735 10 -854 3 -542 8 -1155 4 -3691 4 -3799 10 -835 3 -1495 8 -2996 1 -965 4 -2538 7 -138 5 -2403 4 -3501 6 -2046 5 -908 7 -1509 6 -3389 6 -3451 6 -230 3 -3665 9 -374 6 -3430 3 -1955 7 -1965 1 -4067 9 -3337 10 -1903 4 -61 6 -3001 8 -3400 9 -1552 4 -2890 6 -2014 3 -3231 9 -732 2 -1638 5 -3526 5 -3355 6 -806 8 -3530 9 -2698 9 -993 6 -2242 4 -3945 8 -2827 7 -1787 3 -2816 2 -3444 10 -1199 9 -964 10 -3934 8 -2028 6 -2205 10 -928 3 -72 1 -1366 7 -2770 10 -3320 3 -3434 9 -268 10 -1259 6 -3804 4 -2391 5 -2655 9 -261 5 -2951 1 -3333 2 -2649 2 -1383 10 -3011 6 -3529 10 -262 9 -2760 3 -2393 3 -992 3 -744 7 -2178 3 -3969 8 -3762 1 -946 3 -3910 1 -1213 8 -230 7 -3888 5 -1082 5 -2835 3 -3770 7 -2887 6 -1892 1 -2151 3 -2481 9 -2803 10 -563 5 -1125 9 -728 2 -3036 5 -2200 3 -94 10 -2274 8 -15 1 -430 5 -1112 9 -285 4 -1846 6 -2473 5 -1890 4 -1992 2 -340 1 -97 10 -2422 6 -1589 6 -1530 4 -1777 5 -104 2 -3022 9 -51 2 -2948 1 -2136 9 -1652 8 -1034 8 -817 8 -3157 8 -2614 3 -3735 10 -2900 10 -4014 6 -311 5 -4075 1 -3524 9 -2788 3 -2604 5 -2365 7 -3145 9 -874 9 -3140 6 -3587 6 -454 8 -1569 10 -690 10 -487 1 -1516 2 -3034 1 -3883 5 -2120 3 -3346 4 -3525 5 -2542 7 -3544 10 -2820 6 -3519 8 -96 4 -3883 7 -3115 2 -2645 8 -735 10 -1023 7 -3211 1 -3155 9 -1157 8 -2861 6 -1951 6 -836 4 -705 7 -4090 1 -1653 9 -3096 9 -463 8 -2961 10 -771 1 -1297 6 -3135 4 -865 7 -3926 8 -2438 7 -0 5 -1622 2 -1711 7 -3380 9 -967 6 -1702 5 -3013 5 -3885 4 -3042 5 -3200 8 -627 2 -2182 6 -586 8 -2083 10 -3043 2 -1938 8 -2783 10 -1891 1 -2245 8 -4068 7 -1064 3 -1700 4 -1970 4 -1818 3 -3096 6 -969 7 -550 10 -53 4 -1766 1 -2308 9 -534 2 -3906 8 -1279 5 -3918 4 -432 6 -936 5 -240 2 -2454 5 -2711 4 -1968 5 -3954 1 -2262 9 -299 5 -3757 8 -455 2 -3607 5 -3765 8 -3919 10 -2766 2 -2870 8 -845 7 -3687 4 -1119 8 -3413 8 -3969 5 -3192 9 -2188 5 -1756 2 -2089 7 -2293 8 -2774 5 -2074 2 -533 2 -3081 2 -2759 9 -467 5 -1546 6 -3195 8 -48 2 -2498 6 -1850 4 -1870 2 -3295 6 -1997 5 -3000 9 -1168 9 -904 3 -263 3 -1497 8 -227 10 -3893 3 -2863 7 -1361 9 -2345 3 -1367 3 -3590 2 -1776 1 -379 1 -221 7 -3299 1 -573 3 -48 2 -2177 6 -1485 7 -1889 10 -1443 5 -313 3 -2093 9 -1254 4 -3912 1 -809 4 -940 10 -1804 8 -2271 3 -1416 4 -1500 5 -1392 2 -194 3 -2746 9 -2724 6 -2185 9 -66 5 -1306 4 -2646 5 -922 3 -123 9 -3413 5 -2813 9 -1778 5 -1907 8 -564 8 -2539 9 -869 2 -1251 4 -3291 8 -2513 7 -3115 9 -1125 2 -2143 5 -242 7 -83 5 -3453 8 -85 1 -2734 2 -512 6 -2486 9 -3014 1 -477 3 -2338 2 -3110 5 -1220 1 -581 8 -1492 9 -3588 10 -3617 8 -472 6 -60 7 -2922 4 -2516 5 -724 3 -215 3 -90 8 -2686 5 -3807 5 -3392 1 -2021 9 -19 6 -1037 9 -2861 4 -3148 2 -432 4 -1173 8 -3121 5 -2566 6 -1968 10 -2094 2 -604 4 -1384 1 -169 9 -302 7 -254 4 -2904 5 -145 2 -4 2 -995 4 -3739 1 -3665 5 -1737 9 -1416 6 -174 5 -871 4 -667 1 -4011 5 -896 2 -2247 8 -2252 3 -2656 2 -2104 1 -169 8 -327 2 -1791 10 -1561 8 -3759 4 -743 9 -1125 10 -3357 9 -3114 9 -2583 7 -725 10 -1940 7 -3874 8 -1521 2 -1673 9 -753 4 -3418 5 -2984 2 -1502 7 -3818 3 -2957 5 -1209 1 -2764 9 -3916 4 -268 9 -1777 2 -1827 4 -3680 9 -3945 7 -533 5 -2775 8 -2880 9 -2636 8 -2401 3 -2517 2 -3195 9 -2959 8 -355 8 -703 5 -2513 8 -1113 6 -881 3 -505 3 -3941 8 -1304 10 -2610 2 -3170 7 -112 6 -1002 7 -1582 7 -853 8 -135 9 -2418 9 -149 4 -3195 1 -3857 2 -701 10 -3513 4 -3004 6 -3643 4 -3163 5 -1100 2 -810 10 -3498 10 -1793 8 -3248 4 -3043 2 -637 9 -1930 8 -1924 9 -141 1 -880 8 -1345 8 -604 4 -2442 8 -879 6 -2970 8 -3477 4 -269 6 -719 3 -2915 2 -1144 10 -3399 7 -3813 9 -915 3 -2708 9 -1565 1 -3066 7 -2478 4 -3048 7 -1340 4 -2150 2 -1241 6 -1247 2 -3721 2 -2853 8 -613 10 -642 3 -2411 9 -1623 6 -1522 9 -3000 5 -235 2 -98 6 -538 8 -1609 10 -2392 8 -1724 10 -178 9 -1825 10 -787 6 -542 5 -3492 6 -1480 6 -1532 8 -1512 1 -2820 6 -3357 6 -105 7 -2710 5 -3553 4 -925 9 -2745 3 -3180 5 -750 2 -3860 5 -3783 2 -1058 8 -3367 2 -1284 1 -1993 7 -4040 9 -3683 6 -116 5 -1362 1 -2484 6 -199 3 -1447 10 -1710 5 -2240 1 -470 5 -2704 1 -3296 1 -297 2 -1007 2 -1796 3 -842 3 -1976 10 -3880 9 -2491 8 -1334 10 -2149 1 -1534 6 -2323 9 -1435 2 -1619 1 -3436 5 -2073 5 -2741 7 -108 3 -1309 7 -38 3 -3474 10 -495 1 -1232 6 -2524 2 -648 7 -3154 8 -1669 10 -1009 4 -999 10 -2451 10 -2534 2 -216 7 -2487 8 -3495 6 -2558 6 -3902 7 -2454 3 -2625 2 -2715 3 -3779 9 -2179 8 -3318 4 -1567 9 -508 8 -1481 9 -3080 6 -2339 7 -836 5 -22 8 -3879 7 -3326 9 -2984 2 -2428 1 -151 1 -1614 2 -1930 9 -2412 3 -1842 4 -3349 1 -1232 2 -3240 8 -4036 10 -2171 8 -3873 10 -212 9 -2231 10 -468 2 -2121 10 -2691 1 -3477 6 -3542 8 -634 8 -3735 9 -198 9 -2641 1 -128 4 -2774 1 -263 3 -3531 5 -782 4 -2886 3 -1207 4 -2718 3 -394 3 -2200 7 -857 3 -2340 9 -3493 1 -1822 1 -2077 7 -295 4 -2825 6 -505 7 -3461 7 -670 9 -1836 2 -573 10 -182 5 -391 3 -982 2 -2516 2 -2574 5 -1203 4 -3513 6 -3486 3 -2267 4 -3695 9 -2363 1 -2244 8 -3503 7 -3423 3 -3999 3 -2658 7 -3913 6 -2541 3 -3290 5 -1114 6 -3576 4 -3647 4 -1646 3 -2216 2 -2457 9 -3703 5 -2746 5 -3376 3 -659 7 -2114 10 -1343 9 -2086 4 -3319 3 -2971 6 -4005 4 -1375 6 -1170 6 -3319 2 -3937 4 -2050 4 -662 2 -854 2 -3402 4 -451 10 -3349 3 -2126 3 -143 10 -2287 2 -2887 3 -593 1 -1032 1 -1656 2 -594 7 -1989 1 -1128 10 -3319 7 -1998 5 -3071 7 -2069 10 -1554 3 -1792 4 -115 7 -2918 9 -2782 4 -3855 8 -345 7 -2797 2 -2905 4 -3841 5 -3733 2 -255 6 -3498 4 -1095 3 -3065 5 -3957 2 -2924 3 -823 4 -650 10 -2729 2 -3253 3 -1513 9 -2839 6 -1538 6 -3243 7 -1154 3 -801 10 -2688 10 -762 4 -600 7 -2105 7 -2626 6 -128 1 -1377 1 -2296 9 -2118 10 -3178 7 -3396 7 -3852 4 -666 5 -1785 7 -1105 3 -3982 7 -1368 10 -631 8 -1472 5 -1935 9 -754 1 -2291 6 -2324 9 -804 4 -3661 7 -3148 9 -1855 10 -1930 6 -3434 2 -3554 6 -3591 10 -2791 6 -2845 2 -2105 3 -2015 5 -3662 1 -219 4 -116 6 -852 3 -957 7 -2338 7 -3987 5 -2602 6 -3737 4 -3056 4 -2303 5 -3697 10 -2528 6 -2937 3 -3162 9 -1836 3 -3827 8 -1876 8 -3800 7 -1712 5 -1305 5 -3222 1 -209 8 -1320 6 -981 3 -3637 5 -1975 9 -647 1 -792 7 -1507 2 -3234 2 -1938 10 -1483 4 -3101 1 -3970 4 -1582 7 -3444 1 -2949 3 -1013 7 -1190 5 -1148 1 -1817 1 -3502 3 -323 10 -3436 8 -1119 1 -3362 2 -2291 7 -1896 8 -2170 10 -1342 6 -454 6 -2343 9 -963 9 -1075 5 -1703 2 -478 4 -4009 10 -593 5 -2653 6 -2372 7 -3176 7 -1526 3 -4082 3 -2465 6 -748 10 -880 7 -3472 7 -1581 7 -2809 10 -1236 1 -3494 3 -4079 4 -3407 2 -3818 2 -2293 5 -3369 3 -2813 2 -1801 6 -59 10 -198 1 -3992 9 -2334 6 -236 1 -244 6 -3316 5 -2990 6 -3544 9 -479 3 -833 6 -2926 6 -245 5 -2019 4 -2979 7 -2851 5 -1305 10 -53 6 -2415 9 -1931 5 -3764 2 -2032 1 -2663 2 -1748 8 -947 6 -2500 2 -2854 8 -418 4 -3297 3 -513 5 -2257 10 -4082 1 -1 8 -1076 7 -2937 7 -1751 8 -3295 1 -3346 4 -1350 4 -495 10 -2518 9 -398 9 -3429 3 -3256 4 -3573 7 -305 1 -3082 7 -1754 9 -1465 5 -2276 2 -3530 5 -2678 8 -1407 5 -2504 9 -1186 6 -3854 2 -2879 3 -1378 10 -871 1 -2331 8 -3056 3 -2363 9 -1795 5 -189 2 -3143 5 -2159 4 -2537 8 -2757 6 -348 5 -2527 9 -1724 1 -3451 8 -2327 7 -584 6 -342 9 -2580 6 -2925 4 -641 6 -4050 10 -1828 1 -3155 8 -181 8 -178 10 -1668 1 -3853 1 -2350 3 -65 4 -1608 3 -2429 8 -118 10 -1882 3 -3825 1 -855 1 -2590 2 -1762 6 -893 3 -2457 3 -1224 10 -3890 10 -114 1 -1276 5 -2060 8 -3195 4 -3085 1 -2277 7 -861 10 -1500 7 -2524 7 -1289 10 -3868 6 -1205 4 -1915 2 -2565 9 -2526 6 -288 8 -2945 3 -1622 5 -1458 5 -2813 3 -3097 4 -2671 9 -2965 6 -2969 5 -3544 4 -786 4 -2405 5 -1560 1 -1605 2 -1240 7 -3215 10 -237 5 -3595 10 -3233 5 -443 8 -2368 6 -345 8 -2747 6 -1713 3 -680 9 -815 8 -2224 9 -2214 2 -623 10 -2742 6 -1951 5 -2759 7 -130 9 -2820 4 -2879 5 -1896 8 -1725 3 -4080 8 -362 2 -2954 1 -1689 3 -2461 4 -3068 8 -156 7 -237 1 -2958 7 -2694 2 -1914 6 -2391 3 -3577 6 -2343 8 -1681 4 -2299 3 -2720 2 -2622 6 -3710 2 -2106 1 -3216 10 -3716 3 -524 1 -123 6 -328 8 -3297 10 -527 9 -2020 7 -2610 10 -3599 8 -2014 3 -1796 3 -947 9 -1644 8 -3298 1 -203 10 -1728 1 -1879 9 -2273 10 -2632 6 -2498 1 -3808 2 -3092 2 -2795 2 -460 9 -3496 8 -568 10 -2417 7 -230 3 -741 4 -2318 5 -2703 7 -1276 6 -1134 2 -2665 4 -3746 2 -1546 9 -1687 4 -2365 2 -2681 1 -3724 7 -483 5 -3656 3 -3289 8 -1582 4 -478 7 -60 7 -3636 9 -2142 3 -2531 8 -3973 5 -2122 5 -272 5 -1378 5 -634 9 -1973 5 -2293 8 -173 10 -3989 1 -3287 6 -984 6 -686 10 -664 3 -3921 9 -2940 9 -216 1 -902 1 -348 8 -1656 4 -709 2 -1518 8 -1756 1 -3267 6 -1794 7 -3961 7 -1596 5 -1725 9 -2792 5 -10 1 -2822 7 -3586 2 -3986 7 -3343 5 -2071 8 -2378 9 -2608 7 -2873 7 -589 5 -2954 2 -2562 5 -137 8 -619 1 -2262 10 -406 10 -2433 4 -3242 7 -3350 5 -1676 2 -2181 3 -2854 5 -1424 8 -1790 6 -1862 4 -56 1 -1118 9 -417 1 -2873 3 -3482 7 -1108 7 -3103 8 -2080 4 -3055 1 -864 3 -3334 6 -2351 5 -1335 9 -2175 5 -1751 1 -864 10 -1238 10 -3039 6 -3767 5 -1334 9 -3747 5 -271 1 -3364 3 -3302 8 -2454 5 -3737 1 -3664 2 -1568 2 -3853 6 -3464 1 -3464 2 -781 8 -1655 9 -293 5 -2728 6 -2496 3 -3812 2 -158 3 -200 5 -1915 7 -3365 8 -1803 10 -2644 9 -585 5 -19 6 -1802 5 -3980 8 -3278 2 -2766 1 -3032 7 -281 10 -1232 4 -965 1 -1054 8 -312 7 -2148 10 -2197 2 -3863 1 -4036 4 -1551 3 -2651 4 -1281 6 -4052 8 -2956 2 -156 7 -3504 4 -2777 3 -1258 9 -2271 8 -2162 7 -3594 2 -1735 8 -4085 7 -2516 7 -1228 8 -3534 6 -1860 9 -2620 9 -3304 2 -2466 8 -976 10 -969 4 -131 7 -1138 4 -2071 3 -3482 4 -567 3 -1497 5 -1373 10 -3594 7 -2551 9 -1982 7 -674 2 -1054 2 -1821 2 -1390 8 -2456 4 -3786 5 -2738 6 -3436 10 -2349 5 -382 5 -3676 6 -3791 4 -3447 5 -4019 7 -3866 10 -350 10 -3081 7 -3204 10 -3545 9 -332 7 -379 6 -1295 4 -1439 8 -1693 3 -3008 2 -1867 5 -2420 1 -470 8 -1832 3 -619 4 -1928 4 -3900 7 -1544 10 -1451 3 -3721 7 -1719 3 -112 8 -601 1 -3971 7 -2247 8 -1774 9 -2851 7 -3945 6 -3478 2 -2522 7 -3630 9 -303 4 -2171 1 -2024 2 -807 6 -474 4 -990 3 -85 10 -3668 4 -3823 9 -2731 9 -2748 7 -2283 10 -903 8 -1807 10 -1521 10 -3026 6 -2902 10 -219 10 -461 4 -166 8 -1065 4 -2325 3 -2922 3 -2572 7 -3034 4 -3694 10 -3552 7 -3554 4 -3189 10 -1805 2 -3953 9 -4033 7 -2154 6 -772 9 -7 1 -2616 10 -1200 9 -1237 1 -388 7 -2052 2 -2777 9 -3131 9 -97 1 -1592 2 -1940 1 -479 1 -2770 3 -970 3 -1553 7 -1531 3 -855 4 -2157 2 -3786 2 -3221 7 -2133 8 -1558 4 -2759 6 -2627 10 -603 1 -3477 5 -1714 2 -1945 5 -1936 10 -471 7 -363 9 -1169 7 -1871 5 -2078 3 -1201 3 -1098 7 -2291 4 -604 4 -3558 8 -472 8 -3770 3 -3595 5 -2432 6 -2848 2 -2941 2 -1473 2 -1149 5 -3522 8 -3365 9 -1269 10 -556 3 -2778 9 -955 3 -376 7 -160 1 -2626 2 -4069 7 -196 10 -805 1 -2185 5 -3577 8 -737 4 -230 2 -3555 4 -3601 3 -356 4 -952 2 -417 8 -838 3 -65 3 -3658 8 -3607 4 -3113 6 -984 1 -1346 10 -4080 7 -343 2 -838 6 -554 3 -2613 7 -2947 2 -3981 8 -2537 10 -2894 1 -3578 9 -3568 1 -2281 8 -3941 8 -1258 6 -1634 5 -3416 3 -2580 2 -4076 3 -3048 8 -1268 1 -236 4 -3117 9 -1713 1 -1325 5 -3635 1 -1436 8 -2985 10 -862 6 -2911 6 -1297 10 -2873 1 -2195 6 -1067 3 -2452 8 -2752 3 -198 9 -835 4 -311 1 -592 8 -3676 3 -1032 9 -1838 10 -1533 7 -2586 8 -2980 1 -2646 2 -4033 3 -4062 9 -2260 1 -964 6 -1067 5 -1824 5 -1485 9 -1171 10 -4033 3 -695 6 -2703 10 -4010 9 -3927 5 -2241 9 -1109 10 -3056 10 -3626 10 -61 9 -1710 10 -2030 7 -3077 3 -3519 7 -963 6 -2565 1 -1213 1 -1956 7 -3302 2 -2640 1 -734 4 -278 9 -1605 3 -3712 9 -79 10 -2378 4 -3653 1 -3507 6 -2289 1 -3629 6 -3080 8 -1135 5 -2556 9 -3448 3 -3102 2 -2958 1 -2878 9 -1598 4 -844 7 -3508 4 -2452 7 -305 5 -249 3 -337 8 -1641 6 -1915 9 -2099 8 -1124 5 -508 6 -3461 4 -2096 10 -607 7 -79 10 -1347 8 -2840 5 -2491 6 -2309 9 -3572 3 -3204 7 -1094 9 -2553 1 -2535 6 -2120 6 -2207 1 -1486 10 -1682 2 -2187 5 -3376 5 -1829 5 -1204 2 -4088 10 -3167 7 -2291 4 -921 3 -1800 10 -2773 4 -3553 8 -536 6 -1550 7 -1631 10 -3619 1 -809 3 -2196 6 -2749 3 -940 2 -582 8 -3589 1 -695 8 -3115 3 -2531 8 -1852 9 -2842 7 -295 6 -3658 5 -1991 1 -1042 9 -2772 1 -2378 2 -2002 9 -825 6 -2908 2 -3467 3 -410 6 -3261 7 -638 1 -4001 5 -316 4 -712 4 -3943 5 -1604 1 -2972 1 -385 4 -1485 1 -174 1 -3712 8 -2121 1 -2263 2 -3527 6 -790 2 -3648 5 -1447 4 -1069 1 -472 4 -966 9 -3321 4 -2305 8 -313 1 -3054 8 -2207 10 -623 3 -2843 1 -2223 3 -1297 5 -392 1 -2024 4 -760 3 -479 4 -2098 8 -3766 1 -3740 1 -793 10 -875 5 -734 3 -2361 9 -1495 1 -2583 9 -263 3 -3311 5 -3924 4 -767 2 -1096 8 -3657 5 -1454 5 -1506 1 -480 6 -908 10 -1903 4 -70 6 -1783 3 -3006 2 -2745 1 -2778 2 -2075 1 -2682 5 -3534 5 -1141 1 -3527 8 -818 1 -3067 9 -3208 2 -3677 4 -2850 8 -3719 7 -449 5 -3184 7 -1759 3 -3547 9 -1083 5 -3088 10 -2089 10 -1204 4 -1215 6 -700 3 -2188 3 -3500 4 -3283 2 -888 8 -971 3 -2164 10 -1459 4 -2657 10 -1880 5 -72 5 -3540 6 -2516 7 -3183 2 -3925 4 -187 10 -1757 4 -496 5 -1044 7 -1674 8 -1910 5 -898 10 -436 3 -2711 10 -3553 7 -2242 7 -4093 5 -314 7 -1779 1 -717 6 -2834 4 -53 5 -3642 9 -814 3 -2008 5 -3764 8 -1903 8 -3104 8 -2883 3 -1923 2 -668 3 -3264 7 -2084 9 -400 7 -37 5 -1332 8 -2382 1 -368 1 -2821 6 -308 10 -2080 4 -549 10 -3131 9 -3545 7 -809 1 -1002 6 -3954 2 -1143 1 -2762 10 -1695 1 -2516 6 -3886 2 -2544 4 -3984 3 -3258 10 -1750 6 -3175 7 -1876 9 -1631 9 -2125 6 -1821 10 -1693 3 -2199 8 -1857 8 -3561 9 -4041 6 -275 7 -3431 9 -1890 4 -3510 9 -1703 2 -2084 6 -1740 3 -584 2 -2044 6 -3370 8 -2047 4 -796 1 -3790 2 -2454 1 -751 1 -2693 9 -2581 9 -1504 9 -1132 3 -3271 8 -958 2 -1435 6 -3812 1 -2015 2 -457 3 -794 8 -3842 10 -3216 3 -2042 9 -1434 6 -1239 2 -2127 6 -1875 3 -944 6 -3891 4 -1378 8 -3079 4 -18 2 -3976 3 -1541 5 -3214 5 -3051 7 -3073 2 -1602 2 -3425 4 -1351 8 -1690 2 -1897 3 -1664 9 -3108 10 -3148 2 -1947 9 -1882 8 -2122 10 -637 4 -2600 9 -33 10 -740 6 -4052 2 -3853 2 -2945 10 -3184 10 -1138 7 -891 6 -4046 10 -1143 9 -2222 1 -3773 4 -1202 5 -2821 10 -2819 5 -3248 10 -1468 1 -1003 9 -2874 4 -2326 3 -3856 4 -2754 9 -1046 10 -158 8 -987 6 -498 10 -1450 9 -2469 6 -893 2 -242 5 -965 8 -1404 4 -1237 10 -732 5 -1851 10 -2109 7 -59 9 -188 7 -2796 6 -1013 1 -487 3 -2324 5 -3743 8 -892 7 -4064 7 -4045 3 -3782 10 -1446 9 -2252 3 -3909 1 -2342 5 -3848 4 -2927 4 -1566 9 -2926 10 -1353 3 -2182 6 -3307 1 -3550 9 -2691 10 -2161 5 -18 8 -846 10 -3044 2 -3781 10 -3874 5 -1806 3 -3004 7 -3706 4 -1410 5 -385 3 -2192 3 -2394 5 -1136 4 -3317 4 -2178 10 -4041 5 -2993 8 -4040 9 -1019 9 -2970 6 -562 1 -32 5 -2279 10 -526 1 -2837 1 -2567 2 -3052 6 -1494 9 -4057 7 -746 8 -794 6 -2297 8 -1915 3 -2059 2 -765 3 -1307 5 -1127 1 -152 6 -2790 6 -3288 4 -666 6 -1417 4 -4066 10 -435 7 -815 8 -3398 5 -242 7 -220 7 -1099 3 -3662 1 -4005 5 -797 10 -1097 1 -2316 1 -491 5 -3261 6 -2273 7 -2782 9 -1929 3 -1046 9 -330 2 -4046 1 -3587 4 -3946 4 -3234 6 -138 1 -3011 3 -1700 6 -2820 6 -2043 1 -3290 6 -34 7 -1907 10 -1689 5 -2015 3 -3168 9 -1296 5 -485 5 -2642 9 -912 3 -3574 5 -2187 6 -294 8 -1082 5 -2047 2 -2364 8 -3798 2 -2315 10 -636 4 -3260 7 -3611 1 -83 6 -2147 6 -1444 1 -3128 4 -2620 8 -1805 8 -432 5 -1134 3 -3839 6 -3958 6 -859 1 -3553 10 -1860 10 -266 3 -3831 9 -489 8 -3482 5 -1726 5 -2778 10 -3276 1 -588 4 -1106 6 -3010 10 -1904 10 -2911 1 -1270 5 -1933 7 -1668 3 -2371 2 -1368 2 -1935 2 -754 6 -948 7 -4086 9 -1736 6 -2621 6 -3620 5 -3147 9 -2652 7 -3169 6 -1000 8 -3131 10 -3956 10 -3640 2 -1964 8 -2045 5 -3052 7 -360 5 -420 7 -3965 4 -2531 9 -1693 4 -1793 6 -3131 4 -3668 8 -3973 2 -1992 1 -858 6 -2315 3 -2248 4 -3981 5 -212 7 -2446 6 -1943 2 -2335 3 -1932 6 -2896 9 -360 7 -4019 6 -3330 10 -1234 6 -1792 7 -3785 5 -735 10 -343 9 -1244 9 -32 8 -2145 9 -2048 3 -2638 6 -2376 3 -1678 6 -1517 1 -3968 5 -1278 4 -2850 8 -384 5 -3305 4 -1696 8 -231 9 -3208 9 -2345 9 -3380 8 -105 8 -2586 4 -909 7 -762 1 -2857 6 -3035 6 -1202 7 -8 8 -1402 1 -1382 9 -3977 4 -860 1 -1392 10 -2480 10 -1663 2 -218 2 -2324 8 -3023 2 -3539 5 -1883 10 -3576 9 -258 10 -793 9 -2534 4 -967 10 -2851 4 -732 3 -3340 10 -139 7 -1777 4 -4067 4 -1892 4 -1651 6 -1054 9 -1563 5 -349 3 -1987 6 -4087 7 -1945 5 -1990 4 -1095 10 -2507 2 -2146 6 -2975 4 -2503 9 -4011 2 -2523 1 -3597 6 -2361 6 -2883 7 -4058 5 -2580 5 -672 5 -2903 3 -3705 7 -3364 7 -498 3 -3776 6 -1210 9 -260 6 -48 10 -1825 2 -3355 6 -2966 10 -958 10 -2739 3 -571 8 -2246 5 -1647 8 -107 4 -2268 7 -3306 7 -2320 3 -3845 7 -4052 7 -3121 5 -3152 8 -1457 9 -1899 4 -2679 3 -2272 4 -761 1 -1511 9 -3331 9 -2836 3 -1161 8 -1409 1 -151 2 -4039 5 -2306 10 -3518 1 -2878 1 -3216 1 -2136 3 -3066 1 -2002 8 -1853 7 -2803 8 -3575 3 -2766 10 -140 2 -2380 7 -1638 7 -954 7 -1200 8 -2932 2 -1346 5 -1628 9 -1527 2 -2214 6 -0 10 -3101 6 -3820 1 -2960 8 -3712 2 -3644 2 -186 2 -4003 2 -1005 7 -1048 10 -47 3 -1204 5 -1305 7 -311 7 -3553 5 -2177 9 -2134 4 -2156 6 -3213 6 -1712 3 -4077 4 -1002 5 -3338 9 -3790 3 -210 3 -1744 8 -2771 6 -3089 9 -2018 6 -3079 2 -539 6 -62 1 -287 7 -1220 7 -2632 9 -806 2 -2889 10 -2385 10 -1006 8 -1598 7 -672 10 -654 10 -2968 5 -2954 3 -2647 4 -1433 9 -869 9 -2516 9 -2641 4 -1410 1 -2263 4 -1278 2 -3487 1 -4044 8 -3472 8 -3228 4 -2269 6 -4083 10 -3930 9 -1976 1 -1729 3 -2474 1 -1162 6 -3393 2 -3206 10 -3661 6 -370 7 -1080 3 -169 1 -981 9 -2977 7 -1833 2 -3547 4 -1495 9 -1016 8 -2064 7 -2971 6 -3397 8 -348 8 -627 5 -3026 5 -3692 6 -3596 3 -1235 1 -651 2 -2084 7 -2432 5 -136 4 -4040 8 -820 8 -1265 9 -3425 3 -328 2 -340 1 -3161 7 -3849 5 -3448 2 -3869 8 -2734 1 -1776 7 -1113 2 -3366 9 -2128 1 -2368 5 -1645 5 -468 2 -458 1 -214 4 -1181 2 -3903 10 -343 5 -1483 1 -2450 10 -3092 5 -221 10 -3226 7 -4064 10 -3592 8 -1327 8 -758 6 -2094 7 -1110 5 -2272 8 -722 5 -3483 9 -384 6 -395 5 -1219 2 -2729 6 -2917 7 -2913 6 -2956 10 -1940 1 -4057 2 -1357 10 -712 6 -2062 4 -1233 9 -3567 1 -81 6 -346 5 -3885 8 -3340 7 -4041 2 -2606 5 -3324 2 -171 3 -3975 1 -816 6 -1556 9 -1761 3 -1811 7 -4042 8 -3559 5 -3349 5 -2184 10 -1882 1 -2481 6 -148 5 -367 2 -34 4 -813 5 -1284 3 -668 10 -3340 2 -2051 7 -1805 2 -2500 8 -3417 4 -1497 2 -2223 8 -1964 1 -3321 3 -1006 9 -1753 4 -2029 9 -3651 1 -746 8 -2755 6 -119 4 -2076 5 -1177 4 -2112 5 -2475 9 -933 6 -2400 8 -1364 3 -1998 1 -412 4 -2651 8 -2481 7 -772 4 -557 2 -3258 9 -531 1 -3685 9 -793 8 -1235 8 -3974 10 -987 2 -3499 7 -625 3 -2313 6 -3913 2 -2427 5 -3794 2 -1380 7 -2446 5 -3385 9 -133 2 -24 4 -1239 6 -1955 2 -1911 1 -150 3 -4015 2 -3292 6 -1926 3 -243 3 -3738 6 -3500 4 -687 9 -1642 9 -767 5 -1266 6 -3112 6 -3385 10 -3271 1 -3338 1 -2876 5 -4054 10 -2204 3 -1925 8 -3738 8 -192 1 -1907 5 -851 8 -3311 6 -107 5 -3225 10 -3890 5 -363 3 -2629 9 -2460 3 -399 5 -3622 5 -3672 7 -620 3 -1437 5 -3439 8 -2697 3 -3867 4 -995 1 -2512 9 -1818 1 -2488 10 -705 8 -2226 3 -334 4 -2080 3 -3440 3 -874 8 -1353 10 -2539 9 -3699 8 -627 6 -2928 5 -2244 1 -3730 9 -135 2 -3463 4 -2835 5 -1197 6 -3428 8 -1321 9 -718 6 -3813 10 -3435 4 -2379 7 -3080 2 -3083 6 -3480 1 -1848 10 -1903 7 -2182 7 -2115 7 -643 1 -2700 6 -3730 9 -2113 3 -511 3 -2279 1 -3577 6 -1012 9 -444 1 -1395 7 -232 6 -553 8 -3936 6 -3674 10 -779 7 -566 1 -1341 3 -1673 8 -1165 4 -2998 10 -658 10 -2941 6 -3713 10 -250 10 -3088 8 -1136 1 -1677 9 -2568 4 -825 6 -1363 7 -3803 10 -2531 4 -3493 6 -1263 3 -2768 1 -3134 6 -3503 5 -2271 4 -909 8 -2723 7 -3863 10 -850 1 -3385 2 -3789 3 -115 9 -3542 4 -1523 9 -2715 5 -1936 4 -541 10 -1673 1 -1365 4 -3649 5 -862 4 -1903 1 -3088 2 -2062 8 -2391 5 -2111 5 -2398 3 -677 3 -2665 1 -2741 9 -1309 1 -1217 8 -1124 3 -2501 2 -3134 3 -2086 4 -2115 3 -2170 5 -3180 6 -1963 8 -2031 3 -1489 5 -2129 2 -3046 7 -1148 10 -1152 3 -1231 1 -478 9 -904 10 -760 6 -1973 10 -271 1 -1450 9 -1904 2 -4028 3 -3952 4 -4031 2 -998 6 -3397 6 -1798 2 -1243 9 -669 3 -1103 8 -2561 9 -1336 2 -1898 10 -3757 6 -71 8 -2191 3 -955 1 -1181 10 -1097 2 -607 6 -3789 8 -2397 3 -3731 7 -590 10 -3673 1 -3001 2 -3464 6 -2933 5 -1798 7 -864 6 -3376 7 -2628 9 -2012 8 -1778 9 -4004 10 -2607 1 -2224 8 -3822 6 -1640 6 -962 1 -1156 10 -2197 2 -2335 6 -3502 3 -3850 1 -94 4 -2836 1 -3545 2 -3568 2 -147 5 -3812 9 -2883 2 -158 3 -764 8 -382 2 -3227 10 -1902 9 -693 1 -2808 6 -2778 3 -3224 7 -748 7 -3291 10 -1098 10 -202 10 -3440 3 -1715 5 -1676 5 -544 2 -2446 2 -2419 4 -2003 10 -345 5 -2569 8 -3645 9 -3442 3 -3336 5 -2466 8 -3894 9 -618 6 -2501 5 -1284 7 -2334 9 -3551 4 -222 4 -1225 7 -3703 3 -169 1 -1279 7 -1323 4 -3785 2 -1942 3 -2301 10 -1616 8 -2266 8 -3885 2 -1626 1 -552 7 -1040 9 -3796 1 -1145 2 -3568 3 -2973 1 -2361 4 -1690 5 -3478 9 -2362 1 -2586 7 -2335 6 -552 5 -1042 7 -998 7 -2295 4 -3080 3 -3340 7 -539 10 -445 7 -2453 3 -3289 10 -2697 10 -1077 5 -452 3 -3538 3 -2971 7 -2351 8 -648 4 -2591 9 -1177 6 -45 7 -120 3 -662 2 -744 1 -2748 7 -2016 5 -3566 4 -3063 2 -935 3 -2375 8 -3382 9 -3709 3 -3150 1 -2717 7 -667 5 -1362 2 -3286 6 -2738 5 -298 4 -324 8 -1649 10 -2800 8 -1823 6 -206 3 -2642 1 -710 10 -2488 5 -2058 8 -2183 5 -3690 1 -2807 3 -3797 4 -3972 10 -1086 5 -2752 2 -1000 7 -2083 8 -2655 2 -1328 5 -251 9 -582 5 -216 6 -2669 6 -1021 7 -1870 5 -2365 7 -1388 4 -236 2 -146 2 -3013 10 -1503 7 -3728 8 -1029 1 -3445 3 -3721 3 -629 10 -2488 5 -2878 10 -322 1 -845 8 -915 6 -3599 10 -315 4 -346 5 -3467 2 -1438 2 -3752 6 -2755 4 -2422 1 -3026 4 -170 4 -1402 1 -2791 8 -143 3 -364 9 -2751 1 -3433 8 -1617 10 -2479 1 -1790 4 -1386 3 -496 6 -2842 9 -381 9 -1309 2 -2860 6 -3872 4 -3481 3 -4042 1 -2633 2 -568 7 -3264 1 -1935 5 -1879 5 -3712 8 -3549 7 -1303 3 -3758 7 -557 8 -528 1 -2361 4 -3533 7 -1118 2 -1233 10 -1692 10 -565 10 -112 9 -2924 4 -306 9 -1062 2 -771 2 -422 4 -3627 6 -3759 7 -98 2 -3618 1 -2167 1 -3920 2 -3831 10 -3358 2 -285 8 -663 7 -2211 6 -1940 10 -2724 10 -2462 5 -3231 7 -4059 1 -655 4 -3209 4 -1967 2 -16 2 -2907 6 -1247 2 -423 9 -2550 8 -2504 8 -3717 6 -638 10 -3612 9 -251 8 -1957 2 -2920 8 -1126 2 -4066 6 -3226 9 -367 2 -121 9 -1582 8 -1083 2 -523 9 -2216 7 -365 2 -1006 3 -200 7 -2057 6 -2091 1 -1604 10 -468 9 -1648 10 -1240 1 -2192 8 -2788 9 -309 3 -2429 1 -943 6 -2749 7 -2008 7 -3065 3 -3963 9 -3473 2 -1899 4 -282 4 -621 1 -1027 6 -4082 2 -336 3 -3997 10 -337 10 -1187 2 -2267 1 -3160 9 -1307 5 -1026 7 -1905 10 -1233 6 -3477 7 -623 9 -1811 4 -2416 9 -749 8 -2941 7 -4067 2 -2988 9 -2802 9 -3350 10 -2006 9 -1948 8 -2569 9 -1043 10 -227 4 -2570 4 -208 9 -504 4 -2605 6 -1583 1 -2863 7 -2535 2 -1898 5 -2526 4 -1958 3 -750 10 -1144 4 -3770 10 -2773 1 -579 1 -298 9 -2876 5 -124 8 -3938 6 -2761 6 -1497 9 -2385 3 -28 5 -1902 1 -2215 1 -2232 4 -691 4 -3335 3 -1653 9 -2574 5 -905 9 -2089 1 -4054 2 -322 4 -1428 9 -3986 7 -3064 1 -1395 10 -199 1 -1969 8 -647 6 -2922 2 -3846 6 -3710 1 -2717 7 -872 6 -3434 9 -2872 5 -3901 5 -3798 1 -3308 2 -1375 5 -2324 5 -3747 1 -1766 10 -4054 1 -3359 8 -3596 1 -598 5 -1763 5 -834 2 -2993 6 -2178 8 -1166 5 -1497 7 -3001 2 -3940 1 -3314 7 -2921 9 -3621 2 -322 10 -3712 10 -1826 9 -2031 3 -300 2 -1676 9 -2713 10 -3797 4 -3538 5 -1714 8 -1573 6 -461 4 -2638 8 -3952 8 -2699 3 -782 4 -2420 9 -1389 6 -3213 9 -2469 8 -268 5 -1800 3 -3283 9 -2168 6 -2790 1 -2303 5 -1537 9 -2811 9 -2176 1 -4047 4 -4057 8 -2859 4 -715 7 -3273 8 -522 7 -2281 3 -3620 4 -1318 8 -2615 8 -247 7 -3388 4 -2357 9 -1736 4 -2903 10 -3366 2 -530 5 -4067 7 -1515 5 -1257 3 -284 9 -2575 8 -810 6 -1111 1 -912 3 -2310 5 -1689 6 -605 1 -1094 3 -1493 8 -1956 1 -2774 2 -1818 4 -717 8 -3409 7 -3451 6 -2795 10 -2000 9 -867 10 -1618 10 -3671 8 -2327 7 -3069 3 -3664 7 -3641 8 -1703 4 -1593 10 -2346 4 -2062 2 -2366 7 -2835 9 -3325 5 -1489 6 -3933 7 -622 6 -195 4 -2799 2 -691 2 -426 1 -1178 8 -2160 1 -3000 9 -3391 6 -1186 9 -3507 10 -2895 10 -1630 9 -3024 3 -2015 9 -2312 5 -252 4 -1032 10 -386 8 -1337 9 -4041 8 -67 8 -4058 2 -2072 8 -1684 8 -1896 6 -1753 4 -398 7 -749 1 -729 7 -2602 10 -2766 8 -2777 5 -717 7 -1261 2 -1327 4 -806 9 -2775 6 -1071 7 -669 4 -547 7 -2400 6 -3094 3 -3333 5 -1094 9 -2456 5 -2750 2 -3026 8 -2710 9 -3808 8 -1996 10 -3515 3 -3116 4 -600 6 -1129 10 -2806 7 -1133 4 -3239 4 -3498 8 -3927 3 -3119 6 -645 10 -3976 7 -3000 7 -1941 8 -2398 2 -804 3 -2801 9 -131 5 -3908 1 -3488 6 -2652 9 -514 6 -3429 8 -1486 2 -2305 2 -3119 6 -3841 8 -400 6 -3821 10 -1439 9 -3818 5 -3814 6 -3004 2 -2864 7 -2671 5 -2987 4 -3497 1 -2841 10 -3223 10 -2353 7 -2602 2 -2515 10 -2764 6 -3647 6 -301 8 -3496 1 -2796 1 -507 7 -3450 4 -1967 3 -1302 1 -1883 7 -1472 3 -764 7 -1242 10 -3043 2 -2329 3 -313 6 -2454 1 -595 10 -2469 7 -2829 1 -672 4 -2318 10 -3829 3 -306 9 -2391 6 -186 8 -922 9 -498 10 -2596 4 -4041 7 -3766 3 -2092 1 -1106 5 -1029 1 -760 9 -629 7 -2972 7 -49 10 -1723 1 -1100 10 -1552 8 -2948 7 -3257 6 -1219 9 -1558 1 -2476 5 -1419 8 -3284 8 -3402 6 -872 2 -905 9 -1830 6 -3549 6 -430 8 -2495 5 -1579 5 -2147 6 -3292 4 -1639 9 -1331 2 -2285 3 -1700 6 -3407 4 -1553 9 -667 4 -3829 7 -1023 8 -999 3 -2571 8 -1483 6 -4059 9 -2 2 -3736 4 -3863 6 -1784 10 -3006 6 -1101 9 -1805 7 -141 2 -4044 6 -646 6 -1909 1 -463 8 -4083 8 -3321 2 -1316 4 -2416 4 -768 10 -2575 9 -0 2 -946 3 -2547 9 -716 8 -876 2 -567 4 -429 3 -3650 3 -1392 2 -222 10 -3304 3 -1999 8 -3132 5 -2022 5 -762 9 -520 3 -218 10 -3536 7 -1025 7 -3440 10 -1655 8 -2431 4 -1081 8 -2069 3 -617 3 -2451 6 -3468 4 -2915 8 -509 6 -3601 1 -3734 1 -1848 10 -3266 5 -1321 4 -3339 1 -3907 3 -605 4 -2670 5 -3700 5 -1465 5 -230 9 -1647 6 -1121 8 -1702 10 -1313 3 -3437 7 -687 2 -394 4 -3413 7 -3785 1 -3701 7 -2420 1 -1439 2 -3617 1 -2377 7 -828 10 -1584 5 -2105 10 -613 4 -1703 9 -1085 2 -3265 7 -2187 10 -65 1 -478 9 -1802 2 -548 9 -173 9 -1609 10 -2362 1 -2078 8 -3227 8 -1351 3 -1476 4 -4030 3 -77 8 -1429 3 -2230 1 -2267 4 -3761 7 -2482 3 -3695 2 -2715 10 -1950 8 -3214 3 -191 2 -1426 1 -4025 9 -2288 1 -651 1 -3778 8 -3558 2 -3037 4 -2204 6 -1067 3 -3070 9 -1484 8 -3005 3 -1059 1 -3446 3 -4014 4 -3870 8 -547 8 -2775 6 -3845 8 -1804 4 -2908 1 -218 5 -3093 3 -89 7 -3684 6 -3658 9 -833 7 -1967 6 -161 4 -670 4 -2866 3 -117 8 -3446 3 -2549 1 -1795 3 -2873 8 -1846 1 -751 8 -701 4 -1463 6 -3840 2 -877 4 -1676 6 -1189 4 -2423 10 -2994 3 -227 9 -1188 5 -3373 3 -513 8 -1689 10 -1156 6 -2272 9 -785 10 -2816 1 -25 3 -3238 8 -2060 2 -2353 2 -1282 2 -2330 5 -2565 4 -124 4 -1431 2 -1046 2 -20 3 -1129 3 -3634 7 -1691 9 -2914 1 -1649 4 -2172 2 -237 7 -683 3 -491 4 -334 8 -2083 10 -3861 6 -2302 2 -3605 8 -4050 2 -2811 1 -445 5 -1032 8 -2550 3 -3586 7 -291 7 -333 3 -2188 10 -593 7 -3659 7 -1753 4 -1055 2 -2025 4 -42 1 -3533 3 -778 10 -3235 8 -3881 5 -167 2 -2373 7 -4031 6 -1238 5 -1384 10 -146 5 -2762 5 -95 6 -2201 3 -2946 7 -1187 7 -3056 5 -2049 6 -1761 4 -511 8 -1501 3 -2194 4 -514 2 -1275 5 -2585 9 -1824 4 -2886 6 -1378 1 -1310 3 -3751 8 -1893 6 -2449 5 -1366 2 -1640 8 -1890 2 -3838 9 -3109 8 -311 9 -2731 4 -3516 4 -4013 3 -2313 10 -2471 7 -3221 3 -3547 7 -1578 5 -2093 8 -3201 7 -3212 2 -406 5 -442 5 -2052 2 -3781 7 -3699 5 -571 6 -2319 7 -252 1 -2511 8 -2334 8 -3676 10 -3033 5 -462 7 -3261 4 -116 6 -3862 4 -1353 3 -138 4 -2869 9 -3701 5 -1123 1 -2054 4 -1928 6 -2355 5 -614 1 -2389 7 -2568 7 -3382 10 -967 4 -1844 6 -2337 4 -370 5 -749 3 -3739 3 -2660 9 -330 5 -3931 9 -2422 6 -47 5 -1672 1 -532 5 -2381 1 -153 8 -1234 10 -611 8 -1299 1 -3473 1 -3457 3 -1313 3 -557 8 -1826 8 -1328 9 -2872 10 -724 6 -3361 4 -1470 5 -2960 5 -2399 2 -3695 3 -2674 6 -2528 1 -1879 5 -3290 5 -722 4 -458 8 -3622 6 -2228 6 -2952 9 -259 9 -4081 10 -806 9 -3096 5 -1874 1 -2058 3 -2194 2 -1318 1 -3759 10 -3080 10 -1509 3 -1823 2 -2253 1 -4087 4 -3684 5 -1961 7 -965 9 -605 5 -3052 10 -274 2 -3743 9 -3707 5 -2463 6 -2156 10 -3623 5 -1155 10 -3838 2 -4078 1 -2192 2 -3102 3 -1773 1 -3948 9 -2377 8 -2888 5 -2136 3 -2060 5 -896 8 -3079 9 -1040 2 -1130 7 -3937 6 -3076 6 -3555 3 -1160 10 -502 10 -1344 8 -37 3 -1474 6 -2152 6 -3943 6 -2839 6 -3575 5 -841 1 -1645 4 -403 3 -3421 2 -2622 3 -2038 7 -1854 8 -1215 9 -2510 3 -3126 5 -2836 2 -205 10 -2493 5 -2828 7 -2832 1 -1147 7 -2746 2 -3423 1 -996 5 -3615 8 -2340 4 -3044 2 -2626 6 -1859 3 -2203 9 -2429 1 -3878 1 -1973 3 -3902 1 -1947 6 -1431 3 -954 9 -2126 9 -1750 5 -3783 7 -609 4 -3544 9 -3000 2 -3231 9 -230 5 -1005 4 -2676 3 -1779 8 -126 7 -3815 9 -1502 8 -3379 7 -239 10 -1746 8 -3556 1 -585 8 -128 4 -2657 8 -3755 6 -792 1 -3560 10 -1089 6 -1759 1 -2366 10 -3763 9 -3904 4 -3946 4 -2756 6 -1744 8 -1094 4 -2773 9 -2866 10 -473 2 -3495 1 -2644 6 -2988 4 -580 6 -3062 9 -1291 8 -3403 1 -2381 8 -3605 4 -2384 4 -2624 6 -2276 5 -3504 6 -1794 3 -984 10 -2298 4 -1741 5 -3294 1 -1427 6 -550 5 -1140 3 -3464 5 -3081 8 -2807 3 -2306 1 -1334 1 -2968 4 -300 7 -3997 5 -3240 9 -1294 8 -3015 7 -3973 6 -3172 7 -2599 10 -4076 10 -925 8 -4002 8 -1115 2 -2096 6 -2261 3 -1707 4 -496 6 -2034 5 -728 1 -1528 4 -1093 1 -1655 4 -2484 7 -2747 7 -1296 9 -3705 8 -2130 5 -2688 6 -3843 1 -3428 6 -563 9 -1196 2 -2313 8 -389 10 -2293 2 -2089 9 -1327 1 -2247 1 -1018 7 -422 3 -2384 2 -529 3 -805 9 -1418 4 -2608 5 -2303 1 -3074 1 -2861 6 -2880 3 -1415 3 -1745 1 -3101 2 -3574 1 -2530 7 -3120 1 -2466 2 -3287 6 -1071 7 -642 1 -50 1 -2096 3 -1810 4 -3897 6 -1711 4 -2236 10 -3087 1 -1523 3 -428 6 -3090 2 -752 5 -1303 6 -791 2 -3772 5 -3060 3 -276 2 -3836 6 -1636 5 -3260 9 -298 9 -761 7 -3539 10 -3033 2 -2710 5 -548 10 -2236 10 -752 9 -3956 3 -3436 4 -1190 1 -2438 8 -1635 10 -2186 5 -2279 7 -2011 2 -3246 9 -166 8 -3613 5 -2767 3 -3310 10 -3182 5 -761 6 -81 3 -1125 9 -2079 9 -2713 6 -2949 8 -1109 6 -1802 6 -3473 5 -3316 7 -1995 1 -2101 1 -3781 8 -375 6 -3845 4 -905 6 -2920 1 -2864 10 -2161 3 -2636 5 -3050 5 -1001 5 -577 1 -455 9 -279 5 -964 4 -3290 1 -3165 6 -3941 7 -663 9 -878 4 -3683 2 -1732 1 -2821 3 -626 4 -955 3 -3228 9 -1125 2 -176 8 -3467 1 -2231 1 -493 1 -1354 9 -3457 7 -489 5 -2915 6 -169 7 -2606 2 -3155 7 -1887 7 -805 8 -1201 1 -2784 7 -1515 7 -3404 2 -3131 5 -688 4 -2514 1 -1177 5 -1221 2 -1488 4 -3282 9 -3540 9 -615 6 -1572 9 -2183 8 -1206 5 -2648 5 -129 4 -73 7 -834 6 -1421 1 -3000 3 -1743 8 -3202 7 -3561 10 -254 3 -2436 2 -633 4 -2914 4 -3341 3 -2957 9 -2326 8 -3617 2 -3928 7 -2087 6 -1948 4 -3483 7 -3571 2 -445 10 -3758 6 -2060 8 -1411 3 -3633 10 -2902 3 -2883 1 -2072 9 -122 3 -3060 1 -3294 1 -1679 10 -2728 1 -2040 6 -662 10 -180 10 -1269 7 -1840 8 -2469 10 -3559 5 -2778 6 -2144 10 -2363 3 -2205 4 -2284 7 -400 8 -1167 3 -2692 8 -3226 8 -1845 4 -2370 7 -202 1 -2413 6 -32 10 -878 5 -946 5 -3493 6 -1605 4 -1332 6 -941 6 -3075 6 -2886 2 -917 8 -3930 4 -3052 9 -2986 7 -3234 3 -1216 10 -2660 2 -1263 4 -4093 10 -4015 9 -1480 7 -1227 8 -518 7 -1476 6 -2073 9 -77 6 -1061 10 -3768 1 -1034 1 -3905 3 -1328 7 -2601 8 -970 9 -2644 1 -2034 10 -720 8 -1749 3 -1298 5 -2304 10 -377 5 -3482 1 -2233 7 -3569 10 -605 8 -2151 10 -3546 4 -1699 3 -3277 1 -2573 2 -1318 3 -1096 3 -669 3 -1930 10 -620 10 -3123 4 -870 10 -1238 3 -2084 3 -2368 3 -966 9 -199 6 -3942 6 -2792 1 -569 8 -165 1 -1571 7 -2859 6 -1567 2 -3782 4 -932 9 -2540 3 -3627 1 -745 7 -2420 4 -3761 7 -3870 9 -1642 3 -1394 10 -3151 5 -1286 6 -3902 9 -1126 6 -2171 3 -2645 2 -651 3 -1339 5 -3791 7 -3945 9 -1769 6 -1692 2 -1338 10 -732 10 -2410 7 -713 6 -136 10 -2966 3 -458 2 -1204 8 -1698 4 -2628 9 -1680 7 -1361 2 -579 6 -1948 4 -3507 10 -4019 10 -3171 7 -536 10 -407 7 -1526 2 -1468 8 -3874 8 -3144 8 -499 4 -1453 3 -524 3 -2746 1 -184 6 -1811 1 -52 9 -3121 1 -1357 10 -1017 9 -2192 2 -2987 6 -1137 3 -242 7 -2761 9 -2075 10 -3275 5 -1061 8 -2137 8 -660 10 -1996 5 -163 2 -1761 4 -2318 2 -3570 5 -2478 3 -966 4 -3212 10 -2345 9 -3321 5 -1807 1 -3326 4 -2135 2 -3927 8 -2992 4 -556 4 -1623 4 -1523 7 -920 3 -526 6 -3249 1 -3437 1 -3043 8 -2877 7 -3945 4 -294 8 -289 6 -2722 7 -3440 3 -3979 1 -3144 1 -1985 3 -3975 9 -3826 8 -136 3 -3342 2 -3679 6 -3088 5 -446 2 -2292 4 -3041 10 -2656 3 -3513 6 -1280 1 -2610 9 -2661 4 -422 6 -54 2 -2021 5 -3864 2 -254 10 -1542 1 -1647 4 -3368 1 -3790 5 -3016 7 -3277 4 -1189 3 -969 4 -656 5 -3823 6 -4081 4 -393 7 -3358 1 -2825 9 -3544 1 -680 6 -1429 10 -1347 2 -3018 6 -2662 2 -3516 3 -4074 3 -3215 7 -3970 7 -1252 1 -1594 6 -1729 2 -3765 7 -637 8 -751 7 -2482 4 -733 2 -3850 10 -2449 4 -1382 5 -185 10 -83 4 -3644 8 -2661 1 -1712 4 -533 3 -35 2 -3955 4 -3133 4 -3064 10 -3728 10 -1492 2 -1234 10 -2203 2 -705 3 -321 2 -386 5 -1639 9 -1725 8 -823 9 -934 1 -1222 4 -862 8 -2665 4 -2998 4 -2214 5 -2306 3 -3735 7 -3509 5 -139 7 -398 4 -411 3 -3341 4 -1300 1 -38 9 -1877 5 -1392 5 -1156 4 -3161 1 -3027 3 -2939 10 -721 7 -3238 9 -2148 9 -1675 6 -1853 5 -1912 7 -251 6 -3098 4 -1352 3 -630 5 -3370 1 -65 10 -2325 8 -3688 8 -606 6 -1510 2 -3982 1 -3867 10 -888 10 -2874 7 -2560 7 -2199 2 -1996 5 -2965 4 -879 8 -3151 2 -1253 2 -1275 3 -1155 1 -2036 10 -3880 3 -3907 6 -283 6 -3319 7 -3543 7 -3446 9 -810 1 -2069 9 -2928 4 -191 8 -1380 10 -582 10 -425 6 -235 4 -1995 6 -677 1 -3967 9 -879 5 -3179 3 -3038 7 -1785 8 -1906 10 -4095 3 -3679 9 -2749 7 -1069 3 -188 3 -3307 2 -629 9 -2304 5 -2244 5 -1247 4 -2603 1 -3044 9 -2567 8 -3285 2 -3387 10 -2907 1 -471 10 -2077 9 -3257 10 -536 6 -1722 6 -599 4 -3487 10 -1150 7 -694 8 -1787 4 -3202 6 -3354 5 -2059 4 -1700 1 -2012 7 -1176 6 -2306 5 -2052 5 -2118 1 -1998 3 -457 2 -201 4 -264 3 -1911 6 -3168 4 -720 8 -3410 4 -2493 5 -1687 10 -660 2 -3167 3 -339 6 -1547 10 -716 3 -1095 9 -784 7 -444 1 -446 7 -2945 4 -1198 4 -2037 8 -326 7 -3370 3 -1448 10 -1007 5 -3943 6 -423 3 -101 3 -2099 3 -1 10 -2841 2 -2516 1 -4060 6 -2563 5 -1963 8 -3989 3 -1397 9 -2786 8 -3013 4 -428 1 -1830 5 -2502 3 -1496 7 -770 9 -1737 8 -2612 9 -2542 3 -3154 9 -3661 5 -1271 10 -558 4 -866 7 -365 4 -3517 3 -830 8 -455 3 -3380 8 -886 4 -1429 8 -200 3 -3908 8 -648 3 -91 3 -791 5 -3998 8 -3420 7 -3604 9 -1988 4 -1927 7 -1738 3 -3145 4 -4017 1 -3732 1 -1345 9 -1469 10 -2896 4 -358 10 -1905 5 -2025 6 -52 5 -2466 1 -1332 4 -706 4 -3153 2 -2509 10 -3789 4 -2525 6 -2994 9 -3386 9 -2353 2 -1970 8 -3150 10 -697 10 -3628 4 -3735 1 -2902 1 -2916 8 -1131 6 -2449 7 -2256 2 -1037 8 -873 10 -2524 9 -3729 7 -3510 9 -912 8 -1351 5 -3213 7 -116 6 -2781 9 -3781 7 -987 9 -224 2 -2170 7 -2957 10 -3753 8 -2546 1 -2295 6 -2162 5 -228 8 -2825 8 -471 3 -1198 2 -3532 1 -301 1 -1597 5 -569 4 -1366 5 -920 8 -1937 3 -3212 1 -2528 8 -2803 3 -961 1 -2705 3 -3672 7 -2234 9 -174 2 -854 9 -2816 5 -2280 2 -3101 2 -549 4 -2064 1 -117 9 -507 1 -1728 1 -1150 5 -3312 8 -746 8 -163 4 -1436 3 -2183 5 -3464 2 -3702 2 -1428 9 -262 1 -3486 6 -3200 10 -2428 7 -507 5 -1275 8 -3160 8 -3044 6 -3909 1 -1829 5 -2082 6 -600 4 -2011 8 -3697 8 -1983 4 -1083 10 -2200 10 -662 2 -3974 4 -2660 5 -3007 2 -2732 10 -658 8 -1607 5 -1726 5 -2072 7 -1318 9 -2327 6 -683 4 -1417 5 -4019 2 -2298 10 -2468 5 -2484 1 -640 5 -909 1 -3383 1 -733 8 -171 1 -1525 1 -3995 3 -3358 1 -1303 3 -1440 8 -2982 5 -250 3 -3681 3 -3585 7 -1668 7 -4028 10 -3734 9 -1486 10 -809 1 -2895 8 -3498 1 -1937 9 -3426 5 -4067 8 -3358 1 -2379 1 -660 3 -2233 5 -209 2 -2433 7 -2579 10 -3888 5 -3581 10 -2047 10 -3382 4 -312 10 -564 6 -750 10 -2459 7 -3991 10 -3691 6 -1776 7 -553 5 -794 2 -1928 2 -4032 5 -169 8 -2668 2 -3603 6 -3673 7 -3554 1 -3810 4 -1202 10 -1714 2 -3415 9 -4059 7 -3495 1 -3524 7 -1430 4 -1176 4 -4055 1 -1189 1 -3876 8 -3357 1 -1489 4 -1174 1 -470 3 -396 3 -3206 2 -1713 6 -3938 2 -223 7 -825 7 -3377 4 -4002 5 -2301 7 -3428 4 -3796 3 -553 7 -733 2 -1313 8 -3271 2 -616 6 -2533 7 -3916 6 -1280 8 -1655 6 -1439 3 -336 6 -4030 4 -3584 6 -1626 5 -1568 10 -2000 1 -1621 4 -326 9 -262 9 -1494 4 -3936 9 -345 5 -2071 8 -2090 4 -246 5 -2059 2 -2962 7 -2860 10 -3029 7 -1136 1 -2354 7 -2352 7 -2727 1 -385 10 -3312 9 -4075 5 -3319 7 -2917 8 -1577 9 -3490 4 -1629 1 -1123 1 -380 6 -1411 4 -1559 1 -3765 7 -408 2 -1422 8 -200 4 -1164 4 -3994 7 -1547 7 -3982 1 -188 1 -1065 7 -893 3 -400 6 -824 4 -1566 2 -1471 10 -3063 10 -1623 10 -3839 10 -2209 4 -1860 5 -3279 10 -4000 4 -3763 7 -1994 10 -1841 10 -3347 5 -58 7 -3053 10 -2020 3 -1465 10 -475 2 -3230 2 -1539 5 -1206 8 -3910 7 -3428 3 -915 4 -2602 2 -1036 7 -2873 3 -3426 2 -3789 9 -3867 10 -2420 7 -268 6 -16 10 -4072 2 -2510 4 -1975 9 -4075 6 -1680 1 -2231 6 -3514 6 -305 7 -629 5 -1157 4 -4079 8 -3085 6 -3667 1 -2830 3 -1419 5 -1535 1 -3703 7 -3475 9 -2563 5 -1847 6 -749 8 -2222 2 -3356 1 -1830 7 -1053 9 -3040 3 -907 5 -342 7 -2002 7 -2554 8 -796 5 -2960 8 -288 4 -4091 5 -537 1 -3772 4 -2944 8 -2436 5 -193 5 -4017 7 -3813 9 -1315 6 -354 9 -2268 2 -1458 3 -1338 7 -703 7 -1389 9 -3459 5 -2492 2 -1306 2 -3739 7 -3081 7 -655 2 -343 2 -2127 6 -368 7 -1965 3 -2220 4 -2810 1 -1996 10 -2980 4 -1073 9 -489 5 -2625 10 -3867 4 -3131 5 -2048 5 -802 8 -320 10 -2852 1 -3911 7 -3585 4 -1991 8 -4002 8 -2146 1 -2301 2 -595 8 -3298 9 -1043 6 -74 8 -3826 9 -3145 5 -2067 8 -2972 1 -3083 3 -2167 8 -277 7 -1423 2 -30 4 -835 8 -2595 6 -928 2 -3105 7 -2777 7 -3550 7 -749 2 -2206 6 -3923 5 -1227 9 -2410 6 -1069 3 -1539 8 -691 5 -1029 10 -759 7 -3185 1 -2948 7 -2047 1 -3145 3 -2602 10 -678 4 -1535 3 -3244 2 -2659 4 -1859 7 -1721 6 -976 2 -3808 3 -2188 10 -1352 4 -1887 2 -1073 4 -1462 3 -3347 9 -342 7 -1147 5 -3310 2 -2879 10 -1247 9 -1796 10 -1271 6 -1227 8 -2907 9 -3342 7 -3470 5 -3974 10 -3227 7 -24 8 -1290 5 -3966 3 -1480 6 -818 9 -110 7 -368 3 -2331 3 -2793 7 -1056 8 -87 9 -2185 8 -2437 5 -3128 10 -2431 1 -1472 7 -736 10 -625 2 -2524 8 -2896 6 -523 10 -3900 2 -39 8 -29 7 -3419 10 -1473 2 -3676 3 -1270 9 -1607 5 -2863 10 -2489 1 -185 9 -1366 10 -2688 8 -2721 2 -1557 4 -901 1 -3999 8 -463 2 -338 1 -975 7 -2213 9 -3579 4 -1871 3 -2407 6 -2121 5 -1883 9 -2673 2 -932 10 -1189 8 -55 9 -3505 2 -1278 10 -3984 1 -138 8 -3847 4 -44 9 -1128 8 -524 8 -3695 8 -858 8 -3998 9 -692 4 -3851 5 -1613 10 -3202 4 -2119 4 -1521 1 -2611 7 -3324 6 -426 1 -1362 1 -1218 7 -1994 6 -3575 6 -1661 8 -64 2 -3758 10 -2322 9 -3765 3 -596 1 -342 4 -2811 9 -166 6 -3821 8 -2317 7 -1582 3 -3898 2 -388 8 -403 4 -2876 4 -3466 9 -1479 2 -2638 10 -778 1 -2175 5 -26 1 -658 3 -590 2 -1065 6 -4014 1 -3093 8 -3340 1 -3835 6 -1366 5 -2207 2 -3634 10 -284 1 -1490 5 -2578 5 -574 10 -3098 5 -2438 6 -739 4 -350 8 -3544 9 -657 7 -2999 1 -2611 10 -2105 8 -3416 7 -952 4 -3886 3 -3437 2 -1740 6 -3627 4 -2275 7 -2992 8 -974 9 -3900 8 -4 10 -3258 5 -1439 9 -3007 6 -1782 4 -1625 8 -414 1 -1805 4 -2885 9 -363 10 -2635 8 -715 6 -87 3 -2050 1 -513 1 -2020 10 -2294 4 -3713 3 -3611 8 -640 7 -2474 6 -782 2 -432 3 -2424 9 -2661 6 -919 8 -2453 7 -1694 8 -560 10 -1311 5 -3812 8 -1185 6 -3277 8 -2681 3 -3695 8 -2804 10 -836 2 -2331 7 -799 5 -2602 3 -119 9 -467 5 -3483 4 -706 4 -2544 8 -2491 10 -2124 6 -3472 5 -2085 10 -3649 1 -1534 2 -1163 7 -2186 9 -1385 7 -914 4 -2603 8 -950 4 -3991 4 -1647 1 -2278 8 -385 5 -2320 3 -3261 8 -2689 7 -915 4 -1615 2 -2722 4 -1011 4 -882 1 -2544 7 -3906 3 -102 1 -3270 2 -2172 8 -461 10 -1626 3 -16 4 -686 6 -838 1 -2327 4 -299 2 -1070 3 -3076 7 -2740 3 -1730 7 -3560 8 -3786 2 -977 4 -520 2 -2333 8 -835 7 -3915 3 -876 3 -273 4 -2967 7 -1563 8 -1852 8 -3721 3 -3859 8 -1528 1 -1475 8 -3293 9 -3165 8 -3501 9 -2396 3 -3608 9 -2272 6 -2165 8 -3257 9 -2610 4 -1163 1 -3509 3 -1916 3 -3182 3 -2371 4 -2451 1 -3350 1 -2898 3 -2300 5 -1668 3 -2103 10 -1699 6 -601 5 -1613 2 -1192 5 -2242 5 -1992 4 -1000 2 -941 10 -1213 10 -3913 1 -3555 2 -1632 8 -2423 2 -227 8 -764 3 -2619 7 -3879 5 -179 1 -3913 9 -2466 4 -535 4 -2936 7 -1864 8 -2765 7 -3059 4 -1189 4 -2223 3 -2341 5 -2939 2 -3941 6 -3223 9 -1994 9 -3308 1 -3122 9 -1325 5 -1739 3 -1566 10 -50 6 -695 10 -2593 9 -13 3 -1030 4 -2702 10 -1909 9 -779 6 -3447 3 -3263 1 -1277 9 -1509 1 -3466 7 -2193 7 -1238 10 -482 1 -1026 2 -3504 5 -43 7 -1116 6 -3103 10 -3342 9 -3338 2 -727 9 -623 10 -831 9 -97 3 -926 3 -3812 1 -3470 8 -266 7 -3445 8 -2394 3 -979 7 -1050 4 -2067 2 -3617 3 -412 2 -1346 7 -3277 10 -548 1 -80 5 -3596 9 -3072 1 -2583 5 -1878 4 -307 3 -225 8 -920 8 -3260 5 -3237 4 -1813 3 -337 7 -85 3 -2357 8 -2327 4 -369 10 -924 10 -4089 1 -2310 9 -3379 2 -591 1 -2988 5 -1490 6 -4028 5 -538 7 -168 4 -2168 4 -350 9 -3798 2 -535 1 -1859 4 -2186 8 -4011 5 -3635 6 -1262 1 -2529 4 -1050 6 -2014 9 -2269 6 -3534 10 -2635 8 -1490 4 -979 4 -2981 4 -3493 9 -3085 2 -107 3 -3336 8 -270 3 -1920 8 -1398 1 -1968 4 -1477 1 -244 6 -3898 1 -1176 2 -1237 7 -3657 4 -3846 1 -3963 1 -1973 9 -223 8 -2640 8 -2148 8 -3957 8 -1940 6 -391 6 -2694 5 -2599 10 -2327 6 -1905 10 -762 5 -1770 1 -1145 4 -833 9 -420 1 -970 3 -551 4 -919 2 -1839 6 -2596 4 -991 10 -1659 10 -1917 10 -1809 5 -1835 5 -197 7 -1199 5 -120 6 -1531 1 -1847 3 -3539 7 -1262 5 -1683 8 -5 1 -3279 6 -1075 1 -199 5 -3986 7 -1648 9 -3929 9 -1898 1 -3873 5 -3550 5 -2803 7 -2429 8 -1000 5 -2265 9 -460 2 -2657 1 -687 3 -61 2 -1399 9 -1496 8 -952 3 -3675 7 -3212 1 -1912 7 -3953 2 -1041 8 -1579 10 -2090 5 -2472 10 -2296 6 -1064 8 -534 6 -669 1 -445 3 -2713 5 -1119 8 -1021 6 -3815 2 -2857 2 -2602 3 -3713 9 -2803 2 -3275 8 -959 5 -1625 9 -2189 4 -248 6 -2983 7 -3182 4 -696 2 -3458 6 -2456 10 -314 5 -3712 7 -2531 3 -3989 3 -1422 5 -1620 7 -170 4 -3562 5 -2963 7 -2518 7 -3555 2 -729 7 -3397 7 -245 7 -200 2 -169 10 -2027 8 -313 2 -386 6 -1107 3 -133 3 -323 3 -1767 2 -1878 8 -2341 2 -2469 2 -3722 4 -497 6 -1572 8 -3332 5 -3172 6 -1846 7 -3105 5 -2239 10 -3140 5 -2168 9 -1318 3 -3639 10 -1989 9 -1165 3 -2288 3 -1654 9 -1272 5 -1434 2 -1465 3 -378 5 -2543 8 -3443 7 -2578 6 -1590 5 -3397 6 -457 10 -2220 8 -3763 7 -3461 5 -87 9 -2351 3 -2952 6 -4072 1 -1095 1 -1502 6 -1006 9 -2466 1 -3924 10 -3303 5 -3884 1 -332 10 -1288 4 -331 3 -1055 1 -3754 5 -2886 8 -2959 8 -4087 6 -2734 2 -1949 10 -1009 4 -4041 4 -1906 3 -1317 7 -363 1 -1212 9 -3142 3 -1817 5 -2246 10 -3563 5 -2756 5 -63 9 -3101 4 -3782 7 -2576 7 -3221 10 -1074 7 -1683 5 -3955 2 -3645 8 -1078 2 -4021 4 -968 6 -4093 4 -1355 2 -2889 8 -1407 4 -2986 7 -864 4 -1861 6 -2654 2 -3886 1 -1707 4 -2580 10 -751 9 -750 10 -445 8 -1055 6 -2636 1 -193 6 -2010 8 -2950 3 -3717 1 -2744 6 -450 2 -3456 10 -3531 9 -3257 10 -2757 10 -1168 6 -4041 5 -1529 9 -3601 5 -2412 7 -2878 10 -3562 3 -185 5 -2563 8 -1384 7 -513 6 -1563 3 -681 2 -1639 3 -2177 1 -2432 6 -1291 1 -3617 6 -2337 7 -2274 7 -288 6 -3436 5 -3898 2 -56 7 -215 10 -2701 7 -3097 9 -855 1 -1753 5 -1794 10 -2737 4 -3033 7 -2635 3 -1103 7 -4051 5 -2734 3 -2594 8 -3391 4 -1836 10 -3074 1 -418 10 -3174 6 -5 5 -1850 8 -1737 7 -2913 2 -3168 10 -3044 9 -935 5 -3529 1 -3447 10 -658 4 -2834 5 -3690 9 -988 6 -1784 6 -2519 3 -690 7 -2426 4 -3790 9 -2893 10 -3717 3 -3165 6 -1435 9 -3512 10 -3094 6 -2585 6 -586 1 -1464 1 -2347 8 -2402 3 -4045 6 -88 2 -3054 2 -1431 6 -3923 1 -4063 4 -1475 5 -4034 9 -2639 9 -3836 8 -2603 1 -3079 9 -1162 5 -902 8 -3504 9 -3122 10 -1886 10 -1466 2 -512 7 -2840 8 -1431 4 -2923 9 -1925 1 -219 4 -1482 3 -1919 5 -662 10 -308 10 -2537 2 -3087 1 -1711 6 -2778 6 -530 1 -2722 4 -1949 1 -1259 4 -3334 7 -3745 3 -2895 8 -3042 7 -2625 10 -1071 3 -3360 1 -1526 7 -1847 5 -1362 2 -4024 1 -1717 2 -105 5 -3761 3 -3243 8 -346 2 -2754 8 -3591 1 -3572 9 -414 1 -969 1 -2714 9 -3558 3 -2297 5 -1720 4 -3720 8 -3150 4 -4073 8 -3303 2 -2692 1 -3429 5 -701 7 -170 6 -2121 2 -502 7 -2172 1 -3261 4 -1617 6 -2151 6 -778 10 -2683 1 -2626 8 -2822 3 -1594 8 -1728 3 -3762 10 -1846 4 -1900 2 -3599 10 -528 5 -1458 2 -44 3 -1305 8 -1733 5 -88 9 -1782 8 -3755 1 -1702 2 -4083 10 -3911 9 -3894 7 -3036 2 -1522 4 -3683 10 -1559 8 -687 1 -1649 2 -283 9 -3725 1 -1026 9 -234 9 -549 9 -1874 1 -3716 6 -2385 8 -1511 7 -340 10 -329 4 -3227 4 -3500 4 -3021 8 -3928 9 -3675 10 -2745 10 -4024 9 -104 10 -4067 7 -2514 4 -1982 2 -1922 8 -2539 9 -3064 2 -1065 6 -2145 4 -2365 8 -679 3 -631 10 -3391 3 -2604 3 -3610 4 -3968 5 -600 4 -922 1 -802 1 -1838 9 -3124 4 -2142 8 -1262 10 -1685 3 -2353 10 -2134 5 -525 3 -1139 4 -2110 8 -1900 8 -1330 8 -1132 5 -1346 3 -2477 3 -297 4 -2994 9 -709 1 -705 10 -3144 2 -659 6 -3842 1 -355 9 -1783 9 -1655 8 -833 6 -1879 7 -1793 9 -840 2 -2880 7 -1100 8 -1240 5 -28 3 -524 4 -3320 2 -3918 10 -3232 10 -3721 4 -2752 1 -3469 9 -119 6 -40 3 -1196 2 -153 7 -1412 1 -1023 4 -2199 6 -4020 1 -3339 1 -267 3 -534 5 -1809 10 -443 1 -3047 4 -1530 5 -999 9 -187 3 -682 6 -2101 1 -231 8 -1843 9 -4 7 -1252 7 -2628 6 -2873 7 -3224 9 -3350 2 -2356 3 -3838 10 -2271 8 -154 6 -4091 1 -1366 3 -1692 8 -255 6 -3856 3 -1769 9 -937 4 -2600 4 -1079 10 -2209 4 -1333 4 -838 6 -1543 3 -1424 4 -3972 3 -1069 10 -3741 6 -2895 4 -3091 6 -416 8 -2310 1 -3449 5 -980 1 -1137 4 -3295 1 -2537 10 -358 10 -1877 6 -3183 9 -729 9 -1705 10 -1596 8 -3885 9 -3740 2 -3226 9 -1116 5 -3267 8 -1188 10 -2489 8 -3964 10 -2518 5 -1513 7 -1431 6 -1797 3 -1423 9 -921 10 -3562 2 -1955 10 -1122 7 -3990 3 -3960 5 -1562 4 -1258 4 -490 4 -2236 2 -3664 4 -1782 6 -2973 3 -2473 6 -273 9 -784 9 -2434 2 -494 8 -1196 7 -1416 10 -1631 1 -518 9 -1756 9 -3957 7 -1900 4 -2754 9 -3777 1 -53 10 -2003 5 -4001 8 -268 1 -3237 7 -808 4 -595 5 -1617 1 -1093 1 -2162 10 -2289 8 -134 8 -1671 1 -758 2 -698 4 -1203 9 -1715 8 -2787 5 -3170 4 -3987 8 -4067 10 -1519 7 -2314 4 -1213 2 -3345 2 -3304 1 -3792 9 -3340 5 -2579 6 -307 9 -1753 6 -3547 10 -1761 3 -2886 3 -3110 10 -1389 10 -961 4 -2207 3 -2827 4 -362 4 -816 1 -127 6 -2450 10 -3879 5 -3620 9 -472 2 -946 5 -1408 8 -2322 1 -762 5 -3162 3 -1389 8 -781 6 -1851 3 -3896 10 -790 3 -3365 2 -2820 8 -3210 5 -2584 9 -626 3 -298 2 -1770 1 -219 2 -2076 1 -3885 3 -65 6 -326 6 -4068 3 -2359 7 -1967 10 -3458 8 -2498 5 -3206 6 -1216 1 -196 2 -218 6 -1272 3 -1691 10 -2849 10 -3830 7 -1267 7 -3000 1 -1946 8 -3059 8 -3379 3 -2818 10 -1316 1 -3641 7 -16 4 -633 1 -3907 6 -610 10 -2836 2 -2250 7 -3507 6 -389 9 -3438 2 -1448 7 -1073 9 -3074 8 -3004 1 -3705 6 -3537 2 -2689 8 -2070 8 -2138 7 -2334 3 -3404 2 -1043 1 -3487 2 -908 5 -276 3 -2628 4 -794 3 -2567 2 -135 7 -1559 5 -3642 1 -3973 4 -2905 4 -48 6 -1530 5 -3659 6 -3210 1 -2520 9 -871 1 -1138 3 -1548 3 -336 2 -3684 1 -248 8 -1258 10 -3858 1 -100 8 -3501 10 -3897 10 -295 6 -634 3 -4079 10 -484 5 -1548 7 -3748 9 -1562 3 -0 7 -2139 7 -4024 2 -3352 6 -2749 3 -791 3 -365 3 -3835 10 -2872 6 -2305 4 -938 8 -207 10 -2934 2 -1847 1 -3662 5 -31 10 -3231 7 -2673 2 -1268 10 -2885 5 -912 10 -1940 4 -3632 6 -690 1 -1182 3 -1392 6 -2486 4 -2463 4 -1059 3 -1403 1 -2056 2 -1248 10 -649 7 -1937 5 -3522 6 -3588 9 -3004 4 -1324 5 -1440 10 -694 9 -325 6 -2231 3 -1159 9 -2821 7 -351 4 -1955 6 -3836 4 -142 9 -3406 8 -3108 7 -2828 4 -2230 1 -3395 10 -1428 6 -3546 2 -1741 9 -2505 3 -869 8 -2601 4 -2991 10 -2413 5 -1260 3 -3700 9 -1916 6 -3677 5 -2240 8 -663 8 -1068 1 -151 9 -2250 8 -1435 6 -3274 10 -3595 1 -939 1 -3649 4 -3862 1 -3945 1 -1515 1 -4066 3 -3597 2 -509 2 -3024 1 -2732 1 -2575 3 -1563 2 -3899 1 -251 8 -3423 8 -1755 5 -222 1 -2286 1 -3037 3 -3884 2 -3108 4 -560 4 -1031 4 -2828 10 -3025 1 -3672 8 -2637 5 -2769 10 -2879 10 -2525 10 -950 8 -3348 9 -3913 3 -1365 8 -583 6 -2070 5 -2147 6 -3622 7 -2350 10 -1 1 -2998 1 -3268 6 -2171 5 -2428 5 -1500 4 -4086 2 -3881 9 -2854 1 -2452 7 -1137 5 -1811 2 -3475 7 -573 4 -499 5 -3365 2 -1496 3 -620 7 -1178 9 -471 7 -3491 9 -3427 4 -3926 2 -1732 3 -3207 3 -3701 8 -3904 6 -584 3 -2269 3 -1809 8 -198 9 -2839 1 -2380 3 -3147 4 -3633 4 -3938 5 -422 1 -2110 7 -938 10 -2953 3 -2375 9 -2152 10 -2116 7 -3214 1 -3381 9 -3935 9 -749 10 -93 5 -375 2 -3235 7 -2273 5 -661 6 -1081 6 -2591 10 -2980 4 -3576 9 -2685 6 -89 7 -3791 5 -1324 3 -799 7 -3817 2 -3597 8 -2069 8 -1208 5 -181 9 -2470 4 -305 3 -3769 7 -684 7 -3530 1 -3045 6 -1786 10 -2674 10 -3354 3 -1024 7 -3725 10 -2067 4 -3786 6 -2834 3 -1481 9 -1026 8 -433 6 -891 9 -2960 9 -2241 2 -3283 10 -3755 5 -3801 2 -2694 8 -2519 8 -3572 8 -929 8 -1920 1 -1490 6 -2965 10 -2134 6 -4094 9 -1676 6 -3291 2 -1468 6 -2697 4 -2374 2 -2226 10 -3168 1 -1341 10 -2267 5 -383 8 -1830 9 -516 5 -3775 6 -2244 5 -1994 8 -322 10 -931 4 -1239 1 -3771 3 -1065 3 -2158 1 -302 9 -1232 2 -27 5 -2198 5 -1175 3 -259 7 -1041 6 -441 9 -2057 6 -4025 7 -2997 6 -2612 3 -1795 10 -1736 6 -470 8 -2139 10 -2292 5 -3877 5 -2182 9 -522 6 -414 4 -3480 9 -2813 6 -3846 9 -2364 8 -3167 1 -3545 5 -91 10 -3297 3 -1043 5 -1361 6 -3509 10 -169 6 -487 9 -4011 2 -2829 3 -2796 7 -834 7 -1501 6 -2302 2 -678 3 -406 5 -2282 9 -1730 10 -3180 7 -2823 9 -1364 2 -2150 1 -568 9 -504 10 -3665 1 -667 1 -2582 8 -3717 9 -1298 4 -3866 6 -2818 8 -2768 5 -1045 6 -3522 3 -1155 5 -2573 7 -4050 4 -1652 1 -1452 5 -436 5 -3847 3 -3607 4 -3792 10 -97 4 -1770 3 -1013 2 -1344 7 -522 2 -2092 10 -920 10 -22 4 -1869 5 -2956 3 -963 7 -783 7 -612 1 -1417 10 -2938 2 -2513 1 -3969 8 -1965 8 -3341 3 -963 6 -2776 2 -776 6 -3961 10 -1083 5 -352 1 -2796 2 -2380 3 -3073 1 -1922 8 -3254 4 -1611 1 -2675 9 -2014 9 -1642 6 -209 2 -1987 4 -3961 2 -2989 4 -228 2 -3609 6 -3115 2 -1281 10 -1868 7 -3282 9 -105 5 -2738 3 -2689 10 -1562 5 -787 3 -287 6 -1355 1 -2487 4 -2232 8 -444 8 -2134 5 -1247 8 -1801 3 -2057 1 -1704 2 -3722 8 -3354 6 -3517 7 -1958 8 -2941 5 -341 4 -842 6 -648 9 -3942 8 -3992 1 -3825 3 -2476 9 -3122 9 -2830 9 -3434 10 -3584 6 -1944 5 -1334 5 -2300 9 -676 7 -744 7 -3021 8 -868 8 -2813 4 -82 9 -492 1 -1642 1 -3024 1 -2654 5 -727 8 -3168 1 -930 7 -2031 1 -1202 6 -1500 9 -1101 4 -1638 8 -2348 8 -1172 3 -1112 9 -1455 10 -361 7 -169 5 -2766 8 -1046 2 -3022 5 -3446 4 -2985 2 -2579 6 -1243 8 -2563 9 -3524 9 -1332 3 -872 5 -3511 7 -3603 7 -67 1 -3095 2 -1451 6 -2152 9 -1188 6 -155 1 -2701 10 -2184 9 -1547 7 -3630 1 -111 9 -1875 5 -1778 8 -789 9 -1594 5 -2222 2 -682 7 -25 3 -1114 7 -3784 10 -1524 10 -2182 9 -1933 8 -2809 3 -1038 9 -1370 5 -1205 9 -435 10 -3227 7 -1956 9 -1989 8 -3017 10 -1766 5 -19 3 -3860 5 -1692 10 -1392 5 -1466 6 -536 2 -3076 2 -682 6 -123 7 -1928 10 -1195 5 -1706 10 -1416 3 -2377 3 -2701 2 -2497 4 -2006 4 -4042 7 -3047 10 -2885 4 -787 5 -3125 10 -3153 1 -2396 8 -4022 2 -68 3 -471 9 -1151 2 -2424 10 -2315 10 -2647 6 -923 7 -1568 3 -1455 3 -1732 2 -1619 8 -2236 10 -3652 2 -921 3 -435 6 -520 8 -3827 10 -3811 9 -1808 2 -3463 1 -2904 1 -46 6 -3775 9 -1976 7 -1712 4 -180 2 -3792 4 -20 1 -217 4 -1728 2 -1379 6 -2227 7 -319 8 -4018 6 -672 5 -1396 6 -3473 8 -899 9 -801 2 -1054 10 -2683 10 -2972 4 -1341 2 -1574 2 -2958 9 -670 6 -2150 5 -3907 8 -2075 6 -209 3 -222 6 -1025 1 -1429 8 -1835 2 -138 10 -1879 10 -3717 2 -954 10 -1109 2 -1252 7 -2263 9 -1175 3 -2932 7 -1711 3 -2417 8 -2768 3 -3771 3 -60 5 -636 9 -4044 10 -3915 7 -3548 3 -1739 9 -3539 1 -996 10 -3690 2 -200 1 -944 3 -1825 2 -2821 1 -1539 3 -3258 4 -2918 2 -3429 5 -1695 6 -3019 7 -888 5 -1786 4 -1168 10 -2416 4 -930 9 -3907 1 -784 8 -1125 6 -3627 3 -1924 6 -100 1 -505 8 -1406 10 -1392 1 -2097 3 -1945 2 -3977 9 -3696 1 -3151 6 -1128 8 -1013 8 -3398 10 -3087 1 -3777 3 -1149 8 -463 6 -2299 6 -324 5 -1905 4 -2079 4 -3758 1 -900 4 -2406 7 -1115 9 -19 9 -502 6 -1055 4 -1612 6 -3175 10 -502 10 -952 2 -1090 10 -3677 8 -2921 3 -201 10 -934 2 -687 1 -697 6 -658 10 -1937 9 -1498 6 -3684 5 -2529 7 -2345 6 -2650 5 -756 9 -3051 7 -1827 5 -2805 3 -429 3 -1311 2 -1630 1 -906 10 -3972 2 -2267 9 -2787 3 -2854 8 -969 8 -3208 5 -1617 7 -1257 2 -2686 1 -3185 1 -624 4 -2806 1 -3 9 -2281 10 -1088 7 -3706 8 -86 3 -2751 6 -419 8 -934 4 -735 7 -1050 4 -2650 8 -2974 7 -3507 2 -3378 3 -655 3 -3938 10 -3890 5 -2810 6 -107 1 -402 10 -102 3 -2569 10 -1917 4 -2016 8 -484 1 -849 7 -2184 2 -2664 2 -1443 1 -620 5 -232 7 -1912 2 -3987 3 -2452 10 -1971 3 -3443 3 -1406 3 -1527 8 -3127 9 -3006 2 -1573 8 -2734 6 -2642 6 -3673 4 -3856 7 -1311 9 -3227 3 -2793 10 -104 9 -275 4 -3607 6 -236 10 -1099 5 -2699 9 -1543 3 -3014 4 -2147 10 -263 5 -2195 7 -2457 1 -3089 9 -633 7 -5 8 -1026 7 -1727 6 -3000 7 -2407 7 -2481 4 -969 1 -790 4 -2650 8 -2250 6 -3364 4 -2342 6 -2125 1 -3487 5 -3962 8 -775 10 -120 3 -2409 7 -1693 1 -730 7 -2123 3 -1081 3 -3430 7 -1039 1 -136 5 -1774 1 -1909 6 -3608 2 -2798 9 -2919 10 -1248 10 -3346 3 -1630 4 -2171 8 -3063 10 -2248 7 -446 3 -1885 5 -2906 9 -840 2 -3376 5 -950 7 -1795 7 -3019 7 -3991 5 -3399 2 -2402 8 -1872 9 -2271 9 -2391 4 -3594 3 -3902 1 -2192 10 -759 2 -2296 7 -1765 10 -380 10 -3552 2 -2086 2 -500 9 -1761 10 -3501 4 -3029 1 -89 4 -1115 7 -1058 10 -189 9 -3543 9 -2984 10 -4076 3 -3110 5 -469 4 -736 5 -3463 1 -2013 10 -3046 4 -3498 2 -1238 1 -522 1 -2127 8 -978 4 -729 1 -377 3 -386 7 -1383 9 -2361 4 -2909 3 -2145 2 -1077 10 -2420 9 -1968 5 -2732 6 -3160 9 -1420 7 -1166 4 -3797 4 -3500 1 -1842 5 -3906 4 -1545 1 -659 7 -1255 8 -2148 5 -2412 5 -4032 9 -3519 7 -2829 3 -3433 4 -1189 8 -2520 9 -699 10 -2471 1 -1493 5 -3088 5 -672 9 -2447 10 -2021 10 -3618 1 -427 8 -1215 8 -1756 1 -1354 8 -1478 4 -991 3 -586 10 -3611 2 -2232 7 -3246 3 -3589 5 -2253 1 -1119 3 -781 1 -2485 6 -2108 7 -3947 10 -2229 6 -868 1 -2127 8 -2896 3 -920 7 -4081 4 -3772 5 -568 6 -1216 3 -3173 4 -1450 3 -4033 1 -2249 1 -3957 10 -3035 1 -1729 1 -3325 5 -1007 10 -2506 3 -3994 2 -823 5 -3192 6 -86 3 -386 3 -4008 1 -2620 4 -1866 2 -3206 3 -3073 10 -825 1 -35 8 -2494 7 -1293 10 -3960 2 -1139 4 -2794 1 -33 6 -115 4 -957 5 -293 3 -2879 8 -309 6 -2931 1 -2406 4 -97 8 -2860 8 -1381 1 -3990 5 -1016 4 -1753 3 -871 4 -3896 7 -930 5 -1331 10 -223 3 -1192 9 -1507 4 -3316 9 -2379 4 -803 1 -1127 3 -2200 9 -1403 2 -3959 9 -926 6 -1050 1 -3988 7 -245 3 -3801 7 -2001 9 -516 6 -1583 8 -3727 7 -1131 5 -722 1 -181 6 -3062 2 -2831 9 -75 3 -1255 4 -2148 5 -573 9 -1622 1 -3778 8 -765 8 -1693 4 -758 4 -2215 9 -2774 2 -2932 1 -1038 10 -992 9 -1914 2 -1493 7 -713 10 -1508 6 -3977 8 -3845 8 -895 10 -2137 3 -1989 6 -3691 7 -1555 4 -2778 4 -1204 3 -2078 8 -2235 9 -956 5 -3698 10 -1343 8 -3365 5 -644 10 -4054 8 -2758 8 -1965 6 -857 6 -1702 9 -2673 2 -1519 8 -1494 4 -747 3 -631 1 -2729 9 -859 7 -1461 7 -3917 1 -2298 10 -3868 4 -1318 10 -2140 5 -2033 7 -1176 8 -2504 1 -2810 4 -2413 8 -1947 7 -3616 10 -2610 4 -738 2 -3708 8 -1749 5 -807 1 -412 6 -562 4 -1296 2 -666 1 -3297 10 -3071 1 -3072 10 -1305 7 -492 9 -88 10 -253 10 -2293 7 -3578 9 -3010 3 -1103 6 -806 2 -1956 8 -1767 7 -3676 9 -3808 10 -1456 10 -1549 1 -3459 6 -2544 6 -3331 5 -3148 4 -3730 1 -1873 2 -3367 2 -14 4 -1136 7 -3946 9 -1644 3 -2633 6 -4002 3 -930 3 -4034 7 -3655 4 -2217 10 -1375 8 -848 8 -2156 9 -1357 10 -2487 10 -818 7 -2854 5 -338 2 -1786 7 -48 10 -952 6 -478 2 -4026 5 -2973 1 -2365 10 -1676 3 -101 9 -3287 10 -3129 1 -50 6 -2367 5 -329 7 -2130 1 -3216 8 -2411 9 -718 9 -119 9 -1261 2 -2742 4 -2537 7 -2015 3 -568 9 -1695 1 -1033 4 -1387 1 -377 2 -769 9 -3557 7 -3682 4 -2298 10 -2092 8 -2861 9 -4058 9 -3866 8 -2392 5 -730 5 -1367 4 -1270 6 -1394 4 -1280 7 -3716 9 -3628 2 -3724 3 -2152 5 -3150 7 -1816 4 -3361 7 -3881 2 -2687 3 -1196 8 -520 1 -1285 5 -122 3 -1325 8 -2277 7 -1756 2 -1950 4 -943 5 -3063 9 -3271 5 -667 1 -1585 4 -1869 6 -3748 1 -1021 4 -2974 2 -3761 4 -2004 6 -2236 7 -103 4 -3308 3 -3345 7 -1268 9 -3402 9 -2054 5 -3611 7 -1457 8 -2644 5 -3963 1 -460 1 -4003 5 -1750 4 -772 8 -148 2 -543 9 -3123 5 -1880 10 -2289 10 -3171 10 -2273 10 -3375 3 -2209 6 -2851 2 -1316 3 -3785 6 -3668 8 -678 4 -3604 7 -3133 10 -1967 5 -254 6 -2175 9 -2619 10 -3425 8 -1921 2 -1895 7 -2781 7 -747 5 -3027 8 -1582 10 -2156 2 -1705 2 -142 10 -2922 9 -87 9 -2535 6 -2624 3 -2596 3 -3152 3 -1758 1 -1642 5 -1274 5 -2318 3 -2609 9 -1795 10 -993 8 -839 7 -700 10 -2971 2 -3278 1 -3266 1 -2900 4 -1841 5 -2338 4 -2353 7 -2718 8 -2117 4 -955 7 -1663 2 -2930 8 -1405 8 -1751 1 -1847 5 -2888 5 -619 2 -1495 10 -1827 3 -2583 4 -4059 2 -2441 10 -471 8 -3001 5 -489 6 -2922 8 -3143 1 -1190 9 -235 1 -3849 8 -1391 9 -2917 8 -3836 9 -3760 3 -878 4 -1067 9 -3887 7 -2617 9 -2885 6 -1647 5 -776 9 -1986 9 -2081 1 -3772 4 -2516 3 -2760 10 -65 9 -942 2 -223 9 -3817 9 -977 7 -1654 5 -2963 7 -2599 7 -1756 8 -1715 10 -947 2 -1532 6 -65 6 -3133 10 -583 4 -2094 4 -724 9 -2191 10 -1467 10 -3013 9 -1477 3 -382 9 -1461 1 -3658 7 -2626 9 -3200 1 -3371 6 -4079 5 -3058 3 -605 6 -2811 7 -3553 1 -1942 7 -3466 4 -940 7 -660 8 -2888 5 -3090 6 -1810 2 -2963 1 -3239 7 -2303 3 -1670 10 -496 7 -211 3 -1320 5 -3672 10 -2720 2 -3976 4 -1718 7 -3166 5 -3829 1 -215 6 -2918 9 -472 10 -2736 2 -794 1 -2494 1 -1493 3 -261 6 -1956 3 -146 6 -928 9 -3493 10 -2533 8 -1941 9 -2098 1 -4090 2 -1157 5 -3283 5 -2744 1 -1239 9 -3837 2 -1011 2 -1635 5 -30 9 -1449 5 -3137 2 -3188 8 -3621 6 -1270 9 -148 9 -1486 8 -3255 1 -1833 8 -3170 5 -1359 3 -3614 6 -926 8 -3692 6 -174 8 -3870 8 -3559 9 -1444 3 -1781 8 -994 2 -839 3 -1880 6 -3972 4 -1959 4 -1299 7 -3647 2 -2337 1 -1985 4 -1648 7 -705 1 -1994 6 -1005 5 -811 1 -3310 7 -464 5 -424 6 -385 10 -653 5 -1669 3 -3109 4 -875 8 -1144 2 -954 10 -1703 5 -327 1 -3600 8 -3006 1 -519 6 -1298 8 -3093 5 -1932 3 -1953 7 -10 6 -3606 1 -2383 3 -2947 9 -3537 3 -2803 7 -2514 4 -775 5 -3214 4 -1961 8 -366 3 -1582 9 -1287 6 -2457 3 -1072 2 -2354 4 -2110 3 -1718 8 -1585 6 -3362 7 -875 1 -114 3 -179 6 -174 4 -1479 3 -2347 7 -1574 6 -131 8 -2819 1 -4066 6 -554 5 -3660 1 -3713 8 -1722 4 -2032 7 -4040 4 -2327 1 -3218 9 -2304 4 -1208 2 -1272 7 -3973 2 -2546 8 -1244 7 -167 10 -1252 9 -4012 8 -1738 4 -3182 2 -3331 7 -1971 5 -2011 2 -60 7 -2230 6 -311 9 -3097 3 -3544 1 -396 1 -1450 5 -1281 9 -3761 1 -1315 8 -775 8 -3120 7 -683 1 -2369 7 -245 4 -40 1 -3887 5 -648 6 -3911 8 -1811 9 -2978 10 -2214 6 -1200 3 -662 10 -3517 5 -1484 9 -2694 1 -1649 4 -3097 1 -3759 7 -3353 7 -2757 5 -2043 8 -2335 7 -2178 8 -266 5 -2378 3 -3650 3 -3902 10 -3780 2 -442 3 -1348 5 -3576 4 -3674 1 -5 6 -2134 10 -525 1 -2398 8 -667 6 -1302 3 -2670 4 -3730 7 -3069 1 -1588 8 -2017 3 -3600 5 -847 1 -1333 5 -167 7 -1901 7 -3950 6 -1703 2 -2472 10 -2305 7 -3644 10 -838 9 -3468 2 -1665 7 -1863 2 -2069 10 -803 1 -2941 10 -3930 6 -1134 3 -112 4 -1901 7 -2829 9 -4032 2 -3564 7 -2334 4 -860 3 -549 1 -1721 5 -2537 1 -2876 7 -93 1 -2836 5 -2078 3 -70 5 -722 3 -623 1 -3732 8 -2760 8 -3092 8 -3557 5 -1105 7 -2407 1 -2697 7 -3798 6 -1644 9 -1985 8 -3751 6 -3006 3 -28 9 -2503 3 -3489 10 -14 5 -2102 7 -2773 7 -835 5 -858 7 -3046 6 -2470 7 -2434 4 -784 8 -2623 8 -1409 9 -1491 6 -1584 4 -477 7 -3550 2 -3638 7 -3988 7 -970 8 -1608 4 -2364 3 -2241 4 -3477 3 -3306 1 -1007 9 -3152 7 -1584 1 -1692 1 -3136 7 -1298 9 -1255 1 -1786 3 -300 7 -3535 9 -910 8 -3595 3 -826 1 -2153 8 -556 6 -1466 8 -2361 3 -3294 7 -1322 2 -2067 8 -252 9 -1180 7 -2591 9 -1597 7 -2285 10 -1746 10 -1650 7 -549 2 -626 8 -3492 6 -331 5 -2286 5 -3405 7 -2605 10 -3475 7 -4 10 -2768 8 -1310 6 -1797 3 -589 3 -1515 5 -3233 9 -2344 7 -2541 2 -1787 7 -4045 7 -2420 1 -1966 4 -1472 2 -1069 1 -1283 7 -858 7 -596 4 -976 10 -1710 7 -333 1 -1013 7 -4034 1 -539 7 -4080 5 -3437 8 -2147 2 -159 6 -2971 3 -2139 9 -1591 8 -53 6 -2390 5 -1148 4 -2909 2 -1482 3 -3832 4 -525 2 -2189 3 -2575 4 -1690 7 -3861 10 -3784 7 -1114 4 -2781 2 -1732 8 -128 6 -1399 2 -3284 2 -2348 3 -3542 9 -1330 9 -1386 4 -1547 7 -2263 4 -1135 6 -1884 1 -3998 5 -1497 7 -2167 3 -368 1 -2138 3 -4037 5 -2597 9 -2724 3 -2630 4 -1723 1 -1748 8 -2450 2 -3249 4 -1424 1 -3584 8 -4089 8 -2332 3 -2750 2 -1749 4 -3349 2 -1757 2 -519 5 -638 10 -294 7 -368 3 -3166 8 -1629 3 -1503 10 -3487 6 -2064 8 -3065 8 -745 5 -291 7 -3601 6 -1104 1 -3720 10 -2689 8 -639 9 -637 10 -3459 6 -684 5 -157 1 -2870 2 -3527 10 -2917 4 -808 8 -3481 3 -3827 7 -2632 10 -1721 7 -3048 8 -680 1 -80 8 -439 2 -2997 9 -2375 5 -3000 7 -23 3 -1671 6 -1170 5 -2412 4 -1315 3 -1559 5 -3466 3 -128 9 -2235 4 -1234 8 -130 7 -2290 5 -1172 3 -988 4 -3293 6 -3955 5 -3742 2 -3341 5 -1981 3 -3863 1 -1455 5 -3057 2 -2747 2 -894 10 -506 9 -3800 3 -3837 1 -3078 5 -1080 2 -2605 8 -2867 3 -2190 8 -3406 10 -1964 3 -1570 3 -3135 6 -273 2 -3114 8 -556 9 -3506 8 -3403 4 -1560 3 -1661 2 -2350 8 -401 2 -800 10 -3005 1 -3493 1 -1726 2 -3423 10 -2471 7 -2887 5 -3444 8 -3666 6 -315 5 -1658 6 -1531 8 -1046 8 -3627 6 -3978 7 -3622 4 -1222 3 -2234 8 -2044 3 -178 2 -783 10 -1162 4 -3791 1 -2718 2 -3112 9 -2532 1 -1030 5 -1084 6 -805 10 -4067 2 -2768 2 -1309 5 -3937 1 -3020 3 -3393 5 -2259 4 -2650 2 -2210 7 -3125 1 -2915 6 -2796 9 -2357 1 -2228 7 -3486 3 -1937 6 -2562 7 -2534 5 -3545 9 -390 8 -695 7 -320 10 -2230 7 -764 4 -1925 6 -2854 7 -1803 7 -2432 5 -44 6 -763 9 -1233 9 -3689 4 -2286 9 -1247 3 -2391 4 -3349 6 -541 3 -3030 5 -2707 9 -2244 5 -2029 7 -3454 3 -1038 6 -2677 7 -3681 6 -2450 6 -2275 8 -1788 6 -3029 6 -2 3 -3667 1 -2126 5 -310 9 -1042 9 -4090 8 -3951 6 -3556 6 -3841 8 -3691 7 -1078 4 -1289 9 -2909 2 -2206 4 -3091 1 -1624 9 -1681 4 -437 8 -3112 9 -2679 9 -921 7 -1320 7 -2201 8 -425 7 -2930 2 -67 6 -1225 9 -933 5 -3952 5 -3123 1 -615 7 -3958 7 -1579 4 -3453 6 -944 7 -1351 1 -537 3 -1799 4 -2370 1 -2540 7 -1640 9 -3705 3 -1689 1 -302 3 -255 9 -613 2 -2241 9 -465 2 -1907 7 -251 1 -3398 6 -3306 7 -2646 9 -3697 7 -2996 10 -1177 6 -2513 5 -573 2 -383 9 -1723 6 -2759 2 -1603 1 -1701 10 -1969 2 -3900 2 -2828 4 -696 7 -2191 10 -3280 7 -3241 6 -1950 9 -0 1 -3352 5 -3994 8 -2041 4 -1157 10 -1108 1 -1533 5 -3628 6 -402 6 -377 6 -3321 4 -1876 7 -2851 8 -2439 8 -2134 5 -1246 1 -2580 1 -254 3 -276 9 -1739 1 -2001 8 -1303 8 -3666 3 -43 5 -350 9 -1619 1 -2449 3 -3991 4 -3133 4 -2754 2 -2808 2 -1103 7 -1933 1 -66 8 -3431 3 -1685 4 -781 10 -615 5 -1513 5 -230 1 -395 4 -2410 5 -3608 6 -2031 6 -3742 3 -868 2 -1367 6 -3929 6 -714 1 -1885 7 -3334 5 -334 5 -1331 4 -3245 5 -2617 1 -2360 4 -692 6 -2537 1 -2088 2 -2656 9 -607 2 -2924 1 -2619 6 -3043 4 -278 6 -1781 2 -1913 5 -1933 5 -2976 8 -3063 6 -1946 6 -608 6 -1187 7 -4070 8 -199 4 -1766 8 -455 6 -2961 1 -581 8 -2428 8 -3609 7 -3068 5 -3723 10 -3046 9 -227 7 -523 2 -1078 4 -2307 10 -513 8 -3658 1 -2901 4 -34 8 -2467 1 -2915 8 -3072 7 -3147 10 -1228 8 -1023 7 -2446 4 -1128 5 -398 3 -4016 5 -305 5 -274 2 -1020 5 -1036 4 -3663 10 -3575 10 -1579 2 -1479 6 -3604 2 -2575 3 -716 4 -2443 4 -1533 5 -3364 8 -66 2 -2500 3 -3487 9 -2246 10 -150 7 -4006 9 -4040 4 -2430 3 -4087 9 -1824 4 -11 4 -3395 6 -1865 7 -2906 6 -1713 5 -3445 1 -3127 5 -2756 6 -2413 6 -340 1 -3958 4 -2097 10 -428 5 -2381 2 -1517 10 -1242 10 -1686 6 -1966 1 -3688 3 -2135 7 -2223 10 -1379 8 -3244 3 -3215 7 -3005 4 -790 1 -1388 7 -391 7 -2936 9 -1950 7 -1586 3 -210 1 -1433 1 -3135 8 -1670 1 -1243 3 -1335 5 -163 6 -1191 5 -3350 7 -213 6 -4045 9 -3476 10 -462 9 -3248 4 -3436 3 -1127 6 -1658 5 -1347 4 -2932 5 -2007 10 -1002 6 -1304 3 -2334 3 -192 2 -1257 9 -2227 1 -3308 1 -2814 3 -305 3 -4038 7 -2605 8 -209 7 -1887 7 -3522 1 -2492 4 -3894 7 -3459 6 -3142 10 -3991 1 -3256 3 -220 2 -1541 3 -2844 3 -3940 1 -3425 6 -1313 4 -2499 5 -3559 9 -343 2 -3789 5 -3440 10 -708 10 -1613 5 -4054 10 -729 10 -2120 4 -1730 6 -2600 10 -786 1 -3192 9 -3450 4 -2610 6 -1284 6 -37 5 -2563 4 -2821 6 -2018 1 -1970 4 -3072 10 -1158 6 -904 10 -936 4 -1861 1 -1580 8 -2758 6 -1760 2 -1345 8 -2884 1 -2442 1 -3824 6 -323 3 -3813 10 -3198 2 -3754 10 -3437 6 -3739 5 -3834 8 -2605 10 -2936 2 -1880 5 -3439 3 -2012 2 -2602 9 -2743 6 -1670 7 -1107 9 -577 8 -1446 6 -1641 8 -4044 8 -1785 10 -4063 3 -963 3 -2360 7 -2143 4 -631 5 -2770 8 -2246 1 -2591 7 -1715 7 -2399 7 -865 3 -248 10 -2736 4 -3382 2 -2004 10 -2353 10 -3988 7 -461 4 -3776 6 -3037 8 -3479 2 -2953 9 -431 5 -3361 9 -2087 6 -829 5 -1176 5 -1509 1 -64 9 -1950 6 -70 5 -2499 10 -1530 9 -3704 8 -2965 1 -1674 5 -541 6 -2724 1 -614 1 -2173 9 -528 9 -750 5 -2849 5 -4054 6 -2821 7 -2071 3 -3121 9 -3567 1 -2906 5 -2923 9 -854 6 -3856 3 -782 4 -531 3 -36 10 -1231 4 -1810 3 -3397 8 -3603 2 -3463 4 -1604 1 -3527 9 -3197 3 -1486 10 -2829 5 -4009 1 -1532 7 -1175 9 -2229 4 -758 10 -1525 6 -3036 3 -1694 3 -999 1 -1823 4 -913 8 -3362 6 -2952 9 -3089 7 -753 10 -2687 7 -1754 7 -1881 1 -1237 6 -3456 10 -3011 4 -3430 6 -31 6 -951 9 -3084 8 -2250 6 -448 6 -3423 4 -2852 5 -2908 9 -4023 3 -3381 8 -4050 7 -747 3 -749 6 -1208 9 -2120 4 -2983 2 -446 4 -262 9 -2805 5 -857 8 -2171 4 -1242 8 -3981 7 -2653 6 -2283 10 -1543 10 -23 1 -1594 5 -4005 5 -1599 5 -2883 3 -3549 2 -460 5 -1017 2 -2773 8 -1935 1 -2083 8 -125 6 -1009 7 -2563 1 -254 1 -2960 10 -2676 1 -1954 10 -3727 5 -1390 6 -2767 6 -1238 8 -1064 5 -3526 5 -3394 4 -2459 4 -3292 8 -557 4 -1915 2 -2885 4 -522 5 -1848 5 -2737 3 -3946 7 -1737 5 -2257 7 -3592 4 -2320 1 -3302 10 -3434 4 -3461 7 -3007 8 -2558 10 -1675 5 -2523 1 -723 7 -3009 5 -1337 3 -3338 7 -1106 5 -2530 5 -2830 4 -2189 4 -74 10 -3974 10 -802 6 -3327 9 -982 1 -3260 3 -1319 1 -1198 6 -658 2 -2103 5 -4028 8 -47 4 -3675 2 -3015 10 -2475 10 -2789 1 -3871 8 -4089 6 -2461 5 -63 1 -1527 8 -1007 8 -3740 6 -2447 3 -3136 4 -1291 2 -975 6 -114 8 -3956 1 -1561 2 -1581 5 -3008 1 -862 5 -3916 9 -2829 2 -3533 9 -859 5 -3800 5 -2568 3 -1853 3 -1491 9 -2359 3 -2750 2 -2781 10 -2605 9 -2696 4 -2885 10 -976 8 -205 5 -1297 9 -2274 1 -1614 8 -1070 1 -780 7 -2903 3 -2126 3 -2811 8 -2572 3 -403 4 -541 3 -3383 2 -596 3 -3481 3 -794 7 -2605 7 -2808 9 -2253 3 -57 5 -3523 9 -649 9 -305 3 -3719 2 -2525 9 -3789 4 -1490 2 -3408 1 -825 4 -1038 4 -752 6 -597 4 -631 8 -3349 5 -3790 6 -3775 6 -393 7 -871 3 -1862 10 -2850 7 -1909 4 -3082 7 -670 4 -191 7 -1737 3 -639 2 -4018 8 -1718 8 -311 7 -4081 7 -176 10 -92 9 -849 2 -3130 5 -1542 9 -2422 5 -3978 9 -2606 3 -2164 1 -2940 10 -1223 8 -1207 7 -2067 4 -1123 6 -1777 1 -1010 4 -2333 4 -3535 1 -1159 2 -3640 10 -3455 10 -870 3 -1666 10 -4002 4 -3374 7 -574 9 -794 10 -1852 1 -3033 9 -3344 7 -1505 9 -1418 7 -1254 2 -1426 6 -1210 5 -1344 7 -3439 2 -190 6 -2310 3 -3417 1 -3218 1 -3767 3 -2740 3 -3469 5 -1222 2 -2083 5 -1295 9 -380 1 -4024 2 -2008 7 -2146 8 -42 3 -742 5 -2040 3 -258 5 -3952 7 -2113 9 -2801 4 -2245 9 -2645 4 -406 10 -11 1 -3805 8 -4021 1 -3852 1 -4009 9 -1355 7 -681 2 -3999 1 -3860 7 -3918 2 -1491 1 -879 3 -79 8 -2761 1 -2495 1 -3212 9 -1934 8 -2688 6 -225 1 -3301 1 -3774 5 -1241 2 -1866 9 -1305 7 -802 6 -873 2 -1863 6 -181 9 -2133 10 -963 4 -2507 9 -3048 10 -10 4 -3178 8 -1307 6 -3644 6 -3295 4 -3342 1 -612 7 -1626 4 -3110 4 -1001 9 -3538 8 -3001 3 -1299 9 -3974 4 -1072 4 -3947 10 -1275 6 -883 2 -1872 8 -2996 8 -1726 1 -2986 9 -3383 10 -3697 10 -2214 7 -1144 1 -3011 10 -122 6 -1989 4 -253 2 -3604 2 -436 7 -3439 9 -3014 9 -1132 5 -2497 5 -1760 7 -3698 5 -3682 8 -2715 8 -2697 6 -2802 3 -274 3 -1324 8 -1397 8 -443 5 -1475 9 -3836 5 -1105 2 -2007 3 -1085 9 -1553 4 -2404 1 -582 6 -955 8 -523 1 -3553 9 -2322 8 -1896 7 -151 8 -2408 5 -1242 2 -3562 4 -1487 4 -1034 4 -1626 2 -1391 6 -341 3 -382 8 -2302 6 -612 8 -2868 8 -3886 9 -564 5 -30 10 -3082 1 -3902 10 -2355 1 -2595 5 -1375 10 -432 10 -2434 1 -2049 2 -3927 6 -2082 10 -3262 6 -2287 7 -1298 8 -2777 8 -2651 9 -2951 8 -1161 7 -0 2 -2067 9 -1207 9 -933 9 -3419 6 -1057 6 -1544 9 -3706 1 -1799 3 -2420 7 -1256 3 -2686 6 -940 1 -3258 2 -3531 9 -2370 2 -2615 3 -409 3 -3640 1 -170 1 -918 3 -1854 3 -3581 5 -1183 7 -139 10 -2701 5 -3094 8 -2015 8 -2730 10 -3635 8 -3753 1 -1954 8 -2684 3 -874 7 -2279 6 -1426 4 -1043 8 -555 9 -1957 7 -529 2 -150 5 -3874 6 -1143 4 -3684 9 -990 2 -2689 5 -3365 7 -1868 1 -3312 1 -924 6 -2338 8 -502 2 -1681 9 -3819 8 -784 10 -3578 6 -3793 8 -3022 2 -3336 1 -330 3 -1699 1 -1706 3 -467 5 -3085 5 -1614 8 -850 5 -729 5 -1346 9 -2587 9 -3329 8 -931 7 -3438 9 -94 2 -414 10 -1055 9 -2744 9 -2746 3 -3793 3 -3996 3 -459 3 -1391 1 -421 3 -2880 5 -3881 4 -306 6 -3279 6 -238 8 -2838 8 -202 1 -1912 8 -783 10 -1079 8 -3410 3 -3103 3 -780 8 -1387 9 -3247 5 -441 7 -3453 1 -229 10 -4071 5 -351 3 -1242 6 -4071 5 -284 5 -2495 10 -3582 6 -193 7 -3878 7 -1835 7 -3920 10 -366 3 -161 8 -3202 7 -1568 9 -509 3 -2408 7 -1331 5 -1072 4 -3296 8 -2598 2 -759 10 -2490 1 -2180 9 -1852 5 -2030 8 -2465 4 -1911 5 -3244 3 -2681 3 -717 7 -2784 4 -3661 9 -3235 8 -2862 1 -1307 9 -334 1 -1703 4 -106 9 -243 6 -549 4 -1384 1 -339 4 -3729 10 -848 1 -104 7 -1213 6 -2601 5 -1153 4 -1457 2 -126 7 -1842 8 -2111 2 -1553 4 -433 8 -1721 7 -893 9 -2502 3 -4031 7 -3887 2 -3853 6 -3518 8 -1580 8 -1625 9 -3938 1 -2220 10 -1079 6 -3787 4 -3303 4 -3085 2 -1625 4 -4088 9 -147 4 -1678 8 -438 2 -28 6 -2776 6 -3305 10 -55 6 -3237 8 -468 6 -2505 3 -168 5 -2744 7 -3060 5 -1359 7 -1126 5 -1796 2 -3179 2 -2160 7 -2788 6 -741 5 -2774 3 -2626 5 -1023 1 -326 9 -1254 5 -729 7 -497 10 -1630 5 -2799 7 -2377 4 -584 8 -2909 3 -2738 8 -3993 9 -1646 8 -2446 3 -1681 9 -2129 3 -1006 9 -873 4 -2022 7 -3591 10 -3020 6 -1004 8 -122 10 -2016 6 -951 3 -3229 3 -891 1 -1945 5 -2096 6 -3140 8 -146 5 -1885 10 -430 1 -2179 6 -1376 2 -3049 8 -3672 7 -4058 5 -1300 6 -2697 4 -481 3 -1491 5 -3664 2 -2914 6 -2428 1 -2025 10 -3740 5 -3495 5 -3522 6 -204 4 -1433 9 -3559 5 -3491 8 -775 9 -163 8 -4026 3 -1105 2 -2158 8 -2307 4 -3052 8 -1218 7 -1409 9 -2749 3 -1983 5 -3082 1 -2100 9 -410 8 -3202 2 -2886 2 -2837 5 -2042 6 -1712 9 -1585 7 -831 10 -141 7 -1485 4 -1380 8 -3328 4 -2552 9 -3442 10 -28 4 -3295 5 -448 7 -716 5 -3798 7 -916 8 -4084 7 -617 5 -4088 2 -1303 2 -230 5 -189 2 -2141 10 -2471 7 -3445 7 -3267 9 -3805 2 -1588 9 -113 9 -2365 9 -189 1 -156 5 -3652 10 -3773 8 -67 1 -249 6 -573 7 -3179 8 -4062 5 -2733 6 -1974 9 -3021 9 -3017 5 -279 3 -3550 4 -923 8 -2035 8 -395 4 -4089 8 -2537 5 -1923 6 -890 5 -1996 4 -3414 7 -2303 3 -1100 2 -1671 4 -1092 2 -466 6 -2381 9 -3742 1 -1047 7 -1071 3 -4085 9 -3150 4 -2563 2 -595 2 -3896 8 -3174 8 -3984 2 -1752 10 -531 7 -73 7 -1139 7 -2312 7 -263 8 -1994 10 -1441 9 -2464 10 -2079 4 -3827 8 -820 2 -3448 10 -148 1 -3872 9 -3197 6 -680 9 -3229 3 -1794 8 -3952 6 -3950 6 -2566 5 -2126 4 -1666 2 -3131 2 -2469 9 -2005 3 -1953 3 -3515 2 -1273 6 -648 8 -1925 10 -1655 10 -1907 2 -3675 6 -811 6 -779 2 -1842 1 -2046 1 -3744 3 -1956 8 -529 5 -3925 6 -2731 10 -3582 7 -843 4 -3598 7 -944 6 -879 5 -1180 5 -542 6 -3156 4 -2067 3 -411 10 -1626 6 -3324 5 -4093 7 -2506 7 -2458 8 -2468 10 -2396 8 -2503 9 -2367 10 -3787 6 -2803 2 -4077 2 -1523 5 -2728 1 -446 6 -2513 3 -3613 10 -1775 2 -3457 3 -3930 4 -1573 1 -2969 2 -863 8 -3207 2 -1758 5 -3306 4 -3130 2 -1330 7 -3733 4 -2304 9 -58 6 -1102 10 -2276 4 -1318 10 -72 8 -1817 9 -1224 2 -2639 1 -451 9 -401 9 -2464 6 -560 9 -1965 4 -287 10 -1940 7 -24 6 -1946 10 -3108 9 -778 7 -1854 9 -3398 1 -2151 3 -2923 5 -2725 9 -3378 8 -1374 7 -845 3 -688 5 -983 3 -1179 3 -3101 9 -517 3 -2542 3 -2735 10 -1047 1 -1644 8 -1361 10 -2310 9 -2434 1 -3206 3 -535 7 -102 6 -404 10 -3868 5 -3149 5 -2435 6 -251 7 -2300 10 -1969 7 -598 7 -923 5 -1468 8 -476 10 -2255 4 -828 2 -3250 8 -885 2 -1345 9 -1474 6 -3764 1 -502 8 -71 6 -967 9 -3653 10 -3014 4 -3569 7 -2820 4 -1316 6 -1736 3 -2992 3 -2360 8 -591 2 -832 5 -3902 10 -2303 3 -791 4 -1749 6 -958 8 -2051 10 -2864 3 -2891 4 -241 4 -1918 10 -331 5 -1104 9 -1243 2 -535 10 -2948 8 -2058 8 -2574 5 -2316 9 -2937 5 -1369 2 -1267 6 -1738 6 -1366 10 -2937 5 -2859 6 -566 8 -3383 4 -3538 2 -1572 9 -62 3 -3980 8 -2111 4 -1024 8 -1804 9 -2077 6 -1541 9 -229 4 -3343 5 -90 7 -945 1 -2381 4 -371 4 -2661 2 -3672 6 -3246 6 -2902 8 -3771 5 -3020 6 -3744 3 -1319 6 -3197 6 -2389 10 -46 6 -1502 9 -28 1 -2857 7 -331 5 -1607 2 -2794 10 -495 8 -2281 6 -880 4 -847 10 -3205 8 -4019 5 -1949 8 -3477 6 -1990 8 -344 5 -2752 8 -2034 3 -3588 7 -1771 5 -505 9 -2026 1 -1222 8 -933 2 -188 1 -2132 5 -3767 9 -3484 4 -2768 5 -1482 6 -1943 10 -1640 8 -2812 5 -3279 6 -3959 7 -2610 1 -2045 9 -433 1 -529 2 -873 10 -1385 1 -1994 8 -744 7 -2665 9 -3311 6 -211 7 -1250 1 -529 6 -759 10 -3624 8 -1505 4 -773 7 -1594 1 -3429 9 -1466 9 -2224 6 -136 3 -3932 4 -4086 8 -32 5 -3534 7 -245 3 -3196 7 -1338 9 -1794 1 -3218 10 -284 4 -1747 6 -3710 7 -3343 8 -2297 5 -2521 4 -3802 10 -3643 10 -591 2 -4093 3 -1801 2 -1185 8 -2421 9 -1381 2 -1205 5 -330 2 -3644 5 -1504 4 -3281 9 -3169 9 -2191 6 -3037 3 -3072 6 -1778 5 -221 8 -362 10 -3549 8 -834 5 -2804 7 -204 10 -3044 6 -3720 1 -3166 8 -1170 2 -3210 2 -444 6 -2219 8 -2214 5 -2229 8 -2406 2 -2538 9 -1531 8 -1341 4 -4000 5 -1662 9 -330 6 -3485 6 -1474 7 -2921 1 -773 10 -3340 8 -432 6 -1283 6 -2487 6 -1041 1 -3626 7 -2177 5 -610 8 -2025 2 -2665 2 -1007 10 -882 9 -421 8 -895 4 -1596 2 -1170 9 -386 1 -863 10 -1216 2 -3614 4 -2822 3 -1816 3 -2434 9 -3923 8 -2717 7 -2002 1 -1745 8 -1417 10 -446 10 -396 7 -517 9 -534 9 -2942 6 -1256 7 -4068 10 -911 5 -2907 2 -1927 4 -776 3 -3477 1 -785 4 -2842 2 -760 9 -3268 6 -3425 1 -1723 9 -1879 5 -660 4 -415 4 -1791 2 -811 6 -248 5 -236 2 -287 10 -1817 4 -2630 2 -2992 2 -1950 6 -3474 5 -1824 1 -3571 2 -2758 5 -3343 7 -1821 2 -2972 6 -1291 2 -2746 7 -408 9 -4042 10 -526 4 -3311 1 -2222 2 -3155 1 -3408 5 -3727 9 -3716 7 -1321 4 -172 6 -534 2 -1827 4 -1560 1 -2654 2 -2937 3 -3102 1 -2640 9 -3527 8 -2810 8 -746 1 -3423 9 -694 9 -41 6 -20 5 -1888 2 -2831 3 -1597 6 -12 9 -2351 4 -550 10 -1688 5 -4070 3 -3345 4 -15 9 -242 6 -2823 4 -2870 6 -3587 3 -612 3 -3067 4 -1665 5 -3909 7 -3483 9 -710 5 -1307 9 -459 5 -3370 10 -3711 6 -491 3 -1938 2 -2272 2 -2118 2 -255 10 -129 5 -1726 6 -2144 10 -3655 1 -3228 1 -19 7 -608 9 -2167 9 -3599 10 -729 9 -3547 8 -2491 1 -3318 4 -815 7 -3745 8 -1743 3 -3102 5 -3946 7 -289 3 -3352 8 -4042 4 -3943 7 -3786 1 -2910 8 -2412 7 -3851 8 -3896 10 -1297 8 -1075 8 -3520 5 -717 4 -2416 9 -3535 2 -1494 3 -3614 4 -327 3 -3272 7 -3078 7 -1952 3 -928 8 -1322 1 -2563 3 -1412 5 -623 8 -458 6 -3754 8 -2197 10 -481 8 -3081 2 -2712 6 -2057 1 -915 6 -3583 9 -2544 3 -2841 5 -3389 1 -2732 8 -393 4 -2141 6 -2216 1 -2541 6 -1211 5 -3478 10 -525 1 -2292 3 -2483 7 -696 9 -2828 1 -915 5 -1047 1 -1755 6 -2524 6 -2721 10 -1936 8 -764 10 -2789 7 -3012 3 -1266 10 -4085 8 -3797 2 -2110 8 -2170 10 -688 4 -974 5 -2386 8 -1075 7 -3606 7 -3612 2 -2545 5 -1956 7 -3552 5 -3585 1 -110 10 -163 4 -699 1 -798 5 -1452 10 -3588 10 -1014 5 -1249 1 -3817 9 -866 10 -3177 10 -276 7 -2056 1 -1787 8 -4024 4 -3284 10 -2852 9 -994 10 -3106 7 -445 2 -970 9 -1140 10 -493 4 -1433 9 -3762 2 -3608 3 -887 7 -1315 2 -2146 8 -3944 1 -2345 1 -1994 5 -279 6 -784 2 -137 6 -3041 3 -755 6 -2503 4 -2778 3 -3646 9 -2580 4 -2147 4 -1542 3 -2530 6 -2357 7 -1586 10 -503 2 -3471 4 -1166 9 -3133 8 -2226 9 -483 8 -3475 6 -1640 3 -3188 10 -1548 6 -3520 5 -965 1 -3348 1 -189 10 -3796 9 -3653 1 -3804 6 -371 1 -3046 8 -2189 2 -2543 5 -3253 2 -225 3 -2033 7 -2182 10 -1975 10 -373 4 -137 4 -1033 4 -3898 8 -129 6 -101 10 -3114 9 -3741 10 -415 1 -752 1 -1383 10 -3232 3 -3534 6 -2786 6 -1320 7 -3762 9 -3929 9 -1238 1 -3353 7 -3911 7 -189 9 -1872 3 -3941 3 -3292 1 -2412 9 -1105 3 -1231 9 -963 3 -1098 4 -3351 6 -3409 4 -75 9 -365 6 -4088 2 -570 4 -3450 7 -490 6 -3582 3 -1764 5 -1658 9 -1235 5 -389 6 -1015 3 -1108 8 -4009 7 -1420 10 -4007 3 -1191 4 -3350 10 -805 6 -855 3 -2683 6 -564 3 -1640 10 -3632 7 -1769 6 -295 10 -2004 5 -3962 4 -3720 7 -833 6 -2054 9 -351 3 -3162 6 -3564 8 -1557 5 -2737 2 -2530 8 -1694 10 -3637 9 -1107 2 -1243 3 -474 1 -835 10 -3981 4 -3722 8 -52 5 -2942 3 -3461 9 -3959 10 -4080 1 -3554 6 -1633 7 -1591 7 -2656 7 -540 2 -2305 8 -842 7 -3146 10 -1251 3 -2403 2 -835 5 -773 2 -3458 7 -3165 4 -433 1 -2319 2 -184 10 -3171 4 -1316 2 -3103 5 -195 9 -3694 4 -2688 10 -1936 2 -848 6 -3991 7 -3714 7 -16 10 -2050 4 -1957 4 -1813 7 -3883 3 -3129 10 -1555 7 -882 1 -3957 1 -1613 10 -2381 3 -1205 6 -96 4 -3400 2 -2476 1 -3132 6 -648 5 -2613 9 -307 6 -3069 2 -340 1 -4033 7 -3613 3 -3821 6 -3658 7 -588 10 -3796 5 -1901 1 -2932 8 -533 9 -2864 1 -2976 6 -4058 5 -4000 6 -52 7 -2606 1 -1784 1 -973 9 -1337 6 -1521 6 -2273 9 -50 9 -877 4 -1265 2 -3981 9 -772 3 -2543 10 -2910 10 -148 1 -929 3 -3817 10 -1356 9 -2603 10 -3064 10 -236 3 -1714 4 -2242 6 -2907 4 -1879 10 -2685 8 -2129 1 -495 9 -3688 3 -2593 6 -1157 2 -1048 7 -3763 5 -2224 6 -3561 4 -2035 3 -1208 2 -1515 1 -611 7 -2020 2 -2615 10 -889 2 -3331 2 -2320 2 -2471 4 -3194 7 -2715 2 -3911 3 -2493 3 -2034 4 -2575 8 -2170 3 -1348 6 -1592 5 -3146 3 -1064 1 -1493 3 -724 6 -907 1 -3502 3 -3672 7 -299 4 -2517 3 -3487 6 -3732 2 -964 2 -819 2 -1960 3 -2892 7 -2993 6 -1101 9 -1240 7 -1560 9 -741 6 -1046 9 -2287 4 -502 8 -1311 6 -3071 8 -2469 6 -2760 1 -2553 9 -1073 7 -3543 2 -2323 1 -2572 7 -2027 6 -655 10 -575 7 -2066 10 -1236 3 -1411 1 -684 3 -1738 2 -1257 5 -2553 3 -2663 7 -3251 4 -1204 9 -1806 1 -3003 8 -762 6 -3163 7 -1754 7 -4040 9 -2394 2 -2892 3 -637 1 -1310 6 -697 3 -3016 2 -3237 7 -1357 7 -1590 7 -646 1 -4003 10 -3500 8 -960 6 -1841 7 -1620 7 -1396 3 -137 4 -2583 3 -3340 8 -2116 3 -4047 9 -2384 2 -2503 2 -2827 5 -1135 6 -346 7 -3504 3 -3738 8 -1658 2 -2218 6 -3144 2 -1604 1 -2074 1 -1379 3 -667 4 -1595 2 -2635 8 -992 3 -876 10 -1063 3 -3065 10 -1445 9 -2430 2 -2090 9 -123 3 -3695 1 -3168 5 -2053 8 -281 6 -899 8 -1603 4 -3085 4 -583 9 -3737 8 -1113 1 -3894 10 -781 9 -1529 6 -242 6 -1746 6 -859 7 -557 5 -4039 2 -2021 5 -3493 9 -2449 6 -502 5 -2792 10 -2028 10 -1299 6 -2347 5 -2662 5 -4015 8 -2272 8 -3546 3 -3687 2 -2466 6 -1312 7 -2764 9 -3068 4 -2422 2 -1196 9 -3139 6 -904 7 -1365 6 -214 2 -700 2 -449 6 -3611 3 -3476 8 -4069 10 -2743 1 -1171 3 -4075 10 -2356 8 -3758 8 -2310 10 -1809 9 -1628 6 -3410 3 -968 9 -3434 6 -314 7 -2523 1 -3429 9 -1426 10 -961 10 -1711 5 -403 3 -3823 7 -554 2 -3537 9 -3062 3 -360 7 -3181 7 -86 4 -3597 10 -3837 3 -3963 4 -3378 10 -2796 2 -2759 9 -273 8 -1666 6 -3315 1 -3729 6 -3574 7 -1220 9 -2887 9 -2860 5 -3324 6 -1048 9 -111 1 -3535 5 -195 3 -1970 7 -1497 10 -1656 8 -2179 8 -625 8 -1339 1 -571 2 -443 2 -1193 2 -309 1 -255 4 -2777 10 -1767 3 -2491 6 -1554 1 -3238 7 -2368 8 -2160 5 -2638 5 -2201 3 -2405 2 -968 8 -224 5 -2132 10 -1030 2 -373 9 -1363 3 -1169 10 -2470 8 -3607 7 -3155 7 -1502 6 -3687 9 -2833 5 -3829 1 -3777 10 -2998 5 -182 1 -1398 1 -3701 6 -1395 4 -341 4 -1627 1 -1747 9 -3265 6 -2489 8 -3944 6 -2359 7 -157 6 -2268 2 -1250 1 -2574 3 -4020 10 -1196 5 -82 10 -1647 2 -4038 10 -1089 3 -492 3 -3633 8 -1657 6 -517 5 -1698 6 -1222 8 -3172 4 -2166 2 -2571 6 -1656 5 -1343 3 -1362 9 -3554 9 -2941 2 -2767 10 -3191 7 -3471 6 -2537 8 -912 2 -1923 7 -685 5 -2697 3 -4048 4 -2929 6 -2271 4 -1786 6 -1470 10 -132 6 -4013 10 -1369 9 -1577 3 -894 6 -1411 2 -2049 6 -3885 7 -3098 8 -3958 8 -2841 3 -3300 4 -2503 10 -2301 7 -2377 2 -1867 9 -3131 9 -485 7 -3578 7 -1263 4 -2950 9 -1461 9 -950 4 -3771 8 -1189 10 -3455 7 -81 2 -1035 6 -3512 10 -3572 6 -2891 5 -2564 4 -1776 7 -3028 4 -829 7 -2937 8 -4088 9 -183 2 -623 2 -675 2 -441 1 -1852 8 -2703 6 -2825 6 -463 3 -303 9 -2953 8 -2093 5 -2215 3 -1619 9 -2906 8 -1180 3 -3956 1 -2573 6 -3032 3 -294 5 -2959 2 -177 7 -2688 7 -2499 1 -4038 1 -3699 3 -3859 7 -1459 6 -1642 1 -3293 2 -109 5 -772 3 -3819 6 -37 1 -1604 8 -1271 6 -3470 1 -2858 10 -2757 10 -1798 1 -992 1 -980 4 -645 7 -1328 5 -4002 10 -2225 10 -1932 7 -537 9 -1114 3 -3522 4 -911 10 -2633 10 -3001 8 -2258 1 -3882 1 -3206 9 -18 8 -3612 2 -1648 10 -1319 2 -3573 4 -359 7 -499 4 -3158 10 -695 6 -3165 10 -2167 2 -3646 4 -2764 2 -2407 9 -2155 7 -1448 6 -1667 1 -3127 1 -135 7 -1264 2 -764 6 -506 5 -3105 8 -937 5 -4010 2 -2231 9 -1652 2 -769 2 -2574 7 -607 6 -1594 8 -651 9 -338 5 -3642 7 -3371 1 -3527 3 -138 5 -3833 3 -870 7 -2520 4 -3068 3 -1661 9 -43 10 -3234 4 -3111 6 -1625 9 -2898 8 -3525 1 -2530 3 -2917 7 -2001 7 -1175 10 -4027 9 -222 7 -2333 7 -1872 3 -2005 2 -1496 8 -2605 2 -3973 1 -2975 9 -2649 7 -1952 10 -3835 9 -3390 10 -2487 5 -3693 8 -3397 7 -176 7 -2214 3 -3599 2 -2217 1 -57 4 -1659 7 -1751 3 -3714 3 -2875 10 -1594 3 -3245 7 -1577 6 -75 5 -2430 2 -2506 9 -674 3 -1033 6 -2185 3 -1284 10 -2220 6 -3269 7 -1917 1 -2666 8 -2274 4 -3643 8 -1942 9 -3126 3 -2317 7 -2505 8 -1705 1 -854 2 -1642 9 -2639 5 -612 2 -1006 3 -56 9 -1023 2 -384 6 -3366 8 -455 1 -2153 6 -1079 7 -2176 4 -1206 9 -4081 6 -1285 2 -4094 2 -1142 10 -1307 3 -3587 4 -2844 7 -3226 7 -2457 3 -2921 6 -3132 2 -345 1 -649 4 -4065 10 -3693 3 -3563 5 -513 9 -1167 2 -33 2 -153 4 -3185 8 -1873 5 -1702 1 -3799 10 -756 7 -801 9 -3801 2 -827 3 -472 7 -1096 8 -268 3 -2160 8 -2931 4 -3145 5 -555 3 -3863 6 -2106 10 -2336 1 -1444 5 -3832 2 -131 7 -275 7 -679 9 -599 3 -1184 6 -1464 6 -2622 4 -248 6 -1312 4 -2100 8 -3531 7 -1235 6 -342 10 -2477 7 -247 2 -1424 6 -2989 6 -2123 7 -2465 6 -2203 1 -1443 10 -1773 3 -2058 3 -3027 10 -1329 7 -3578 7 -731 4 -632 5 -2656 3 -2901 5 -343 6 -2157 9 -596 3 -163 5 -3700 8 -2955 8 -2670 4 -3695 1 -3428 5 -727 6 -3111 7 -1253 6 -1870 8 -2787 6 -909 9 -1820 9 -3830 3 -3126 6 -3118 5 -3670 7 -3757 8 -3454 7 -2750 5 -2097 4 -3445 4 -1166 7 -3947 4 -3770 5 -2125 4 -2132 10 -3089 7 -250 10 -2423 4 -1737 7 -2687 1 -2502 2 -919 2 -2354 9 -3074 7 -2245 3 -2155 3 -3640 4 -1670 1 -82 1 -116 10 -2480 5 -2174 9 -2497 4 -1910 3 -3481 8 -957 10 -3011 3 -3902 9 -1144 2 -3894 10 -2668 3 -2266 9 -1738 1 -3002 6 -3280 6 -988 10 -3073 8 -1148 5 -3624 8 -3011 3 -442 3 -2771 5 -265 8 -1151 9 -676 3 -110 3 -1421 4 -2040 5 -281 8 -2145 3 -1174 3 -1546 5 -367 6 -413 1 -238 7 -1650 9 -937 6 -1036 10 -905 5 -2108 2 -2969 9 -2356 5 -1495 3 -1575 1 -52 5 -1737 2 -1457 1 -573 2 -3489 1 -3301 5 -2585 5 -3978 4 -3945 4 -2554 8 -1266 6 -1736 6 -2138 1 -870 4 -4036 10 -924 10 -547 3 -943 3 -3859 4 -1390 5 -2047 8 -1852 2 -2780 3 -2684 5 -1665 10 -613 4 -1398 7 -3509 7 -1605 9 -740 1 -243 7 -2659 2 -899 6 -1406 1 -579 2 -3301 8 -2814 7 -467 1 -2460 3 -3172 7 -3746 5 -3238 2 -1272 2 -3292 9 -796 9 -151 4 -3114 9 -1102 4 -4072 7 -3927 5 -930 1 -3501 3 -3166 2 -571 7 -4062 2 -1367 2 -112 7 -2477 5 -860 4 -1057 9 -2105 10 -3283 5 -47 1 -3477 5 -891 8 -553 4 -2510 7 -285 1 -1484 8 -4022 2 -1414 8 -134 1 -1085 4 -2299 2 -2428 8 -1288 5 -1487 4 -1354 7 -1115 8 -1920 1 -615 8 -2485 5 -2692 9 -709 1 -893 7 -2945 3 -118 9 -1232 8 -3262 7 -1332 5 -2284 5 -2410 7 -3191 5 -3808 6 -3573 2 -2134 1 -1291 8 -2215 8 -4017 2 -13 9 -3263 8 -3875 10 -493 8 -864 2 -179 8 -2933 7 -663 9 -2633 7 -1485 6 -2004 2 -178 9 -3816 3 -678 6 -3019 7 -2792 10 -83 7 -3328 3 -77 2 -2991 6 -1643 4 -780 8 -2627 6 -3422 10 -4085 8 -593 1 -1798 6 -1606 6 -1045 7 -2765 5 -3186 2 -2260 8 -3972 7 -1132 5 -1900 10 -1759 6 -2290 9 -1212 4 -698 7 -511 1 -3331 7 -1185 6 -2565 1 -481 5 -896 7 -3301 7 -3907 7 -1014 5 -3916 1 -3628 3 -897 5 -1626 7 -1935 10 -1200 7 -3970 8 -3287 6 -927 2 -385 5 -1665 7 -2625 3 -1068 5 -3819 1 -2727 1 -1770 10 -3401 4 -1035 5 -3934 7 -1747 10 -3304 5 -1699 3 -739 10 -2396 3 -438 2 -3852 10 -2536 8 -619 8 -3535 3 -3758 3 -3889 1 -2887 6 -1720 9 -906 7 -3930 2 -3424 8 -2388 2 -1193 8 -2670 6 -3415 6 -3748 5 -1005 2 -3621 1 -2117 6 -3173 1 -3138 4 -3527 6 -790 3 -1633 5 -1725 10 -1700 8 -895 4 -3164 10 -3433 1 -165 1 -554 8 -1332 3 -1330 7 -1063 9 -2077 7 -875 9 -1378 1 -3839 9 -1907 3 -3274 8 -1444 4 -3809 1 -1834 7 -447 10 -13 6 -353 1 -2807 10 -3759 2 -1007 10 -3404 7 -1943 4 -1538 5 -1627 5 -2355 7 -1113 6 -578 9 -3056 3 -4034 8 -1812 7 -1388 9 -662 5 -2030 10 -24 7 -1600 10 -3051 7 -1495 1 -3155 4 -2911 7 -3017 3 -3764 7 -3561 7 -2259 8 -1092 9 -1312 5 -2132 10 -1929 10 -1297 3 -164 4 -1759 3 -2554 5 -3570 9 -2073 7 -68 8 -3225 1 -1222 9 -3001 8 -189 10 -3512 8 -3954 1 -4007 10 -498 9 -3559 7 -4052 3 -4066 5 -3914 10 -214 6 -149 4 -3949 7 -1491 7 -1783 1 -39 9 -1576 2 -3915 6 -1422 3 -2488 3 -3578 5 -939 10 -2467 1 -3742 10 -3990 3 -1156 3 -638 8 -308 5 -414 9 -2119 5 -2310 6 -491 8 -1948 9 -3551 1 -197 8 -2189 4 -2492 4 -2503 10 -3930 9 -3180 3 -1251 3 -1713 6 -203 10 -79 6 -2020 8 -2585 2 -2096 3 -1790 2 -2869 6 -1174 6 -2765 9 -1261 3 -2399 5 -637 10 -2318 5 -2306 5 -3370 7 -3379 1 -1732 5 -1503 10 -3555 8 -2024 8 -3905 6 -3491 5 -197 9 -340 1 -192 10 -1165 6 -3663 2 -2625 4 -2784 5 -3138 10 -3624 2 -3707 4 -2747 3 -96 8 -3822 6 -2740 7 -4083 7 -3339 8 -2041 10 -3050 7 -3165 7 -3096 9 -1375 1 -658 3 -3089 7 -586 9 -737 9 -2962 8 -3511 4 -2051 8 -1653 10 -2080 4 -1883 8 -2251 3 -1934 6 -1480 9 -3874 6 -276 9 -3255 8 -1860 4 -376 1 -71 7 -3753 2 -80 2 -3707 6 -1065 4 -978 2 -34 9 -1967 3 -964 2 -2802 8 -497 2 -793 1 -3976 9 -276 1 -3541 7 -2997 6 -444 10 -1180 10 -3008 1 -4091 10 -2304 4 -2965 6 -3270 5 -2441 4 -2822 5 -657 6 -2631 8 -1358 10 -1783 3 -3165 3 -1865 1 -3323 6 -375 3 -3779 5 -2505 3 -1645 10 -957 3 -1491 3 -1214 5 -3670 3 -2193 1 -720 2 -3241 10 -3819 8 -2112 4 -3301 10 -1264 4 -3937 3 -3991 9 -2233 9 -2788 8 -2477 5 -2449 6 -3996 10 -1614 6 -1843 1 -2732 4 -2658 2 -1930 9 -1400 2 -3464 10 -3043 7 -1099 6 -1698 1 -2485 9 -904 9 -3305 1 -161 10 -3368 3 -2575 3 -2376 2 -3414 10 -2415 2 -2241 3 -1118 3 -672 2 -973 3 -63 2 -3909 10 -2730 10 -2677 8 -2879 7 -434 8 -3328 1 -372 4 -3892 9 -3724 3 -1471 1 -1378 6 -3369 9 -244 7 -3068 4 -864 7 -1521 6 -2038 2 -3124 2 -1781 4 -2580 6 -324 1 -1703 1 -1230 2 -2407 6 -3972 9 -1775 6 -3082 4 -2442 8 -159 1 -971 1 -1686 8 -1022 10 -166 3 -3153 3 -3406 10 -1865 8 -1902 8 -2309 8 -78 1 -1521 7 -3207 10 -3637 2 -2802 7 -2388 4 -2204 2 -1263 9 -3758 7 -210 1 -2319 9 -561 4 -3534 9 -3902 2 -3460 8 -3392 4 -2231 10 -3718 9 -3019 5 -1126 9 -563 4 -1770 1 -1615 8 -2212 3 -3923 4 -745 5 -1638 9 -2814 6 -2652 1 -1114 8 -3194 5 -2302 9 -2308 8 -1040 4 -1210 4 -1632 2 -1359 3 -2478 9 -2613 5 -1037 7 -588 4 -602 3 -4014 7 -2961 4 -2047 9 -2435 1 -200 7 -1265 3 -278 3 -1610 4 -3825 10 -3239 6 -1101 2 -1300 4 -645 3 -180 5 -987 10 -626 9 -1288 6 -4017 3 -1451 10 -3465 6 -639 9 -830 3 -3332 1 -2983 10 -3702 5 -3877 10 -1450 4 -1003 5 -1545 5 -85 9 -1838 4 -788 8 -3927 10 -1056 8 -2778 6 -3679 3 -1002 8 -3338 5 -796 5 -2418 2 -3877 6 -279 8 -2305 8 -3895 4 -3515 1 -2818 4 -667 8 -2259 1 -2268 1 -2727 8 -1497 2 -777 6 -2200 7 -2456 5 -2856 7 -1571 5 -990 10 -1046 3 -3554 2 -3317 2 -2117 2 -49 4 -3251 5 -1138 4 -1020 6 -359 10 -2453 9 -2468 2 -1970 7 -3781 8 -339 10 -707 9 -1294 7 -3950 1 -846 8 -3362 9 -1275 3 -2627 5 -2665 3 -2785 8 -2626 5 -733 9 -1160 1 -3159 6 -143 9 -2164 2 -3928 2 -1972 2 -3856 7 -3888 7 -3983 8 -1829 10 -37 6 -255 3 -1327 9 -2513 10 -1368 2 -744 8 -709 9 -3809 9 -2173 5 -2777 2 -961 3 -421 1 -875 7 -1552 6 -1624 7 -3938 4 -1100 2 -631 1 -235 10 -1125 1 -168 10 -3547 7 -2353 10 -3006 10 -763 5 -2716 3 -2657 6 -3549 9 -214 6 -3547 7 -3270 6 -436 10 -3474 8 -3223 6 -4019 3 -4083 4 -1913 8 -422 4 -707 9 -2853 3 -1850 4 -596 4 -3455 10 -1307 3 -3706 8 -1441 10 -3879 8 -3858 3 -472 9 -1711 7 -3057 7 -1080 9 -498 5 -2332 9 -1374 2 -1178 1 -1673 7 -3260 5 -2625 8 -1925 7 -1769 8 -100 10 -3527 10 -3042 7 -3425 8 -3027 6 -1279 3 -2027 3 -469 8 -17 2 -2782 9 -341 5 -129 6 -2538 8 -325 8 -3066 3 -4047 6 -90 1 -1170 1 -496 8 -3767 3 -738 6 -978 4 -1727 9 -2483 9 -2017 6 -657 4 -2139 3 -775 10 -2472 9 -2787 8 -1504 3 -543 1 -1331 2 -1313 1 -554 4 -3997 6 -2823 8 -1521 10 -1342 2 -3175 5 -2162 3 -2970 2 -1781 9 -121 5 -1868 10 -1220 5 -1315 7 -3619 1 -729 7 -1148 2 -167 4 -915 10 -2197 9 -1387 1 -558 4 -3475 5 -803 7 -1223 8 -2789 2 -2020 8 -121 2 -926 3 -368 5 -1726 5 -261 4 -3162 3 -2490 10 -3168 3 -3301 10 -3438 5 -1498 8 -1912 8 -2145 9 -3118 4 -3638 1 -1186 10 -734 3 -2438 1 -2923 4 -1900 7 -2894 8 -3372 2 -759 8 -2318 1 -2312 7 -551 2 -2008 7 -3030 8 -960 8 -212 9 -470 9 -4042 1 -115 3 -3981 1 -2901 6 -227 2 -3460 6 -3819 8 -2974 2 -945 4 -3000 9 -2475 1 -2146 10 -1307 6 -1835 4 -3016 9 -111 6 -1804 3 -1492 10 -213 6 -578 4 -1962 7 -538 2 -3498 7 -1504 5 -3276 1 -29 10 -1751 4 -3691 8 -3940 7 -3590 5 -904 7 -1308 5 -2836 9 -2607 2 -3977 4 -3483 5 -914 7 -3591 8 -2957 2 -1456 6 -1058 4 -156 10 -1229 8 -723 4 -323 10 -1036 8 -1588 7 -1119 2 -2304 2 -1258 6 -2374 3 -1511 6 -3309 8 -2197 4 -1922 1 -2663 6 -1672 7 -3887 5 -3053 6 -1402 1 -548 8 -1584 1 -2087 3 -2285 1 -2296 2 -2219 7 -352 7 -1082 2 -1095 7 -3190 3 -2965 2 -1491 4 -3628 2 -678 1 -989 7 -3992 8 -2804 9 -3427 10 -2437 8 -354 3 -3931 2 -2727 6 -3545 6 -3365 5 -1510 7 -2345 10 -127 9 -3498 10 -636 5 -1057 7 -178 4 -912 10 -1125 9 -3365 5 -84 3 -938 7 -1288 7 -1381 1 -1918 4 -2141 4 -780 8 -3992 8 -588 1 -469 10 -3797 1 -3704 4 -3692 6 -1990 4 -891 1 -4079 7 -547 9 -1882 5 -3816 10 -926 8 -2927 10 -2006 7 -2486 2 -3632 3 -1220 2 -2238 10 -3433 9 -1246 2 -3886 4 -3922 3 -218 8 -2179 2 -3334 1 -193 8 -1378 10 -3579 7 -1791 7 -3787 4 -873 7 -2528 9 -518 6 -212 9 -3299 9 -3114 10 -379 1 -2024 7 -681 2 -3421 8 -399 10 -3187 5 -1665 4 -1808 6 -1987 5 -1748 4 -1625 9 -385 10 -987 9 -3359 7 -2821 6 -2169 4 -3375 9 -3512 9 -3189 7 -1068 8 -3790 4 -3807 2 -22 8 -1287 6 -3718 9 -2858 6 -2126 10 -4011 5 -3800 10 -2661 2 -1947 8 -3834 2 -303 2 -2622 3 -3913 1 -1811 4 -61 5 -3661 5 -2741 6 -3856 9 -1455 8 -1637 6 -3822 1 -849 10 -1107 9 -4017 7 -1863 9 -835 10 -1701 3 -2071 9 -1073 6 -3155 9 -3832 10 -643 4 -530 1 -353 1 -1161 1 -350 1 -2528 8 -3713 9 -880 9 -2421 10 -3781 1 -2390 9 -2151 6 -245 2 -2899 6 -3547 9 -2772 5 -2134 1 -1827 4 -1552 10 -3487 4 -900 3 -273 5 -1946 1 -3128 2 -3301 9 -3175 5 -934 10 -1779 3 -1199 9 -1233 5 -2228 7 -2105 1 -479 8 -3535 1 -1742 2 -2390 7 -3399 2 -1660 7 -849 3 -1652 9 -3332 8 -174 4 -2965 9 -1165 8 -2794 8 -1638 2 -2881 8 -2527 3 -1570 2 -2307 5 -979 2 -2832 6 -3507 8 -3430 1 -3962 7 -140 7 -3207 2 -3306 10 -582 10 -2746 8 -81 4 -2122 4 -1226 6 -1454 7 -354 5 -1664 2 -2109 1 -1697 3 -2452 4 -2398 1 -2224 2 -1679 6 -2330 1 -2358 3 -2942 10 -3842 2 -1411 2 -353 9 -1879 2 -1117 6 -255 1 -2495 8 -1126 9 -1947 6 -3705 6 -270 10 -1351 2 -2900 1 -3427 7 -742 2 -1158 4 -2501 1 -868 10 -3810 5 -449 2 -2496 5 -972 4 -3187 9 -291 4 -2278 3 -1057 2 -1471 10 -3238 2 -1171 6 -1463 3 -2833 3 -2529 10 -2831 3 -567 10 -2484 4 -973 1 -3606 5 -154 7 -2688 3 -1188 5 -1853 4 -3407 6 -710 1 -1598 10 -6 4 -2315 9 -3218 10 -577 3 -2530 9 -2622 4 -4048 1 -1208 1 -2226 4 -1064 9 -2499 10 -3998 7 -496 5 -1751 7 -4021 7 -2966 9 -684 3 -3805 7 -2747 2 -1818 7 -2879 3 -3599 6 -2593 5 -2186 10 -3511 10 -1100 1 -1821 6 -3472 4 -2858 7 -2920 5 -173 2 -3517 4 -3322 9 -3410 4 -2233 7 -392 9 -2204 7 -3584 3 -356 5 -2406 3 -906 9 -2577 6 -2631 6 -444 3 -2593 9 -2065 8 -53 8 -661 2 -2175 8 -365 9 -1178 9 -2179 5 -2548 2 -4022 7 -1486 2 -3648 5 -1654 3 -2129 1 -3787 1 -3637 2 -980 8 -3142 1 -2176 1 -847 2 -659 7 -2132 1 -3193 6 -70 4 -3333 7 -3145 4 -1512 5 -292 4 -1357 6 -1603 4 -64 10 -4048 3 -1027 8 -3850 2 -3056 4 -1658 8 -3884 7 -2822 10 -2949 6 -1058 1 -2301 8 -3666 1 -1829 3 -3148 8 -2784 4 -281 8 -3434 1 -2237 1 -2413 6 -805 2 -1900 7 -669 5 -2412 5 -2964 8 -3704 3 -468 8 -3184 5 -3394 3 -3059 1 -632 3 -843 8 -1157 2 -2788 3 -1339 7 -2516 9 -650 1 -1764 2 -3082 10 -1718 5 -2034 7 -1360 4 -4023 7 -1123 6 -424 3 -1087 1 -1181 1 -2253 1 -531 2 -1485 6 -572 3 -3615 8 -839 2 -2062 2 -1142 8 -1175 5 -3997 2 -2481 3 -3086 5 -3060 4 -3474 1 -1045 1 -1009 8 -2648 3 -2472 8 -2130 3 -362 3 -1695 4 -3669 8 -3233 8 -1840 7 -3803 3 -3042 3 -882 10 -3123 1 -3752 8 -3475 2 -3648 4 -583 10 -1334 6 -612 6 -163 1 -3764 5 -1912 3 -1816 10 -2696 3 -842 6 -257 1 -4033 6 -3039 3 -2051 7 -1188 5 -2949 7 -255 9 -3385 1 -1189 2 -3189 9 -1669 2 -1227 2 -2908 7 -1812 8 -2435 4 -1842 9 -1452 2 -2649 6 -1876 6 -770 5 -2038 9 -3784 10 -1738 2 -2144 6 -214 4 -618 4 -539 2 -2360 6 -350 4 -307 4 -807 5 -1564 7 -3877 2 -3824 10 -1023 3 -2440 9 -2700 8 -2239 4 -2076 4 -3086 9 -3480 5 -2189 10 -3143 5 -3434 4 -2389 8 -3170 4 -1231 7 -1376 8 -554 7 -2525 10 -2580 8 -4069 5 -319 4 -1771 5 -2893 7 -3742 6 -1438 7 -1010 1 -726 6 -3146 9 -2214 7 -351 3 -2878 7 -1791 9 -1475 7 -1457 6 -2583 8 -1730 10 -116 9 -2972 6 -3886 9 -1110 6 -1906 10 -1406 8 -2044 2 -1333 1 -3736 5 -1384 10 -1298 3 -2877 3 -1274 4 -1711 5 -3467 9 -925 5 -504 1 -3689 6 -3026 4 -1071 3 -586 10 -2394 2 -315 2 -2946 7 -747 8 -51 4 -2317 3 -692 9 -3653 10 -3718 10 -2106 8 -3031 1 -1970 4 -1763 3 -3037 4 -1116 6 -1784 1 -3486 1 -551 2 -3451 8 -3809 2 -2572 5 -3576 1 -3229 1 -151 5 -723 3 -1748 9 -519 3 -2762 3 -2266 2 -121 7 -1905 10 -2294 9 -629 9 -2232 10 -1590 2 -2437 6 -1092 10 -1153 3 -2067 2 -1825 10 -1631 1 -103 1 -129 8 -2731 10 -1265 5 -2754 10 -3176 2 -2385 8 -1620 3 -444 4 -1231 7 -1496 1 -3681 10 -2951 3 -3148 10 -172 10 -1414 9 -3775 9 -2671 4 -697 1 -3632 5 -2440 5 -3099 2 -350 6 -3080 10 -1314 8 -2759 4 -2801 3 -3304 4 -2912 4 -2351 1 -940 6 -2725 2 -3543 9 -3971 3 -1649 3 -550 7 -125 1 -1696 9 -2743 8 -2277 1 -543 2 -1262 7 -550 7 -920 4 -2277 10 -2466 10 -2648 6 -2442 7 -1983 1 -1438 2 -2167 1 -2256 10 -183 6 -2832 8 -2037 1 -2829 7 -284 3 -138 8 -1758 1 -2109 8 -1146 5 -3817 10 -799 8 -325 4 -706 10 -1790 6 -445 2 -1734 6 -123 8 -2187 2 -1960 7 -75 2 -359 8 -802 5 -1384 3 -1140 4 -2396 5 -4087 7 -2680 7 -3182 8 -3436 6 -899 7 -1437 4 -1502 2 -2046 9 -452 9 -3709 5 -1733 9 -1547 2 -1729 10 -3826 7 -1387 8 -185 3 -513 9 -3068 10 -306 2 -1585 3 -1244 6 -977 1 -1751 8 -1350 7 -1112 8 -2683 2 -3677 6 -1196 2 -100 4 -4058 3 -897 6 -1915 7 -927 2 -480 2 -892 1 -3033 10 -2510 7 -2915 4 -1296 7 -2536 1 -255 6 -2584 1 -98 5 -1922 3 -1547 6 -3939 6 -3795 10 -3628 6 -2484 8 -661 3 -3160 1 -1991 2 -607 9 -1305 1 -1910 6 -3274 4 -2755 4 -2570 2 -2550 5 -3805 3 -3987 3 -1123 5 -1105 3 -3047 9 -3404 1 -684 8 -3036 5 -3368 8 -2208 1 -2049 1 -1761 1 -1416 10 -1559 2 -2246 5 -612 1 -92 10 -1815 5 -926 5 -1552 8 -438 8 -2828 7 -1502 9 -2894 7 -3200 4 -2227 9 -2483 7 -3918 5 -3274 3 -2318 6 -1762 2 -2416 1 -2081 6 -3583 6 -2357 8 -1319 2 -657 3 -4073 7 -1517 5 -3633 10 -1945 8 -2331 5 -3289 6 -763 5 -3895 6 -1698 3 -1658 3 -31 8 -2042 6 -2543 8 -413 8 -831 3 -2182 2 -3657 2 -3790 4 -2894 9 -1186 9 -3197 2 -1102 4 -1728 5 -689 8 -1189 6 -2347 1 -2034 9 -1046 8 -2342 3 -3731 8 -3407 5 -1307 4 -1156 5 -1946 5 -2779 8 -743 6 -334 8 -1101 9 -1831 4 -1158 8 -3068 2 -954 4 -3810 2 -467 7 -37 8 -339 1 -74 7 -2022 4 -419 1 -615 5 -1498 6 -548 10 -1759 2 -1873 2 -3670 4 -2614 9 -1278 1 -908 9 -1115 6 -2677 5 -1732 3 -3546 4 -3924 1 -2665 1 -1387 2 -3622 6 -1333 8 -1977 10 -4051 5 -2720 5 -2555 3 -607 6 -3498 4 -799 2 -3439 1 -1422 8 -3862 6 -959 1 -4029 2 -47 4 -2013 5 -3339 10 -2797 8 -3463 10 -1923 7 -2693 7 -276 5 -3223 2 -3887 6 -4060 1 -3765 3 -3480 6 -565 5 -3616 10 -3576 5 -2612 9 -4049 9 -762 5 -551 9 -1439 10 -2131 4 -544 10 -2124 7 -896 1 -163 4 -4021 5 -3887 4 -2329 4 -1714 8 -1209 5 -2238 5 -2096 10 -517 10 -2526 4 -2825 7 -2802 6 -3625 2 -255 6 -3419 7 -2404 9 -1538 6 -3235 2 -2416 9 -30 3 -3790 6 -977 10 -590 8 -535 9 -542 9 -553 3 -3670 5 -1373 6 -123 7 -735 9 -1218 9 -2397 8 -2703 9 -2846 9 -827 9 -491 1 -2986 10 -3797 3 -2170 2 -1397 3 -1185 2 -49 3 -1207 9 -3167 1 -466 7 -1659 4 -3479 9 -874 8 -3136 2 -1377 9 -879 2 -2961 4 -4020 10 -642 1 -2826 5 -3641 8 -3631 5 -1084 7 -324 8 -1660 6 -3774 10 -1663 6 -3907 1 -4027 1 -290 5 -963 6 -2344 7 -3325 9 -87 10 -1110 10 -1760 1 -825 9 -3647 9 -1213 5 -849 7 -1494 5 -3980 6 -922 8 -586 10 -1807 1 -3755 6 -2477 9 -302 5 -2174 9 -340 3 -2047 10 -1973 9 -3168 5 -2419 1 -3039 1 -4020 9 -2298 5 -1796 4 -3313 6 -542 4 -2913 2 -2069 4 -2407 1 -3566 7 -2190 10 -381 6 -2826 6 -2811 3 -305 2 -608 5 -3637 10 -617 2 -994 7 -1737 5 -761 4 -3223 2 -4070 3 -897 4 -2223 9 -2796 1 -2449 5 -1933 10 -450 9 -516 6 -1468 4 -2999 2 -3656 1 -3197 5 -2286 1 -3695 7 -3210 6 -2723 10 -930 2 -796 8 -2608 2 -3529 10 -2512 5 -3975 10 -1475 10 -1425 9 -2602 2 -2782 9 -1919 5 -1362 9 -214 3 -1476 4 -3714 4 -47 5 -1776 5 -714 5 -2815 2 -716 8 -1040 9 -415 1 -1683 5 -3396 1 -876 7 -2724 6 -1825 4 -2314 10 -3581 2 -2430 4 -282 6 -862 6 -2300 10 -2698 8 -3704 9 -1554 6 -939 10 -3315 9 -1561 3 -838 5 -2454 8 -2397 6 -1186 4 -1103 4 -2363 7 -698 5 -684 4 -3117 2 -2500 4 -3798 4 -4080 2 -2324 2 -739 6 -505 7 -2872 4 -476 7 -2891 10 -3213 10 -3634 4 -147 2 -282 3 -25 10 -2759 6 -465 1 -528 4 -2579 8 -2013 5 -3811 3 -694 4 -1180 6 -791 5 -3556 4 -3981 2 -3378 5 -3526 7 -2021 3 -2459 10 -3528 10 -3855 10 -3024 1 -3266 8 -1298 5 -2308 1 -236 7 -3047 5 -1001 7 -3633 3 -105 7 -2072 2 -2751 2 -1806 8 -4014 9 -720 4 -1813 1 -3026 4 -648 6 -2818 5 -1021 9 -1180 9 -1859 4 -1921 5 -1925 3 -477 5 -3051 9 -3474 4 -2718 10 -695 2 -2738 3 -181 9 -2138 4 -1474 9 -3440 10 -2442 10 -3753 7 -541 3 -1271 9 -2280 4 -1212 2 -3028 8 -3066 10 -3241 5 -1439 2 -3323 9 -3958 10 -2619 5 -4056 6 -3306 2 -2598 4 -1865 10 -300 8 -3693 7 -2055 4 -710 7 -2292 7 -3443 1 -498 8 -3295 3 -1591 1 -2208 6 -4032 7 -1800 5 -352 3 -780 2 -1835 2 -65 9 -956 2 -2303 3 -1494 8 -2362 7 -272 3 -2916 3 -2190 1 -633 4 -1862 2 -806 8 -3214 7 -15 10 -789 3 -1854 9 -575 2 -1241 8 -3633 7 -2771 7 -1776 7 -2664 1 -2994 9 -1300 8 -2878 4 -1185 9 -3652 2 -990 3 -205 5 -3316 5 -3237 9 -2604 4 -441 2 -241 8 -805 4 -3357 5 -1179 8 -2796 10 -3949 2 -530 9 -2938 6 -165 8 -3716 1 -3697 6 -3085 1 -29 8 -2242 9 -1622 9 -877 9 -1876 8 -329 2 -508 6 -3600 10 -1514 7 -3301 10 -1829 1 -2099 3 -2960 3 -3851 6 -1275 9 -2714 6 -2747 7 -294 10 -1226 5 -3453 2 -3326 8 -263 2 -2873 10 -3305 2 -417 10 -141 4 -1773 6 -3875 7 -2042 6 -2796 10 -1964 8 -2719 4 -2902 3 -2893 7 -239 10 -344 6 -2385 8 -472 9 -239 5 -2319 5 -2847 2 -2649 8 -3116 1 -347 6 -1848 3 -3705 4 -3340 8 -751 3 -695 9 -1393 7 -2153 1 -2148 1 -1848 4 -659 4 -2177 1 -2038 10 -2754 5 -1465 9 -3122 5 -2960 3 -1113 2 -3649 3 -3225 6 -2647 9 -1474 6 -2094 4 -740 1 -2325 5 -1224 7 -3048 4 -457 6 -2720 4 -3779 6 -2298 10 -1805 7 -1752 7 -3417 3 -3801 4 -2776 4 -2012 6 -3307 3 -2844 7 -2872 1 -957 4 -2252 4 -3174 9 -3675 1 -2599 8 -2037 6 -3173 9 -3304 3 -3000 5 -696 1 -3583 10 -2956 5 -899 7 -1427 7 -2211 10 -3065 2 -3351 3 -797 10 -1283 7 -120 8 -3194 3 -729 4 -2692 10 -3422 7 -2526 8 -3354 9 -790 3 -259 1 -55 3 -505 5 -68 8 -540 1 -3416 8 -3584 3 -1268 7 -729 2 -1840 3 -2573 2 -3843 3 -3823 9 -2592 8 -3453 4 -2886 3 -1236 5 -1562 6 -2156 7 -613 4 -2763 7 -912 1 -585 7 -2341 2 -754 7 -1028 1 -2006 4 -1767 5 -1965 3 -3078 8 -3587 2 -1418 2 -1086 9 -2082 9 -1415 7 -790 5 -3031 5 -1441 10 -3496 7 -966 1 -3562 5 -2816 8 -938 3 -2216 1 -1150 5 -1925 1 -1068 6 -2860 2 -1014 7 -469 6 -2987 5 -473 1 -3009 9 -917 10 -2700 10 -3394 3 -2324 8 -736 7 -2990 7 -3043 9 -896 8 -1146 1 -1360 10 -3906 6 -348 7 -3786 8 -1004 5 -2974 3 -558 9 -2854 5 -2777 7 -173 7 -3332 4 -450 7 -2464 9 -1195 9 -3235 7 -3336 2 -2254 6 -818 3 -3798 1 -810 8 -3606 2 -3025 6 -778 6 -977 7 -3549 2 -4015 3 -2736 7 -3550 6 -3889 4 -2921 5 -3176 3 -4 6 -1305 4 -4040 1 -1225 1 -3314 6 -1222 9 -1197 8 -3932 5 -3991 6 -493 7 -2644 7 -241 8 -562 5 -1097 3 -2632 6 -2480 3 -3129 5 -3096 2 -3585 8 -655 9 -2600 6 -491 4 -2467 2 -495 9 -3969 6 -3467 10 -45 2 -602 3 -763 6 -1876 10 -1188 8 -3089 4 -2316 1 -3761 10 -228 1 -3596 9 -215 1 -546 2 -1716 7 -1940 4 -2585 2 -1780 7 -262 5 -2560 7 -1845 6 -86 1 -1080 4 -1350 10 -606 9 -1391 7 -2634 8 -127 10 -2256 3 -2794 9 -2617 3 -1509 10 -2103 6 -1893 2 -238 5 -135 10 -3003 2 -2917 10 -3425 2 -2607 2 -2136 3 -2216 5 -1414 2 -1484 9 -3474 6 -3871 3 -78 1 -1613 4 -892 10 -3655 9 -3129 6 -832 9 -2100 5 -4092 3 -2112 1 -2649 2 -676 10 -3347 10 -424 9 -860 4 -3666 4 -1185 1 -1872 1 -1811 10 -213 9 -144 4 -3984 8 -3748 4 -1716 2 -2523 9 -482 4 -2002 1 -1501 6 -3333 5 -1641 9 -1867 7 -3138 10 -330 4 -3154 7 -710 3 -2139 1 -3269 3 -1694 3 -1437 5 -2333 4 -3433 4 -4 5 -2452 7 -3848 10 -944 7 -1822 7 -4025 6 -3936 9 -1309 10 -1496 1 -3341 6 -1435 3 -803 6 -3276 4 -971 8 -774 3 -2286 8 -1316 10 -3276 1 -797 5 -503 3 -4020 8 -2517 1 -452 6 -2644 10 -2338 9 -3013 10 -997 5 -3485 3 -556 2 -1037 5 -3610 9 -211 4 -4015 10 -831 10 -1715 3 -1365 7 -1098 2 -487 10 -111 1 -2022 10 -3957 7 -1276 1 -3879 9 -3127 2 -1973 9 -3891 10 -2944 6 -3106 2 -3939 3 -386 7 -1665 10 -2078 9 -1125 10 -1577 7 -3543 7 -853 3 -3798 8 -3801 7 -3169 6 -2880 1 -1540 10 -1518 7 -2083 9 -1616 9 -2814 7 -1787 8 -3727 4 -3708 6 -2186 7 -1693 8 -1577 10 -2225 3 -2065 4 -1931 7 -1138 1 -3381 3 -2675 1 -1153 1 -1507 4 -347 7 -1773 9 -2601 3 -133 1 -3813 10 -3061 1 -163 7 -168 3 -2578 3 -4076 2 -734 2 -999 6 -1907 2 -3972 4 -493 10 -870 1 -1613 7 -2118 7 -1742 9 -1165 9 -2074 10 -3320 3 -874 1 -2703 3 -1014 8 -1310 5 -3038 8 -2369 9 -984 9 -3684 4 -961 4 -1278 2 -1791 3 -3968 9 -1462 6 -2801 4 -146 6 -3717 8 -3445 10 -941 4 -1709 8 -3112 2 -3192 7 -3353 4 -2564 8 -639 6 -2140 7 -4056 4 -854 4 -719 9 -780 10 -2091 7 -2748 7 -1123 6 -773 4 -2572 8 -3240 6 -3156 9 -1985 4 -2845 2 -3011 2 -1830 9 -2768 7 -1079 8 -23 5 -1702 8 -3920 7 -2925 6 -2318 7 -3833 2 -1659 4 -164 9 -455 1 -3237 6 -3397 7 -1751 9 -1247 8 -3951 8 -659 5 -2424 6 -894 8 -4082 7 -2904 10 -3148 5 -444 8 -331 3 -3653 4 -166 4 -1331 7 -2053 8 -3411 6 -1266 7 -3971 1 -67 10 -866 9 -479 2 -2452 3 -434 5 -1926 2 -2563 3 -2434 5 -2808 7 -3612 4 -509 1 -146 5 -112 5 -726 1 -5 7 -1767 9 -213 5 -2630 6 -914 3 -2248 3 -295 3 -3251 10 -3771 3 -2556 5 -3851 3 -1227 4 -1444 10 -2455 4 -3500 9 -2382 4 -3745 1 -4040 10 -239 2 -3552 2 -1812 1 -404 9 -879 6 -593 2 -2620 8 -960 9 -2935 5 -3247 10 -923 1 -3362 4 -2746 4 -563 3 -228 9 -3501 6 -699 6 -72 7 -2701 2 -1265 3 -350 3 -213 1 -3267 7 -2167 4 -2325 1 -2896 8 -3789 9 -1296 4 -2459 3 -3485 3 -3459 7 -2028 10 -3655 4 -1965 9 -1673 6 -1843 10 -3491 5 -1532 9 -2204 4 -1427 10 -2541 2 -1947 5 -3718 6 -1105 5 -2498 3 -3322 6 -1985 5 -434 5 -2948 5 -1763 9 -248 2 -1467 7 -1719 4 -263 7 -3514 8 -2057 4 -1461 6 -993 10 -417 4 -1400 7 -1956 8 -3824 6 -964 10 -3822 8 -3459 8 -3676 1 -2537 6 -2853 7 -3629 1 -2855 8 -1975 1 -1607 1 -855 5 -1423 7 -1692 7 -1080 3 -28 9 -86 4 -3955 8 -2773 6 -1108 7 -55 6 -3905 7 -3796 7 -3143 8 -3808 8 -1687 5 -2304 1 -1328 6 -1150 9 -323 10 -2591 9 -2083 8 -1145 9 -3254 7 -2660 6 -2134 6 -317 2 -3971 6 -268 4 -155 10 -1067 6 -2810 7 -3214 3 -717 2 -3692 4 -3479 2 -2901 5 -2943 6 -1958 2 -3965 10 -1896 2 -1538 1 -2294 5 -3815 7 -1433 8 -2680 7 -1012 9 -191 8 -238 8 -3300 5 -514 10 -1643 8 -3348 8 -3547 7 -2874 8 -3090 3 -305 1 -3842 6 -3085 4 -2127 10 -3843 10 -3473 7 -2005 8 -1809 5 -3217 1 -2968 1 -3422 7 -76 3 -3216 4 -1470 1 -3350 2 -221 2 -382 4 -1982 10 -244 1 -1795 1 -1951 8 -1818 4 -393 9 -1339 2 -442 8 -479 9 -2304 1 -1068 5 -827 7 -2639 6 -2554 6 -1999 6 -4078 6 -1905 10 -3957 3 -2424 7 -1143 5 -486 1 -2832 6 -157 10 -4082 9 -1143 10 -649 5 -2647 9 -3693 2 -3595 4 -1778 9 -2170 9 -3830 2 -259 10 -1417 2 -1061 1 -2146 10 -1642 9 -463 8 -2849 5 -2323 5 -3355 5 -2378 2 -990 8 -2692 10 -879 7 -1674 8 -261 7 -3914 10 -1842 2 -887 4 -4036 7 -227 8 -1592 6 -720 1 -1761 6 -1326 6 -2286 10 -386 9 -2863 6 -78 6 -3986 9 -307 10 -445 9 -3940 7 -529 5 -939 4 -1459 4 -966 4 -3798 9 -683 2 -1323 8 -313 10 -3093 6 -420 2 -1586 10 -1256 5 -1726 5 -1772 1 -1464 6 -3980 10 -2147 2 -3727 8 -641 8 -1577 10 -1207 8 -4035 4 -562 2 -2492 8 -72 4 -1535 6 -2706 1 -2845 9 -1676 4 -730 3 -1964 9 -3894 9 -2393 6 -2790 2 -869 7 -1139 10 -1784 1 -2365 7 -1750 1 -88 1 -3565 5 -1199 6 -2526 4 -3472 9 -1295 1 -2082 1 -2587 5 -3150 3 -1238 1 -2562 8 -3926 5 -2277 10 -1317 10 -764 4 -1292 3 -2153 3 -3582 2 -1921 9 -256 6 -1318 1 -1202 1 -177 4 -1154 9 -2986 9 -3936 6 -3273 5 -290 6 -1024 10 -2780 4 -3986 5 -516 10 -249 3 -2905 10 -2844 8 -2862 7 -2524 1 -2837 5 -3402 8 -3161 10 -2999 9 -2960 10 -3824 3 -2495 10 -1385 2 -1335 8 -813 10 -1090 5 -3901 7 -1055 6 -656 9 -2570 4 -3329 5 -569 9 -2055 2 -2018 5 -306 7 -323 3 -2866 5 -2095 1 -3068 4 -3174 3 -571 4 -1682 3 -1345 2 -2909 1 -656 9 -1484 4 -3164 2 -2571 10 -3966 10 -3340 10 -3728 8 -7 2 -2608 4 -2421 7 -2362 1 -3003 10 -3149 2 -903 4 -3827 6 -1493 7 -1841 2 -858 8 -1451 1 -3172 3 -1973 1 -3439 3 -2296 3 -1634 2 -2457 1 -532 10 -1046 2 -3357 2 -2972 8 -825 9 -3344 4 -3911 4 -1051 4 -574 7 -3352 3 -534 4 -3882 1 -2328 7 -517 7 -3393 4 -1929 2 -1767 10 -733 5 -2664 1 -1410 5 -444 6 -1540 6 -968 9 -2640 6 -1875 8 -1901 9 -3463 6 -3969 6 -351 2 -3927 9 -909 8 -1050 7 -2546 1 -3510 4 -249 1 -3123 6 -163 3 -549 1 -3607 10 -1638 7 -3195 6 -3973 1 -104 5 -3502 9 -3134 9 -2764 1 -2263 9 -3943 7 -52 3 -849 1 -1057 2 -1287 5 -3156 5 -1769 7 -3908 3 -1059 1 -1455 4 -2934 2 -25 1 -2676 4 -3981 6 -3527 7 -1243 4 -1259 2 -3833 8 -1258 3 -772 6 -1262 7 -1837 7 -3722 5 -1901 7 -3677 10 -613 2 -3232 3 -776 10 -1169 3 -2073 2 -839 2 -617 8 -1811 5 -3395 1 -1528 3 -1681 2 -2428 4 -1405 4 -3810 3 -3260 6 -3019 9 -844 1 -74 10 -102 10 -3149 9 -1048 10 -808 9 -36 2 -2902 6 -2605 5 -1523 2 -2765 6 -1940 6 -3654 5 -3120 9 -2253 5 -1651 5 -757 6 -1246 9 -3442 2 -1811 4 -213 3 -3163 8 -3938 9 -405 2 -3465 10 -2497 9 -3963 4 -2858 3 -2911 1 -2586 4 -4093 9 -283 9 -3429 5 -74 6 -2552 8 -837 6 -3303 5 -727 7 -3844 5 -3646 2 -1480 10 -190 7 -1495 9 -2341 7 -2280 5 -3956 4 -3860 5 -2735 2 -2861 7 -2927 1 -2012 5 -477 7 -99 5 -3191 4 -813 3 -3000 8 -3213 5 -1658 5 -450 8 -869 3 -3025 7 -1170 2 -3437 6 -3514 5 -2433 5 -1333 6 -2050 7 -949 8 -2985 1 -3727 5 -889 9 -1630 3 -3443 4 -737 7 -1991 8 -1580 5 -3192 2 -2548 1 -968 7 -151 2 -535 7 -3856 5 -1164 10 -411 8 -1538 1 -2929 5 -1978 2 -58 10 -844 4 -1501 9 -1059 5 -2496 7 -343 2 -2893 8 -3966 7 -2075 1 -3105 10 -756 8 -1687 1 -3754 4 -3947 3 -3306 10 -1523 7 -3955 9 -6 9 -1945 1 -1488 10 -2653 8 -3688 8 -2749 8 -3167 8 -79 2 -1526 2 -1585 7 -2095 5 -768 1 -1069 4 -3216 6 -1781 3 -2165 3 -2393 5 -1828 4 -2526 1 -1814 2 -1977 9 -313 2 -1930 7 -3803 3 -2629 5 -452 9 -353 8 -961 9 -880 1 -2662 7 -3725 4 -1329 5 -1008 10 -763 5 -2644 8 -4013 5 -2516 7 -3550 5 -3797 7 -833 6 -3309 4 -2095 2 -439 1 -3984 2 -2296 7 -2670 4 -3352 8 -1106 7 -2232 3 -3932 4 -3922 10 -1295 4 -1182 4 -594 9 -815 1 -527 3 -3211 10 -1929 9 -1906 5 -280 1 -464 5 -2700 1 -2133 9 -3273 8 -4053 2 -2384 2 -2509 5 -1247 1 -3745 2 -910 1 -1524 5 -2412 6 -1260 3 -3277 2 -2078 2 -1625 10 -3767 10 -1966 1 -2711 10 -2454 7 -196 1 -1331 5 -659 1 -118 2 -3428 1 -749 9 -826 2 -2708 6 -1021 5 -407 2 -149 7 -3176 3 -3310 3 -3951 1 -2425 5 -1010 6 -119 9 -2677 8 -3760 8 -3345 8 -2116 6 -1001 5 -730 2 -1085 1 -2347 7 -2704 7 -3235 4 -3178 9 -2172 6 -1846 5 -2144 3 -1166 6 -1492 6 -3283 5 -3655 8 -1124 2 -64 1 -212 2 -1912 1 -1218 9 -1051 1 -996 6 -3157 5 -3308 2 -1891 1 -1235 6 -937 1 -1820 1 -597 1 -3382 1 -1882 1 -4090 3 -1612 2 -1884 1 -1009 4 -2989 7 -196 4 -1635 8 -3632 4 -253 9 -2051 1 -1045 9 -2473 9 -2292 7 -936 5 -1725 4 -327 5 -665 8 -2335 7 -2937 9 -2483 6 -3251 4 -407 3 -1280 2 -3407 10 -3574 10 -3480 7 -238 4 -3999 6 -618 4 -3899 5 -1123 9 -1492 7 -2447 8 -1335 3 -826 9 -2229 4 -3643 10 -2979 5 -4025 1 -2136 2 -2100 2 -1338 8 -2546 7 -3854 10 -1368 9 -2271 5 -2977 5 -1645 2 -1515 9 -236 2 -2812 8 -175 9 -627 6 -2281 2 -1236 2 -36 10 -2909 3 -3086 8 -3846 1 -1818 1 -332 5 -2912 9 -869 9 -3898 4 -1285 3 -172 6 -812 2 -2672 10 -2888 7 -1850 3 -3499 8 -1832 1 -1431 8 -2801 1 -1080 10 -443 6 -3893 5 -185 3 -2316 6 -50 6 -3849 9 -1137 2 -2962 2 -4079 10 -4014 3 -1702 3 -4055 9 -971 7 -2515 7 -2299 3 -1150 9 -2989 9 -626 3 -1572 7 -2233 5 -1392 5 -1257 3 -415 4 -598 3 -109 2 -3403 6 -3411 9 -1894 4 -678 2 -461 6 -2764 10 -3142 5 -2613 8 -2219 3 -3810 8 -3510 9 -1744 7 -3700 8 -1986 2 -2106 3 -756 2 -2888 1 -1485 8 -1857 8 -1187 9 -355 7 -3227 3 -4019 3 -2485 8 -2139 9 -3517 3 -3665 10 -3618 2 -3358 1 -1591 9 -1886 4 -746 5 -1721 10 -2471 2 -3938 9 -2506 2 -257 6 -3861 3 -3588 4 -3619 4 -2627 4 -2528 10 -1881 1 -283 5 -108 5 -583 1 -852 9 -3783 10 -1538 10 -3931 5 -545 8 -3042 1 -1533 9 -1555 2 -3840 5 -1863 9 -530 7 -1842 10 -3966 10 -699 2 -3960 2 -1644 4 -2685 1 -1162 6 -1059 6 -3406 3 -2804 10 -1028 1 -3754 2 -3937 2 -4020 10 -2036 4 -1653 6 -449 10 -739 1 -2067 3 -681 3 -296 3 -1138 9 -474 7 -365 1 -1211 1 -2919 4 -223 8 -3724 7 -3490 6 -3310 4 -1509 2 -2406 5 -3450 9 -3188 3 -2492 4 -3031 3 -3321 1 -2125 10 -4070 4 -2449 6 -1269 7 -3132 1 -733 10 -120 3 -2009 7 -4013 5 -17 10 -2805 7 -2016 6 -3240 7 -2478 8 -3622 8 -1511 8 -1567 6 -2208 10 -2421 6 -3722 8 -2612 1 -1459 5 -863 6 -3812 10 -2234 2 -1230 7 -3000 2 -1165 9 -472 1 -2724 2 -18 1 -915 10 -3744 8 -2865 4 -520 1 -2297 9 -3469 8 -3748 6 -3301 8 -1674 6 -1260 4 -677 9 -2398 4 -3377 6 -1748 1 -2111 2 -2876 7 -3086 1 -1776 2 -3505 7 -2367 7 -3830 8 -3390 3 -2124 8 -3984 7 -2916 10 -2396 10 -1677 4 -3013 6 -3362 10 -1284 2 -3097 5 -2508 1 -2664 5 -721 5 -3878 2 -3689 9 -1648 7 -2708 4 -3937 7 -3415 10 -2761 3 -1848 4 -3019 4 -2555 3 -111 6 -3243 6 -3377 9 -1007 2 -3769 3 -75 1 -1195 8 -3968 1 -1205 5 -3756 2 -1689 7 -2596 7 -2909 10 -3807 2 -2871 6 -891 5 -3409 10 -1890 9 -3724 9 -3611 6 -1052 1 -1946 7 -1375 3 -3432 3 -3178 8 -2517 1 -3172 3 -3873 8 -1527 4 -1220 5 -85 6 -3112 7 -2539 6 -980 5 -1022 2 -1934 10 -58 10 -1859 7 -143 3 -706 2 -776 6 -4088 7 -2987 8 -1736 2 -501 7 -416 5 -3276 7 -77 7 -133 8 -3566 8 -3177 7 -587 3 -2859 10 -656 4 -2130 8 -2668 9 -1738 1 -2399 10 -2485 4 -3758 8 -1255 3 -2870 8 -3970 9 -2660 1 -2949 8 -582 10 -3207 2 -2460 6 -1037 2 -2300 8 -1438 4 -4064 2 -1513 3 -47 4 -494 6 -206 7 -1883 5 -1907 2 -736 4 -4037 3 -3008 7 -2975 10 -2136 4 -3351 1 -1895 4 -2824 5 -1546 8 -1755 6 -3513 5 -3462 5 -1907 3 -3329 5 -1296 3 -2762 9 -2642 9 -82 6 -2056 5 -3469 9 -605 6 -3834 3 -1662 8 -2204 5 -2231 7 -146 4 -2484 6 -3002 1 -1163 3 -624 6 -3993 2 -2431 3 -1430 9 -1017 7 -3450 2 -3416 3 -3215 4 -2245 4 -2873 1 -2984 9 -439 6 -1604 8 -2761 6 -3029 1 -3048 4 -1137 10 -1633 9 -227 4 -1271 2 -2495 4 -1169 9 -1108 9 -2174 10 -760 1 -1547 4 -3924 9 -604 7 -3079 6 -885 2 -2456 3 -1240 5 -1766 4 -1145 8 -2033 5 -243 9 -741 9 -1280 8 -268 7 -1348 10 -2468 6 -1947 2 -3334 6 -2374 8 -1100 3 -1003 2 -1812 1 -1689 7 -2109 2 -869 10 -2552 9 -2960 5 -2530 9 -1542 8 -136 1 -106 1 -3308 3 -3104 1 -618 8 -2468 3 -274 9 -2516 2 -2462 10 -167 9 -1544 3 -24 3 -3147 10 -1578 3 -1684 10 -1813 3 -5 1 -3684 4 -597 4 -14 4 -3326 2 -3728 1 -3867 3 -1580 3 -2587 10 -258 10 -669 1 -3150 1 -2015 7 -3335 4 -233 9 -2223 3 -1279 1 -2399 8 -1167 10 -764 6 -243 10 -3235 10 -2591 7 -1599 3 -359 9 -2827 4 -3682 1 -1980 8 -3899 7 -2449 1 -1698 3 -2179 4 -827 1 -725 10 -1837 9 -994 6 -1699 3 -2040 10 -1349 5 -3794 6 -1975 3 -899 9 -1515 2 -2600 10 -786 1 -1387 3 -2082 5 -3476 8 -821 6 -3768 2 -3541 4 -3394 9 -101 1 -1668 4 -3432 2 -1090 6 -2710 7 -2464 4 -783 4 -1648 6 -1163 6 -3060 8 -1299 8 -387 10 -3744 6 -86 1 -3529 8 -1085 2 -478 5 -2557 1 -1208 8 -3767 4 -3163 2 -3179 4 -2419 6 -4022 9 -945 6 -2826 7 -2412 3 -2783 7 -2515 10 -3818 5 -42 8 -2945 10 -659 2 -612 4 -2484 10 -507 4 -2027 10 -509 7 -1775 7 -219 10 -3733 5 -1724 3 -2606 3 -270 5 -3653 1 -446 9 -2719 7 -4095 9 -2103 8 -2007 6 -3257 7 -859 1 -3995 6 -2388 6 -1915 5 -3262 8 -2459 6 -2279 6 -3530 2 -2919 8 -2965 6 -34 2 -2017 5 -1253 7 -3971 4 -2495 7 -2716 9 -1389 4 -4077 1 -1104 4 -1028 4 -3428 5 -1546 4 -299 6 -3312 6 -1072 5 -2479 4 -2192 1 -2238 1 -3105 10 -1571 6 -1337 2 -2908 10 -1875 2 -1750 5 -401 7 -1336 1 -391 3 -2926 6 -1003 8 -4024 3 -3327 10 -1976 7 -83 7 -2317 4 -1943 9 -2391 3 -1602 2 -3199 10 -814 5 -1774 1 -3056 9 -3815 3 -1400 3 -646 5 -1686 4 -490 2 -2353 2 -277 3 -2074 9 -3402 8 -3429 9 -2517 5 -1931 5 -1980 8 -2791 1 -3549 2 -2698 4 -2777 6 -3019 4 -4079 9 -792 5 -1955 5 -3295 9 -1284 7 -3477 1 -1507 8 -1621 2 -392 2 -3275 7 -928 7 -2196 8 -303 3 -1769 5 -1724 1 -3960 1 -3209 6 -3037 1 -1241 10 -3146 4 -782 10 -2661 5 -2943 8 -3586 6 -340 9 -2135 7 -1911 9 -2699 6 -95 8 -3039 2 -2367 7 -2958 5 -3882 9 -3449 8 -243 10 -552 9 -2760 8 -2455 10 -3781 10 -947 3 -2362 3 -1366 5 -2659 1 -1249 6 -2635 6 -1623 7 -3472 1 -2849 5 -1229 4 -2687 10 -1355 2 -1584 9 -3270 2 -3116 9 -2472 2 -2153 9 -3907 7 -621 2 -3047 5 -3107 6 -3363 7 -3685 2 -1547 1 -979 7 -974 3 -2389 3 -2831 8 -2506 3 -1606 3 -1470 5 -1346 4 -591 10 -1795 1 -1332 7 -4040 6 -297 8 -1954 4 -3511 6 -1782 7 -1520 9 -2969 5 -2671 9 -3977 7 -2638 4 -3619 7 -786 3 -3257 3 -763 4 -2652 6 -155 10 -599 1 -3494 7 -552 3 -3219 3 -1255 3 -1876 6 -3060 1 -900 6 -2407 3 -1507 1 -792 8 -1845 10 -2111 2 -2230 5 -2385 6 -2740 6 -2447 9 -911 1 -2998 4 -1109 4 -869 5 -1662 6 -4048 9 -914 8 -2359 10 -216 6 -378 8 -2837 1 -3926 10 -3501 3 -3393 6 -4007 1 -1902 4 -3258 5 -538 4 -2889 5 -2581 8 -2136 9 -719 5 -2366 6 -1234 6 -2322 10 -3818 3 -1252 1 -1789 6 -1990 9 -2398 1 -1553 6 -2756 9 -473 1 -3485 7 -3505 6 -1284 3 -2581 5 -1242 6 -1747 1 -942 9 -1096 3 -1135 3 -1890 1 -1320 8 -1667 1 -1116 2 -3184 7 -939 9 -3598 3 -526 4 -1118 1 -1665 1 -1227 10 -1265 4 -3687 10 -2978 10 -2239 2 -815 3 -2967 7 -1659 8 -3103 4 -1883 1 -3833 8 -1532 7 -643 7 -617 3 -3370 8 -3932 8 -747 4 -2065 4 -3693 10 -2748 8 -2243 1 -1536 4 -3248 9 -1416 4 -3548 5 -2847 3 -2237 4 -1162 6 -3825 5 -2114 10 -3252 6 -1964 9 -3489 3 -562 8 -202 1 -1575 3 -200 2 -3315 9 -1280 3 -2739 3 -1078 7 -3897 2 -1554 5 -1255 7 -1343 4 -1977 5 -1749 6 -2750 3 -2046 9 -3983 10 -3405 7 -922 5 -1938 2 -3494 6 -3635 2 -3980 3 -2397 8 -3953 1 -60 7 -1387 6 -362 3 -2219 2 -1653 10 -1805 10 -3002 8 -2108 6 -3855 7 -171 5 -3775 4 -1388 4 -709 4 -699 10 -1828 5 -3516 8 -312 4 -2154 10 -2842 7 -1965 3 -1431 9 -1067 8 -3379 9 -3313 4 -1866 9 -886 3 -3556 9 -3018 10 -179 8 -3483 6 -2181 7 -265 8 -2894 4 -760 9 -112 6 -2990 9 -850 4 -2042 10 -3815 5 -2783 10 -675 3 -2881 8 -677 6 -1226 4 -3428 5 -359 5 -579 3 -1254 6 -1816 6 -570 7 -3744 4 -44 9 -3334 5 -3261 8 -1909 6 -2931 1 -1659 3 -492 7 -1073 4 -887 2 -841 2 -2602 2 -3509 8 -603 10 -1714 4 -1821 3 -809 9 -224 1 -3666 3 -3812 6 -3970 3 -3649 6 -50 3 -3019 4 -337 5 -2172 7 -1856 3 -3381 3 -2345 5 -2569 8 -1495 1 -143 4 -822 3 -1152 4 -325 6 -1158 4 -969 1 -2245 7 -4003 2 -1184 8 -1384 7 -2700 5 -638 2 -2678 5 -318 9 -285 4 -266 6 -4054 4 -2122 6 -2459 1 -3677 8 -2581 6 -1368 8 -2160 3 -3780 4 -620 1 -2793 4 -457 7 -3707 3 -857 5 -2506 9 -99 10 -1180 9 -2180 9 -1890 7 -4050 3 -1183 5 -2802 1 -3624 2 -1006 6 -2492 5 -1166 5 -3142 7 -543 7 -2801 3 -2949 10 -1413 8 -2872 6 -2388 10 -1403 6 -2665 8 -2479 9 -3318 7 -110 8 -3980 6 -738 10 -3142 10 -1171 10 -790 10 -3130 10 -964 8 -606 8 -2039 1 -3452 8 -1297 5 -3460 2 -3782 6 -1166 9 -4016 10 -2143 1 -4041 10 -2028 9 -3978 6 -3559 7 -1250 5 -2541 9 -2820 7 -1870 1 -560 3 -819 7 -1609 7 -2502 9 -390 10 -1708 3 -118 1 -521 6 -3816 6 -3859 4 -1345 6 -2919 9 -2643 7 -1412 5 -1989 10 -2703 6 -2515 1 -2868 3 -3693 7 -455 7 -1093 2 -2679 2 -2363 9 -3000 1 -2765 5 -290 7 -1684 7 -3626 6 -3971 5 -1148 6 -2333 3 -747 9 -2110 2 -3879 6 -2762 9 -2628 2 -1588 3 -1640 5 -2527 8 -1003 6 -3761 8 -2203 1 -941 5 -1764 10 -1998 7 -1486 5 -1778 9 -1418 6 -337 1 -3546 9 -362 5 -2899 7 -3449 4 -3803 8 -950 7 -1249 8 -2378 9 -99 10 -1556 4 -2744 2 -3619 2 -2238 9 -3069 9 -3224 7 -1837 7 -2342 1 -1946 9 -4086 6 -1742 9 -1820 1 -1183 10 -1308 4 -3928 6 -1287 9 -3580 8 -44 1 -2977 6 -1350 9 -1425 7 -1066 2 -2408 9 -1575 2 -2153 5 -3102 4 -135 9 -2758 3 -3540 9 -2125 2 -3796 5 -1795 4 -2676 8 -2096 10 -1415 9 -1715 7 -698 4 -3273 7 -1510 4 -2942 7 -2997 9 -2941 7 -2202 3 -4062 10 -590 1 -3500 5 -627 10 -2489 2 -581 3 -1042 8 -1675 6 -43 7 -131 2 -3194 2 -819 4 -1607 7 -3809 1 -2648 8 -3470 2 -2942 9 -2001 5 -1924 7 -3722 5 -222 9 -3344 5 -3909 2 -2361 2 -2594 4 -1451 9 -3194 6 -1582 4 -120 9 -2885 1 -2690 5 -1055 3 -2236 2 -3249 2 -1360 7 -2533 9 -1395 8 -3741 7 -1236 4 -2317 1 -1469 10 -3676 5 -1420 7 -1500 5 -2717 6 -2934 2 -2777 9 -1271 6 -1889 1 -1360 4 -1969 2 -1 8 -1097 2 -285 2 -3900 9 -98 6 -2889 8 -1734 3 -1370 4 -3999 2 -2008 2 -3511 9 -978 6 -3747 7 -1106 8 -804 3 -2414 6 -1744 1 -3141 4 -2357 5 -2289 7 -628 6 -2054 3 -1367 8 -1695 2 -4061 4 -1786 5 -3531 7 -33 5 -742 1 -2882 7 -2326 9 -3730 8 -2581 5 -309 10 -1523 5 -2461 9 -1090 10 -245 9 -1961 8 -3826 4 -54 4 -1745 10 -505 6 -2734 4 -2879 7 -1429 9 -1780 10 -3763 8 -2085 2 -3185 5 -2030 3 -2534 4 -919 4 -2008 5 -2816 5 -27 10 -416 3 -2021 5 -243 10 -40 8 -2354 7 -1027 7 -4095 2 -2714 8 -470 10 -588 4 -772 2 -3791 7 -3294 5 -835 5 -449 8 -3746 3 -3762 4 -1143 1 -3125 7 -3422 8 -1590 4 -685 9 -4014 7 -1522 1 -2477 1 -214 7 -1584 3 -519 8 -906 5 -1375 1 -1575 2 -893 9 -3991 2 -4075 3 -2622 7 -153 7 -3756 6 -3697 7 -1795 10 -595 8 -629 9 -2880 9 -1810 5 -588 8 -2662 2 -1139 10 -569 5 -1782 2 -3787 7 -3767 1 -1391 3 -627 8 -2146 8 -2783 6 -2053 9 -1052 3 -1296 7 -634 10 -705 6 -2795 4 -2854 2 -1760 1 -3363 10 -1466 5 -56 5 -851 1 -2764 7 -1497 3 -1736 5 -1941 6 -2446 10 -241 2 -229 10 -3804 6 -3108 5 -1487 9 -3061 1 -858 5 -2141 9 -2349 4 -3767 9 -1256 4 -1550 6 -3940 3 -1370 8 -1105 10 -3710 8 -1315 6 -2278 9 -997 2 -214 7 -2548 6 -2822 7 -1375 9 -2782 7 -3766 9 -581 7 -876 5 -3832 4 -2883 5 -2986 7 -4065 7 -3648 8 -145 1 -1937 4 -4011 3 -1086 10 -3544 8 -1886 10 -237 7 -3133 2 -364 3 -819 1 -781 5 -2542 5 -2604 7 -2559 6 -3899 10 -3298 2 -966 5 -395 9 -3784 1 -4078 8 -2710 3 -4042 7 -3175 10 -2684 9 -3774 7 -383 2 -3091 6 -4046 1 -3959 8 -3781 1 -2175 6 -740 6 -411 5 -1898 6 -2382 8 -547 8 -3019 3 -523 6 -283 9 -3178 3 -1883 7 -2690 1 -3197 8 -1920 4 -146 7 -3725 7 -1329 2 -917 9 -1706 7 -3474 6 -1181 6 -2814 4 -3708 7 -1462 4 -878 7 -269 4 -3182 2 -2670 3 -2691 10 -2122 9 -2636 7 -1210 10 -3383 4 -1149 2 -653 3 -1396 1 -2248 5 -3643 1 -1201 2 -2968 5 -2970 8 -175 5 -1271 10 -2576 10 -2053 1 -1152 4 -2494 4 -1518 8 -3679 3 -41 9 -948 3 -3693 10 -140 9 -1344 2 -4017 4 -1112 4 -1346 7 -715 6 -2235 3 -775 5 -3889 4 -366 5 -1064 2 -890 10 -2363 3 -3281 4 -1309 10 -3842 9 -2127 1 -1367 5 -1636 1 -3201 9 -823 4 -708 9 -1983 9 -1512 3 -2129 2 -501 7 -1491 6 -3694 4 -2763 10 -2142 8 -4078 10 -3497 3 -880 2 -2604 7 -3884 5 -336 2 -2806 2 -1601 10 -1318 8 -189 1 -3017 6 -2059 10 -53 9 -340 1 -804 1 -508 9 -2675 10 -2330 8 -3161 10 -2351 5 -1687 1 -1371 3 -2029 5 -2386 6 -131 3 -986 10 -666 5 -2479 2 -3762 3 -1889 6 -120 8 -171 10 -2181 7 -2300 7 -1117 2 -3836 3 -1859 9 -2446 2 -842 5 -2529 2 -1749 4 -1705 8 -757 7 -664 6 -3193 2 -82 3 -1006 9 -2332 1 -3011 5 -4090 7 -2689 7 -1373 4 -2161 4 -3314 10 -1193 5 -1015 8 -2770 7 -2225 6 -621 5 -128 4 -137 7 -2432 6 -2231 2 -2693 3 -1964 9 -654 4 -943 10 -995 8 -2439 7 -2169 6 -662 5 -832 7 -1131 1 -1045 5 -3220 9 -506 2 -2067 4 -915 7 -658 6 -3416 6 -1950 8 -2760 3 -2297 7 -4051 10 -1467 1 -2248 2 -2795 2 -1615 9 -772 4 -3245 4 -288 7 -834 5 -3795 4 -2689 2 -2726 3 -2606 10 -1767 5 -72 10 -2680 4 -2656 4 -2325 6 -3643 8 -3035 8 -1738 8 -684 3 -3832 8 -3728 1 -2275 10 -3107 10 -685 3 -3846 4 -1982 3 -1690 1 -2032 6 -1210 8 -1781 2 -3382 2 -2247 1 -690 1 -3735 1 -1611 1 -2958 1 -3543 2 -3484 7 -3383 4 -1395 1 -2098 9 -1474 5 -89 6 -509 7 -1644 4 -600 8 -462 10 -59 4 -946 6 -2324 6 -2871 1 -996 6 -1638 2 -323 7 -3103 6 -2134 7 -1541 5 -2401 4 -1727 6 -3397 8 -1731 5 -3671 1 -3651 8 -3635 6 -2892 2 -2833 8 -2641 8 -3525 2 -3738 2 -3686 10 -3111 2 -278 4 -1384 10 -548 3 -3772 7 -3536 6 -481 5 -3748 10 -4052 7 -572 7 -2653 7 -3797 4 -3867 10 -1799 1 -2206 3 -1947 4 -870 4 -1611 6 -2400 6 -438 10 -2292 2 -2975 2 -2863 3 -3747 10 -3738 2 -1865 4 -2427 6 -3084 6 -4044 4 -1387 6 -3262 1 -693 7 -1125 10 -797 5 -1355 9 -957 6 -3781 10 -2182 1 -1077 10 -70 9 -930 7 -3118 5 -1067 2 -926 7 -3068 5 -2984 3 -2713 7 -3882 1 -3359 4 -2119 6 -692 10 -3093 10 -3144 3 -1783 10 -2775 8 -732 5 -2138 4 -291 5 -830 8 -3752 5 -3154 7 -613 10 -1945 10 -1703 7 -3138 4 -3954 8 -3963 5 -1989 6 -3506 2 -2544 8 -556 8 -3623 6 -1378 1 -1324 9 -21 6 -164 10 -1064 8 -1277 5 -3024 2 -3754 8 -2917 2 -3126 10 -2715 9 -50 3 -495 2 -2961 1 -921 3 -2361 7 -43 8 -2014 10 -568 3 -2542 1 -1475 2 -2515 10 -2829 4 -672 9 -3836 1 -607 4 -744 8 -2107 7 -3118 8 -885 10 -800 10 -1649 8 -772 2 -3713 10 -2800 7 -1421 9 -2111 1 -367 3 -1137 4 -2645 10 -1226 4 -1095 8 -3364 10 -2810 8 -3614 8 -767 4 -3589 1 -340 5 -2647 5 -3762 7 -2526 6 -844 2 -2353 10 -1499 2 -1824 8 -4043 8 -1580 9 -2023 8 -581 7 -2697 9 -3806 7 -3330 2 -2796 4 -106 7 -1667 6 -3121 9 -491 8 -1080 6 -959 9 -961 2 -3875 9 -1256 4 -2327 2 -3024 5 -3579 8 -635 1 -4051 8 -364 9 -737 5 -1404 5 -3039 4 -1559 5 -3169 3 -3517 6 -2128 4 -3883 4 -1955 1 -983 4 -1682 3 -2348 3 -445 9 -949 1 -1529 1 -3623 8 -836 1 -464 6 -2192 2 -3156 2 -2592 10 -648 6 -763 6 -1012 3 -3458 1 -3242 4 -2700 1 -3724 10 -3058 10 -432 3 -2621 10 -1386 1 -3954 8 -713 3 -3324 5 -3680 9 -3210 9 -3257 4 -2281 4 -2674 1 -3355 8 -3129 1 -1323 3 -3924 10 -337 6 -1993 4 -1410 5 -3095 2 -3873 10 -3867 4 -3841 9 -1699 9 -2316 7 -2441 1 -1398 5 -1372 8 -3995 4 -2726 7 -861 9 -1707 7 -3939 10 -776 1 -1101 9 -2112 6 -2337 1 -1129 3 -109 1 -2993 5 -1271 7 -1855 5 -1510 6 -2564 9 -1272 1 -2118 5 -746 5 -598 6 -1460 1 -3752 4 -2891 2 -841 9 -2446 10 -1140 10 -540 1 -3855 5 -2087 4 -2580 2 -1335 2 -1649 7 -4039 5 -3382 10 -477 10 -1215 5 -2158 1 -1163 9 -614 8 -3517 3 -2429 3 -3744 5 -342 9 -3027 1 -2399 6 -3211 4 -917 8 -513 10 -1910 1 -2413 1 -25 9 -605 7 -689 7 -273 9 -2299 8 -720 2 -1356 4 -1476 8 -3038 8 -1046 1 -638 5 -3954 7 -3113 5 -2904 3 -2826 7 -366 2 -1060 1 -3101 4 -3623 1 -1046 6 -1648 8 -2319 10 -2580 7 -2740 7 -2132 8 -77 8 -1541 7 -431 1 -2630 6 -1872 7 -1048 9 -3717 2 -1889 7 -2224 4 -1570 1 -3920 3 -2350 1 -1044 10 -873 9 -1551 10 -3882 1 -2499 2 -2603 6 -2066 10 -843 8 -3173 1 -2002 7 -1935 3 -1349 6 -2279 9 -3933 8 -4052 6 -1380 3 -3553 5 -3262 1 -1718 10 -2127 5 -3522 8 -218 2 -3081 6 -2212 8 -1414 4 -217 6 -3319 10 -4093 9 -60 2 -1841 9 -2929 3 -465 2 -3793 6 -1815 6 -3592 3 -649 1 -1222 9 -3654 9 -1126 9 -1883 3 -2413 6 -3066 10 -784 2 -403 6 -2530 8 -2289 4 -3445 1 -3904 1 -1237 6 -1146 4 -2062 10 -1773 2 -483 7 -389 10 -3913 9 -3234 4 -2214 5 -3441 4 -3730 3 -1729 5 -20 3 -1698 6 -2113 1 -2545 9 -1532 9 -3480 2 -3967 10 -202 1 -3625 10 -906 1 -2771 9 -1194 4 -3498 10 -2758 2 -1058 1 -2733 3 -1833 8 -3340 8 -2451 3 -597 8 -3409 9 -3920 5 -2411 4 -3056 6 -181 9 -2203 2 -893 2 -2040 9 -1594 1 -1887 6 -2415 7 -2968 8 -1160 4 -54 1 -2270 7 -3801 8 -3270 4 -2981 6 -1512 6 -2325 6 -2816 3 -3150 7 -4048 2 -2805 8 -3535 7 -3593 10 -3500 10 -3281 2 -1360 10 -3597 4 -2721 4 -343 10 -258 4 -1255 9 -1939 8 -2824 1 -1726 3 -3129 7 -2754 1 -1694 2 -1952 8 -4061 2 -89 3 -1078 9 -2207 1 -771 4 -3160 6 -2529 10 -1275 10 -3569 7 -2421 7 -1878 8 -221 5 -2530 5 -2271 10 -1718 5 -2790 3 -1023 5 -1544 8 -1108 5 -191 1 -2823 8 -3379 8 -289 2 -1688 5 -4060 3 -2126 9 -3701 2 -1720 5 -2772 6 -3700 2 -2136 8 -1689 7 -3815 4 -224 2 -1875 2 -2927 5 -1911 7 -1582 3 -1257 5 -434 1 -457 1 -2981 4 -198 8 -3030 3 -3133 9 -2475 8 -3167 4 -690 6 -1754 8 -2109 6 -35 1 -3007 6 -1491 7 -2420 3 -2540 1 -3714 3 -1454 4 -2217 8 -2945 8 -3523 3 -2892 4 -2897 6 -1730 5 -4003 4 -2276 8 -3587 7 -3226 6 -0 7 -916 4 -903 8 -3079 5 -1591 3 -1633 1 -1316 2 -3577 8 -2644 7 -893 2 -77 4 -140 7 -2672 6 -1022 6 -1499 2 -1639 10 -1104 1 -737 2 -1403 8 -159 2 -1386 9 -1607 8 -277 10 -2007 7 -1950 3 -6 7 -3642 10 -897 2 -2337 8 -2005 9 -1552 10 -2996 9 -2807 3 -3706 3 -2722 7 -738 3 -3131 4 -769 5 -839 9 -579 3 -376 3 -127 7 -2292 9 -2064 6 -293 3 -2664 7 -3159 1 -1316 3 -3741 10 -2200 2 -3235 8 -1615 6 -3673 2 -2027 1 -2041 3 -2158 9 -502 3 -3259 6 -2920 9 -2991 9 -750 5 -595 10 -77 4 -3058 10 -21 2 -2507 2 -1414 7 -2714 7 -2649 1 -2054 8 -2386 10 -2074 4 -3972 9 -1599 3 -984 3 -910 2 -1353 7 -103 8 -1232 2 -1963 3 -3550 5 -1089 3 -83 8 -2172 8 -2716 8 -2012 4 -3828 4 -3398 8 -60 3 -3319 5 -258 3 -2440 10 -1001 6 -1323 7 -3974 5 -3416 9 -2292 3 -3393 7 -3653 10 -826 8 -165 2 -2911 3 -2145 10 -3586 7 -2063 1 -3343 4 -429 1 -1006 10 -3920 10 -3762 8 -3335 5 -911 2 -2266 7 -3226 4 -3291 8 -2664 9 -2491 5 -3306 8 -3442 1 -1825 10 -640 6 -1598 8 -3616 1 -3793 3 -2566 10 -1866 7 -2764 6 -2351 7 -1548 9 -322 4 -2280 1 -3559 8 -1545 9 -3684 3 -1570 7 -3097 8 -858 6 -3959 6 -1860 1 -2740 2 -1148 9 -3830 1 -2356 8 -2609 4 -1264 2 -3457 5 -413 5 -327 4 -1687 1 -749 1 -1883 9 -1180 10 -337 5 -498 7 -28 9 -1865 1 -3618 1 -1249 9 -1827 7 -1126 6 -725 5 -3055 5 -1678 4 -803 4 -1274 4 -892 1 -1335 1 -17 1 -2755 8 -1539 8 -263 10 -3628 2 -1536 6 -3625 2 -2750 8 -1723 3 -754 2 -1215 1 -2468 5 -1915 7 -2581 5 -2083 2 -2500 6 -1408 1 -3553 7 -491 7 -2703 10 -3716 10 -2080 6 -3910 6 -2597 1 -2884 10 -2393 2 -3050 6 -353 3 -2432 3 -1449 8 -1730 9 -3401 8 -2603 3 -3666 5 -3757 7 -3451 6 -2631 3 -3513 4 -2051 3 -249 6 -100 8 -3249 1 -2676 8 -3349 2 -595 9 -260 3 -1321 2 -613 1 -609 6 -733 9 -3565 3 -2844 5 -1077 4 -1335 5 -56 6 -1635 1 -749 8 -3556 7 -3628 10 -707 3 -1128 9 -4037 8 -2115 9 -500 9 -205 7 -3402 6 -3212 4 -2871 5 -3626 10 -2295 1 -1035 10 -576 2 -804 6 -3995 8 -444 1 -172 7 -426 3 -2358 6 -790 2 -354 6 -707 6 -821 5 -3885 2 -1713 8 -3784 6 -3039 8 -558 8 -3662 4 -1602 6 -3633 5 -3148 7 -2544 1 -2897 2 -1868 8 -2020 5 -4075 9 -3637 8 -3963 6 -2467 10 -2682 8 -86 8 -3390 2 -3339 4 -1037 7 -89 10 -2146 5 -1745 6 -3121 6 -2060 1 -3569 6 -357 4 -1103 1 -111 1 -3413 2 -1193 8 -563 5 -2826 8 -3744 7 -375 6 -1013 6 -1568 6 -2868 3 -1608 7 -1941 10 -968 6 -3423 8 -2918 7 -1782 6 -2209 1 -167 1 -2760 8 -1729 10 -1217 4 -2875 2 -2347 7 -1611 7 -2309 3 -119 2 -723 10 -3352 8 -4079 1 -1694 7 -1800 7 -2296 4 -2053 3 -2343 1 -3538 8 -1106 1 -240 3 -3200 10 -538 6 -2704 9 -3566 4 -3644 7 -3603 3 -2059 10 -1172 1 -3726 8 -2693 2 -1746 9 -220 3 -1058 1 -2733 5 -346 1 -3561 8 -2016 7 -1905 7 -1291 2 -794 3 -2621 1 -2879 7 -1422 8 -3040 5 -966 6 -346 3 -4074 8 -3107 3 -250 6 -1903 7 -1823 7 -1941 3 -1193 8 -656 3 -3856 10 -3578 9 -1671 3 -1408 1 -3973 4 -1335 5 -2952 3 -3572 1 -567 7 -2517 3 -3453 4 -3350 10 -2637 9 -3576 9 -3449 2 -1793 1 -3411 3 -2143 7 -1627 10 -1174 7 -342 6 -850 5 -2827 5 -1367 3 -2783 8 -364 3 -1103 6 -3247 3 -2149 3 -2201 3 -2631 5 -4090 3 -3626 7 -1042 2 -972 6 -1913 4 -143 10 -2251 5 -1762 5 -2310 4 -2592 8 -1443 4 -1123 3 -716 9 -3583 7 -2524 5 -3119 10 -23 9 -1015 6 -3945 4 -4069 3 -3508 4 -3067 9 -693 1 -262 8 -2509 6 -2148 6 -2193 9 -1492 6 -2472 6 -895 8 -2772 10 -400 2 -786 2 -2090 1 -2208 3 -479 9 -356 4 -2267 8 -1695 8 -792 9 -2903 5 -3171 6 -1243 9 -2349 2 -3895 10 -491 10 -3972 7 -713 2 -3522 4 -2937 8 -1718 7 -1770 8 -807 5 -3955 1 -270 9 -2996 1 -647 5 -1867 7 -3583 1 -3476 10 -1452 10 -3630 10 -1799 4 -711 10 -1450 10 -3530 6 -635 10 -2022 7 -495 8 -3385 10 -1741 7 -1236 2 -643 5 -4066 5 -3752 6 -875 9 -3582 1 -2377 7 -2184 10 -3864 5 -1079 3 -3044 10 -3813 2 -3966 9 -629 5 -2299 6 -1582 2 -1480 5 -3984 1 -1689 1 -1082 2 -3190 8 -646 1 -1348 5 -589 7 -1961 2 -2145 6 -1364 2 -2677 1 -188 1 -2570 4 -2986 4 -3024 1 -223 2 -3571 7 -2605 6 -919 8 -479 6 -1142 2 -199 8 -2507 4 -3255 9 -1555 3 -1862 4 -1569 8 -4003 2 -969 8 -2461 5 -678 7 -1907 9 -1502 3 -2990 4 -1026 5 -3877 6 -2041 9 -3876 1 -301 7 -432 3 -2509 6 -928 6 -1432 2 -3112 6 -3095 4 -1818 5 -2142 5 -3986 1 -32 7 -1349 4 -2403 1 -1060 5 -1802 7 -555 9 -4018 4 -3565 7 -2161 10 -2194 4 -3926 7 -2095 9 -3729 3 -217 7 -352 10 -2548 8 -3679 6 -2553 3 -1063 10 -1533 2 -3447 6 -1027 10 -712 6 -1118 5 -3083 10 -873 9 -3612 4 -2727 5 -729 1 -1895 3 -2700 9 -4078 6 -4089 7 -3265 7 -1583 1 -3546 5 -2689 2 -1640 4 -3344 7 -134 4 -3114 3 -2242 4 -2980 1 -1594 4 -3626 4 -3225 8 -3137 4 -1634 1 -2588 7 -3933 1 -844 1 -1466 2 -3288 9 -3192 1 -1987 2 -2357 6 -16 5 -2817 10 -128 2 -1160 10 -2992 10 -2502 5 -3972 9 -2395 3 -1275 7 -625 4 -907 2 -2265 7 -3172 4 -3225 7 -77 3 -2146 2 -2817 2 -3845 9 -3691 8 -600 8 -611 2 -417 7 -2645 10 -75 9 -711 1 -564 4 -151 4 -3541 8 -3038 3 -3912 9 -3342 3 -9 9 -1553 10 -3576 6 -1170 4 -98 6 -2700 6 -3086 3 -2591 2 -413 7 -2521 8 -3016 7 -1118 7 -4000 10 -1018 8 -722 10 -3952 1 -3646 7 -3920 4 -448 7 -3415 2 -2990 2 -984 5 -1211 5 -1659 8 -1928 3 -1319 2 -774 3 -3266 8 -752 7 -2279 10 -2854 6 -2941 9 -3060 2 -2874 1 -3549 1 -3379 8 -751 7 -3009 5 -3099 2 -233 1 -3321 3 -1889 4 -2192 9 -3140 3 -1338 2 -1980 1 -3517 6 -1434 1 -1576 9 -3398 10 -1951 8 -3785 2 -3229 10 -497 7 -1914 9 -82 7 -2467 10 -1546 10 -3857 9 -1230 9 -266 3 -1664 6 -3702 4 -480 8 -3512 5 -123 5 -3271 7 -3467 3 -3861 9 -455 8 -1743 9 -2004 2 -726 7 -4059 6 -2982 10 -681 3 -3533 6 -2857 3 -2731 10 -3075 10 -217 1 -2691 9 -2311 9 -30 1 -2142 2 -3943 6 -1285 2 -1664 5 -3455 5 -3493 3 -467 4 -1220 3 -439 7 -2905 8 -718 10 -795 6 -2965 8 -2864 1 -2547 8 -2790 6 -832 9 -1498 1 -1664 10 -1942 8 -878 6 -2726 6 -1088 10 -174 8 -25 10 -3262 8 -1573 6 -3861 3 -2993 1 -3965 1 -2892 6 -1820 6 -339 7 -157 3 -2762 7 -76 5 -3179 9 -1356 9 -686 2 -3302 3 -3262 6 -2467 6 -500 10 -3046 10 -736 2 -649 3 -2925 10 -3501 5 -238 6 -1303 1 -913 9 -693 3 -2173 3 -1814 8 -3080 7 -3560 4 -3904 2 -1921 9 -2389 7 -2600 8 -2192 10 -1275 8 -3306 6 -287 10 -3722 4 -363 3 -240 10 -602 7 -1671 3 -1677 7 -789 10 -2319 1 -2771 1 -585 10 -91 3 -2105 7 -3282 2 -3942 9 -2825 3 -26 9 -3405 8 -3732 1 -1612 10 -983 5 -1469 9 -2819 2 -2995 10 -890 2 -3616 8 -814 3 -2376 4 -3578 4 -3499 8 -3319 8 -2801 3 -3953 6 -3239 2 -870 5 -2468 8 -2992 2 -3429 3 -2117 10 -1945 6 -1143 1 -469 5 -2804 9 -2309 9 -2124 4 -1763 6 -3604 3 -3640 1 -2045 8 -2531 5 -2763 3 -2395 1 -2323 2 -1081 10 -2078 10 -1731 2 -364 9 -1714 9 -578 7 -1469 6 -1905 10 -129 2 -389 1 -94 8 -2873 9 -1124 6 -824 2 -3386 5 -1700 2 -3658 9 -2415 8 -1264 5 -4028 8 -1663 8 -1435 10 -4002 5 -3274 6 -2072 1 -3006 2 -376 10 -3595 9 -3275 10 -1755 1 -548 4 -232 5 -3179 3 -1100 7 -772 8 -3330 5 -3967 3 -1494 7 -1770 4 -2269 8 -896 2 -1058 8 -1698 8 -3801 9 -1633 6 -667 9 -2153 9 -3867 1 -3617 4 -415 2 -671 3 -1993 1 -3368 1 -2161 3 -3957 3 -1938 4 -3215 10 -12 4 -1450 4 -3852 3 -3372 9 -1514 5 -2308 8 -1153 2 -422 5 -1824 10 -1575 1 -3979 9 -3026 2 -3162 6 -3247 3 -1939 5 -191 9 -2677 8 -3849 3 -3871 9 -1269 4 -2867 10 -2521 1 -110 7 -2569 6 -3901 9 -1302 1 -1441 2 -150 3 -4029 10 -1336 6 -243 8 -3365 10 -3901 9 -1297 2 -3664 5 -3507 7 -1263 8 -3142 10 -2079 3 -642 1 -2478 3 -3766 10 -2993 9 -3337 5 -2224 7 -1444 4 -2939 7 -1226 2 -866 1 -957 4 -3813 9 -982 4 -2114 1 -247 7 -2946 3 -744 6 -923 4 -3534 4 -2790 7 -2840 4 -1963 8 -916 6 -592 4 -2187 5 -1236 5 -2522 7 -139 1 -3331 5 -1705 6 -683 10 -3383 3 -2377 10 -523 3 -3815 9 -3822 3 -541 8 -2128 1 -431 3 -1719 4 -3104 6 -2394 1 -1679 6 -1341 1 -1555 10 -2818 6 -1818 2 -3978 6 -3784 5 -211 8 -28 3 -2160 6 -2290 8 -1029 1 -500 4 -664 9 -964 10 -1349 10 -260 6 -3889 1 -224 9 -3846 1 -3442 3 -1542 4 -1834 10 -137 6 -1918 4 -3657 4 -16 5 -3626 10 -762 5 -1907 10 -1306 6 -976 5 -31 9 -2618 5 -643 2 -2273 4 -1515 8 -196 4 -754 10 -1134 8 -892 3 -1800 9 -1698 8 -2326 8 -4061 4 -370 3 -3209 3 -3852 9 -2499 8 -195 5 -1606 4 -2600 9 -1248 10 -3417 8 -691 6 -3882 9 -2000 5 -3657 10 -1219 8 -1453 5 -1806 8 -2896 6 -10 4 -2545 6 -3165 7 -3882 2 -2855 10 -3935 1 -3647 9 -71 8 -3790 1 -1891 8 -514 2 -3790 6 -2152 5 -3046 2 -594 8 -2930 6 -2927 10 -1739 1 -2559 7 -3408 2 -1081 3 -771 10 -506 3 -3537 6 -2946 8 -3995 7 -1245 7 -2097 5 -3222 9 -137 1 -3918 9 -1969 5 -1077 4 -527 2 -317 7 -1836 3 -1238 9 -582 6 -2554 4 -2292 2 -1106 7 -1709 5 -3980 2 -2134 9 -3310 1 -3476 9 -132 4 -3924 6 -3875 2 -2794 1 -3632 1 -728 2 -3674 1 -3873 9 -3649 4 -1185 7 -2722 3 -485 10 -272 6 -1181 5 -3942 6 -4013 5 -65 10 -3027 7 -2131 2 -390 9 -82 2 -2018 1 -3598 5 -2083 9 -1188 4 -1583 2 -736 8 -2779 7 -2101 3 -1522 8 -674 5 -3751 2 -1947 3 -4044 9 -2536 9 -191 8 -3053 9 -2025 1 -2984 4 -33 1 -1426 2 -514 7 -2972 5 -3109 4 -3106 6 -2568 2 -2309 7 -3966 7 -2344 5 -1173 5 -1885 5 -2939 7 -3867 1 -3595 4 -4083 5 -1132 2 -2868 1 -950 5 -3194 4 -2220 5 -3917 4 -580 10 -1304 10 -1540 5 -3223 10 -825 3 -1436 4 -3907 1 -2911 9 -15 3 -3371 5 -1200 3 -1092 10 -916 8 -668 7 -4035 6 -2062 7 -1581 9 -804 2 -3293 9 -2459 7 -2831 10 -2755 10 -2931 4 -3780 10 -4013 1 -1060 6 -3093 6 -238 6 -440 1 -85 5 -375 8 -622 3 -803 2 -2099 10 -2261 7 -2677 10 -2598 8 -1134 3 -3503 2 -1761 6 -2114 10 -278 4 -2703 8 -1153 7 -818 5 -3369 4 -144 5 -1992 1 -2033 2 -1942 2 -44 9 -3582 10 -354 10 -4004 1 -3363 5 -2129 1 -3445 7 -1353 7 -46 6 -1934 2 -3555 9 -2423 2 -1947 8 -3976 7 -3853 9 -124 4 -3854 9 -1633 5 -102 10 -3302 7 -1801 9 -423 4 -1740 1 -2919 2 -404 10 -2831 9 -2348 10 -2235 1 -1242 7 -2536 10 -2623 10 -655 5 -634 4 -218 9 -757 5 -1516 10 -3683 1 -1746 4 -3826 2 -2137 6 -191 4 -2889 6 -1793 3 -3265 7 -2244 4 -1057 8 -1190 8 -1085 9 -286 6 -644 10 -3189 6 -3934 1 -1957 3 -34 4 -1837 6 -3480 7 -2206 1 -747 2 -1688 3 -2107 6 -3892 1 -3119 1 -2198 8 -2862 7 -1662 1 -1857 8 -1132 6 -3316 3 -1877 1 -3550 2 -2671 7 -190 10 -1450 1 -2910 10 -1173 1 -3742 6 -1907 7 -2345 8 -580 8 -0 2 -1920 7 -2737 3 -1030 2 -2061 9 -2704 7 -3309 4 -1204 1 -777 1 -81 10 -906 10 -1049 4 -3803 9 -3684 9 -1256 6 -1970 9 -2133 3 -1968 1 -1532 2 -2992 1 -3285 10 -829 2 -156 8 -2882 10 -120 8 -499 10 -1962 3 -2202 7 -4015 8 -2883 6 -327 4 -2502 9 -8 6 -1896 6 -2862 1 -1220 4 -3890 4 -58 3 -2273 1 -2074 10 -3090 5 -200 6 -2522 2 -624 1 -592 5 -1190 4 -3879 9 -84 6 -1193 10 -1612 2 -3239 7 -254 2 -3689 5 -2560 10 -422 3 -3726 10 -617 6 -3673 3 -3806 4 -143 10 -1326 9 -952 5 -211 4 -3346 10 -2984 3 -80 3 -2045 1 -371 9 -2921 4 -1924 5 -2656 8 -3435 9 -3882 6 -1410 4 -967 4 -3102 1 -2018 10 -1122 9 -3656 10 -653 2 -1418 4 -1107 3 -2603 6 -3792 7 -721 6 -3489 10 -1092 9 -1186 8 -3296 5 -2136 2 -2847 5 -1660 3 -417 2 -3312 9 -1811 8 -2537 6 -2928 10 -1383 5 -2939 2 -2065 9 -1781 7 -3544 6 -1042 6 -342 10 -2704 9 -2433 6 -194 4 -2000 9 -2886 9 -1010 2 -2869 2 -1508 9 -157 3 -2606 4 -1790 4 -2353 6 -1723 9 -429 5 -3385 5 -2976 2 -409 7 -585 3 -3346 4 -3500 8 -636 4 -478 5 -921 2 -2642 4 -3195 5 -3676 8 -3798 1 -1651 7 -16 6 -228 4 -1168 8 -2865 7 -726 8 -839 10 -3906 1 -2140 9 -3875 1 -636 9 -4087 1 -1551 6 -3299 6 -1899 9 -3215 9 -2406 1 -3391 2 -4087 1 -1259 4 -3409 7 -450 7 -2905 3 -1733 6 -647 1 -2220 10 -1894 2 -744 8 -189 7 -2138 5 -2569 1 -2941 4 -1627 6 -234 3 -3382 9 -3326 9 -283 4 -3659 10 -3223 3 -1083 2 -21 5 -3083 6 -98 7 -3288 7 -198 2 -3577 3 -1638 1 -2968 7 -251 9 -2460 1 -2706 3 -1224 8 -1773 7 -995 5 -770 7 -1972 6 -1375 8 -3830 9 -754 2 -2173 8 -627 7 -1797 6 -3883 6 -1402 5 -1736 6 -3818 6 -1851 6 -3316 7 -2677 7 -663 6 -593 3 -2773 6 -2694 1 -1355 6 -2838 4 -1222 7 -4049 4 -2128 1 -1802 9 -1112 8 -1812 4 -3774 4 -1166 8 -725 4 -2677 7 -2281 9 -1746 4 -2493 7 -641 8 -11 5 -1462 4 -2250 10 -166 2 -2528 10 -961 7 -263 10 -3339 3 -2827 4 -1732 9 -2883 7 -859 7 -861 2 -3158 2 -561 2 -12 3 -4009 3 -1000 8 -1035 2 -2937 1 -629 6 -4084 6 -633 2 -2601 6 -2352 6 -1079 3 -438 7 -3352 1 -3240 8 -2414 6 -2520 7 -3806 1 -1134 5 -1567 4 -2601 6 -827 5 -2418 5 -1640 8 -934 6 -2003 2 -1361 9 -977 7 -3833 6 -3506 1 -1192 1 -857 5 -1151 7 -21 10 -3669 7 -3653 8 -2881 1 -1425 2 -3634 8 -2023 2 -1825 4 -3340 9 -377 8 -3265 8 -1108 10 -2393 5 -3781 1 -316 2 -1475 10 -2501 1 -232 3 -3331 4 -1765 3 -2788 1 -3280 3 -2253 10 -2090 7 -3222 7 -2724 1 -1265 2 -3847 3 -855 7 -1994 8 -3149 10 -1469 6 -2450 4 -2419 7 -946 4 -2779 8 -711 10 -3970 3 -229 5 -782 9 -2264 9 -3732 6 -3980 8 -770 4 -2639 7 -2716 10 -3583 8 -3474 1 -2085 5 -1121 2 -2257 2 -3388 2 -1328 7 -916 3 -2169 2 -2166 10 -3003 7 -2230 8 -2713 4 -176 8 -869 8 -1994 1 -912 2 -313 4 -3754 6 -2763 4 -714 6 -3634 5 -3327 4 -1620 9 -2297 1 -231 9 -1057 3 -1101 2 -1041 4 -691 3 -2083 10 -485 7 -3271 10 -1475 4 -3822 1 -3339 7 -3785 9 -3305 10 -1931 3 -3387 10 -3887 7 -3685 10 -3844 3 -1839 9 -2068 5 -170 3 -3234 9 -3413 1 -317 6 -1483 5 -2165 8 -3199 6 -3312 6 -1195 5 -1172 8 -896 1 -58 10 -3517 3 -1279 4 -653 6 -1822 7 -2863 8 -1141 8 -3424 9 -3958 3 -655 6 -404 5 -294 2 -186 6 -3461 4 -1354 7 -3243 1 -3536 5 -3069 3 -3268 6 -1595 10 -2915 9 -3721 9 -2327 4 -3800 9 -2860 7 -2215 2 -3780 7 -3230 4 -46 1 -370 6 -866 5 -2080 3 -3315 1 -1324 5 -1029 3 -3766 4 -1751 6 -1476 2 -986 8 -2803 1 -2111 4 -2338 2 -3724 5 -1879 4 -1931 10 -2497 10 -1532 10 -2527 4 -3131 10 -1814 9 -1523 1 -3901 7 -2319 4 -2899 9 -1437 3 -1660 7 -585 10 -3484 7 -2269 8 -738 6 -2207 9 -2969 4 -1485 4 -211 6 -2838 4 -3531 6 -2513 9 -3864 6 -2400 7 -1134 10 -454 10 -3850 9 -208 9 -1813 1 -3291 10 -3528 6 -3959 8 -1339 8 -3506 3 -3121 6 -761 2 -22 1 -364 1 -2628 8 -3881 2 -2965 1 -2716 4 -2487 7 -2730 9 -3318 6 -629 6 -1007 6 -435 4 -1478 5 -3141 2 -1374 8 -678 2 -1904 1 -1834 1 -1269 7 -3504 10 -2939 8 -2599 2 -1427 3 -3212 8 -3345 2 -3406 7 -1938 1 -989 4 -3785 1 -934 1 -437 6 -881 4 -122 4 -3791 1 -2000 7 -1631 7 -1329 7 -164 3 -3300 5 -3287 9 -3086 3 -2094 8 -804 7 -2223 3 -595 3 -530 8 -1273 5 -786 5 -2472 7 -740 2 -2264 7 -673 9 -2361 7 -1326 1 -547 1 -2008 3 -1050 8 -1852 3 -2884 3 -602 9 -937 2 -2085 3 -516 7 -2260 5 -2234 5 -1887 10 -2430 4 -2722 7 -1956 4 -2459 1 -2905 9 -3195 6 -3568 2 -597 7 -167 2 -2975 8 -812 7 -2980 8 -2173 1 -1286 9 -414 10 -2575 9 -3431 2 -218 5 -509 4 -599 8 -2253 2 -2425 8 -1903 7 -1882 3 -3459 6 -3750 8 -3879 7 -3658 4 -93 3 -2907 10 -4093 5 -4046 10 -2553 3 -628 5 -353 4 -2955 6 -1148 4 -1622 10 -421 5 -1751 5 -3036 2 -465 6 -771 4 -2380 5 -1939 9 -3015 7 -1858 8 -268 8 -2522 1 -3363 6 -1936 8 -1255 3 -3555 2 -2728 6 -4022 1 -299 2 -3805 10 -2651 5 -1905 4 -1401 5 -454 9 -814 10 -2090 8 -2793 10 -568 9 -3842 5 -2281 3 -2515 4 -1920 8 -1894 5 -1752 8 -306 3 -3519 2 -3708 4 -213 4 -2748 10 -588 8 -1499 2 -2297 5 -3789 2 -126 9 -681 1 -3899 1 -1572 10 -475 7 -625 10 -1258 4 -1460 5 -2488 5 -481 7 -2448 9 -820 3 -2882 10 -3490 1 -2711 3 -644 10 -31 3 -2255 1 -2522 9 -627 8 -22 10 -2711 7 -1282 10 -2480 1 -3949 3 -2798 2 -1383 9 -2992 5 -1491 2 -1989 5 -2155 2 -3580 3 -1215 5 -2340 8 -1715 3 -3344 5 -3397 5 -1089 8 -2778 10 -3895 1 -321 10 -958 6 -3883 5 -1945 1 -3373 3 -1180 6 -1698 4 -3567 7 -3144 9 -783 5 -2923 7 -3221 10 -2758 8 -3915 8 -1535 2 -3194 3 -1792 9 -572 9 -3530 10 -2444 5 -2855 2 -768 7 -1914 7 -821 5 -1860 1 -2994 7 -2926 3 -3594 4 -1054 9 -406 8 -2511 8 -3791 4 -220 1 -2195 6 -242 9 -42 4 -1349 7 -2944 3 -1880 2 -1480 6 -1805 10 -2634 5 -3381 3 -1064 5 -3218 8 -3391 10 -3118 10 -330 1 -2075 1 -2774 10 -3123 9 -983 3 -2024 4 -3016 7 -425 9 -3109 5 -899 1 -2521 1 -4000 1 -2850 2 -3023 7 -2190 2 -3453 9 -4093 7 -3034 7 -747 8 -2485 3 -2066 9 -2052 1 -3465 3 -2692 4 -2116 2 -546 3 -448 4 -2518 2 -3365 1 -1695 9 -253 6 -164 5 -2151 7 -3215 6 -837 7 -553 9 -2582 3 -2285 5 -592 7 -1127 5 -482 8 -2803 9 -652 5 -3119 1 -1567 3 -1987 5 -379 2 -1883 10 -3841 8 -4038 6 -453 6 -2498 8 -224 8 -629 2 -411 5 -3853 10 -3104 2 -405 3 -1898 4 -1693 3 -109 2 -469 2 -496 4 -217 7 -632 7 -1710 6 -125 10 -1567 2 -2568 7 -2245 9 -3151 7 -2354 2 -1887 5 -1005 2 -2726 7 -1361 7 -1381 3 -1383 3 -3041 6 -2252 1 -346 4 -759 5 -2045 9 -2877 8 -2281 7 -2373 1 -3292 4 -657 4 -988 6 -3893 6 -1043 9 -788 8 -1341 4 -664 9 -1247 10 -3285 7 -2839 10 -670 10 -593 10 -3427 3 -238 7 -3747 8 -2380 5 -146 2 -2775 10 -2790 1 -2458 7 -791 9 -4028 6 -3665 5 -1495 5 -2756 2 -1237 9 -2449 4 -1139 6 -3249 10 -2747 9 -1513 8 -4050 1 -3195 1 -1455 9 -3482 6 -2337 4 -1523 2 -1430 6 -1146 5 -1655 8 -4057 6 -1455 5 -191 7 -1671 7 -2028 5 -3530 10 -395 9 -2020 4 -3583 7 -950 5 -1105 9 -816 10 -2189 7 -2677 4 -9 2 -483 10 -1606 1 -2663 10 -2964 1 -1523 8 -3645 8 -7 1 -729 2 -185 9 -1680 6 -3629 4 -3886 9 -1507 8 -2202 10 -1123 4 -1048 8 -2469 8 -2455 9 -1450 3 -4064 10 -2044 6 -180 9 -2370 7 -3996 10 -398 9 -1462 1 -1442 10 -3583 1 -2750 9 -1643 4 -2951 6 -79 7 -421 3 -2778 4 -3693 2 -1015 8 -773 3 -3014 1 -1025 10 -3488 9 -3026 3 -3108 9 -3945 4 -62 9 -590 7 -2486 7 -1035 6 -3525 3 -1705 2 -2160 4 -873 10 -4040 1 -1300 10 -442 2 -3648 8 -2035 5 -3611 10 -3103 5 -447 7 -1494 7 -1342 8 -3676 6 -1441 2 -2882 3 -3626 7 -3349 2 -979 4 -960 9 -2272 8 -2477 6 -1631 2 -2462 10 -1635 1 -3521 4 -1538 10 -915 2 -1891 1 -356 2 -3373 9 -81 8 -900 7 -3236 4 -3149 6 -83 8 -890 6 -1643 8 -714 1 -4041 6 -365 6 -1457 7 -1521 2 -2580 5 -2290 9 -471 7 -1491 5 -1655 2 -2727 5 -3081 3 -2307 2 -3816 6 -1678 9 -1613 1 -1890 7 -3107 1 -217 9 -863 10 -1852 6 -554 9 -567 2 -3700 3 -3559 4 -3870 4 -3695 2 -276 7 -2593 5 -1009 8 -329 7 -1381 9 -2848 2 -3548 10 -2045 4 -512 3 -2469 3 -791 3 -1518 10 -4088 10 -997 1 -4045 10 -825 10 -1449 7 -3425 2 -2816 10 -3579 7 -1068 9 -653 8 -1616 6 -2336 6 -1459 10 -3783 5 -2128 3 -2882 5 -2405 2 -200 4 -1164 9 -2094 10 -1884 8 -1645 7 -1624 2 -2066 7 -1488 4 -1136 3 -2658 10 -2102 3 -1189 7 -3775 3 -1370 7 -3049 5 -272 10 -2760 10 -954 2 -3127 3 -2438 8 -2670 3 -3395 4 -274 9 -2558 5 -1144 7 -2557 5 -647 2 -2018 1 -1909 2 -2846 7 -467 10 -2055 8 -3092 7 -1822 3 -3765 8 -336 2 -610 10 -362 8 -3569 3 -1180 1 -3754 9 -1901 5 -1909 6 -884 3 -2760 10 -74 3 -635 4 -1752 10 -2238 3 -663 4 -3229 2 -1013 3 -1376 3 -1501 4 -2606 2 -3462 1 -326 3 -305 8 -846 9 -990 2 -3598 10 -3582 8 -3796 6 -1731 1 -3279 6 -3472 9 -60 7 -1910 8 -2982 7 -3372 10 -2114 10 -541 7 -294 8 -2316 5 -3760 1 -1284 4 -2374 5 -2717 1 -1313 8 -932 5 -3137 2 -1373 7 -4088 5 -1820 4 -2512 7 -2813 6 -2251 4 -1727 10 -704 6 -483 10 -3281 9 -1622 2 -1284 3 -1293 1 -3241 7 -1508 10 -696 2 -2944 4 -3889 5 -1075 10 -1680 8 -1084 9 -2060 10 -2892 7 -900 5 -2589 7 -1025 4 -3950 6 -953 1 -455 2 -1016 7 -1344 7 -2688 8 -467 9 -2597 9 -2859 8 -2643 8 -3544 6 -1000 8 -225 4 -1473 9 -2134 2 -26 10 -623 7 -2449 9 -479 2 -3936 1 -935 7 -1490 7 -885 7 -437 7 -3937 1 -1729 4 -3078 7 -2020 6 -330 9 -4064 10 -1392 10 -2589 2 -4080 5 -2785 9 -2570 9 -3420 7 -2709 2 -261 1 -2595 8 -2383 8 -1986 1 -991 5 -3796 7 -63 6 -2499 6 -2323 2 -3772 3 -960 1 -1186 1 -3358 3 -2414 8 -940 7 -3606 7 -802 1 -1913 5 -2900 10 -2078 1 -864 2 -3210 3 -4023 7 -3678 9 -1792 10 -3996 5 -2024 4 -2605 7 -2645 3 -1420 5 -3328 9 -2147 9 -2813 2 -1841 3 -3458 9 -777 5 -3564 2 diff --git a/tests/opencl/bfs/kernel.cl b/tests/opencl/bfs/kernel.cl deleted file mode 100755 index 51ce5a08..00000000 --- a/tests/opencl/bfs/kernel.cl +++ /dev/null @@ -1,53 +0,0 @@ -/* ============================================================ -//--cambine: kernel funtion of Breadth-First-Search -//--author: created by Jianbin Fang -//--date: 06/12/2010 -============================================================ */ - -//#pragma OPENCL EXTENSION cl_khr_byte_addressable_store: enable - -//Structure to hold a node information -typedef struct{ - int starting; - int no_of_edges; -} Node; - -//--7 parameters -__kernel void BFS_1( const __global Node* g_graph_nodes, - const __global int* g_graph_edges, - __global char* g_graph_mask, - __global char* g_updating_graph_mask, - __global char* g_graph_visited, - __global int* g_cost, - const int no_of_nodes){ - int tid = get_global_id(0); - if( tidPA0fnnAb^0k%=C$=Y3XUxrq9ew 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 Pao?DSziRlsK==M1iiYY* diff --git a/tests/opencl/bfs/main.cc b/tests/opencl/bfs/main.cc deleted file mode 100755 index 9104c94e..00000000 --- a/tests/opencl/bfs/main.cc +++ /dev/null @@ -1,297 +0,0 @@ -//--by Jianbin Fang - -#include -#include -#include -#include -#include -#include -#include - -#ifdef PROFILING -#include "timer.h" -#endif - -#include "CLHelper.h" -#include "util.h" - -#define MAX_THREADS_PER_BLOCK 256 - -// Structure to hold a node information -struct Node { - int starting; - int no_of_edges; -}; - -//---------------------------------------------------------- -//--bfs on cpu -//--programmer: jianbin -//--date: 26/01/2011 -//--note: width is changed to the new_width -//---------------------------------------------------------- -void run_bfs_cpu(int no_of_nodes, Node *h_graph_nodes, int edge_list_size, - int *h_graph_edges, char *h_graph_mask, - char *h_updating_graph_mask, char *h_graph_visited, - int *h_cost_ref) { - char stop; - int k = 0; - do { - // if no thread changes this value then the loop stops - stop = false; - for (int tid = 0; tid < no_of_nodes; tid++) { - if (h_graph_mask[tid] == true) { - h_graph_mask[tid] = false; - for (int i = h_graph_nodes[tid].starting; - i < (h_graph_nodes[tid].no_of_edges + h_graph_nodes[tid].starting); - i++) { - int id = - h_graph_edges[i]; //--cambine: node id is connected with node tid - if (!h_graph_visited[id]) { //--cambine: if node id has not been - //visited, enter the body below - h_cost_ref[id] = h_cost_ref[tid] + 1; - h_updating_graph_mask[id] = true; - } - } - } - } - - for (int tid = 0; tid < no_of_nodes; tid++) { - if (h_updating_graph_mask[tid] == true) { - h_graph_mask[tid] = true; - h_graph_visited[tid] = true; - stop = true; - h_updating_graph_mask[tid] = false; - } - } - k++; - } while (stop); -} -//---------------------------------------------------------- -//--breadth first search on GPUs -//---------------------------------------------------------- -void run_bfs_gpu(int no_of_nodes, Node *h_graph_nodes, int edge_list_size, - int *h_graph_edges, char *h_graph_mask, - char *h_updating_graph_mask, char *h_graph_visited, - int *h_cost) throw(std::string) { - - // int number_elements = height*width; - char h_over; - cl_mem d_graph_nodes, d_graph_edges, d_graph_mask, d_updating_graph_mask, - d_graph_visited, d_cost, d_over; - - try { - //--1 transfer data from host to device - _clInit(); - - d_graph_nodes = _clMalloc(no_of_nodes * sizeof(Node), h_graph_nodes); - d_graph_edges = _clMalloc(edge_list_size * sizeof(int), h_graph_edges); - d_graph_mask = _clMallocRW(no_of_nodes * sizeof(char), h_graph_mask); - d_updating_graph_mask = _clMallocRW(no_of_nodes * sizeof(char), h_updating_graph_mask); - d_graph_visited = _clMallocRW(no_of_nodes * sizeof(char), h_graph_visited); - - d_cost = _clMallocRW(no_of_nodes * sizeof(int), h_cost); - d_over = _clMallocRW(sizeof(char), &h_over); - - _clMemcpyH2D(d_graph_nodes, no_of_nodes * sizeof(Node), h_graph_nodes); - _clMemcpyH2D(d_graph_edges, edge_list_size * sizeof(int), h_graph_edges); - _clMemcpyH2D(d_graph_mask, no_of_nodes * sizeof(char), h_graph_mask); - _clMemcpyH2D(d_updating_graph_mask, no_of_nodes * sizeof(char), h_updating_graph_mask); - _clMemcpyH2D(d_graph_visited, no_of_nodes * sizeof(char), h_graph_visited); - _clMemcpyH2D(d_cost, no_of_nodes * sizeof(int), h_cost); - -//--2 invoke kernel -#ifdef PROFILING - timer kernel_timer; - double kernel_time = 0.0; - kernel_timer.reset(); - kernel_timer.start(); -#endif - - do { - h_over = false; - _clMemcpyH2D(d_over, sizeof(char), &h_over); - //--kernel 0 - int kernel_id = 0; - int kernel_idx = 0; - _clSetArgs(kernel_id, kernel_idx++, d_graph_nodes); - _clSetArgs(kernel_id, kernel_idx++, d_graph_edges); - _clSetArgs(kernel_id, kernel_idx++, d_graph_mask); - _clSetArgs(kernel_id, kernel_idx++, d_updating_graph_mask); - _clSetArgs(kernel_id, kernel_idx++, d_graph_visited); - _clSetArgs(kernel_id, kernel_idx++, d_cost); - _clSetArgs(kernel_id, kernel_idx++, &no_of_nodes, sizeof(int)); - - // int work_items = no_of_nodes; - _clInvokeKernel(kernel_id, no_of_nodes, work_group_size); - - //--kernel 1 - kernel_id = 1; - kernel_idx = 0; - _clSetArgs(kernel_id, kernel_idx++, d_graph_mask); - _clSetArgs(kernel_id, kernel_idx++, d_updating_graph_mask); - _clSetArgs(kernel_id, kernel_idx++, d_graph_visited); - _clSetArgs(kernel_id, kernel_idx++, d_over); - _clSetArgs(kernel_id, kernel_idx++, &no_of_nodes, sizeof(int)); - - // work_items = no_of_nodes; - _clInvokeKernel(kernel_id, no_of_nodes, work_group_size); - - _clMemcpyD2H(d_over, sizeof(char), &h_over); - } while (h_over); - -#ifdef PROFILING - kernel_timer.stop(); - kernel_time = kernel_timer.getTimeInSeconds(); -#endif - //--3 transfer data from device to host - _clMemcpyD2H(d_cost, no_of_nodes * sizeof(int), h_cost); -//--statistics -#ifdef PROFILING - std::cout << "kernel time(s):" << kernel_time << std::endl; -#endif - //--4 release cl resources. - _clFree(d_graph_nodes); - _clFree(d_graph_edges); - _clFree(d_graph_mask); - _clFree(d_updating_graph_mask); - _clFree(d_graph_visited); - _clFree(d_cost); - _clFree(d_over); - _clRelease(); - } catch (std::string msg) { - _clFree(d_graph_nodes); - _clFree(d_graph_edges); - _clFree(d_graph_mask); - _clFree(d_updating_graph_mask); - _clFree(d_graph_visited); - _clFree(d_cost); - _clFree(d_over); - _clRelease(); - std::string e_str = "in run_transpose_gpu -> "; - e_str += msg; - throw(e_str); - } - return; -} - -//---------------------------------------------------------- -//--cambine: main function -//--author: created by Jianbin Fang -//--date: 25/01/2011 -//---------------------------------------------------------- -int main(int argc, char *argv[]) { - printf("enter demo main\n"); - - int no_of_nodes; - int edge_list_size; - FILE *fp; - Node *h_graph_nodes; - char *h_graph_mask, *h_updating_graph_mask, *h_graph_visited; - - try { - char *input_f = "graph4096.txt"; - printf("Reading File\n"); - // Read in Graph from a file - fp = fopen(input_f, "r"); - if (!fp) { - printf("Error Reading graph file\n"); - return 0; - } - - printf("Reading File completed!\n"); - - int source = 0; - - fscanf(fp, "%d", &no_of_nodes); - - int num_of_blocks = 1; - int num_of_threads_per_block = no_of_nodes; - - // Make execution Parameters according to the number of nodes - // Distribute threads across multiple Blocks if necessary - if (no_of_nodes > MAX_THREADS_PER_BLOCK) { - num_of_blocks = (int)ceil(no_of_nodes / (double)MAX_THREADS_PER_BLOCK); - num_of_threads_per_block = MAX_THREADS_PER_BLOCK; - } - work_group_size = num_of_threads_per_block; - // allocate host memory - h_graph_nodes = (Node *)malloc(sizeof(Node) * no_of_nodes); - h_graph_mask = (char *)malloc(sizeof(char) * no_of_nodes); - h_updating_graph_mask = (char *)malloc(sizeof(char) * no_of_nodes); - h_graph_visited = (char *)malloc(sizeof(char) * no_of_nodes); - - int start, edgeno; - // initalize the memory - for (int i = 0; i < no_of_nodes; i++) { - fscanf(fp, "%d %d", &start, &edgeno); - h_graph_nodes[i].starting = start; - h_graph_nodes[i].no_of_edges = edgeno; - h_graph_mask[i] = false; - h_updating_graph_mask[i] = false; - h_graph_visited[i] = false; - } - // read the source node from the file - fscanf(fp, "%d", &source); - source = 0; - // set the source node as true in the mask - h_graph_mask[source] = true; - h_graph_visited[source] = true; - fscanf(fp, "%d", &edge_list_size); - int id, cost; - int *h_graph_edges = (int *)malloc(sizeof(int) * edge_list_size); - for (int i = 0; i < edge_list_size; i++) { - fscanf(fp, "%d", &id); - fscanf(fp, "%d", &cost); - h_graph_edges[i] = id; - } - - if (fp) - fclose(fp); - // allocate mem for the result on host side - int *h_cost = (int *)malloc(sizeof(int) * no_of_nodes); - int *h_cost_ref = (int *)malloc(sizeof(int) * no_of_nodes); - for (int i = 0; i < no_of_nodes; i++) { - h_cost[i] = -1; - h_cost_ref[i] = -1; - } - h_cost[source] = 0; - h_cost_ref[source] = 0; - //--------------------------------------------------------- - //--gpu entry - run_bfs_gpu(no_of_nodes, h_graph_nodes, edge_list_size, h_graph_edges, - h_graph_mask, h_updating_graph_mask, h_graph_visited, h_cost); - //--------------------------------------------------------- - //--cpu entry - // initalize the memory again - for (int i = 0; i < no_of_nodes; i++) { - h_graph_mask[i] = false; - h_updating_graph_mask[i] = false; - h_graph_visited[i] = false; - } - // set the source node as true in the mask - source = 0; - h_graph_mask[source] = true; - h_graph_visited[source] = true; - run_bfs_cpu(no_of_nodes, h_graph_nodes, edge_list_size, h_graph_edges, - h_graph_mask, h_updating_graph_mask, h_graph_visited, - h_cost_ref); - //--------------------------------------------------------- - //--result varification - compare_results(h_cost_ref, h_cost, no_of_nodes); - // release host memory - free(h_graph_nodes); - free(h_graph_mask); - free(h_updating_graph_mask); - free(h_graph_visited); - - } catch (std::string msg) { - printf("--cambine: exception in main ->%s\n", msg); - // release host memory - free(h_graph_nodes); - free(h_graph_mask); - free(h_updating_graph_mask); - free(h_graph_visited); - } - printf("Passed!\n"); - return 0; -} diff --git a/tests/opencl/bfs/run b/tests/opencl/bfs/run deleted file mode 100755 index 7fa690ed..00000000 --- a/tests/opencl/bfs/run +++ /dev/null @@ -1 +0,0 @@ -./bfs ../../data/bfs/graph1MW_6.txt \ No newline at end of file diff --git a/tests/opencl/bfs/timer.cc b/tests/opencl/bfs/timer.cc deleted file mode 100755 index 3e907f4c..00000000 --- a/tests/opencl/bfs/timer.cc +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include - -#include "timer.h" - - -using namespace std; - -double timer::CPU_speed_in_MHz = timer::get_CPU_speed_in_MHz(); - - -double timer::get_CPU_speed_in_MHz() -{ -#if defined __linux__ - ifstream infile("/proc/cpuinfo"); - char buffer[256], *colon; - - while (infile.good()) { - infile.getline(buffer, 256); - - if (strncmp("cpu MHz", buffer, 7) == 0 && (colon = strchr(buffer, ':')) != 0) - return atof(colon + 2); - } -#endif - - return 0.0; -} - - -void timer::print_time(ostream &str, const char *which, double time) const -{ - static const char *units[] = { " ns", " us", " ms", " s", " ks", 0 }; - const char **unit = units; - - time = 1000.0 * time / CPU_speed_in_MHz; - - while (time >= 999.5 && unit[1] != 0) { - time /= 1000.0; - ++ unit; - } - - str << which << " = " << setprecision(3) << setw(4) << time << *unit; -} - - -ostream &timer::print(ostream &str) -{ - str << left << setw(25) << (name != 0 ? name : "timer") << ": " << right; - - if (CPU_speed_in_MHz == 0) - str << "could not determine CPU speed\n"; - else if (count > 0) { - double total = static_cast(total_time); - - print_time(str, "avg", total / static_cast(count)); - print_time(str, ", total", total); - str << ", count = " << setw(9) << count << '\n'; - } - else - str << "not used\n"; - - return str; -} - - -ostream &operator << (ostream &str, class timer &timer) -{ - return timer.print(str); -} - -double timer::getTimeInSeconds() -{ - double total = static_cast(total_time); - double res = (total / 1000000.0) / CPU_speed_in_MHz; - return res; -} diff --git a/tests/opencl/bfs/timer.h b/tests/opencl/bfs/timer.h deleted file mode 100755 index b142e279..00000000 --- a/tests/opencl/bfs/timer.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef timer_h -#define timer_h - -#include - -class timer { -public: - timer(const char *name = 0); - timer(const char *name, std::ostream &write_on_exit); - - ~timer(); - - void start(), stop(); - void reset(); - std::ostream &print(std::ostream &); - - double getTimeInSeconds(); - -private: - void print_time(std::ostream &, const char *which, double time) const; - - union { - long long total_time; - struct { -#if defined __PPC__ - int high, low; -#else - int low, high; -#endif - }; - }; - - unsigned long long count; - const char *const name; - std::ostream *const write_on_exit; - - static double CPU_speed_in_MHz, get_CPU_speed_in_MHz(); -}; - -std::ostream &operator<<(std::ostream &, class timer &); - -inline void timer::reset() { - total_time = 0; - count = 0; -} - -inline timer::timer(const char *name) : name(name), write_on_exit(0) { - reset(); -} - -inline timer::timer(const char *name, std::ostream &write_on_exit) - : name(name), write_on_exit(&write_on_exit) { - reset(); -} - -inline timer::~timer() { - if (write_on_exit != 0) - print(*write_on_exit); -} - -inline void timer::start() { -#if (defined __PATHSCALE__) && (defined __i386 || defined __x86_64) - unsigned eax, edx; - - asm volatile("rdtsc" : "=a"(eax), "=d"(edx)); - - total_time -= ((unsigned long long)edx << 32) + eax; -#elif (defined __GNUC__ || defined __INTEL_COMPILER) && \ - (defined __i386 || defined __x86_64) - asm volatile("rdtsc\n\t" - "subl %%eax, %0\n\t" - "sbbl %%edx, %1" - : "+m"(low), "+m"(high) - : - : "eax", "edx"); -#else -#error Compiler/Architecture not recognized -#endif -} - -inline void timer::stop() { -#if (defined __PATHSCALE__) && (defined __i386 || defined __x86_64) - unsigned eax, edx; - - asm volatile("rdtsc" : "=a"(eax), "=d"(edx)); - - total_time += ((unsigned long long)edx << 32) + eax; -#elif (defined __GNUC__ || defined __INTEL_COMPILER) && \ - (defined __i386 || defined __x86_64) - asm volatile("rdtsc\n\t" - "addl %%eax, %0\n\t" - "adcl %%edx, %1" - : "+m"(low), "+m"(high) - : - : "eax", "edx"); -#endif - - ++count; -} - -#endif diff --git a/tests/opencl/bfs/util.h b/tests/opencl/bfs/util.h deleted file mode 100755 index b67abc0d..00000000 --- a/tests/opencl/bfs/util.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _C_UTIL_ -#define _C_UTIL_ -#include -#include - -//------------------------------------------------------------------- -//--initialize array with maximum limit -//------------------------------------------------------------------- -template -void fill(datatype *A, const int n, const datatype maxi){ - for (int j = 0; j < n; j++) - { - A[j] = ((datatype) maxi * (rand() / (RAND_MAX + 1.0f))); - } -} - -//--print matrix -template -void print_matrix(datatype *A, int height, int width){ - for(int i=0; i -void verify_array(const datatype *cpuResults, const datatype *gpuResults, const int size){ - - char passed = true; -#pragma omp parallel for - for (int i=0; i MAX_RELATIVE_ERROR){ - passed = false; - } - } - if (passed){ - std::cout << "--cambine:passed:-)" << endl; - } - else{ - std::cout << "--cambine: failed:-(" << endl; - } - return ; -} -template -void compare_results(const datatype *cpu_results, const datatype *gpu_results, const int size){ - - char passed = true; -//#pragma omp parallel for - for (int i=0; i - -// internal unnamed namespace - -namespace -{ - // types, internal (class, enum, struct, union, typedef) - - // variables, internal - -} // namespace { - -// variables, exported - -/*static*/ CmdArgReader* CmdArgReader::self; -/*static*/ char** CmdArgReader::rargv; -/*static*/ int CmdArgReader::rargc; - -// functions, exported - -//////////////////////////////////////////////////////////////////////////////// -//! Public construction interface -//! @return a handle to the class instance -//! @param argc number of command line arguments (as given to main()) -//! @param argv command line argument string (as given to main()) -//////////////////////////////////////////////////////////////////////////////// -/*static*/ void -CmdArgReader::init( const int argc, const char** argv) -{ - if ( NULL != self) - { - return; - } - - // command line arguments - if (( 0 == argc) || ( 0 == argv)) - { - LOGIC_EXCEPTION( "No command line arguments given."); - } - - self = new CmdArgReader(); - - self->createArgsMaps( argc, argv); - - rargc = argc; - rargv = const_cast( argv); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, default -//////////////////////////////////////////////////////////////////////////////// -CmdArgReader::CmdArgReader() : - args(), - unprocessed(), - iter(), - iter_unprocessed() -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Destructor -//////////////////////////////////////////////////////////////////////////////// -CmdArgReader::~CmdArgReader() -{ - for( iter = args.begin(); iter != args.end(); ++iter) - { - if( *(iter->second.first) == typeid( int)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( bool)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::string)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::vector< std::string>) ) - { - delete static_cast< std::vector< std::string>* >( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::vector) ) - { - delete static_cast< std::vector* >( iter->second.second); - break; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read args as token value pair into map for better processing (Even the -//! values remain strings until the parameter values is requested by the -//! program.) -//! @param argc the argument count (as given to 'main') -//! @param argv the char* array containing the command line arguments -//////////////////////////////////////////////////////////////////////////////// -void -CmdArgReader::createArgsMaps( const int argc, const char** argv) { - - std::string token; - std::string val_str; - - std::map< std::string, std::string> args; - - std::string::size_type pos; - std::string arg; - for( int i=1; i - inline const T* getArgHelper( const std::string& name); - - //! Check if a command line argument with name \a name exists - //! @return true if a command line argument of name \a name exists, - //! otherwise false - //! @param name the name of the requested argument - inline bool existArgHelper( const std::string& name) const; - - //! Read args as token value pair into map for better processing - //! (Even the values remain strings until the parameter values is - //! requested by the program.) - //! @param argc the argument count (as given to 'main') - //! @param argv the char* array containing the command line arguments - void createArgsMaps( const int argc, const char** argv); - - //! Helper for "casting" the strings from the map with the unprocessed - //! values to the correct - //! data type. - //! @return true if conversion succeeded, otherwise false - //! @param element the value as string - //! @param val the value as type T - template - static inline bool convertToT( const std::string& element, T& val); - -public: - - // typedefs internal - - //! container for a processed command line argument - //! typeid is used to easily be able to decide if a re-requested token-value - //! pair match the type of the first conversion - typedef std::pair< const std::type_info*, void*> ValType; - //! map of already converted values - typedef std::map< std::string, ValType > ArgsMap; - //! iterator for the map of already converted values - typedef ArgsMap::iterator ArgsMapIter; - typedef ArgsMap::const_iterator ConstArgsMapIter; - - //! map of unprocessed (means unconverted) token-value pairs - typedef std::map< std::string, std::string> UnpMap; - //! iterator for the map of unprocessed (means unconverted) token-value pairs - typedef std::map< std::string, std::string>::iterator UnpMapIter; - -private: - -#ifdef _WIN32 -# pragma warning( disable: 4251) -#endif - - //! rargc original value of argc - static int rargc; - - //! rargv contains command line arguments in raw format - static char** rargv; - - //! args Map containing the already converted token-value pairs - ArgsMap args; - - //! args Map containing the unprocessed / unconverted token-value pairs - UnpMap unprocessed; - - //! iter Iterator for the map with the already converted token-value - //! pairs (to avoid frequent reallocation) - ArgsMapIter iter; - - //! iter Iterator for the map with the unconverted token-value - //! pairs (to avoid frequent reallocation) - UnpMapIter iter_unprocessed; - -#ifdef _WIN32 -# pragma warning( default: 4251) -#endif - -private: - - //! Constructor, copy (not implemented) - CmdArgReader( const CmdArgReader&); - - //! Assignment operator (not implemented) - CmdArgReader& operator=( const CmdArgReader&); -}; - -// variables, exported (extern) - -// functions, inlined (inline) - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line argument arrays -//! @note This function is used each type for which no template specialization -//! exist (which will cause errors if the type does not fulfill the std::vector -//! interface). -//////////////////////////////////////////////////////////////////////////////// -template -/*static*/ inline bool -CmdArgReader::convertToT( const std::string& element, T& val) -{ - // preallocate storage - val.resize( std::count( element.begin(), element.end(), ',') + 1); - - unsigned int i = 0; - std::string::size_type pos_start = 1; // leave array prefix '[' - std::string::size_type pos_end = 0; - - // do for all elements of the comma seperated list - while( std::string::npos != ( pos_end = element.find(',', pos_end+1)) ) - { - // convert each element by the appropriate function - if ( ! convertToT< typename T::value_type >( - std::string( element, pos_start, pos_end - pos_start), val[i])) - { - return false; - } - - pos_start = pos_end + 1; - ++i; - } - - std::string tmp1( element, pos_start, element.length() - pos_start - 1); - - // process last element (leave array postfix ']') - if ( ! convertToT< typename T::value_type >( std::string( element, - pos_start, - element.length() - pos_start - 1), - val[i])) - { - return false; - } - - // possible to process all elements? - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type int -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, int& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type float -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, float& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type double -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, double& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type string -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, - std::string& val) -{ - val = element; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type bool -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, bool& val) -{ - // check if value is given as string-type { true | false } - if ( "true" == element) - { - val = true; - return true; - } - else if ( "false" == element) - { - val = false; - return true; - } - // check if argument is given as integer { 0 | 1 } - else - { - int tmp; - if ( convertToT( element, tmp)) - { - if ( 1 == tmp) - { - val = true; - return true; - } - else if ( 0 == tmp) - { - val = false; - return true; - } - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of the command line argument with given name -//! @return A const handle to the requested argument. If the argument does -//! not exist or if it is not from type T NULL is returned -//! @param T the type of the argument requested -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -template -/*static*/ const T* -CmdArgReader::getArg( const std::string& name) -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getArg(): CmdArgReader not initialized."); - return NULL; - } - - return self->getArgHelper( name); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Check if a command line argument with the given name exists -//! @return true if a command line argument with name \a name exists, -//! otherwise false -//! @param name name of the command line argument in question -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline bool -CmdArgReader::existArg( const std::string& name) -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getArg(): CmdArgReader not initialized."); - return false; - } - - return self->existArgHelper( name); -} - -//////////////////////////////////////////////////////////////////////////////// -//! @brief Get the value of the command line argument with given name -//! @return A const handle to the requested argument. If the argument does -//! not exist or if it is not from type T NULL is returned -//! @param T the type of the argument requested -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -template -const T* -CmdArgReader::getArgHelper( const std::string& name) -{ - // check if argument already processed and stored in correct type - if ( args.end() != (iter = args.find( name))) - { - if ( (*(iter->second.first)) == typeid( T) ) - { - return (T*) iter->second.second; - } - } - else - { - T* tmp = new T; - - // check the array with unprocessed values - if ( unprocessed.end() != (iter_unprocessed = unprocessed.find( name))) - { - // try to "cast" the string to the type requested - if ( convertToT< T >( iter_unprocessed->second, *tmp)) - { - // add the token element pair to map of already converted values - args[name] = std::make_pair( &(typeid( T)), (void*) tmp); - - return tmp; - } - } - - // not used while not inserted into the map -> cleanup - delete tmp; - } - - // failed, argument not available - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Check if a command line argument with name \a name exists -//! @return true if a command line argument of name \a name exists, -//! otherwise false -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -inline bool -CmdArgReader::existArgHelper( const std::string& name) const -{ - bool ret_val = false; - - // check if argument already processed and stored in correct type - if( args.end() != args.find( name)) - { - ret_val = true; - } - else - { - - // check the array with unprocessed values - if ( unprocessed.end() != unprocessed.find( name)) - { - ret_val = true; - } - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the original / raw argc program argument -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline int& -CmdArgReader::getRArgc() -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getRArgc(): CmdArgReader not initialized."); - } - - return rargc; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the original / raw argv program argument -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline char**& -CmdArgReader::getRArgv() -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getRArgc(): CmdArgReader not initialized."); - } - - return rargv; -} - -// functions, exported (extern) - -#endif // #ifndef _CMDARGREADER_H_ diff --git a/tests/opencl/blackscholes/exception.h b/tests/opencl/blackscholes/exception.h deleted file mode 100644 index e4650d99..00000000 --- a/tests/opencl/blackscholes/exception.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -/* CUda UTility Library */ -#ifndef _EXCEPTION_H_ -#define _EXCEPTION_H_ - -// includes, system -#include -#include -#include -#include - -//! Exception wrapper. -//! @param Std_Exception Exception out of namespace std for easy typing. -template -class Exception : public Std_Exception -{ -public: - - //! @brief Static construction interface - //! @return Alwayss throws ( Located_Exception) - //! @param file file in which the Exception occurs - //! @param line line in which the Exception occurs - //! @param detailed details on the code fragment causing the Exception - static void throw_it( const char* file, - const int line, - const char* detailed = "-" ); - - //! Static construction interface - //! @return Alwayss throws ( Located_Exception) - //! @param file file in which the Exception occurs - //! @param line line in which the Exception occurs - //! @param detailed details on the code fragment causing the Exception - static void throw_it( const char* file, - const int line, - const std::string& detailed); - - //! Destructor - virtual ~Exception() throw(); - -private: - - //! Constructor, default (private) - Exception(); - - //! Constructor, standard - //! @param str string returned by what() - Exception( const std::string& str); - -}; - -//////////////////////////////////////////////////////////////////////////////// -//! Exception handler function for arbitrary exceptions -//! @param ex exception to handle -//////////////////////////////////////////////////////////////////////////////// -template -inline void -handleException( const Exception_Typ& ex) -{ - std::cerr << ex.what() << std::endl; - - exit( EXIT_FAILURE); -} - -//! Convenience macros - -//! Exception caused by dynamic program behavior, e.g. file does not exist -#define RUNTIME_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//! Logic exception in program, e.g. an assert failed -#define LOGIC_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//! Out of range exception -#define RANGE_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//////////////////////////////////////////////////////////////////////////////// -//! Implementation - -// includes, system -#include - -//////////////////////////////////////////////////////////////////////////////// -//! Static construction interface. -//! @param Exception causing code fragment (file and line) and detailed infos. -//////////////////////////////////////////////////////////////////////////////// -/*static*/ template -void -Exception:: -throw_it( const char* file, const int line, const char* detailed) -{ - std::stringstream s; - - // Quiet heavy-weight but exceptions are not for - // performance / release versions - s << "Exception in file '" << file << "' in line " << line << "\n" - << "Detailed description: " << detailed << "\n"; - - throw Exception( s.str()); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Static construction interface. -//! @param Exception causing code fragment (file and line) and detailed infos. -//////////////////////////////////////////////////////////////////////////////// -/*static*/ template -void -Exception:: -throw_it( const char* file, const int line, const std::string& msg) -{ - throw_it( file, line, msg.c_str()); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, default (private). -//////////////////////////////////////////////////////////////////////////////// -template -Exception::Exception() : - Exception("Unknown Exception.\n") -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, standard (private). -//! String returned by what(). -//////////////////////////////////////////////////////////////////////////////// -template -Exception::Exception( const std::string& s) : - Std_Exception( s) -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Destructor -//////////////////////////////////////////////////////////////////////////////// -template -Exception::~Exception() throw() { } - -// functions, exported - -#endif // #ifndef _EXCEPTION_H_ - diff --git a/tests/opencl/blackscholes/kernel.cl b/tests/opencl/blackscholes/kernel.cl deleted file mode 100644 index e094e57e..00000000 --- a/tests/opencl/blackscholes/kernel.cl +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -#if(0) - #define EXP(a) native_exp(a) - #define LOG(a) native_log(a) - #define SQRT(a) native_sqrt(a) -#else - #define EXP(a) exp(a) - #define LOG(a) log(a) - #define SQRT(a) sqrt(a) -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// Predefine functions to avoid bug in OpenCL compiler on Mac OSX 10.7 systems -/////////////////////////////////////////////////////////////////////////////// -float CND(float d); -void BlackScholesBody(__global float *call, __global float *put, float S, - float X, float T, float R, float V); - -/////////////////////////////////////////////////////////////////////////////// -// Rational approximation of cumulative normal distribution function -/////////////////////////////////////////////////////////////////////////////// -float CND(float d){ - const float A1 = 0.31938153f; - const float A2 = -0.356563782f; - const float A3 = 1.781477937f; - const float A4 = -1.821255978f; - const float A5 = 1.330274429f; - const float RSQRT2PI = 0.39894228040143267793994605993438f; - - float - K = 1.0f / (1.0f + 0.2316419f * fabs(d)); - - float - cnd = RSQRT2PI * EXP(- 0.5f * d * d) * - (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5))))); - - if(d > 0) - cnd = 1.0f - cnd; - - return cnd; -} - - -/////////////////////////////////////////////////////////////////////////////// -// Black-Scholes formula for both call and put -/////////////////////////////////////////////////////////////////////////////// -void BlackScholesBody( - __global float *call, //Call option price - __global float *put, //Put option price - float S, //Current stock price - float X, //Option strike price - float T, //Option years - float R, //Riskless rate of return - float V //Stock volatility -){ - float sqrtT = SQRT(T); - float d1 = (LOG(S / X) + (R + 0.5f * V * V) * T) / (V * sqrtT); - float d2 = d1 - V * sqrtT; - float CNDD1 = CND(d1); - float CNDD2 = CND(d2); - - //Calculate Call and Put simultaneously - float expRT = EXP(- R * T); - *call = (S * CNDD1 - X * expRT * CNDD2); - *put = (X * expRT * (1.0f - CNDD2) - S * (1.0f - CNDD1)); -} - - - -__kernel void BlackScholes( - __global float *d_Call, //Call option price - __global float *d_Put, //Put option price - __global float *d_S, //Current stock price - __global float *d_X, //Option strike price - __global float *d_T, //Option years - float R, //Riskless rate of return - float V, //Stock volatility - unsigned int optN -){ - for(unsigned int opt = get_global_id(0); opt < optN; opt += get_global_size(0)) - BlackScholesBody( - &d_Call[opt], - &d_Put[opt], - d_S[opt], - d_X[opt], - d_T[opt], - R, - V - ); -} diff --git a/tests/opencl/blackscholes/main.cpp b/tests/opencl/blackscholes/main.cpp deleted file mode 100644 index 840fb9f7..00000000 --- a/tests/opencl/blackscholes/main.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// standard utilities and systems includes -#include -#include -#include "oclBlackScholes_common.h" - -//////////////////////////////////////////////////////////////////////////////// -// Helper functions -//////////////////////////////////////////////////////////////////////////////// -double executionTime(cl_event &event){ - cl_ulong start, end; - - clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL); - clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL); - - return (double)1.0e-9 * (end - start); // convert nanoseconds to seconds on return -} - -//////////////////////////////////////////////////////////////////////////////// -// Random float helper -//////////////////////////////////////////////////////////////////////////////// -float randFloat(float low, float high){ - float t = (float)rand() / (float)RAND_MAX; - return (1.0f - t) * low + t * high; -} - -//////////////////////////////////////////////////////////////////////////////// -// Main program -//////////////////////////////////////////////////////////////////////////////// -int main(int argc, char **argv) -{ - cl_platform_id cpPlatform; //OpenCL platform - cl_device_id* cdDevices = NULL; //OpenCL devices list (array) - cl_context cxGPUContext; //OpenCL context - cl_command_queue cqCommandQueue; //OpenCL command que - cl_mem //OpenCL memory buffer objects - d_Call, - d_Put, - d_S, - d_X, - d_T; - - cl_int ciErrNum; - - float - *h_CallCPU, - *h_PutCPU, - *h_CallGPU, - *h_PutGPU, - *h_S, - *h_X, - *h_T; - - const unsigned int optionCount = 64; - const float R = 0.02f; - const float V = 0.30f; - - shrQAStart(argc, argv); - - // Get the NVIDIA platform - ciErrNum = oclGetPlatformID(&cpPlatform); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - shrLog("clGetPlatformID...\n"); - - //Get all the devices - cl_uint uiNumDevices = 0; // Number of devices available - cl_uint uiTargetDevice = 0; // Default Device to compute on - cl_uint uiNumComputeUnits; // Number of compute units (SM's on NV GPU) - shrLog("Get the Device info and select Device...\n"); - ciErrNum = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_DEFAULT, 0, NULL, &uiNumDevices); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - cdDevices = (cl_device_id *)malloc(uiNumDevices * sizeof(cl_device_id) ); - ciErrNum = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_DEFAULT, uiNumDevices, cdDevices, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - - // Get command line device options and config accordingly - shrLog(" # of Devices Available = %u\n", uiNumDevices); - if(shrGetCmdLineArgumentu(argc, (const char**)argv, "device", &uiTargetDevice)== shrTRUE) - { - uiTargetDevice = CLAMP(uiTargetDevice, 0, (uiNumDevices - 1)); - } - shrLog(" Using Device %u: ", uiTargetDevice); - oclPrintDevName(LOGBOTH, cdDevices[uiTargetDevice]); - ciErrNum = clGetDeviceInfo(cdDevices[uiTargetDevice], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(uiNumComputeUnits), &uiNumComputeUnits, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - shrLog("\n # of Compute Units = %u\n", uiNumComputeUnits); - - // set logfile name and start logs - shrSetLogFileName ("oclBlackScholes.txt"); - shrLog("%s Starting...\n\n", argv[0]); - - shrLog("Allocating and initializing host memory...\n"); - h_CallCPU = (float *)malloc(optionCount * sizeof(float)); - h_PutCPU = (float *)malloc(optionCount * sizeof(float)); - h_CallGPU = (float *)malloc(optionCount * sizeof(float)); - h_PutGPU = (float *)malloc(optionCount * sizeof(float)); - h_S = (float *)malloc(optionCount * sizeof(float)); - h_X = (float *)malloc(optionCount * sizeof(float)); - h_T = (float *)malloc(optionCount * sizeof(float)); - - srand(2009); - for(unsigned int i = 0; i < optionCount; i++){ - h_CallCPU[i] = -1.0f; - h_PutCPU[i] = -1.0f; - h_S[i] = randFloat(5.0f, 30.0f); - h_X[i] = randFloat(1.0f, 100.0f); - h_T[i] = randFloat(0.25f, 10.0f); - } - - shrLog("Initializing OpenCL...\n"); - // Get the NVIDIA platform - ciErrNum = oclGetPlatformID(&cpPlatform); - oclCheckError(ciErrNum, CL_SUCCESS); - - // Get a GPU device - ciErrNum = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_DEFAULT, 1, &cdDevices[uiTargetDevice], NULL); - oclCheckError(ciErrNum, CL_SUCCESS); - - // Create the context - cxGPUContext = clCreateContext(0, 1, &cdDevices[uiTargetDevice], NULL, NULL, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - - //Create a command-queue - cqCommandQueue = clCreateCommandQueue(cxGPUContext, cdDevices[uiTargetDevice], CL_QUEUE_PROFILING_ENABLE, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - - shrLog("Creating OpenCL memory objects...\n"); - d_Call = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE, optionCount * sizeof(float), NULL, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - d_Put = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE, optionCount * sizeof(float), NULL, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - d_S = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, optionCount * sizeof(float), h_S, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - d_X = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, optionCount * sizeof(float), h_X, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - d_T = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, optionCount * sizeof(float), h_T, &ciErrNum); - oclCheckError(ciErrNum, CL_SUCCESS); - - shrLog("Starting up BlackScholes...\n"); - initBlackScholes(cxGPUContext, cqCommandQueue, (const char **)argv); - - shrLog("Running OpenCL BlackScholes...\n\n"); - //Just a single run or a warmup iteration - BlackScholes( - NULL, - d_Call, - d_Put, - d_S, - d_X, - d_T, - R, - V, - optionCount - ); - -#ifdef GPU_PROFILING - const int numIterations = 16; - cl_event startMark, endMark; - ciErrNum = clEnqueueMarker(cqCommandQueue, &startMark); - ciErrNum |= clFinish(cqCommandQueue); - shrCheckError(ciErrNum, CL_SUCCESS); - shrDeltaT(0); - - for(int i = 0; i < numIterations; i++){ - BlackScholes( - cqCommandQueue, - d_Call, - d_Put, - d_S, - d_X, - d_T, - R, - V, - optionCount - ); - } - - ciErrNum = clEnqueueMarker(cqCommandQueue, &endMark); - ciErrNum |= clFinish(cqCommandQueue); - shrCheckError(ciErrNum, CL_SUCCESS); - - //Calculate performance metrics by wallclock time - double gpuTime = shrDeltaT(0) / numIterations; - shrLogEx(LOGBOTH | MASTER, 0, "oclBlackScholes, Throughput = %.4f GOptions/s, Time = %.5f s, Size = %u options, NumDevsUsed = %i, Workgroup = %u\n", - (double)(2.0 * optionCount * 1.0e-9)/gpuTime, gpuTime, (2 * optionCount), 1, 0); - - //Get profiling info - cl_ulong startTime = 0, endTime = 0; - ciErrNum = clGetEventProfilingInfo(startMark, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &startTime, NULL); - ciErrNum |= clGetEventProfilingInfo(endMark, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &endTime, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - shrLog("\nOpenCL time: %.5f s\n\n", 1.0e-9 * ((double)endTime - (double)startTime) / (double)numIterations); -#endif - - shrLog("\nReading back OpenCL BlackScholes results...\n"); - ciErrNum = clEnqueueReadBuffer(cqCommandQueue, d_Call, CL_TRUE, 0, optionCount * sizeof(float), h_CallGPU, 0, NULL, NULL); - oclCheckError(ciErrNum, CL_SUCCESS); - ciErrNum = clEnqueueReadBuffer(cqCommandQueue, d_Put, CL_TRUE, 0, optionCount * sizeof(float), h_PutGPU, 0, NULL, NULL); - oclCheckError(ciErrNum, CL_SUCCESS); - - shrLog("Comparing against Host/C++ computation...\n"); - BlackScholesCPU(h_CallCPU, h_PutCPU, h_S, h_X, h_T, R, V, optionCount); - double deltaCall = 0, deltaPut = 0, sumCall = 0, sumPut = 0; - double L1call, L1put; - for(unsigned int i = 0; i < optionCount; i++) - { - sumCall += fabs(h_CallCPU[i]); - sumPut += fabs(h_PutCPU[i]); - deltaCall += fabs(h_CallCPU[i] - h_CallGPU[i]); - deltaPut += fabs(h_PutCPU[i] - h_PutGPU[i]); - } - L1call = deltaCall / sumCall; - L1put = deltaPut / sumPut; - shrLog("Relative L1 (call, put) = (%.3e, %.3e)\n\n", L1call, L1put); - - shrLog("Shutting down...\n"); - closeBlackScholes(); - ciErrNum = clReleaseMemObject(d_T); - ciErrNum |= clReleaseMemObject(d_X); - ciErrNum |= clReleaseMemObject(d_S); - ciErrNum |= clReleaseMemObject(d_Put); - ciErrNum |= clReleaseMemObject(d_Call); - ciErrNum |= clReleaseCommandQueue(cqCommandQueue); - ciErrNum |= clReleaseContext(cxGPUContext); - oclCheckError(ciErrNum, CL_SUCCESS); - - free(h_T); - free(h_X); - free(h_S); - free(h_PutGPU); - free(h_CallGPU); - free(h_PutCPU); - free(h_CallCPU); - - if(cdDevices)free(cdDevices); - - shrQAFinishExit(argc, (const char **)argv, ((L1call < 1E-6) && (L1put < 1E-6)) ? QA_PASSED : QA_FAILED ); -} diff --git a/tests/opencl/blackscholes/oclBlackScholes.pdf b/tests/opencl/blackscholes/oclBlackScholes.pdf deleted file mode 100644 index a7b777d75d9c36fb4bd50e5c8147a8a0b102b3c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206856 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

$^wH@%W1P>%kVIE+m@6 zmOHAdOsZTyf3eSW95)(Io2bR z4a5~exhrZN0=7?!zGm1u@hqji1aew;I6M6w@f9fcS9^<;KFHb%&N_9aEVM|at+a2A zdP{`n9~-w4O4P3{{2ds#$}BO&i83Y!elSME34d6FelKfKa-8D;!*&D;3ws#i^bSXU zeatfIyAu`JSm>CXp5+2&aYKZ-SqT1TF#$)T_mOKn(>;}ZVU&<711_izGCt<8T~Ny! zVK*P7N*sDLFV+Ya9+E4Etd<$69D>+VFIfV&3`v0b*kpl2m0bgv~(=;+d_XO>>AvN8q0eAQ-TAB}ez+J~D%1QMkbbDNZX&-B5LtgX#wBG^PA(QcaX(?gT-(+|yX^%LuNi zUs!gpHY|iG<@u5g(m}LnHgW$j@|_WmCXpz-edQ90Ms44xk8tj}^gU}faR|tUL{A3v zSr1HNZ~b(+Ye-+Gc3R@s}SxMcAm%N%o&rnJCu8mxZR!a);W7;04P zLR-F!7SKX>H};b!e7Ec*CR{9lm2FPs#nEMC2Hc7h$tZI3acIWRKg_bfXk(uzl{nv4 zI&>oW9CHIny=x{*E33+w&MEwIEL6R`kZ!Uk7!7Y%T>%T{1MqC2a$tVt{2J6mwlbqk zNTYmi?YGWk$BNE(l|QN~HWK7Brrdi8lw>Hab!2R`?-Jl)A`@NI51Q`fbTP{Bg1h=I zT#8djCaQ$Qoa1H}=MP6YLJQgqk&z}gKvWyx!)1K@wXBSHXA#Jzmf70k27f*=uUj_7y?N1RCt=Z5IH;fJ8$7sIqF@H*3^p zbR$CMB<$T$J|<_be{3mL;fCZMc^oGX;5$@jL6>Pm&fQyFp*FArja>1|K5y|er{$=K z`m}=Hf#rnL?WHWqqO+%*c%H|8*=-8e3fAA-Dm=#6Uo6mfNrlIiS((cVsyYw}CQWol zRftB+T#sLb8z(@|>ao*-UXur*Ptqcu2p5}`R7$J~u@C&^Xm#3HLa{l~xX18=4iG|O zwk6f!Qd|&j&^8#dE}qCth47wM<%o_W)(@v}Uvw|J+l09rBww+NJozqZ&r;`D(E5BP}iO@X;VW zaf)NUrDa4$_cv2(a*EHN?}*(ENJtw;J|Snyl0xHwtq}hRBa!QOph+X@uUDYmy@cL* zB3+wI^K&6`YHPz7JlLzqCt$&jy8jF;O>#r7gR2v!?C`;C0N5S}ZRP1FL~mI!m&0>( z9o}VDi;ey{ink>+TxdGv z(g|{?><(OOD#67?p1MiSkSzGS?4dr#=hi-%9nW=Gok&GER!m@l*d|-1fG?~+S(?`5OGVUv=`U>vpC;&Vl(-f(ch1wrS9{AOL9t~oa z%*QubiQ62=g`~jv0Y(v)7FdwTLvAMk>ts^t>)v+2Eo=*nRcCwl(z$kUnqRxyxSg)i zaBd!1GfW9&dmB@HnSQj~J)<)f)#8&q276{hNP0tCaScTRT=CdbrC|YI_YB*W*y41F zcD#u=>OIQ5UWkI9Q?IQQj?F|ENnLySd{B zKxsL{)qu+C?}KU=CwyVmL!4R(g45h#83=pb9A%e%AQS=|r1=NlZ-);phlV_bECM}t z?K7{wfQK4+c{2m46m}(81mJZ5rAxCQhBu1tWvMt3YQ+}*K!1e#R`}71ecMon7F0~Q z+`$u5PO?{8YsKT`%j?>QiHLNd8iUu~1qgy`nNKvEH)_CbUJcc>B*+_pji^##V{B$F_j$7+6lWMa?@)%5~>*2SAFfZBsF_c zbTHr2q|kO?S%wtHL=Cpk0D+Hgmx~-MogQJ!jJ;RvlbLUlyEfZ=#@OnL!_((OxalM4 zBq&q(DadWrCotsp9@+ZGDkZGS3hk5-%z{#Uh}Ljy=CFN*{TLSl3AR8~3E?N1b<44x z4493zMdhA%wu-cJZA;0+bdC{&PRDc#ZQclmZI+Ea!3=t=a<*ym?}d}V=H5-+kr^cm zkuJo9hl+@-EeA4$E#ymIV{;_OE+rc&;RPCuwNRZ^ALM`(bnXF4&P|u2|E?nuCr&=w{|)EvfdABL8Oo z2g(vjO_)e;jY5XQxSFa$D?I*OT}&k=#?KKzyPO1p&F?9#t9!tXOBo-hl1UH{;j`&& z_pJO|32zjkd3yu#2qN+q282=+_NTW8#`_o~sx9cf)b@T9e`*k9Oa1C$M#4(UP{d48 z)3gbUYYG7yECE~7%V3AhMnIebO^2dO1YAnPj)h`d+5aAk?P6-{$>|EOqF;SWL3e0P zB*Ox4m`ar>FlW^5OW*#K@0wO=W>pKmD)y%fgY*_h6>)-Ag&`6O{=GqXyum$N`$71S zXC%-OdaFPQW5G2c2+vo6>3Rj$t zg~1EMx;lLfIk^`RjGFqLst;KZ7PybusE#NkhU=?@p~}F16f)<6^ASpW*vv+J@!!bw zm2_yc+cqKL$HX1RTY6{)r%^jJS8jIuZk!waa`3Tq2GJYWke3Jjn}=r>Pa3ATRSIn$ za6%s$BY(Jjvm43K%WscvW6JY1<*IJp4m_TN49vX~2?T2bmw53$4mQ_{Da(#J8Qf)x z3R@R5r@uxsR>>-gt6{2NVPGQg^TR8;q2mHGf?1OMz+4!pt$mPDP}|wfT{S=Y%?2qC zk4~S-6N;tjzVybxz`&PN%fvoOyA~PyVF!pJ5z`jx1iQjr!dlMN+j?msu=?yV6{_r# zY|zvJm!THRHGWTLmL2i~(Gw<)ZSfp_DHMY3nxE&qZHi^pA?#Le(gb;7qa6>IRvF29 z9*1?KV4x~mA4h}=O>@ILp?ykH3}OmI5Pio{{pN%|nG`R-HmR>3%sWb{=Z(NXbyrQ7 zzO70yLz#SI$+#AE7lDw7sWAgKKWE{(`ImYU&=ZB40%K1Ei7SAeopBDe)#3eHTJ$MP zK0xf*x~?M#xwGmfBJPc+?5^+Huf|Ewj66Qx6u8pD><3Fs6Ui=A4Q-LC8IkLPnd4C$%r#<!1+6+%D;3*|3~g;u0PBfzns1QZ`{v+hrs{SvcX2g_S+x+ z76SiQVEq3@BgfwmgTDgYnYjQKCs8vC2P3;T3)jC&qX;l^*r%$Ycr8@y5BFd!)gkTK zG@ckLp^qfb8V+EqmbNJ`7NJ4VGKqEqh2}gxocsiZ8j3+3>qo?z%(7lzXgD}3mN@Mx z^hsnWs7NIbPmqA)m~mC;9yst&B4=!a!89XaH~ZRi_0)O?!r`R{aR-?}Cw<_$A-)io zkk@I?Gm}{EA621~t~;v7`fLd?Gm;GcWY}duO4PStU2)z{kUk+cbH4%teCht=NC2!u za1L^b<1g~sF}S+$8f-MJUzn4I231D1 zaSF<+T6=>Cu9p8vg10MECJqr*pBv_ft+${{y_gF1vV%n`ZI~DbM5l|vHcQ3>r#FWi z3t?N6u=PDNK3HP}w8&=B_9FsJ2m%b`^FG}%m|O)^*~lUTrb{z=Gs#&rEytO3UIse3 zQ^3$X_e?cyVpZ0A2_WbeRlQpn9wY7;bge+6>rRUk0+>l5%CLi=&DXAfJ;e zMa7OVh7r_miTBbv(dZA_nRJBG%ZF)!TO%ok2m4X=NlOfQY{NZhBgk_b#7!Q=7`~kT zB=!%=9gc;Inb;07@qZpLC*^Y!0vWGibo-`Dapizd2g|dGBLROaQkU&~L@VsQpbn?6 zT@Z#B!49EMa`DcLm#%t?ev~(FN5#WjtzlcX z8-dcv`U7gWfYp6^5{rvgK5~j6Gg2s852|mY9!Z@C|0rY?l!loiH>u@2%h+Nl5wIzv ztWyTw=o$TXq9{~;lLOZffiF9-pcrh}&+B?S>T}ei2ZImJ3RNHGXp?c! zXZ+Xw<6m^+-b*8k!ap%d_*NTag&eoCbxT(U7qwul$f~vY3LjXRUBTZc695# zPWQ==wyuSC6+<(CY?k>$Z&_JtTqn!@frQLyXa&EP_6WPS>_TF~E@VZa$HZRor$WNo zygIrTHHO=Rg*lP|N5pxs3AQ=@v50d*$-;nsI8U9#Gg#YQkTu=O7DT*dkE|T@0Pd`% z4Kn;WQiI~;uPkw>lvnmS*z6$#vHS%G)I;X!sdpdC1<*txG!V57#LWk%(dYZr#5~ka z92Ace16tq{xCfjZM6{K`?`^YO@kBo=EGSzgAQhB$436cf6%+dBZRv}qnY zm_<+GcyT_V{pbEw@+-PbVNA1hHu-a!VJgdp4)c%0VEopDIFj9Z#d;y1b$D={b+G7U z#|O44IP02_W=c2KB*@6inR|t&TKpNMggbkXd7y}!y(cKK8|_5aCQ=^ zrFlZyCA)6^Iug!>+Z%6$gRV&EgRX&l+X7WenyqeMHjh~-^nx*7U3PiL$7Z8>BcB`v z0x~-6)PYx4rRAAV!NTGz8I$oDk65AvM$liY%!6U)3Hq6g<;ON!;-s}Q#XWJ@ zzJIOyy3DF;k?Q?kP(6d;dNOAYUO*#2cY4k(kAkY0X194t$uSCDB@AgQXA$(IE6*_A z7+b}s8DHPjT1c%tjK#OI(12S)R+TlGWKdhm!~e0JK!x&>-m*9v_lL0*?Uc-Coee%q zxqCJ2qd9HGIeei|rm>>$h`6m13g!YPlun-xzp!;g61b$~AiUpfB7aSrJf+gbEo+@S zf*nI%hl`tG(DQZYiofDjhvUg$|Uxxb~&j-b}qNduVoG1(rnxucb!hy+93a=%F6p=7Aeq? zliEO$KdK|YZcPGD2ycSxRBv28C}vdPMqTkc5om4})Cy?oJM^tZHgA9MJGUDG{Bs)& zU_$!yu~W(y{1uN{qQI{tAf>b4wDh?L&E8ka;P&i6!;JC8Pu3++Pz?q>1}=KWR9iSGSPZVe1|#Z1ie zAJ~VD6jT>Q33}o0MXqiW?`GhnF5vrrZZ9f)Sd(zmk`~r=dvq(GALE$4qbRcVNSm;z z${~Moc!tOClHiUrff-S8=YDx?MOfyRfJAU;kL${ayytL8Q)aU$lHOfzne^tQf6A3^ zu!X}Mc5?QAeJnhVwOgrYb2EK;D&%@)sV>XbYP zlP0fTbOo!1TKbyzdcrrT?mbwf$>~U?*~VvV74#LH>FTuQDrg3;?T|#3yuwUy%*mey z))g-zSRI|tbc3d;AE2ZrqzN98*yL*An9np_r0hE^dYG?<4*1~qg^V5|Ejn2A>)}Qq z7HTPaW^16_d37|u*s4tfokFO4LH0uye28RXC(5gl;`;HG7UM<%FMwN|cp$IIny58B zw0+%np%3H+uWl|gkG)<{>X4Ro=e5UbZ?OI=$HNWw{7XUWvYKq_Flvh!rIJWL)Wlb? zl-2KzVpG`VZDKk8Pqy0lIl41v^kdV3mq|DE4}D#wtMi^C3yXVq&$8F$-zpY95*XLU z>7bJ`b_a1ZnqZX3P)y)Vf63i&dEpx`$uAHf3Vw;_st=(jY&oW1`__-eaJ^A>#g7&b z7S@$F<$bEDMfu#REU{6`6X<%mHY(0r4vrTic4(kKJ8{O%sSgLp5ZdYcAbtByO|u5O zq08u!CPqtpSiG`m998<*&JRh>I8G`6F*4@CnJu&v#dBXMr}N5tjuPw<+viSQ@oCi- z_&t)XYKN6+*M5B&bu~yR`n(@pPd#cE_-gGc#*ef$rdgwC7Ts(9d`lR-`WSVblKG=- zs)i=2hCaxR-ln42`C-r&BK?Eiskn;1ndCG>tR4}dgMs#%y65Pa{PRX>?)HRge8Q3o#Q8- z;@|v+-xi3!T~p*^GBq=BBx%0RfoB7Xn_0h0gxZrJZ=||ha_%em#28XQxfMfBGQ%jN z@0~BF_fB`B(sFvQg`Fl9fJC2hgr7JK`G82x!At4BJ0kM;R+qzY4w9)i_CS5>ed03hU! zpLk})u1j_fW|s7^G%B}V@{BD_=KAZ5@vuDls8bYH1Z@5Db zqt7*l;C!`)UYO_57ych-?a|Ud3v{lb`{)nzst=iMGE2W(o%{LP7)Yq7(VX*P1Cb-q z)}^DH4p-NEzj=~KD+U&yP7t$G5K~bzhRGg1!gPrVN)@RhJmCtD)^i6j0zU5ZG!s61 z{hXy9EsfyRqe-prB3?UF*e-J#nXNxU_)FU)-E`M<_8fJJj*v8I*kjUs390mW`^AIXWts1A3KHkgzdvD^wKu*USedAp(#lkg&Dj^alV7Ov%3K23gS5T zlx8REJw_ZiDNQsC6z!sWVD=Yj>>c%PMNF)8(W3uRGS~=(e8DX2P!*fe3WwZ1u%W1k zEZ*CPp{-`%q#P7iStPJ({}lf)I1lqZqu5u+yj4Uyvb@lFl+0!L#shz05q7N;7JlXe zo3V$@s#Nad(uVtaS6GZjR%kR2M-Y7XDX(1SO>$S)vtqk3gSyCZdC2WCO#-wlD^HKo zgn~er5!AqG>R4`RBp5N-p}^~9j0<`$v9W@7CPE{UhA43H;-If}C(z3hGg{<{Q_?4J z1FT!>k|-kq2gjGV*t8FPsT{^lbTrf0Dcb#~=6S;D&$q&`7&@g?>oquc7GX$m9%|dv zxEAvcC%uWz(U^3Pe$@p6gjE|TU4`<>lB{cHmh^G5u2s9StuEt(GeM=Mci&dJt9BF6 zshMaa@<1*qThj5BsD60bw1^U;ji#nY1Ib`3;u5&bCC{;`&OR_5Mt5QiGZs3SrDKc34VC*j zaAssMnphe?V81LBd{UW%JAs41R?6!$p0rq%HEO`e!b{5yiXU!-{;Rc>=(8#Nm zysQD()aVv zYO2MMS97$b?J4VzFf6MDrCA;YFpN_lY6IB_3l)VdEQroC5~XV+wKMvhOp_W7ehU4viW?!lNFUz@sLh5F^zXkeyCAdT7D z)0w*a4~vdHS_pe$la;+RI(@Km(}FHx6ACE0Rl}g#hbZcK*aXhg-9^c@eOe@Ny>cCP z$wtm#MKlT4NC#G7y`IjcHkIdzf*%o}vJj`T`V+xtqZ8(hBUY{-&!K|U#g#zeLlqwb z5U^ju7}Cde$(>4y7QKIRCYf1^uQZ$F`1F=S?yCs&2Akht+U#nPlns z{TO=jnisFJm!SC`mgnG>2qQwly+=hY~Ev@PM>T~!UaSg;cPO)`nbu+*;oDOJ4pEMRE zAGl9>p$r!~;eW8-S>X{yg_(}@>-1vX&ZNB7wpz+zB}nyjy>`)_zB4ZJdgd}2;NXdE zzl^@j{>i^lP zx)9voUF-CoMT9IUhu3526k`~?sCXv;k`~mfYpL?{g=MqVU_zzY^fdzP#p7MRMal&b z-@q$L>xwN>pbyc~9-2FdJL;=c4Cogy{A_+?A{ z#7*zlf7;4sh*w(@qT;t*C@35N5jEF@)JIw2PE zo!-}~ZWnsDM~QlMrPNi1#m-!!`oNlN>p)ht{0=>XRP=|26da60i~H}?tcxef56En4 zYCK{0I1!$uo&C}EAf&b3--51$IEs&ac`O-#A%K9O;;jFL>cjj7L;M}F`CIj2;`kkp z`zyp(#mLT3-%6iO(AvWAmj?6iNB6$f4f`v)m-&zAUPi7zG#?HYK)f#_KP%l8^`nQwh`a{3_YpDNZdVd5j|GU#; zV|<$)U}mfUxZ?lK>HQIVNOzV1DzUy%l5w{N;G_@BPmg8y6QqLH^Z)nTv>x zi*EftTzus}NvHoghXX5zPgOP}p1)v==u@SKX>_z{$Hya1L zHiMwPz0n&<7?c6lT+4qjwwc{uSPDEeOm|L3(n9;ZLy=>^Qfhh?DPKfxKfW<;S(Ccgp#6_ocBUJJ#oI{LzBgKNV5H?rS# zQQx{07h)Ngd&ZDH{zS+VN`A#ruVDINb{O+{2W6hS^(WJvyj{G|3!qR6@QuCqzp8P_ z{D;NruO%-eA^gVKZ@l+gy8R7yAOb9#w;$u5+%F&@AtNe4qvUF7U~K^aZm4Q9v1+oh za%wZN|9W9z{{4xKS(BNKQCphMxP_Hx}a$9{AfTrSzZ3FM!GHZ6bfj zFUEh$FM#;{*B3MU-|Z}1e@le7R#x^m()@QWcFwnF`PUaK$M3tc0jyPTBm9-uf+<{*X%lBbU6f*T0ZVfW>MAs9^c_^oqZB(fYrkY@oz@@o6r9}P|vT-h<_b&{=r~?W%5?&^bK1C zIN~_G&COnu<(JU|J#$t zza_8qzr6Q?ZFXka zI{LY0*!?F&Q2|Yp@nn1B@if=dr@c1!*VDDv$5(gjpRnEhNV$ZHp_S1JLmIT#1`3xh zg|24*lc?*juajpAdYTIz~J48j-w*cUyz}?_4hdK$`Gf7T%nj5frs0h60-3I zX5yugNzt~jHAfqXALW+GH=$4jmIsoux>ZN*hzB=VDLYK+6=z^sDupTEBl!c0P^Q9# z)P>YRF&h%sI%~qu;7el^AS`hR@>F7%-l1Oi0z;wvfIQdbOl$mb`VtG zVf_jf*`ccd>7X49QK4ajV1cI9!eQ}~bs%I-KV2it$HXMKz*)$Xf$QUBeLGGl?tqc7 z4d(A~w>IQ{+BpI&@(P498-W6OKH`G6WuoCwA>WZ{kq=`zH+60jINM=6-=GfH@gAn+7%og5QAk&;bz!s!1kQM8;WTL7q03 zP_zA(2d4t5KLW0?qRyXW^Q~%`>VT287!p5A(T`O+!#_{I`JBI8o|463*bo`(GfWsh zf{rdIK5OTDCr;{E(X1W?7nv^xrL5E%4~Xa9-k{}B%vWcN6yd+o5jsU`}Tg@kvot+OjZ$YvzEAcMho~aL8BUSyZx;sDksg&YmlT!aB|gEpzcn&s>3` z!2W))HF^wLh=BoZ1ARi|5{pny&C=qcg2uDbxx?lZ`nlLFLv(i&J~J~h-o}@KtM8au zb``GTMJgb)CF-%jd#}nRB9rWhORhe<$Y9l|{*&dMbk7#(!o6z=2mTNfd4yIwE$3$= zo4zNL#f;MrJoj)vtXc4wMuB$BU+4DF8~nHxtA8l7=EbQ7t|80bze;VDO%t1%Mr{kc zruC1cU#vIJc!zC`Ty8!edps%Vx^)X}ge+37nDtQ2etfQp(*eq1jFLTY>p2Ou45L<} zVPL(JBd0%;43F0`vmXh&kW(BtupO~V`{5nB-Qqu7ly9Uc{yo-11Y}2iX_&iwHC4%t z1*4ax{_|CxH)mpsVFqQ!VqNNx-m{>fW`RTL!>UPdVnHZAa(}eIklyi4^cNDeORAfh zXrI{ngxw(?5&}<;gW;dWN3e%p%d!OcCm-9kpL{QYrBc)uS_Q9HPCsVmd3hOV4Idys z1PP2mu18@8iPn`iJq#!m@zts;!IraS<9bSIN-k}g%<*Uw&__VII4Qe4ZbjlI+lhs$ zvBEmK&vkEV_82fHNq1zYQ7<3km$_q|elNzwJ!@?bPiD-5@31+vj*@4kK7n?*D+!nX zUZ%2Q_6`o?Tiu>~00adB^F;)PFYC4}3gyl!6&DCTd4#}}DwRZ-!c?`I`Z3t-*xebQ ztYC^S`7OYwKua5k#xI0|BPs15OFhQs1r-S&HDk#%4ypZ5=bBPrC zpg>$TtMW%WnKUdX zUOqL9_JBfIt9(t}jNoshm>JU}f{&+IUyplkNCk$}RSVnwyr$&tq7$~Gy0lc7L{l*4 z{nb(bwDzOp*81lFJ-)~9Vu(>(r6X4OuXgU7&D_-H{TX93g7&IxI&@Dy_9p{3#RJQC z9p%sO^dq+qQ6EXKrCTaQx%f6{y@&~Hmc+^%N`o&qgJ7&6JwY)BybROExG$?XQ|G?1ppr6f%7zXSOGCgw3OjdA4h6A^I~LVqiqGh+;(x8#{LCXY~{cHl3_ zmvM2+gYfe%RrWkf(g0^>wF^K{qRhf~h%Q$?AhL9WmM$6dKYC8Tr$!9h8r-TVZZ@%z zS3p8!TndFM)Q3dmk$*Q}Ge|{3nN8nA1ru%u4mQe}4O@tp0i7MZhY~J`f+mATOmi4o zLetMCEF%n__>nKh1vmc^0$j`K_VK3Txqkg>RN1ku`1Y|arx?7T)0Myr*fgwkMBE4y zq-$niefhF%EEN0&7$#3~Um$?=uGs~$`OxIxAU&E~u1Xb|J3zc^>^q)tcT^y3Ri=Amj z2S^RngTs-w=FT4~LqkKt<=Z8|3P?x8D-ETI)D5W*ogthJ@C(kz=)BtNa^x~h7Ya%))P z;-ix3+AHfyfLV^`pqxsb>RLhsjJ$pI5lES zD#Fi?h`TOo#Ktwv++`^5lOqlmLt4y3k#KWhYS0a088Kh(9iY<_J_}i?mR)xHKpi8Xq2}@XOC* z-z8+4{fS_r58p!LobeI-=yg)?CizYje}i&v~)3cUpz+ zX^c-T1{mI@>^zS{;vM`-FcRcgGaIzn)>38T(!Xzpy>z|gv_s;K#`XS_70_!?ZwNdu`W)tR z27V;p!fDdVYx<_=N!o7BE!-R&1X->Cp1%){fxs8ar--23X{MB^2U9m(XlLFCMNf1%ZIl;_oZx`b9HH4TXabt(WFe=9usI z_IPO*E7A$H~I;ec{$~=Q4*I^q%bvdn;*D>29*RPGb zgGZ}{CgMPyc`X+UEk~(}@au*Pn@*fYeJ3SEbgpU#3J6apbY43*>&LD4=H~P5$Evo= z(_x;Ay$lzM&!#_1(F@ok=jUsVt|*?BBPFUuse zx^8y(n`!C`beOvv#g{Y$Psr3`yIvy{v*Cz595zNbQjH%_t*>@eZRH*CS9EV2!6(-l z)MkF#nh8%;P|6)4LHBz|?Gf85Q4%p?@1vsoXtwn=IeDF7>1L;jyvk5dov>yU9#hmv zMvJBJ=E9S>q{!01Nqi|CH`{e_UQo=^DtPyY=3~ZiM7oq})Xm7@_W6;-V>*Ja_tO4y zbrp|-?ktpZ2pSM#C+2xVp+PsG@Y@=3~OCnx5;}O!# zjHHe!KMS4=D!1G8N!NN7RTv?WPFvef4}AN?p6n_o=}@gTus1gt*4M1*(bc+9Dt)-* zAx~^l!a=<`NpyT{)cE=QZ>#tSBYUtL;meVL(MH7~pbVHS{HrQ4ZaN*trAtAqUG((8 z{Pf{Qi9Sbvp%U(~vP0$Rg59$Lavt;nd&&rVo)}{F5afplv%M~>M3wE)-GIajWLfHV zba=Kur?Ke@ML{^Q0kOIqe}Z825#$6jl83zwp<9$&`u?d((gNw#M}u7t5`bo%qkv-< zqKbSEhFJu@Opy|DutnH+$%t3RAU0cPgR$Ty3Wg%weISsK?@rbqwmT@KTZ>&LW-G|r z9t{R*v*YL@^YG2Ih@bD7<8s{_Rm$Ll6qe5e+ z8L{CPh_VqOD*l^c1?uPtoH*+Zj1>_xAILMLPmyBb%*+TPkz4%6v0S9lPZ`3o!qt9w zBy&5gTvAJesNBg*GY7L#5R<0OzT{IN8Ui$C@NHt=0yHL!;8KQ!Rdy-^<25CvA)r5b?|xFkPRUV``k9IoPzh$xNT3g6+o38PBIzT+=S!KwjD1VpM`(`C_-3;2c;!Dx zx*w7?n(kV4PwP*oFJbZiG0C&rsRl)5Y`oGf(vF4Go8Cur1l`8HDQAVN{Am;fN%FLMou>pgb3Bq5IzV`*zv{@jqo}CL1JxPF3HsPPq zyuugWX+3b|c+ejaF_>}D2Jkeu=19YlKMP3Q%=lq3B{QO0aI!SY7T8k+lhtLhO_Su} z;N_vPr;jl*cF%h`VU8)|V0~qmuUf~dc=(=QPUH2{ed4r@6Z$(jVPwRS34yFQ-Zm-P z#V*-I6+R`oS-YMWKZiFdt-!KgHe*$IBs>$h(mU1oq*}zX6!`@}SqOYRyW+^*j_0|K z=z23a=;47IG4+yA-}xAqJ>K`k2a~lXuRpnN)7$}nRw{0JJD=@wZ|9+IF*2ZUht~5j znVLmjoWK7-yNZ^QQn{;>*h4WSaSl0F=c&0kvfJ!e%DvB#UehPt|X zu=MrDQ>-hx@z z(A2XfEl&69+A`ThO_I^yU_u`j>a!%fP4i1Fi}Xi?bWMxUH9ynPg@`~4POg^b_gh*HCZ%HUZ{ z8xeW3GCfjT^nux~&=7>d-1n8(yxamb{~vAd6dY@~Xzj+fZQI6-XKY(Dww)QPwKmq?wfBEc)u}qw7k$xRS9f1@)mz^)o-uf0SXsoz`@^G(B1hBt**)mX z6JF8m!AlVZbZ8}0$NBkK-i>A9^vKjvP7%ycSdW*VN2neQg#=Ah zKbd@(g4$%ybb)1hMg}Ney!8Un)J{%!-Rr7vlgJ$TK999C2~Am1)m-)tt#=Y@tRx zDAo74DDBK06bW=JCTMP9XxwiZaUwnW7)M)a;Gq@Y%E;>~G|qm-9)GcoVG8_GgYd9a zgGqFKU0Ui`URVxNkKbiB$j^z4zMM9hsBq~`ph#tWG-$Is&8E~oOpRu%_N|7#-me{R#T9u`eC9dpT=~o-f8$x!q{{Q=+%pzs zHA2fLQi8&-gS^!pWLk#q5z3NSCu%TD>H%^X&in*ZE%vE}E|YDAMA$`O3zJ(R*MUSg zeLV5YECYdvf6kB-NU;j27HhbiRpO9F!JqV(_ zfQ}%Bd2}Q3qyk^G^Nu0ppR7M^%|+I$POPG;;1`+corBRle; zZM-|-#npk;ZjiP)3HID#ght65xnrLAb!dGdv-h@WK>9nYZXoRT^=On7;=j6uW>a(m zqVp|l9pGOoj?Z?X%KA2MRSUdlsl1|DdZiecFzq|;HW7(rlawEx7KYNd@^F<;+7faI#D@ zRhRA#rmmmWl2wzN%!N+Hi=DJq%?Dr9;H?%m6EL! z>F;>jggM6R>Ba&kMv2r9VO!V;*Z-;lf{_&siVSWrVv?;3_9c6f(+6sJ+keM8)XfU4 z?M5CJ^+VY_50$bx6XlSah)Yl(>P@0zMIKB34xi##t>Q-vLYvaFPbsZV#M1pKLRT~+ zQDB*qcALji<`cALgoJzEATk-Q=T%cRvbIX-As$cly_Oxj+42?+pY4sfalrNdLc*w@ zvSIgAh9_dKl6aEEVkvG-_rb`TP0mc0$HrKuuPAXmzhaHe3-M>^EVO7qjv%u|Nr`eq z!hCg#9?}_V*#lX@==T_Dc9?=}G*#Qo1M9-P489U6cUnx$kkkB{s0l-1Fu;-pFg-vd zd6@BQsr7xfzQeta;mBFKox2&^OHY654vIR&m&majZ^N-j>(b+uMlH(B;Su+ zj$z63r5w~EwlNvu49Es^se8U-s>C3+-#l$~16R0>d~gVK5Rmk-0iY>EL=O;{fpAsy z1QjD^Lme2Oo@lo`+hBe-Vy?&Hu1e}7Sj+O+;?GgfzRkfs`U8exkxIocO>{*A_1 zQK8U`MF2ry6zi71OjJd0lDVjSSy!$$?TXlzPQsbeSw^0`frclYnINs_NNRCGNU_6) z7b;Q#gei|lQHmPDztyx6+S_Yn1$+L}-rF~Ker_0Cdc*vF1?wGQGFacL6IO2kZ-? zfkmoHb{enq0b<@J7LSXO^oVc|FRnOCubSXy*R{`em)G=Cwu{s11uG4CPVrIJ@fNe( z{MO)0M~kt#n3cxKsF9JW$Kzq-WVGXv&Ui&e@ew;YIh(k>u+8?~mz&5&lSb zf?Zy{?R9}5KUf%qB_Rr2qW<)VIBv#7Hh`?KxAmmTMmTD@?ZIFdtB zm6Xa5I0Ri0Iaq!$mWq%^Z@5^9w9K$MVu(wSs)DJw_D04E>{3R6cIo(RE+_dD!ft%}_v$L}?aDLNsc5V&^ zX0GqN&wu0zWGrm07=@MpkzDwGsDFnR{+ZDcw);nP;X9omMD(4M`3JxL$td~l06DrC zJO6t%0vqGMU8Ma_(y#k(@B8P9;D4dK{|fi~JND#YXaC=75C04HWM%noo&1hSm>Sx^ z!~6{2P={4eR>u+W00}3;nprGz_XqF^w?ZR=i^3D{sQzSvj$c!g?S~IP61xH~Ed9|4 zrA2Rpo~yE;Hq?SaxW3x%d=aLU|5E-(%caP+NuZp*Tj*J*G@$uv>SE&R;-bsxXzNRG z`z!Z4>+9=&8wdi(0Eh~lj!8f)xI1`azAR6Nw4%unW@ zz1lE8fcU@KN2Ml*6ERgu+E9Vif`@Ep;Mw7lftUbjK*Putw#|V>hasRy4$!;#vS#E{ zxAPRhNIby1>ReetBCA}EJU~KDaZyXaQ8}5uAblba58(W%I|xT88wZ|2sq$1k*Q55v zOYLBoapl>g24P*bz&g)c*c73lwb(j(V5xn-TE&^MFSO88!lBf&PPU&WT0SGp?Se+~#@fsfP2MJH3=bt9RHC6xKXTod%j%F&Z$*cby1XN`9 zypc3JOeRDW@5)+ULZ%%%Rl{)rRG#YGxt?%RlZTF=A*`TFG;OAugrdKhXI?GCA8P-%W}7>tLJl9JR@-n1y$f)K|_! zdS28de3zqEMl+#}rj)yoa0}XBOLh^w^M}YDsa7QD3p9|<#y=v@8Lo&Ipi$I35R+SWOL8$69Q zrMVQYny1}6dxxOyf`V?&o^>C3>9e2FXj20^1er5f8sq=Kp4TMCO*WrbOCM1}%^4w{ zBsGG@6jJ7!*I92Bq-fFMUZ4b@e559>70LEE6Fjgg>(MItQ)`%D)eQgZ+@9u5HxUz#JM&JRLLV!0tD&*%ggSXeReKXIZVB!Qba!92CuY|5@? zib-_JvNeWoJfaHvV5&iiWQF%yN!611PTX>Q7`XH2lpI4@R>d;`?l4K3&ScO9hGY{= zxLK|!iYNQ|i<%SMJY&`^eIVg!u^ux|I>4;b^cV&LjXMlGva|6NDxOK36i>sQp0WM1 zVh0+R&3Fz#NAgx0-M&6oreOt}tNTx@d|&AIC;q$Rss~2yAcbyb?O1RM`Yw)xDOo-G z&%A#ZwCGgt2-XJfwM6|C>=FjQ&#Q0R)|>*RRqc^4;+L?9b+KJe&uIhg7sI#HuEE9? zm9_+MyCmokweI*mL#W3P}MszU$gN0@VNQ-#;tmi zzDPonR_qsc9h|QiUx8zdn_33d$)}8mvj$_dRmti-ZGyTrpW+ac*AUU$;Srm0LNj)l z7HdAdV(ZhtCmdGpxA;9l?U356$4-@R>yhB-1=B7sUh(>lBYp&)FP`_I9?_vuUdvVi z-G|3h9<{ZljvetWE_VgCW(Ml7>k>Sao|}J`z|9)3B>%LLy|}NcP9x{gERt#b*tQji4<^2~ zg&_p-v)v}cB2rnjZ<7!J_!Kj&bgM&1Y14SbNlXud=$A~7{uLNQlGj#ZaAHFGv)wW) zDBd201C%(3M;n1nnQVd*IVyI(Wf!aHT{P$_3VsDnpVo+AmPVaw!#&f`uylQ+vElg>O{Ejv6eCCX7WGI3#*s zzn~Q4gvLGDMiF6~u=n!Pnz|uG)ufRZAs%-U8Yar0{s&noU8g914`vIkOp099+`bK` zc*jz+9c?n2Q~Vo;+@^niOqJ`+xacHwBpD{HEMbhTRVL;lE)cFwIMDnn@YNDA z@~m}_)k(jW4j36}_5>UR(BED`goB=cL4vgf3xeaUxdp7L8z(fXXnx zL9eTTD6^o!7&Heg7!0bHH{~wDEQ*U&gyeXs6C}L(d{kV1K3!#VI~`4Me`mM2Y3YzF z)kbWC&uRUJWAflvm42MtnzQwOR*pWv5A zz(57q_9X8rdK=g~r!ny(t$lh237%jfp?=@8mlzZk3#w2h*dwXyBPRCNaBn;?qnVW? zrg0Gd;hv_2jtx2n`5x-tn^e1VvIAao^gxS?peA-J^`-FTLDLkaUZH~0C%4;;WJ0Cd ziw=O0hdd#AZZI5oE*mgrrYD7r2~IK*&`zZfQneJ9s$WZj`fQ8CUPF)jk&u+kqz`x1 zIarBK?Jeg?GAPu{kh)xaBgum$g%M14bQ3NqN&8R?C$o5(8o^CE%BsuR3mi{lj&#A8 z=*_pe^O#%cA;>SCTAWy9S~wPo08I%kkLg3h`3Jr-xR?zpRY27c!I-GE;g@|m6I@o_ zlkqkcVHVjkf<4MBNL%(t?Y#oR5R7ZqynI$1sV9f=4Fv(0@=IluXjRnoSg?+JSG(w* zgstE~A+AW~s3zCt4sYcZGEEabamSr;^+C7(?pl4QU)-Vz9TeS)VoSLPH?E0Uq9cRh z-uxfU^Ati~6JF!PWcXZ7tYSMEs5evE3}QvU)8lz{0mptNw&@B^D$(LEiS?oWRH^Ly zkeIV}!DZ*|QxP*Q&j;guSW3`D7%^}xqxy1!jaHgS2?e?0)mCPf zs1q+?dvrU=toO@mU}&ot@DfAe3{zoDRl1`4aE1VINzro(^`~9)lQ%I)5;gti7Jl5M z!-}?_EV>y24w{~yH;y3;!+-kid~akeDhxm1Sy!Qaa*o^=7?Yl-I+iQ>dF+fXFB&gw zGtVfeJK$s)P>Yw$EG4cNEUY9L&AC5LMQifP2MV67wVLydZO(}o7oYhXwcqi)Ta;ZQ z1FP1n0|O`W^kkNl@Kx5*>*bT<4XmEDZJuLva$ zbLlrS^)~+QYj127Py1;DElxbnN`I=b@H+2)%;S=j$NCCRTUVI6>X>c2v|sSIWQ+@N zTtB(f@v`zy)z@E`sG41-jQzbbzcgL!K8ASyt%|nK=r`R}O)-A%p&bhY@%wRQPo!DauI~xQkYJ~godZRf8w>+y{ zW5fEP02a#_O_xIMw$c^xZ8+`P7zqee#2`uni{hszDDAxZWVs683cQ985=1>W=44WMcEbg0!s(L*^n2#wY>H3))qBc;2!aoFG zs!}*1u7$M>;zrx)V@L)t_8v; z#CB&JR33N@&Ui#IlnIt>IWMpjvjddoM&F(@9Eb*E36eX#R~Pi{6Tu~)u$KO5=$s%UMYSRacBt zfzf>ghG^w5&}>iR2j7oaSO@5r0wXAzTUYDB$-HgN4awoaMGBMOj}-LFaaxW+S>(rm zo)0+MBnXtkSV~e9v}i)tWG@S*l#fq|+HVO$XNMp{>CU_|2wF9mzK+ zu1K%aL_@@X>k=3&d$*P(CZ66Edjq@fgMWcqnS*YPs@cnYv1^qOWi$-uPv46zHWx^UP1Kt2i(w=$xs|cWOy%K*x=Sr_Vg0sr-L~b^+>NEv}U9z*F zgONINxo_*_Hi3}#o@thLPEKG>m{2esYI?00cBM@AJ39dHRy8c-FbUoMR`?2;I@L5s zC@R1;3#Vg1PFJEUiQ6;QR-|r$Bx%T;8um)SvX|Q#c}pG~0BX*e8Y-`VQ=Yjt*;?Nq z^GVjUAi$72Z}0YFUSi=FMRwwMAp;0!TwC0%Cti5Y&WJg4WtKEWK1U-$@-ClAh~)%= zf%KmyH5LMOrjF9>na89E>OoXP$PuQ?h0s5^tHjif5>rU$aP{a2I)b^_0($esGzZEi zIRuH6vd+0XM{hBa4XA>?8|%g+TrsX#rgmn$bH9R`7PV89V8h$6M_AZYTK|X~qLl99 zZn8x;W=bo>mCU$Ff(h>-1r*0aD(#%}MR$su?CT#tfKDwKX8BUc^#IFRPfm+B@bkMT z!*0Jc%>~=_!;6ST%ALDimxt6XJZw|(gJ7;AXK-4(?RKJVX7^wIh@_ig`c2T`` z`ncxjwb*;GQ$c*{l;~F(naov6ake@ebkG`E|C!i(p-Am&O?jKL7@t@?7D6#ly4F=V zQ45l*!8_dCyl~NmJ&;aOH3y}#2B}g8*B8eTeP<)KClbGs6teB}OfD^anidon=g!#k z%=?_>G~IQ);dP($cvYrIk9IBGsT53G3Ng>%2b!#djzmjzx_Rav?$W|4QtKT0ltf2n z*IW5O&_r7py2u~^zNv*NRrs(KIIEC4avuGP>x>~&F2Ylm?b$SKpP$DZbp>^nz#NsZ zdpZ-PWZ7CcnX<`-_N-dGpt7f+(n4Y69fgzIt$#W9Ea+Rcw5{-q5nj~Ataiejh)14Z z`c;W*dl7xVzy?k{7WZm>r~C5Oil73ce3GiO%wh!nW1{cGvLaQ`m>KMmQ}hj>H=zYT zNy8W2T^bJ@P`@TFlW^{yL9*M3vzPHg8gZq&xK*tQLMb(_`LU&)BAVseF0Ue z@ptLj;7=q<2T9HTO!Y>E`jg+rtnxbAxL^*ZMY7k;H;S3qV4F)-&1Q+ zA_GK+?u}C?r!q{sKlEB#C*_yEF(|_OC^K0;Y8VOEyH_#`-g^9;Ts$I)&*R7jxY}%ANbccCEjm zzwLSfk6C|KvCR18V7)VPqu+J4F9$Y?FJTVOw1+u*LzYfszO1(W5btJqcGmSU-dkQ> z?YV0O@r@>@iU$@=GEqb20X!@p`jry zFq{Yo*#zJPSO-)FXzbAL2!dRL_yKJJZ-MB6`XY3Kp#6sJ)!Z@NVY|V*AvM5ohxrK- zC_bSsdIHG1570w-0OaLDdCDoI<{=1qfj7YJc6x_)>Q*PWjAb51*K1cN(3+;wjU%j5Xq#Lp`XsU&g+I8}hxt-V#uJNu zY4>RTst!avcWp{M#U(|V#U?bQFE~34&7LZ?Mis@BGo{$#q7h{Y3k{G$U)IQ9b zw0rs_F3sXH91sdNtx2Qvhw|!nn5U(EWIg)e>TyZn)MHcpf=+d3Q#(Ai4IYT|mG>|H zMi3_kr|RuB-@MBEL6_e2`9-CLqlj*x(w-anmdz61=dyNuAx>#ZHOso{6G*&G_=WV6 z$CDXgICFV(*08?gkqJ^Zy}>amtv4+kKSW2?65F}8`4)l zNmD*gs@ZouWu%|QbJ)V{Z>^-DD+hy~ofG3y<7~IspiPB^m8}ufyVx}cU)p-}^L|T$ z>v_LKBEgXqMiFYHNiwBx+Aa%;Ock#z#uP)u&66m;Z>;@bmD&)eKj19doZ$z` zCF5&g1BS!x?({=Ib``$LW8Q#ytQyQ<(z39}(NlIWhMSfbH`l_>$8HCnFu~JIam5 zYY8=tM&q#X#|dr@D(}biI1hPDZ8wppKg03fbuSmPQ$;OB6{4J8y4RAE!`PhiFM{9l zt*#f|+y4ro{^dFU2VeSsl5hX%0RDIR_J8;OzAaoP_^@ZBWA#r7{TmW$)R zjo|%<1pHrxO%4{;|Ln+j0l(<$1)ul1{NPzGp3i3UW(Cl&XYfg(|g;17!BQ0a}yGQ5Lt^(L{RZ z{gl_&m)~>G_DAYpL?$4ht6pFYB1*+7DT=_O@%SSOAi(bFS?$fh0Z|O3oqWuXIg$*ZAFZ^`FVJ7c>cOK*l91=(bGKop@?DU9do}C;(B3Z{DIKgM`kb~a-T<@Dsu472C=WhX|hMct5;$to?mxWCqh19Qg_YP2*~`6@N5K7gFO#*+KQlg0!S z5C-&)>+4s%cZui?Im@G8F-q$&6VPNxON}agGMt%?WI@4%pDBTuRWu(^%CKOsIKkj5 z*)pI@i|rdG%|}Bm`}Ir~P?_c}iwfg4+y!~a=<$n751`A@l8@-A)TxrNaZCYNF$<7l zu>sT9zh4ntBME{>3wKwj;65mbnYC~Th(AJKdi?zF*r$iH`hY9%f~l@lC+-~WwLm)H zScmcx9CNcbbaBDGx;7}9E7oCnW5mI(d7MI@T@M(SD+q7(EI!U>B>i|kKeETNo1*VQ z>?X#Z$iDT?^4^YTg{SPis#Rsnm9BiAnhVF=qX2TVkA{IM0#t`1ai3-rX_2#+^X$6M z^+wuX?^PVCY%%hB98HEI3#$ZrC#NANsxlZfXP8m}!R|xuRlcdLM++_^19J_T9p}=X zT>R4eupk_vQJoJtaiyMQIV0|Vb5gnu%i(r#-_r^O6u>-Do8%@+V;H8hNxEl*a7beMkoprCh~ z-{N1$w(0@9Tu=YAXRh{ww5=Vdn&is}ZC}L1`eQYAN>w#T*9gbYuZUJX9uU|Iw~O~_ z3qJ0$og&JQ7Ak>o#4q*R+kU?9<**r5(|o9o;Jn(qHT~oVkfdM_XGyyuJ9cYrjcgsC z{64FQTaX?Z^~q!cI}e>#p*e2ViG*{rR=XuzZBC!L$#;HF(>H8k5q`5k&-Mij0PKxy5Nb1|J7IC!v#MaM zyN#od*zXDUgQ<5+#_Q^~W`q4}-an-K?oGUFn2lb3D--QwunUeo^6y-)iHWF*Q&CG> zPrO?X;@0K{?&IaOe%P6RMKZbDPAo~Aw+3dFmN0lbu0H1sEW(}xNdem17p*zuE#$!w zX2x<`5YAo;b!l)E^9^J*!z^YJ=LEwQDQm+JfE~?Y8I_qAJJF9r?1Z*+`TndZx6ggD zLP-syFTl&*o{=Q7)=xk%O4lM@2t{o&o06KBWEzQx?6qOjI+=nx2x~ZBcv`iUWCTTg z^&!dPk!d-PlZ+!l(t_L9(0=X9MHVbz_ijhmEU5{ytWxl8(=-*J^mc>)q znUI2Y;RwmGzN@Kqe<>+eWBB^bIW>*^Fu0b_zF?yd4w!If)QOKI{=qq8R|A=m#r0`$gAy6FV^($uWky?vdk>GsPgXQLtH{_Is9?*| zCxasd5F|mFG$Bz3K_8Qe)=3`DrJ9~dDzQ+JVwX`VL#K9BEoVUTD}{p$j6?#U6~Tl&Fk!)nl@u!YZ1S}>--OR$j26e* zEz1ClVoNQm<$ICAE)|ftg|fQR$+<~RLe+%=1nN#lUNdkYPE`zCl`=Cf>pR#_71z6v3L&(xZzIitp%WcPx6n4Y9V{XfRxVohsSsEmAUFiVWoPCqM3pHW zR;_h}`vH|#=xLSHQk+%ThH}rYBJ@;B(Qs%=@%Hb9-nn1D(w`SfPL&@3Ned58l>jv+QXa@xJ@MD#(PQ z<8c&~%#p4aT3cSr{rx^kS(G{4l5kA^u-X-rPc>*CeDY!0wC@gHiK@r{c;tP?lD9lh zR`qDd7}!9R$Xyw2F2esbk~~SMLXV84V@q6LC1W3q@(^InbKX6c4|zLouH3Rp7qpO# z^4_<&!L&RN{M*W+9qXKSbuUwmX4;h7)_!3cw&mioKZ3qp>E)dpSR>c?i<{GK*K~nE zUSlsC7p1nTu(H8DIJe~FQ_ioaOhV5YEhYi&&W8#za@6G(@YVNu8#0iWoG#Wv74-us z8GK|=u0|E7H}PRpNhN0TIp`D#Qq#F4kbs2jNfg`eI)_%9 z?jkKV7LytLfQVdIM1o!4`%tg-;|oUzfe!9rHv=i@#mT3S=ETY=u>)I67mdYVuTHmf zJ&Q-=>SLSd12q@j9+#-MYd=f4WdBBC-;ER0wr-7e6!I`V*4gRxHvpIcepVzS_39~N zb}%Z1y1MptOCFcu7z0Jhn8vV1(;o2MclIxVNBm36l;>k1vfW=EHuDWNj@*ImzkZIm znF@Ai?qNFj&*oQqUN=U&Q(Uxpx*SU8pIAHn*jF592~GAm{#z1VS7W<%k%K{H=OajJ z8!EB5g5sg-av1p$EOdA(xh!0RX+t|W?mT66l8w(QNxY=Em^xfb%k|gqOKf~aXftk- zzAsk7HAEaEH3#v-VDe-s|NcGr3a`$1`%ja%E|Ubz#{rLlk&@}C;r@= z+Xo&BJ{Ny_C)~GEA?uZT=2}@d$oIuPuxv9oAIINa zF;o6B+||Iq8c-at6iRdJ+aHneaT6;u>VzVpY6JjqM1K#$HyuOEWE`XwIdP<$I|4b5 zjuALBU>aLa>}{CNQ&-@WFCadTVc*{!13q?dAD^a_T_PHbhv2+ozRR+i zkbVtlb%N#ofNd4R5(P!9G(ZY71jP%YxI#(}X2SUVJh(6m!>AwuF(@7b#9H zAw3*vy(t9div*->0Fm?qRUhuxLLy|-biiY6IcgiLlnI_io zP~fq!SqpQ23Y=HyS3@DB0QP9MfV3|JC8}%e9nux}ky%VmCgKUxD~`H)3XYhCu|MW` zGC=xJ6#68F+}|4&aKxI{X&ifW{_#u^o;cD~!-*)qJMvLQNKz4WMArUNE5LpspeAl8 z8Tt5-Gj4s_SfQ~u)R@yBqKf@->I?^$qGNNcvYp0~>v&WYx`O_WcTR{41JJE-(Kn!t z{nCx%Zf6BC$jsNwB_14n)Ytf1hQAYu>S?pBh#4o#1UXS@8RPsBWyph&Na0V+kCb-s z@7kcGWX~#tWoyx!Mc@~N@v}m4Z`^PWk)!A3+{5|UNT)bX0#KBG#?Yu3vtSs46AY?( z_pdNB%g`kbTANv>1x|S6K-Oe2?qBZ{9^thn>+moC*(4^69^>t^SIRDGyCr`?EiqUN z{)Ln@NQYze=i1}obsbI8q7j##ETyeBiNuH7LeXfi17#_mBs2WhjN&3h5c#Rsw;z~G zoC~33hb}7+)*ie%p0j0#_XU|}hZ^LS1!Z$4kw}>NH8BE~3BI8gPJNf+FIt6z;L^SW zUo_?|jUMI3kll^`3tmSWaTMyl43~Zid#=VsL zx(Ba^gomuRM0ZN=s2>p&dMQ|V07>6SfMo;t5yH`ce%5(FHMMR@`<0^+Lj>)fnp0?N zq7Eo^Fq@YM_0xVXCNM4Pg>u)O&mAZZlzGjD3k#h~<58x)Q8a$(3MsjmVLk8g~>% z15iB*-OL+|t-jEe-}2Z_zkrO#;f%#mHq!L5YM#D*Pu9;(r>ibG5Q_;?HYAwk4GM5; zRB>2%%@G+R$OPwIW|j*y3P>n;$znwvz1l3XmY9BgKp3gK6n8vahcoD6L;e!Ym z3!_HkWa>aQbHtT3e;x&k)xeF9?)??%Ig8Bf+@AZ-t!-{E zbJrn^QV%pAie1WIIiHQ)gve(&8O*@jqvFAeW^|l-ta7+LEP+RXNB2jOM~2?hY3h^f zIk!3CIovr~)3J9_ch(wRxKD()v%W;1bO|J;oz%Ia1o-)pj^!6ie&Ov6Ivw_=L$oA631@k0rI9dJ4cTBISyaO+7Kr67w43}Qx*C-;$tg(p^Nu>>XKN>ss_ zs)abxve!H!@uR_MAg?=4h1gW+Tj?Q-b?{n`&>gp1`iV3>IxbR+jvNml&??PgG~?0R zie;@;*^K_=i@JXsMq5~6uLAD_dPI*Ba)Q&6tLkc#uh1S>`rT=N0p93bI7Q9jSESi->LtU(9EyV2qQx zx_X{#Z}q!?@Ddr%C?(Z4nlR4V)-(#uCYS##Bf~mbMyQJ5d1e2=sfy?pd$a}AFd!q0 zq^-YXoK)|QOPjJN)sODkvb2pm`gW4=crT6g)L|jOL*S^1`^2rqTr_J$Co2{KBP>eM z5Rt{!Wnc$uUqZzWuG3R)S2wRGTsm-BNzLUaultM?FNAIhb63Y|jH)WGAA5H##54t! zJjoUwj9m&=z-qdXng#q8xNeOqdcUIi&V&40i1+iAn*j6&TQs#jYXYZ&uhRSIS9CKs4HWmp1E+<^! z=(9500GFZ>DwW+>Zjve1vI`jp)M>JM*0xIr++A-x^6b);QQGMbbPr0|utrtxwZbo! z&5U%3H_=LgO)6=I*pwEs4yp0|(M{&oVvMphnWZ%~8v1c}cO0CAOw!v* zsgJAhYNZlaw@TSS#q4+1C3}hmQPZ+8Q!RiBVDUz_!%)m=A%bjQBnB6!OodGR<~M{2(BI*p8l=5Wy6JFO z6}mR~bkiF9K>7-4G@ho(K7mdbW|y&W5;6kalzrpz~ipZ+%s=!bVj5>2Z=>UsA4oONjkwDpWQ1u*X*?D%}v=M+=S3ejuar=8fF1-hOd_)>T_ z@w13V_ukLA@Sl(Z!q*xX3{dzg3{#7=G6-6sS2mm=6~;`95)%{lij z=vO!ipLB}fsLz6|rTfe}Pw;gDoSH`))yfmoV0Z}L^nZ0>OWB=dEruTwCY(z9Gk%WU z!9yNc;l)&17xXzs{|JbY5-c)|#f>wplWEmA*yLW_-%64VJf1Y-8N4a9fV^-9U4d(3 zbdT6fl$z38n_>pmQ6bWT%@m-8ES=|)^KA${>V<$My2l@c)3b7hKjx2l1>c#cgV>nn z&T+5l2EJw6afH*GtC>O5l*z7N>B^9JfF3cQQrm&`Kp4|o!TcNtHA!qng(A`8{T=L` z^EaxwZgcfntDhY?FxDKjQ3ThX@rPi-XCH6J99}X)F-v*L{Fi6En^53DXQOB z$Q(cH3k_^DzjY&A7?9WRKmexQwce%fthAHRbbv5}%?#1A9f^>`@s_<=OD z*QdR#=t{hQ=HoyU*g);53Aa zh+LG1C8e~bur!?LF7iy^c8epQJX7>jk+TaoqyZ5>|6&*|Y|q{FqON5o^2_5$*(v-n3e5X z^pWM2>l?;BOON!k!{ws7g2L%LunTU>X;gU&Y`laM^~Ae}4ui-?o9Lq>bd_nhBM<+G zv17q|{==LUH$5xklo6bj32C;K!fd@+HaFj%}Bo{2d#m$C@W!UX|RT zI?wYC^T%5%&7K1vI;)Y-wr;t54SbLrfu7t=>CtRC`A;U7L#}wgXs3u>1b1bO1@H~D z(;I$bp`M0%c!k|P<@%4XBF{A%YM z1jz_*eeD(od*a>guGx0pp59c<(-920bI&P{B)GfT3~I~15d+zOgtOS4;*qThn6B7U zJb6>T>Daq6(xZ_`e?FVgEx8iwcH+Wh^f$xvULqnS4s5^YG0)%&#<5S*YGCHi_+`8y ziZ8+cg~q(zdyTMgFMKc~p6)p9^dTP2Gwp_!!%{?H0sM!Bz6XZeJtaf&T@NzCAH=|g z;Fw_cQ_-1lAaQ9e-i-R?6Yl9s-A!I=VrD+W@S&X$_iL}y(;vW9^YYw%X#0HCX?*Pu z4)TVdmjLAng+Yd*Dc4(9vIy0*L4CxA^`)AM*C#0(K`t(7S(hnl6(@7fR##e;Xq^8P zV_^O0!e9C2xalXtxy7@oLdv6kue?)AQP?X~^Bb>;g#A>Bw% zJpcCb;_(|6noxq_`TbM<{fqR0=c-6P|5Ls5nBsQz&}XXRfoFAEj6{La7fg(5%R;n= znS5I)J+$-JL02!h7c;h34>Q^%AOSduCCP_sK%;}({Oj$Z1NAv={)J&ZeA$$9Y+Z+r zx36HT!?25Z&S%MoB>A#FaEzm->QC|7(n>!EEvmP0QLUD{@C;amj%kT;r~Xhu)SehM z!1zOQ8)4dr`8Up_EFA=YIjF<^EJgDypP%L z5x4cM+@uxkp4nm8!4Zxf{MW#}=nq(c5I8x+GMw(9l+O8lq}ZXZCo&0HFjLHfihhLS z>j?ADb6VNFGb+_5-&+664~XJ{Uv{DW}O|SCNZ|=EIl{UvamVHi(nu>f4ek#onZF6KowQu*1s5 z{VblYhidQvZAZq&%MWfQec;m4D+vD1L@CTmVnNIf+co_1uMWqX-w5sW~VU48eLd+JSIxGPL zb9vggndwD)zxr9Fi{Z5X=rwXtpMSYGv0(Uy^8V2sdwU=`l!Kd`<_CDAMZhkfIEcJT zdqoj^apQ(h827~P?-&mY9d3A>gs5_zz*SE@MbN4F5wLP> zFxU|L>%od!-Pek-l)2Yr!wHTTq%bc!r(J@(<|v-tMK@tFClaz5Ht%>1N1RQaUCT(w zB~O5jZUjiH5rU4nvU_}50#C#r7%Xe2cMrJ%fh>kuNn;U9oI#*_z-@_Sb}@A9Ol*3$ zgnU!N7nm5rN%kh5;6I^H7(%i6pqPBOnj-t8MH%6Ojlt$Hw3xMzryw7LvnIj&p=`*z z>6pOX<`%-%2;I^wdMNI57>l#*+Zeb)8kQDx!2(9!G5MxMJXX=RrowGs@tpm!=vDY? z<#30;Gs8CLQJ!usqS1GsDAXnmmXSj`iWZrLqvi~@!~bG4@$wQTxi#?0{i?$mhc8W8 zUfWkD?5QoThqK}2=7>c9Yf!BP2`C3n^xrfifirBQ_^}yy6H(p?ti3kg z3$EFWA%{Bwa|Q{h?w5&|PC%ev-K@dOJ+Nt`J9QqxPDJPEtCn*nAZPJ;Ss7?`s~tKZiLxOcYzPsErla2CZomrmFG^R z#wRVJYYtdCgJked`*#<;omy$lSkWvf+s13W&^U#NItu2`pTxtt2tF-goF8S8)c7H0a_+E zi(1UI^<>-LdKd<@z23Mh~k0_Rx|hFxE{Vrni+}&>i#oa#8#q7;r*-9 zj!bI}V2KdfOsmYZ7uk+ewVC=ux+{zhY0y(+$~Dm~q@0?-_EzJhg{v{}yFp89cQ8%1 z)~heQJ*Re*7CB1D4@*mGNX4w{1$rot3LIxsm9~}Hz5+Vz;vG7cjCozS zlE%;*E-35iT@1WpQDaMQcuNubQ6|%Z%4?pgqfJfG-?u4?O6g5*`H&1X+=0WRGwVO) zpEV<+5A!Qx%^a<`4(uhV+p+319Yjzg_q0E*M?^&AaLmAI$lvd#4NBuFZkDIwMpr2> z)w^IulCrX<4cKxofeZ0okHn%rrV(& zA00+IxoP~Z4kV3PJ#Gv+$C1ia9Y;A_NN!@80rFBiOKs4cJ)m;d#3cYI{(zV60wPiT zC_rQ^eH-Kd8Ts3SLn1DV{59pgI?U#<1^AJByybnI)^YzD6Sa-I-WSRdo3sMy@n?rC z0+=+OgA_2j98et(dA?DMA(kDz}Ov?N|3ko}p^O=7F^)A{hp5;IM2Sd4#8OOzN7bAy1GDrt*Bp{T>Eymi7INSB2RJz@U+lhw;Ad5Bzq=itjU}n(Io}?SAbY{# z`JR4Mx7Nryk0dUCEBvVynVwG}KOp=Ys0-+J;Jq(lbdYnktGzUQg2JUm*>6pPm zP6F?~*Ly8CHoOubA9N_qQ?R$_#1yaeIIfi+d({&WQAVK>d zX}w5PMRU?0cADWb!8FjOLrfDPj)IuI+u(tJ{>0b77b{Bbrj46M(4)VALJkRVPEi{} zpWcZ$jVkHwprgPj^rC^jIw${rn$KPQ9j5lAn2qG%tlWf!SqH4}usn5q z%U;zO3MTmcW|qx_HR)=gHoY0Z1uC(ia8m&BSe5J9oc}9>e3Z2|GydVrU}2<9B5^h$ zzUTp{cTB)-IjZZpU4*(6$vs7JF>+o^U*%j?dHM5is@|OIo5HnOPNbq8|6K<@i2Rk$ zZS5|)YmjpX3JOUtTCcy^bG1OJ+AlWcU_B58(17I4y|6PipByw{sQ#A*g_KrCU{h+HQ?@jBci8t*0)AS9`7PUFR>3 zTCMCv>;`RFoKyqOEDE{ux3F<)sfSNQz%j7ax_J@hO>R`yw>A{)Y)58e1?dhYOqJZJ zQuZ5HTPipiNZfAC*9F%1HKK42A;<7Lr_!QyK z#iPjPBVLKx^t@}`YhTJZ^u3jeBHjGMyT<8@p&?v+{~(Cy0#;c;JLu98q|Tw6a*&Rd zplf-6ys+CZnKZ1X?L!LlcroOrtN6e+2|0H4I}*bFB@!wJrjk^YjQVwofEg>SK~%Pk zAjWY<&VJm%`E+XF+@Ib|TVQ|5^^2IkdTvNB5ch%=!~Phqa?0dHMw!50ZGLVU_UG)9NH~ zns)j4CLC$2^T)hzpigtnk2!kOubzOFUHO@=f? z*TsvqwnkS576o>MtGF_HcmI)nlyeb^NT45XVsNz+-0(quO%|iwH0cpd4dX;Qty$21 zzsGLL4fSq-Kt-^PkQxT69`dL!AjB>}E{UfVNT8ivD}wAG;2z#>cshA5f-`;sVO|gb zh(l`_;iSk6dk&|Tgt*WQO2n5DE}^fXARzc32Uy(SM*RXDJVFp)fe5)73V`AXR23NF zw#rjuUI>vW5UsP#DaT3nOqUxX zNkVD~>TklDc)bhM3uOQhX&0 z?kZDiSDbaJ>_Ml@%9!jTmkl7BplsUqssStmQT~g8H6Uy)gE1zK(^wdbNZ0|oymK&X z;Ff;fR5-T4nu++9`e&tvBsd^SA*5HqnR~z7ZNFst#H7Dh`D2t4u!ncR#y3k0WtB;B zCXHTZCC?YR1*@7KfmrmW%@+V|tN>tYo}LRzmyzFT`vxB&qn&Q{CxUG zx_9h{@TTr!VAm4>+mO&8eYxSIRT}BiWbzFcF~~UQX7bh+kL*>bc;|;M7Tam&!8&0B+ZJ~#C{f!)P3H**dQqsR zl@_GtkH>*)O+;?zPT&jiA;l+SYH~Z6eSVXm1}?W<<(eTzHl2fqg?=%={u;jTqR-l` zVFZj+*(OJ=lGmyD7ZJx?jp}%{dFoWBp$dkB;Y4TbYKA5-SS6xyGBsAal$|H5&6L|L zE>@N_=cf8{ULaMv3z}4u!9lGs>g&G;^GUWMBljlMe-?jDcrxk1H?`rFwBM|GaE;Wqu`ok>@y^@5FcK>Cb+bDZe1v zpUGeq*;#~e7dE?D!EiNjx_x@7WJRB3x-Ua!PmA7tsm5UA>XPVB4`NIehcv6vmgdZ3 z6gBTgG1{nc*Xk~9E$}UT22x~4eIqa5(-aB_vA@CsG&P3<%^7&(tj?0w%lDL4j zwi`{TdoBS~A`Sio`hj=%?B;xV}Ar4I9Wo<~!-Z|s- zMLFi9$79Kx*Q0WZhazZ2JA@4;^>X6O5&3=E-SzRQw=d!W(+5bJTcxe{?_F$boQqWX z30q39QWfhJrIsl!NABpPdUHBj)dnkINj8|kZC=z;6^227bmBAtNb;nGBdL^ESDz72 ziJlslofEQKUn_)$1QiZnr7;$XKN;h8hC_;K7x*YaZN_U$e(l!K5$ayK4%Pv^Ph2xX zZZ0iLlkJ_bPF|iu=+oB;Qq*k{N1!Jne6%>ZdS1bGnUODCBpfM-~^Gr zl9Bjhk#E6eA(OUG*_CtYzh2j91mg#df3@xkYKR_$*8;LRWf$5sjl$m(dk0+odg|`@ z)Wyw}1u$py%~Rd5#fJImo|`i;$@A3~!k>dSqtIHT#f?`fYD0JL0*{xi)1(C&l1vC4 z-bD-~L?oB=LZl=XVY|WzV%|sYIS2pzgkg3n4w0u2&?Hf3Qd~|Ui2DYkAVwusz{e6} zKB08R>I&Qv;1{{hhp!{9Ci28ffS?Wh!~}13%OvI!)YmodWZs12{^p_HqQ0WL(zDel zt8%_VN${;x83gl0E37eJ{Tk)$txIs=;Nm%aaCAms9N-Wow!0A);ABx6<08PGG$g3J zr~!$Xu;C!V=si$`ObMe_2NhpxBujA)5YK_2vcP6g{Wwgn-yHqEo3&P>aYg(aZ|=oj zY>Y(8vUF$zWOtOpO#4`|KBYe9+AXIP3h!A0#AtH60zx|1v>$U}@|(J0?aTqf2il0i zN^DWBmDWGm+3CtzcJ$nA4E~}sEr^V{hWNMl;{v3$QX|r6O%a}TNJadqeQ%vx)*7H?5x$*|h&iaSyt+C1=);D znNd)q>oO*v0}(kfqCu)LSM<;mc42!FQ7k7`Gz&f@Ga}>`ZfWOpx!`YT0)sHQ#ldm= z1Q?Jzv5Nxwx}$df!oRgW;`9MF*!P6fr^YO34C@+SuZ%*kDRfn_^1+lx4G}@GW4w{B zkK02|^kb&)B`?1sRc3%GdC&)pMXrcJshE(|hwm)2P7#$yul)AU0)H8uQ_pp3zPbtN z+`X4SuZ?AMd*aNp1M56;^X|J?@7|K_R;b>ax$t&qnBGK-P3C9B}dD?_#QX8Ln4=K5{qSF+kL7vt@d(R?a#k;n=zIJv`DQA zS78E@P$@xBvSv(+)!{-RYX}k&5F-hHHUZ=cwn!E=s1L-j?Q3hdl)CE1YwMh<>*M=R z9+Cr4d22ua9wC!@5?76ck_YA8#tqFhFgE-kQi@V?nEhc)+hJC`1^qob4*EY3J-jv} zmv(_*M}2R-v_tteA{4Fz#s~bJCg84KG^uQ~)V@1@xH|nx_Gt>3!BO*gWXW4*UV=L- zL}e5Clsgjg>xb2}ITVwJ4H8;}-_<L1>nZ> zDJ`kk`1T2S$&y6K$QTOrPe;Pibf=okf@t|ZZKs%AE)rt z=Yo5%?1Mgi)tiY|=V=gDcC`NJyeczr8k)kDo(GITW#P_}GiMPK>WjvWAt2K1n2|YG z37YC*s-)Yj41;kY)yPeWvAq!fBzPi*Ujk_6kDtMn-*Q)KVU1KbY1f~1D>GzFY5`4N zyPcorMv1&oRc84$(49>#U|de~Ik<~K-hKuDx*T!}y7jMS#h$A6ZcVL^1eXrDCwBO- zsWX|tC_^mcQVYFX2^cmn`kHU=;#L}OLZdv(TyppHR4812`5!TttcB46B-{-yik zdr){XQtyWft3ec%C4=^RU@C$i5stcd$pICbEamqnZ8z9N|5h`ASrh^>gyU7e}S z5A0*9u3CIDg~kkdpIhHgM>PdNnx;|dG4hrk;rA+P8GJRpwU10y z0--g$tFGiCRP){>(QdVhlw#O`^mTe!OiW^Nd&cE1i(b1*ExRSX{QQ>UG^1nX9oV!1 zX|~7IdE24Zoze?g+lP;?@idM&J`*gWv~6I5df}WXthf3DH1zeHe+l|CkrrN6=zUOE7y7k;IX4$|xE;@3ke5(?)QL2uQPU*kG34v~iBIO@{lXxy=;J?m5(vb&y*hK`~t?S_QJbXRXIjzeh zVig!Jn6R9!^$k92z(*V~%B&aWmh5m~OcsyX$-r=|UsbEMItNPQC=ZlaaxH> z`KjGGA<-W>%37z4)GcmU6}~vXGL}95DXbK|^S31@xrbMxeAlW%pIaMh17*K*y|!5? z2ach-&oDJZl98*y9U`Dn3&F);D0RM%F`b;uG@lCgK*m`Kp8{uh=rPLFmm^t{+8OCqvzw7|v_Lg_PCAAlEuvr<5EZcKix2|@VZNEE>fui#@?`-t4WuT zgw*kStf^boqQOjBM~QS|zR0Z2*8|%rYqtkN!q?o_*?^G~wJxH`hh+be6o}GZ?znK~P=4lULb;lMYKTgE z8@uk8L?V$C&^10zG@1^Yw&bWXoH@?x`@vJkAXG-cg}bx|N|1WCasR{Q!#QUK8MKhT zA#QJ&5-#rif(h3MhO>PUXrlF!Nw-=OG-~Epf(~W}tZkx3d!M2{R5#9G5PuZQxUKLu zlrge3<$AQurr4Tw)(d!KUYd!hUVPeN+JW|+-Jw?lT#_H{ej`)-A^+8dS=GMPs8B3u z1mi;N^7C4C^hK4M`5!`4Il^HMF1}(jBkrKeHlKz`cXpP%dE0agYO;QG^^AP5`VWIF zdpuRC^% za64m+$tjWANS79nNnzFC>Y#y32QO3(98 zu3v&y|FW1oV!{S3oVI|i4o`euG2uIU#(fW+7qINc!;*oX14y&DB+pJ&i1a-R-u&yg zq2sx`x>Xf6!PPwct@!h0BAX5V(apWR>gJoRe|%5P$IZ7+;_w-MZ}08k?XeOYv`;d? z=)sAAh6EIiASO*%AwUU9P*IYSho#VLVfukst&9RW{1Wyx*ZgTrWldGBQA(tuFegH` zf}vDdv+6bt?CIzIyy^CK75DBdpHjb~@hnz6Z+6xRDOuMr7U4yn37w|LE*U=wqr2(S@@muB7;evjTAFC%~+fobDgDJnBb#1SO zOuK*14%a~|D5lT7uH1@bE}H^aGL0*9#R7j_~^zEPUeJ9m)pKXX&@p;icvm_Kq}#! z0h3N@pyB@f;j&b=R_NXb^LTZlwN-O(zZ7!7s=O8JEZ4Gh3`ut-*O@={xu_X$XZp(V zbURh`j1y7QKC9YW=L!|o5+>A_EZ*iN;p6fMF~<=@XT34q9M0p12c;^DO2b@(>|9kV zU3Jm~FV&ja!po=PFk`ZhOF8{U-k}MeYlo!qJogO=?(sBhq-;@wxiD-ueC$K(A04B+ z*=v)y>g=KW`7OJWWUQbkcRoDFC3rn0H|rXTm(4!MzWl%Q!E!?yyaJ|=!4+PvGiJUs zktQW?PFVpeR5Z2gTeiSCPS?3D+RkK=FSp=pKXWw}HD$YjZ?4VN@bdh6i6sy`)E~BB zfnRW`waP)|W?`RzF#)_u3mLNp+Qb@r)v-Lf8=PlRPSOaqmLT7g2bbe*$0RMO9HI|- zy~EL8ZGE}@;`yh4AM)>@ztX>sbYkt=-Ik?-^L)FUfYO>0S2p>)WjC}dP0}l>5z!Q# zqb%?OGAL!!v#JIfo-a|O*C)8ZoR>g8-XdQ}^v~plO6lL6r_<@ zG^^bepQXIJgWMC7_Ypggp8kqx860$XWZ+EBNa~npG_`3b^^y8C^KNlrW6dJ-nm0bx z6-Ex5F1b}M;e0Mfh8}=6{>|dE^k{i2z1y+E-+}+Rw|g7AUDi10eG@b1@1j|i^DUqniCreu_) z&9T-*cO@Z&`OYQ}Mq%7yG5!Kq1tC{HFS01pTEj?wsKTJa`@$89?5Oq=nRl7($?1$$ z%#RJ2bPso__bLruL|}+ z=$PFLtT!O~<1awF{i${&P(YYaHU)4xi-#=}R#8kCoMqd%P+BzQ)d{+aZUp>omZJvD z#U3~WW5FEdd9UJO6*}egxvje9HRJFx2lIP2I%jigVd{&t<0?JaV#XmZzj+^L|N2Y} z@*qti{ib*f(ReMoxi5GEu>IiI_gTqMJbdh4(@a+G0Wmjc&*9$ zoJ(QbTD>7O+ha__HivmN(V0%QYG{B*Ttn*WBGu{K zZCh@)G4o*vA5n4+-?d_uQqq{O$(M+sj*+NJ9-|#Yv^MU` z4Q*%1kb$$OpHVnZa^2pKa;Lh1$dt=87fwNROZbWukVG5^`_kdSkoRLO4B5NS+EF*A z%i;zTp5MQt2b&cVuwXZ=Ch!eKF3*M)XlJ<{4R|naC*hA>&-CQ-C-tQF zhJzwXH5fZ?)(6Q6( zHxfC^WD750HCE|ETYtVK0~U(NZKcYi^r2n`4+|SrlK8W_{pnkv`fS=i1xt%OQ53`*+;SMI-LI!(KXvocCY^;mS^Myle>u4`MoyQ2gw+F$_y{rIu{n zTs4G^>0g$nh;jxcwWKdVzpAW?dNkQhuIi+Cwk6rjhA&_XW$A`zI>_Qo=cUyp$<*!Z zpIXQau!J%^mC0`IQLgy%#@`KLi@G?!W)|>{3!F}Z)gwcdK#hBXB?NpyXpQ_mE(t>q<6RWt12!zpqu} zKYC26#h7yTUPE-;ti08#=4NFo&1*$0@S>LW8hTd1Yc~}Y?iZ`aameKDj!x?L2QLx2 zsGd-vi6Oc%ylNbV&#X^vX4=~nfP+=GHV^ut=Ww9D(mqo8EULu{;|c!S40g?JoQ=bq z+Iv@m1O9;XQYmJ?Ph|ZFW@uEnGR%<&o6sxQbCFNrK|4r0yUZ4(b64Aj#| zI=y$=mIf!fCzZLsPI0awJFIvlpL4oL=)Lq*O*tNf<;4F}CGQldPCX90<+lxM+}p z+36aXt8S72oP6xqH6#ZY&WtfDS9mzz6h#yT%_MbJq>aMBiuS2gT2B%F3gnt*rg zsv0mHfyCK|Kmt`;cgY)p|1d0Qr9V-|pnux>AXg%vD5smdWNJj;P@{=?Bn-;4-e}tc zgUb$q9@yof+p%3Ur#63yX6VNT>JIvimV0v<``abwaQdzmYWq0{*$;#NciT8Ugq@cz z@PY5A0M0K)X6p&o0o(^%MDx$E$AR1Tn)i*!wt{W>I+B@i8SiN9!wDf-oaean{aYy` zmOr$9iJW7(&N+K>x2+lLHR~JK9{4l&{cyHIy^XIi!09+n(0Fk(`16pQQOF{E>r)O> z-b+a{=E5QoZ2|@$GQ!ZKs!}#V`WVyDiU_<&1oJ4OVrvG2@v-CNrYH$^6DNw8qjw5^ zPXbSi7gA{E4Ftcgyb|8sYam^?>?AP?{Cp#VZv05Jp`TKX3}+ebQq6Yf&GK@?So{z4 zsk;^OOR#9$pN~UazG|)Jm2mIEpFVAo&wUJ}H5%kkap_G{G{Ue;#esY{vR-aeH;z_9 z{SP97xfnwCgD3BT8q!j^MXBmrf#$hAM`}4@^FC{(Z6}Yy%u{<;H4hq!X!wBfCN-~^`@z`r&E&= zF=ci77z&uHW7l-x;tq^ZI}I71rhNR%HZ?YQuq$((@>X9tAj!#OL(F`3aF-LYwR%gd z$q6K12Pc06l`9sSu#MqS0KNd*ONQ+5(!r}y!5x9Blpr%44uckkz%9xJty{1h1Dznz z*y{-es%B9KTNCq&{wCT1quGgIz2e~R7iGO7Ndl@AwF8AD-u&y+`6d(wO%b$jE^(J~ zH$;L^9fO)jmEZ|YApb^j%-Y|t`DTK*Evvg@3y?7M74T}etK*0hu_SW2;E%^(KY%xR z<}pN2$B=&60j%PB=nN&ycf^?d-y>`gqb;O5RVbYNnVdCXr69%kRM$k8X)H_s$`Nwe^PXG!)n z#5PtEzR^1y*O9(Jd4}|G5Js;ry>SxU6>8=<)5k5ch;X&yTq_{&!!o#b`mY!r{)h3D zCuU*PKVK5K4j8eF%jxD>ty`M#ONX8w+BtA3^ZCx0*jQ{RI<$$Aw7}TOHU+7R!d-c- zZd&uCU79MqLj~hrT~lkprD|Da9^~#_Wmdv)=35wQVh02fBpss~qcZSC8A6l?6-g=$ z88n$8_wk0aEBaz6R=vghO+)<}{1`b}g3b%~~)hl4{FtJsaRn1oN zOL}EK3dFzgFM}iYZReXrI8doQYpD1Xg_gJ%zaQy$*b9$6fmreDwa~H;DmcaXXEK-2 z^=_f(QL8PrRIONpYe;2VE!)kMwSrJ!itWpLsdtT3P%T5a`4Lq&1o50)e{(?rjoGE* zCcIibtIX1Jb%luL)~y1Cl=V_%yegsZqdwRrl`%LUeVP{$oVPf<6-Q!!LTf|0fl_3B zBqd`Ubn2SeKQ;18lGNaqa}~(rZ#hHmOO>WE>&_0ozj15qMF@lboif)p$S&YX`Mrg+ z&jWOPT^%%bJw^lQQfGQN^8#9hzY2|E>_k)x4|4<#HoU(dVb$F}_cD&Xakyi8+VCM} zn$UsRN!UfJzg!zfr)HbNze1!0R9r01xF#Eoq+JiiUnP}?X)O>di{*Ten~k!qI7U-W zUw|c)zn0ZJ%#aegqSfm}usnPLRtl=CBq1eDT26PFB2gaWYs7G+Cf!k;-!yDlwj}nf z-(j@DqEHCyYijQ@2r5JX`!(XbIMm{Rv-^kp>)u)XOk%Ex=++{#z$8*!xu=9gy@*sZ zl`?BC&R8;)iit#4(XUAIElkn?gf70=g0Q&CEv0t8U>V5b;`aT<3*7jf+P|$;`7z zS{yrRbRc45N~V^ydC&-{3v{*1)nW#FZjS)B4IHB)mLJiZl|*&5YSwi2Avrj*UH09X zCh8@ob0`)~RV;h++(@)}E?%Z)nfF_M@%!LIz;CX1Pn=G{k)_{z6Q)LZEc5k`b1WlPaLQ2OKC?3 zI^^K7j{5O*JL^AP&Nxqsv+Q12*o2@K;O$tf3W9OO9LL>LL5ApT=xjFUMF7GoyVAQNo*zuqZx)QxGmZBX72T16Pw8Q#8NWG8bK|%eOCWaNYk__?=r7btmjs zP4i_XG`7@LttpJS#NzjOt`b6+O_vn>a&}Fs-?W8yKJPx=4YL~-`sqxYBYQf|X6tow z!8)%c>cTyb5u<%BB7nHMiWR-yh0pr6gl~roV-?3iT%T#%H^|7<%yKCzbv-oks!2aSWt~|RRX9!Xrt-|qUGZ{R*yS@u{L~#iJ7B@(i79^d}Oq|&# z!0lA#p;2mxf&caxXA5-#^~TzrBr*VJ_Jn~RBe(KY4>tnhMKKM}0S=VTTXB=C0+FSm z?}W3$ARR?B)PS7Skj2*;!RX;D9MMOp!a7F-MX6QXlJmmZ+2hI+Sy{CysYV+ zX0hKoSeJ8rda_5oj~_M++Dypjb6_5^W$1Ou=Q2CZOM>U!c(>Yktxs$>SoO@@+zSZMBjZZo z33vH`6Og}KNIW7ICqA-ca>dXJc*cZ6HWW6&&8zexmh?Cq5|T`ZD?f zEwEyIahJd1P1WVbHf4#ROR=~)z7WF*kcu}_Hy=thGf?c!Hl-xM*s78R*d|(|SXClU z)e`n^T169@@5qNcMb=nqLtL@45tX7;_?S+&&Zrrh^j^e7)W4uQx~{S^CD6qnOVY>Ct435=G^S3!L@AlLxY*c^ z)^jKMwWO*{lJrX+sr49O@^#G+NC%DMLs8buplE-_B@;q&Hmxyfk?v{@sv*i5tYZ}f zUwR}X%(+6Q2*(0R9VXPm*sSn{@|biI1lNJg?V(mc%ZEWAYV;9ZVRcY^OB?45zXf(; zojRH0^m&ZxR65E-E!ERfPb8_P9dx5O){J{ktfU4telM=k8%d)*8zNdVXh&n>cv zKYcmQ$7CASBla8pdRZI$WcTEHU^@@r7uf2-hzvpizr7#kQ=9V$5nf{5&;H`b=^Wbo zn_QtbNq0|r;}N3VuIlT{(bVGJp-WD>v$mTG@EgGZfEOi=?El64W%)<__@7`{7bE8% zQZD`f39DuN7X??w(8*cY!qAa`k&)xSXtiu?>;&vg|1e?y|I0r|7zo%H|2da|fR*8A z{c&3USId93|NB}0#4r%Bu(13q`k(E;A7x_a_|N_Sh-3aSV=@r@)B4Z;PxQZ0b5$&D zOr7LR-IVNX3~d#ZX(gQvtu2lJ7e<$jo&LY6zUr2?g0@aSDytvnucfW||G;JchaJoE zPa6M@(Pd|(V`pLdACm6>eaZhfO;_F2(%izCfQ5m9Ud-Ci+=+nm-@&jPGBdFMJa?uadM*PKvo5`$ld-9-Gr`Wa0TL${y=-dcv z+1YyGTOcJ+A$LGQKucIc101#_gu>==Y4>;wwmUp+#Q+OLopR_Jm4zi(oVh)w+;ZVK z=7KVm*1)9-;(e8KrL%7TX&(hqo1A}nw49E*?x!cdx39mi-M&e`fnfmrxqnQc@fmq) zWJ9NE(Sn)S0O1CiTr{0^)E*1~Tfp%@lNooOxTEH?02w9${p)+<<@@$NIaMuqp#fZt zT6jkqyeby({resza+8ed#=GlGZ(0F@bHE5FHYIj6!`7||_2->`(7A||Ji$EZ0N#uw z@T^*8LLP#^4bO`Jy}zwnFzp#wb)kC)^ChO6c0ydQ^jBIFJ}H93)HZ}@scCCX1yXb(v@GLC!p!@wZD2} zcKfSbpgQ8uz>@mn+l_(SYJ8|=;J^(sbbKLx1fd+_O#c#u#zyG>eX+iweFQA@x@O4( zC#eHuCIAS@eLless(mx|+DlZ9k@rDX77@pfp^0xLU*O{18p)m{djMe+?H?aTzOS+U zx=%}(`h}*}1Y@cAi@$F}&)&2SvA99LSh&uutqO)spF=^KL&i!u7S#&Jg9KC=vZD7W zoenqHV;&%2_LEZpCPghsglahO9S!J>Ru&DYf^x%%UDGKq)BYd}21I4mI@uWnZ7U2; zQZ{HzO0$zmvpfUB)bS6IZlMIiz;0;XNy5z{FT=K=?HqBvge3T2IkoZeTfH;nX5!nU|yF&3{K9z+zwUj0IAOHA4Jv$#YhsYx?$J0%h<(#%_SG)7= z|Hg=Kf{Cv21)#n=2&?E)T<^)Z7`oW*Gjk?bl2&InwRG*hzzMGR`zYsLQretX+0xvq z4|`?GS6drcu;YDbHP9W|j-hRqxccpl2e$V&`|)I<*nJQgA=r`<$6e{{EdF@9vrWl)HT!bUhpj7TQ|#=cANSlHXY)@vfG|5Sv#@Tbj$r ze34HJj|TSE*IUE+z9aM(CX<&@nLFCifsIg{IBnFJ0TXXjLuGX%_SzG}R>KktE7Bi& zX0w98VL#F{yJ-awvP)_Ao2bb6bsDsOLxx?mvKCWi(6%7|QxDI^2o@wbq;bfn7V1%$G$=+~%P~|2rd2t@eF3OCp&yVOmg2c0Tjc_>(=~KRROD#G zN|mOP{$$uvoygYb)nRzy)ZF>gYx@rDIYsZyBb_7D2EgAArW_bBiz=?ytJJC=Jt*JH zq!NwvK7Rw~af_61;T8&>%W2bXZ36FjD_2EFMC~GxyT8vtp_lkYswsP{Pdzb)Hf~K; zz4`e=Z?>vz8no|@&TD<+Tc2y+j%*J;?}+bfzK!FWOjei_<4i{m2R=0C&$#?4>VIK# zvwX#O3r^x58ac&*wyx9`7nVuXTjS&whd86`Zi$*ZVq|Y4Ve9|K$aAIgk6EDEt-3Q% zR6kz*rCW;M``u~W!ncvimt{QXHifPh&9#2IFXuai+vxYwcRrGKz=l7%)vUMw9YbI~ zJn%;}<#F}HW*`5VA$eKT2)nnKiJ#`C2O^EbBD)mxlylZ>g#AOvzRVg`x^ESbgZ#4 zL$-oip~*P2elv#LdT>LcfApZ=4cMbb?a4sNKYGx{f9XMkI9C-{Q=k_%vlsbKpPhC z*bkC~$Ni%RrRtj{duLl~blD=R=Gc_Sv8lOby$QK(U{G#OX<0?Cjfm0qMkwMx%ZnMg7n zM-c@|E+*?_2}??$lwt`b^~TDnkdciH$gGD-&sXbh5_wQAzj7&+Q5iSI0{ur2sx;0z zhMdnu?3*oA6OhTW7F?@Zmi%qdtuc_~n7ZeYI1Ph6z zFlzycfFN4XIhZQiYvkjrp|4_f+bp#F_W#lL7GQBLOWP>!4#9)F>)-?n8iIRpcXxuj z1%kV~1SdEI2=2k%gS*>5guTzsKHu5*eE+@Aedb}Uo}TWm>Z-S@8)osgKwe>?(n)0r ztx|3Y{pswY<=AbzV@Wv`rW4u*@zl}0_T53!!o~s@tGy8gtNqqWx7386R^H_CDyqC% zu4KLdKL$$vs7UtQ7QG_3CdOfpR1Qhp9L$gIIt2;M0?1|>x({V;dDSG`yh2$MCyUBi z=xi*Gu?uv0c;;blLDVD$k{$;&@^~FVg(U1omnf-HH#XF}RAKT`q}RuV!8T>@S1o4^ z0)c0Xvd@Xn>jZR5m<0p~=1=~_n8=oOjZ-{`pu<(lHM^xve{Wc8q6ER15GW!1iW~Kd z0+q#(Q}PIWH9`Ye(GTwPnnC}Dj8Ly6>Plxi3i1MdH71JVqI^YrRdNbEbcfd=L__U^ z!2?|oRqRHjZRB685vY?y`9GF}t`kkhcJ$!fxS%tTtNLS)y9#@F7^#avQ6!IJs@i=A zl&pUhgbP=!hN3Czb()^xZF`~^;yIztCySw?=8{YGYX2bN0%-e?N;!-^)6Jmrd6OPa z?=1|8C`@T(u?@bmEM-D{zZhl6dLvblOXJK~kqRG%ezj2GyL}P2JPqEIg^y^?lNkKu zvnZ5n3M@=mT1N~WEM4#UXwq2Cf#)OFcFKHd?O7v>ot!CcSU@#Z% z`HErVo(-}YcO?rO%8K=#^Pliij%qr)lY>kdmaPrtONP6=ex}eP)6svJydAT9Le1te z1bvJt*5+qGk%Uuap3<>q(@ed2!}-QD2d4&0)tNKE4&P$r3nud6>1RaJ9pI70Gx`o~ zvl4EvdDd1J!%Mq-4mcdW!aEV2%J;6{;FQErLcI;!J}0VA@DF33=Q~><#z2S)906kz zq#*-A?%zF|h%5C_Mw}QKjMS5x;=+`;Ex{5?c(_6a*YoF16Sx306rMaGU!)ZfqdDiA}fQv1{b4C)72@|>-!2N z0^?}C(e;Ar)V*WcfW;IH3^&#;7J*Wf0-6gT#Aj!m| zRT1g>5Qg6y6JjW5ErhqnIO89!qCet#`e4<(DcP`VK(m43uz^P1E&l#-O|BE+nvX8P z&<6hz?o$Zji!ja=onkwh9eLrn9r6(h$T|Ij}A== zfh=T@ypJq`j-nf8GdFT>Lib0^`z-F_0$2zB2XD+#w8l73!I6o*bIb>5QeChl7m5tm z{=iJFF1+6)*1#2yG4?QZ_`Fyw_# z%KqRsC`f{@QiI@+js0nD5L^8y!qb9|A<{dg=x`p!v?a4i%>0?q-s_Eq-WU+~kwO~K z&k8twHj|ejhz8IIXn^fNaEH9l7i0@D8pUr6FE2>hAy5yoNd=7GoogfL?qfrL4_L)v zG{VR+-Xh*$Y8d3oPj48gsceUvK>-9U4iV_k&Z^g?e{8R_9ZpSEu+>eC*XSih{kza@n7FdH)#WeopsCUvRSP(NU1JRI9upe1I%3BG6kVkEB;r5u|V01cG4Ka&V zB+(S4Rcs>-V$tuO=UfmGcvvfMrmSnei0qT%Zay?cA4MFWp4(tGHk@__Av)R;uv{++ zzK;Zl<~%=|zDnc2bgBbPDT5(>DS~Kz^({)Z^&4xQ?*#@;T+ZN;5I6|}A4=sb-fSVQ zf}$0DdV~ADSV8fmnJ|_@KbFF<&*$ru?f!C0%|g8@Kl%giq=fWFK)`j2GE&85S!S|<>ZFO#5IL6Xz zdvAf&EPQ4E9Je-4J{GlJS*DiMk10f3KV%ltP^JuDvO>dN*(z9HO^ah*6e%Kq;aL8I zSLdS1;J`sxuF^lbo4tH#AF7Le3l$Iqe2%cO+1``)-NTMacP9JHbc#bpq)$U=H z`huo*i<*))2g5@Z8|CY%%!^W* zeGS#9kJ5QICLcB3oms%j%4S?+hJL<>gSP=bzJnxrik+gybY1akJ^Ea30#Ti(jCk7w zw?lpF>yM8tpEah8WL!83>5aJgBxu(T3+v=R(hpRB`aJRRRItvn@z~)q zTDDTI(#C4t#`Jwnmz|ZM`SK*1xk0TjNjaB}P)zP-KYPTz{nzMJA5pr_wpfTy1U^sW z?_Fr2g-T#G^3S{lAoe<&G6;5PBY(25LU&2$ONH1aUd>yv?M_XxD1Z&Y(6h}m+~V!+ zMK&EwiO)F9ud?jE(^D|pF2N2uYjv^mx&wvE71wsLN#$@rA(zsXU=_O9<+X_~kd}JM84zb{nOrNqR zmmG;qzo*t@ph+diNY;L^=$n)*t|^u))seo?K(MEHjnUs~5=mlwx+^=6#@^zcMbU9nZ6nq1B#dbv^ z6V?Sc82rxXK=lcY$(yxxU07mNKqt|SeZHv-QGwP*w%)V_AX@SRXD(lQ%>EW(ma|QR z_=s+c!!)jjA}Vua&lT>cOHpOHPaZ&0(~O+&i(#``%V%X%*dsrIA1RY8ijil_ogXhw z5guN1XLy$?_56gUalO(VkT48|V%CD^;~}~dI*hkXNY1?Y`6ZB0S>TF$k^-E?yUCpS z(H}R@$#KR#*eNKrK&fKeJ2i`bt(5sl-*WIygj_v)qvezTo9uIVcH#%nQ?;M#Fir4v zga#=eQ&hdCcC^8`t32&NA4uLRf@FQRI%B3gf20gn7Dy=I3>+nn@I=;oK-iD>R$A#( z2xmDZ_$I?D5WbEn?(znUpD>3q3B4T$^jZxk2a%I9tL44i$JnXj{VS?V_nG zcckDm*Zz;{J)XvCxnr~SV~?aB3Xr8rVyN?SGZKnDyx-HU_TR`F#n2!6q?5zKJP!E; zMQ}XE@eg3bqGSwhVq5>2-Bi zjn1->D@Ib7jF(P9}=-jC>k%_~>T*%DQi)kT3O#uA@xaGozv7 z=5kq5u3nbs{`zj=n0%Vz4S#A_s?1x>d6a4A4dx@6IV9`P=H-v1)-1<(*7B~)DL*uc zkeb(}B{^DD?i)*5-a8vL9@hLiCcTN}ChS zZa3Opcf*q{5_+P)2!6m;F`~}TMQK8zPp}$SiB+f(4u6Okrg@VC*YzcBJ5G6nY>KKa z`+eo1u-m&E2BnfF*&H5|%BmplNtz#(d^HhydU6G)SU)=RR%WRO%Q_ZVHu?c(q6_o7 z>)PF%UjjCm<%~7EjNt%&6C_TaR(>izS1t2~%ia&x?fKLG8O!<_+s$%i%_@wH*CiG_ z(QavVuo)+f-_m{CLOtnjLic#@;EbW-N0~3k}*fp=9yl=l~9CAy%6dBe$awonl<9=-^ z?-kyFh4O_L=N4klSef0duH9y)_n`z<+JF*%B?fs4LoTxygk-IaX^89_v!Ve7KZgmY_ojYXSSbbJ^+dg zns)1vxHIBSczZe=`|Zc+lPBm?N1G@Q?}TOJ-nIfQsQvu*@E;(Ftz91F!3eTpj_w2E zx0v9mh&gr3(2=G9O-KNEfe-a{In+Ar(}75uD|&BcYZ;^yxO@BdG(~TG#6nJ73Pp2s zGaVM)G8+|B~HtCZ(C)=7Hn>UwMt3y8pa=Z zxG-r-GJ6H!rzw;)5krUUru41ho%gh5wOHrnOj`x;< zh#ktl=X$Ux8xu#5L9b#a9ux5tLSpBmUnEC20kOzL?*+l~_WqgY6U~*A;N6@^ejf;m z(^OFDj=NWIA~wOcRUkndp+yr}{MA%F{2SzW8ZE7kkOBllFL+FQgl|wqT<9>f4^%s5 zPFhtUBQ)atQ@FNF&9|!f7~h`qYsSl6_K14K>5qFt`WPlrz445}*GWBAM$v1ruKU$~9x!*>idO;}Q>LL`8t#9EpDKU2jisK`&M>=C^P0qaKpm;kQRH&UVh< zkEra7bsq*ZhGmVrXbLzn?do6$)&~MM=LbUP2Q&sSGD>~LHt^*I%8B4kG2`o_7*TK; zpI~}oK(J=R!im|+X*`)W!nL$~6k>u>{lwWgZcfO$Whf|?Gjff;dkpIu?0+4(>9C2b zKCmV=r$e=YSn$wI=YHemp01ulqY{s6TbmT1DMdeg6CHI1QN=dCAI>f2P1wL9bV8G! z)qA*@*h@i5d)_#uQo4yM{J70vx*!9bgl-zCJUSz_cU9PiV=!_*kfR(8UNwYbL_0@ikiHRZ{nQ+q zDrn^9*9fQic9rjEHv+wYOhY*Q!Mjz*e4AkEcT54c`Aq#7NGv?FZd2V;Rg)I4%#F(| z$j$Y*lt;|e*axa;lsn|O@$ix1p4jQ9EOZ4y9v!rTZbRB+O`YrLu;1VC!1mF&c%hoWGePm zT+|K6m81>lGZr&Wv)Vg__6y$i^_utqJX@MRy20U_ayZhRlQsEUJ=?xT(x>!>7#UBT zTk@s_00$387-o`RjDhlL+(UJaOSW~*2T4AVS27~EbNkisLz2+c<2$5pu}D7PGd3>p zy@lGln0IPvg7%=486HAiu1@M!q!=eu$H%prWMin@at;9#a8m~V0KNeE>PP}pPEVp! zTIjmx>Z?0hbUVumGWK5h$Ry4l#s)3c$35D6(i`hF`Gs$5|DISE%s@>!aOwJED%kQdOMMkng7AX) zL=)q4Z9o3dUs45JL)4Wad`+cPNPIz;p4W z(hDno#F#W#f%1&48@(2w4ZDDOSa zozj^ZTd(=L2Ob^Ve^4)0k}S{u)f3t3<9kM`Jqc1%%9agAU#}oMrv`1ZApeOLtd%C| zY1Xz8k8cmv(q*A}^VCd6;$qem;0LV~;Kt##coE}!QzB3_mA0UmEV10+Nl0LU`A!tC z_N4O8{}2yJ z_vv1%gXfUmC2Z-9o068+LMp0l%{^2-ao{zgTxc`~M@>ZCO!&2W*b!a*W3ne7fwtJ{ z)cW2i@E_`rV{lMKOnk(@hS5-h1){C1!ef7@Ko!MpQ19rM|0MPKxYkce4A#SOVaG}7QZ5R7>c*cjQS#Y31Pb-yC8KG*;& zs=gU38YC>-8J=8xolw9sjTwV=Al)D7bIq@t`X#-JZEF5qqnUPph9m)@8MuthOn6k8~{UT+^_=(rJ`D zby_zk?m+W7Zq|;~%QWb~>6MOJ+|L}W94nx5oqm(x`g6(bFmMrEtcgSF#e5lq&Q%Lt zi?EW`Rh$@@pT3YU^88IkufjIGA*nus4+%7 zd@63s%6cM4n8mfYud*eZMt)F5N7$HV7-MWD9Y4q>k|$vdMJ5bQAxC8mb5|V}H{JdQ zVzuOz97k1`D2|pVPtp~JJ^wki(bkIfYg*NO9(CXyesDII;&7iVli=)b?kG7?FtwRJ zlQ9l;pOt?a7JXKhaXQ3{k7)+^&Pupn;_`9S7JHvK%*0$!;Fl|n3?yfGgiqegr=Vx$xX*O zZ6)_&0cF)XO7LH#uG=&=xH-EAOEv5)g%Nlhn9LQcLSMC3-yaq2 z)US6O%*e0xI7}0<{dwiEO*-C z6LO_6oel*c=z+E%UwDt`EbI@Qp=^A zL#^Vyr_lLVv=DT(kq(Q*?F*tWmu=?Cb&?r)6gJ(awb$CbY^__45tl~asJE>l19OTM zV&Hp>WQNb*$-Ff=n)Ny6A$Jg(9K&UIWvT`XmT(8b0kJFa^ZK~VRqb1#qLl(-&wbi51qv>7za!}4s z@)OsCNuz3tLqN*Yh*o0r0pVv4c>bJPSDbEoI%$_OW%D`#N8Dk+VBj^v7E>TEK1tj= zsvVogyzw6pOt!)JimdBS)UqdVLejSNfHKWl=nolit@;-S0-{|oIkF(Vb6Kll$Az7U zFnkr^sp^9txWmB5NikmStn@84W@MGJ{h%eXNo<#`=WI_4GKB6H32IBcP%q;pf^gkE z9lTf*#kudKKgWOuH8&qb8gdRG8%cmEp0=hgR>1ONTaZ>?XS3u7Ei9^8rk{nEbtUvkXhZa;1Pt;6Q)I<( z$Vf^`?Ut5QmL**!l1EDAVvFDCS{&Jjt|zmQcNE}ZMN4CN2s$5N>opV!@7FweL82DM ztHuMN#BA}oy-DB2Lb&Cw*&4P+@nUFxq)$znI*tIZuVS$;_jMOF&Y4w{x$iY;YdkM0 zISVQJp86wz(YGUSwFs)3R?Gu{sWPw>@JjI1F-R&xEtMQ}B(GfAzFEZ9C#t8#>9aFI zODdn!%7)Qa^T{oj07}K#ZpB1kA!;eofU(XZG64a|l7mq=8wFoLj@?o%1dVY%e59d@ z=d2?kg$3xD05qTCSKZOL@BJ%1^C&SEpXaqePA0{U#4}7p63pIC5NFy?S?^Nx7y}^ za?E!e^8rM`Z&&l8NHWxhvK%eZO?Xj`Fl$|mro3(eV+}%Z&XV$|x{fRw+c~55+qvPb zQ)=z&4j?6)5=?%G!-C}M<)#w^t>}Qogf7HSPL^qG@d7;;YiuY=7G;P6*thd6Dp-r- zc;8Zjl<`1zB5mY?j8<4%z{ZR5LR4>R40}Mr*Vs@vfG5xmvMGMZkk9}<(k3x-7|Dvz z7n>FeBJs=^KzS>(;*AcngG)OL+A%kykJgi&8^{gmKTyB6B2m>2IOmeiLXh&VY}`nW zdu8c#S-^wVoTqWlooMdG^f77Gg&8}^4z}Q+?)sD`;bRmcAnb=U4;A(uX}HeUHrq-& z$x~Zz<<(^-vXB`Tkb-Y-&0sWo9@BZ~*f)Awy9IU}JpJ48wlCb~j%Y0}SorsaYPI-A zk|rG-!|`x_q&3u1<-a#c2o&`=oXrt| z)*c~5z;HI`Qna4J84tx^enw|u?S@qO2Fl>}2K)5-z)H}GCDzhAudjs=3n~ATaVK8G zm&bH+s(2E}DZMyQ4+KiZrhs~uT#=6t%Lzte-$|UUFxkwP^!=bBM6 zqvf*u!#5rM3Sy`?LKQwJ$B1Ou!2`6O8-dt(l0>MHFlxAOF&N8mBZ8H7s+0|q0Oa!d ziW)R!gv#uT{B(p>A5GqnP1G>P6qm`@O2lO=;_l`uMWwC7OVGXIAL016e`J=sv^zVJ27=j2>{ zkyrQXcPZArDyMOK#!p(0#rGL#6H_&|*V{pF_};-v%QL<)AgDDkY5hPIqt~ZJVJry_ z-nnUKT8I3lx^NV#f6jskLw(Zd6{1R6a7|d=>Aq=JjQ1_ohvHI6C$^4s?(E^}ww5pB zc|8}y%zPy>9WlludnLDd?Rd!8qWNgQaav)VI= zDVDzSBG<~InY`gi3QD3(@-k{29uph@jFe={ELsath^p6ORVPMmF9| z1Z3pW2|1M%NXs3FR+qF|em%mn>Yy1h5YiB;@=Ocm(jj)Yz7Phy(&(2 z99&*hvm#Tdeyf?t$#-cap!?tP`TJ48{g|S99S-?HQDm;YJE)7%Uvp#=WWzyeZq{>D zLvsbPfkGw5$`TT3@b8+Kl1E$bT^rhs(yHglg0;&rOiwwyt-1we_vEy>mtpv1e0~@{ zhwL47&Xv(D1vdA(j{38{F%PUa$&6k$i1?Ob)zWwNiw(XO#ZcC03dsoXEB85XYhn^k z3ldTmUz+dq0K09N#ga?w)(M+@uAK@di~@CREl4&gI5unN0lR%Mt9tWu71qzwQq{^L zI%u@aXs47F!?3ZpZ8qhZ0W4!6jR!R##Baec1ybG$pm(4|Deh36ZmZNH;FOD4zPhmI zK%GQ)gU;B+J-XGOu4bUYwX!a^zmd+C4rr!3yYLZ-Jl+QL82*t8pJ->{&K^ZsjI7p< zN++Hb*Ig({(jovM@6kb|+zEQ#)tUnjMwrVWqX3zejP{#LBap3kH^cIGVaUU&48);dj>bl4-MD z+nDW-kTSn$xku#h<@^DiD~(rf97?%;eOiWW&DRWx-1T{t-x35V?>nW;&$n)K8Jb)z z4g?I0&5jpy^FKr<*WDI}ic~UVygseqgaynZ1d;X`kg)g^rH-^dZb@1-#DY=N?MG&b zI8u4>fJvfez9kS7e;?}Y00G;Gsdj1I1^hKUB;pjRMeZZ(_PIbfF)&fBX^?qzqg9`(e-6`$8;_+CS}XS?Ib&CeQoa$6 zc(TK*_1pwAdm41I-TRg>Rlt5Ckc9Nn>8gUd*_&9mB4YJ*RNcA9i1^`D9hMRzYf+hS zq6>-@!dg*F^oU5L-VyO2F}ujcbm`k{R)a$1aYFoyiZUC{69x+S*t0}FlSxHbbU~`h zFmdbv@fiWDn7wm!@(Z;i!w9r>L2oTeu2!%uf%bqeBT~rG!KFbs<&D_ZkbOtoo_HjEo58&JtKHg1sVlBsbMU@ zT6F-D#yRy*?{9ZQVe4$ex^`G480zX`AV*LRZTWi~x-giBgQS+<+6B*XmmJIh-Ub8z zK2Mc41bqtjID|&}lQ=B)GOv$~pu7jwTWojT!ZWL}$K9CeK7*v7IpT-IKsz5zo!QE= zy=)Udj_^g(Y+r+UN@c01A4m)IKA-B*><^6 z{3(*PlAlR>s7+K#cZB^QzT&iQ<7+svGg2_`IOnyeVNJiTAUeJYwc+7S|7FsRB7}gb+15 zE{GnIci11>?m7628>rmF_Su1_;&AU~Wwx5d<9>`VSTDh)>pVL~bb;pgp=jn6frMNp zGp(DKUG;%f+lqc~}a02k+bdDvOpUDigN zn$L{4<3WxE0%7W0b5EC8Z6^il&gA?q`m1G&I3et=Cn0`01I0IUdYj>kUH7$5DV-S^ zYAv^Ugq8?Ps#Y?h&P~cEI^!9o^sgHopDq_F@j(WchRb_z$LN_5`9X)~vQ*}ung==g zwvC6smoRfyuvn-wBag_8d`f!KE0F~0G*!Cj707!qIo}p$t$EcGc%rwd`-=1v1BC+MLdaV8)MFjdF9=?5$N25Xd&5HaeGT1BLSkOtsLF*^L*c!-*r!;3oD6cr*BC#UOxTiLt13p|hZsN%^)Afk z8Cb*~pK2Gyf70jV6h2Bdl2fHjkQ#~v+7@a!B~f{{iKWWeqF(J+#j$w%+n&-0_KxBC86CBm08FoIT9-mD6QKHTk&rWGN}{lgz1If0BGz zL&Q8`3M>**RIc#5bbV>4z6_J-%(9=&ui>EV%Shpxdxd6qkM{Ta=xVF7+npE?Jl$#n zN6WLsj9OH!_~6>W2)EY`5iaN4vz!B*4a>?AXdNH|gILhFty;&e+ld3NdPAA)GOQDX zmHnbOT}Wx?4WRXXH?~O5ct{C*UW=ML2ghL8u65NjNC%R>d2A3^XaEl$#8ihSU7;U3 zfWKr4i1S3(#dm+YA8p3`IAhOY0?d|`rc0TbIQ{xD`tNv`KiyXGvpn(ASrdT8uVTCs z#&lVMzDmUmbDfcRHIc%eaIG`hg0G&=L! zj#OEFzMD$27M(Q`dUc*uu9poV;waFez|kAr7ab|ZqVME9tH$P3ro>E;b&S(3@9eJP zlTGdJ6UQUw>afTdkt>Y@IlT8ZTK2?w z7?p4LExYUF=LOU4y+3zmVZ@S9zOpOZk#9UQhvt&WDq{>`?Up;jI_Tkt9a#Pqwt3xtvOFV6)zB; z@a(=h7QVz`KmX2TBV%#aol|2?HV5475WLFUtD8K&j0eKQNF?Xt-ob zoG}uG=mAtGK0DS^w+&=eCt5Jl=sh^aCGRF@?HpNz0cXZ-ok)Ch&2%+tP#t2}Ov2cX zffb4dXb#w^j%ASSt5h%(AACzN2v0Z}U$~PS^%l=f#fKl4Ik&@cX}4y?a?X=`T}Nd* z$yQ<_A20GT%rBrOU(0RBxwUBJeA-eBT2IL;LQl^6qS{=n*HpZQx8;)HDt)ub8_`^$ z3_UcUi->-5^G1(3R%<<~HFzs|R8qQ#tAtedHIL&eV8~3n?lwgH>zoN~^b#Y1|$nA&5byRxp{S^-R&2`AZ$8K;wdxf`hmHd71i7o=kHO-J{Rx+CkHy<%cav6ypi>A@zv+dJz z!OcZ7@8lZYTED3H!f-dZt}-z~lxEZFOR>n-akZplzOlAbn_0Pto`Wy->gr-8%*Rw# z_rTE(sYYcvgblh#yi_ADM=ZHCI+56wl&()v(MS@6SHzO*PBJ^ zjp)zakhpv}wE4-lOfB$AMMFhzYm(INazW8F%b}r0OHV4#E}U^-Gj@UyCQDe*XEU!z z9|0tehGSrOr*aIG?5$pIgCvP6(t9X5o1xjJcy0rtFg(&Dt2AGB`LqqazDLxblkWr+ zMMP6e$}N?20vO!Nb_QZU)>D54ocCT8icYBqEo~v~TSHeG&e5^e9I*Av+$6Ap4R3;b zird8gOd6M;NH#@|!WS#$#velk9K73vtwFOR|E4l=L(%xz80?hWb!RyJqtU6`5t#w# zcSZ4^iggGS?rvg;{Axs`iMEc2r}$xDgX^&{!jPFFMXb}8G-sLlgqSn~9AL8?t1g?0$6tu_bHaqmQJ zno!U;AmBS2&<5)fBSY?26%8<+DlD0qH<{I3$?&3l>L;{1yoHZ)=w`gHYMnVoEaC)|B=H!+!Wc|lGeaZ1_N=_?0dB`>Y zY>G0!FzPI2i8;%uA*;qm-4=;;e79hlen?_sMSuUoubFlxMa3j;5M$_A{wOL@D`3!3 zQPD;{pTb z0c)#kgJ!m6E@q`)b2!l$tms9>uBp8G+1LBAC@2aVN)xdqf#lMIc_M~wb`m$@mEBh@ zHj0(THC#PYmf&?WcFUo!UtbMNS}Oh2hEF31`}kU4zp~-+akPJSqChxGmqi7~xK8_B zG)79}+7QcZsc~e|-Ok0gJTQ&xhsn`~(L3VzFfAB*pZpU?Gv7a5?o}7ExqLDHnAAZy zs?=p%=NhtuSU`?hecombFd<_%3XnVR@J8SRRaeDqcxulYm;eV?Ns1`_Dd+3*E+($O zm=Co}m{(t>dyG3n!f~v4hC!>z=>UP=lsRfK(@4~s=ml6@Hp* z$J?0@RB`=QCA@ExVwQwiPZ5|JEQY)c+d4l+zNSBAyoU(e$n!T(zlgw($m6Hl2YZ*Ni zt0&pS*;RNKHz%)^+G()9;5VOCW+)uKHbUTOQO4W5Xr{|HO_P6RY{s(cRPLpm!x=U* zZf^BffC;|0*$f$(%1%T5l`90#*CU;1gEjh5ZFzv={s2;FH4g^HuhXxx| z0wV|l=Zh4*{N792pah;6E740SGoG0NnCd23&zIE>s0!@pF${=E`F9+?LGBb*=m(aO z910r@`hgrAmmvFTslE?fF5F%#N#ClE7Y5IQK#-Q*ckW^=WIL0J3`apAg_uLDDWQJlvZs(k>3rofBG(>^f)LjIOaeRM&lH^h!0MSEa(X zq92#CU&{tK-Ue7=D=?Xd8;v1|%o5Tk2RIE|j^Ur%FJf8>yM4=c&Bdah1J$H8Q408#WTRra^2V7+8F~nIBUwWKXHQ?nPs^^CF`?XFqN;un^+-Z%kiuhh9YS-fuxXVAJwziZS7j^+t81ej58R~HX z2sj8y9p}-1BM$jfm)}hQ;9&lj3Fz6m zSpTaH{>~V}{+EmY8@GSK(#qvv==keHpre^^f9XJXLP-EaI03ZIDn>SW#(ky;NSpGl8J!} z0E{z*Kb-!~)XJPuNP(9ZIHCfh3K7!_jD)Q13=Hk~`56U)p8KVMIHLrkf`gr-zJsi; z-E%Ml7+)G`{4%=cOFuy?D{F_}w0d^nAF=jdP{#aBVe>o6fT=>o)WE^SUIS?DXNv+lTx<;N zOk70F0A>azE+B%LfNp(GoBw-v{)$+6#{c0?j{k)_fA#&p1Sb1$%uN3c0?!!!9Re&Y ze?kBNboO7bmv_(Ce=j|^`Fq>H_xh{POZ~sU|Eu+%{LlNpfAZ(Z|8#%p z_gAk!+x=DlSIwWZ0@nNnH(_f>J5xhDAf1$~!r!p=f0=IB|00k26Gs2UGzR3i`kRM< zlKzZQHkRL1Q#Q0S(6!Q~7qYf60FqGszs!T|zimVQ3v_@v{BMde|FuT3{+i$Kj{URD z3V2@GUao)E{qr5b`P>=+B>Un3u5rNJ!@&+LJ!faOU(#QCa1Fl~i1fpLYa`G>W zfsCVrg{hUH{a@?BuO2T${IQAv7u)AC1c5AdzY6aSU4To=OIgv>!NQR0@d<l!;2E+oy5O_BPu>wlf1^$?VSOd#MAO^s?=NeOB3;Vz8^DO@FlYCi1fs=fJ>B}Tv zwEUMiVGtAG(AL1gOo0N7fg*H&iFp?KTza0q^)CY$14R=7#p;5%0&5(B^?x(RUu!OK z_wbC6f9)QCNc+#b2ll^~n->%QiVUD#UY7bloGM5J+_3*;LY5a30$wKfV#0r$lMrw& zdO%H|jb{8ycN^d=UH_)rhUU2ZT%K`xRmH*jJzkvAz60~V;^?l=ITFN_*c^SSD)Vl8UPH6f9Uhqnl7U8w=Tfd{ztOcGgEM|r%6n!IMCHq@_RTnJ90% zZOMD}nKxTW;q(&^DrQIeVazDs*&+9Cf+d3urCZeB@oQ;>*c ziGgAyjhZ1FR6!LijcZ(*5;YacwqhtYcu_1y5<+xo?`@{Q=N__{>=j~tjJLux8sRvy zNSUA>S~yjS(1rpP{Q6*95;#&(1K8lPCS~EICSwpJ0ug|I7lF@#KKw#HP$o>HnLfC$ zS)mQ7xl!cQ^m&6JNU9W-F+b_FLZNoN%PnQqp#UfO299mO$6oFWGq@jzn4IK;&&vwV z^^MBc7J!Q_DiBEkz$2nG3XB7E(E9SHoTTgI4S`+?WK8IgVQ)M5GeFEn2QZ)uviV5E zIaRtS50ju7u)~a0Qf%Uf>w#{Qc+@L%jd%wan}5^u!JlD--)L{uAQD5$hqMb12j74g z+VD>0#6{{&BHi*%<-%2U`m)OKrD=LU@~q!}rWXDjZ*@$XZ5Wc@Dd>4T|xu{@dXPE7t9s_&ZX`N z3DgfFIEwS6GBitV6J}%3HP|~aJXP$lq<2R^!q0n4+v|19oykg!vWoPY-aXqbQ&Gvy zZhkopgAng7udDV$t(yuT@rbBOn3^NAnq3IX$k0R;uI88Bp83ENvr5(1uLV2qdV-D! z*;QN|=-DBx)%8r>b&fsIEV&<*sjveJc zl_$j9;I4Vxwye6R4i(3F-{%w`QJldRei(%?CVk4+qLZN*&>O2G$EzFYd8NU~P58#E zt*l@`DT$$^@lIzt9&vDJ6Wfb&Xc@Y6kuN3E@cKg;&ij-E)v}#>vlFUd4%PYfZtWb7 zi8o@}C4Gwyp2&h=-~04#6lIRu$`L4zur4|cp!7P|>x@9Fm$#hHx{JYBJ>N&er_A=P zt%A-%d@tFR3g~JqtIN4x5VCAuI3>h=;%_V2mA+mgdF^^zmX`kfNN!tkQ(BL;HN!BD zV*fl1qum ztx$5S-+qlSGrs5P_dMtOJl{XeQ?GYE@7imxz4l)F-Fxk|XXg~T+eYq;F)_LNFl(WC ze1C%8>N=JDbW3A(6&dO=l#2AcyL9Qz#)_Akh($gJ-_Ly_eqou8YQV0Kc};;ueFxvq zd$Qnyl#bj^lK>VY)qgY*0}kM$dp?$-X;=85P-Zf)cKAEm@(5#%<$8*HjK7*!4*bz| zC~KR@P;Z~ywTRDc#rYEPqW*y+!_TXh1X0r&+z9h?`-(k2)zn?ZEtQSVdY_>i6?cD_ z)0cPX?(csn8ylO~yuG-jIum?L&1uRyYJ8_DW?N?^*-b0k?wxYKasMe|Pj9?crkRqh z*ID+}-Uh48B@W?ciyfup^^ZS&^;A5|R;1Qt57O>jv}7n%Oup9I^vfzUN?-%~J&$CGs7*31JOHMSLq|w)o{(j2usu3ye0qRd9o8uYBvT z{yE(u!OP+ZnGC%2rTU$H@hj6yL*foTT_K**f0Z+k7ES0=*89Lfla%-M*>^7iyN)E7LAY*HytP|~&@L?|`>c6C&v|Bov}1L281 zPt|0qwloZr8-{OaZ+m#WyPLccI?`oCM)t+WBE=~KM|+Rc z(`%CPa$&FLIMi()#xChTCP{e)_xLb3L%g^{!Q-{3^@s1D4DW_n=v}eUt6roo)8_-H zG*)`|>1RA%qZL;CckQ4kNemJmN$SIA6XC(KSmZvEDm`3g@2}6Xk-E36u^Zz!@vX>%t59OG%_6O zn9DXV9*x<1NQ~`o@2q_2)ZC0Tviy$V%tcEUsYoCEE&U{NeeXc;jK)|D}J8I>8)7(=jFsd(b>i{#pY;*W$Z^sL~3r?S*kil zaQ;lV-n%;6e4WF~a?4Gpy+5y`-xrH9f?s1a;Z9cN%-q1|_bpCls zI%z)JC~Tg)wSoI;d1B>;LnknYN@QGS$LikuOEfmrZFa2U{=bSId=QOQ+;A)GHhe2V zWr1%4BXaJ6>y^(Q8kahR-)(?{=DXX62iqlGWMbd)(f@jaJ6( zEZbuB`{9Hpl_j>~vA4*xV{a9cia4Udh?}M+D`lo|P8ba<^fPM)=(wX|hELzG<>^Qj0kvWh-S8-;v9T zIj%vv8g7e1VfFNP6+s8@N|%&Lr#udx|1|9`@rFdlB~GU_!_dHKdqPa;rnKK&eCAh+ z+Qvt#rgffCOY6}&Qm(*M-7ea$<1wfuGgU3yDLWwbUWsy*09X zUgKmoZT(EG8F{%@LrN;OJfX4BOG*x|+M~j1J>Ah$S6&!j>X)AL)ib2Qyn*2=x8r$n zYjaTbRV%LZ&ByW2?dY!y9M2DQr_>Fm+*tbbNkZ{pdfufSqq@W*?PZ(JS~lc$ul#&r z)3dG%r5P+__YR%A>tA@RO)Z&~aaM%jnBZ(_sg+o~^+wXA#8Ff3;tZL?Uk;|6bXRrH z70XAzk4kPl`{{ybboVw^O?_#;R>LC8JMTlo2AayFZ1-y!qry?ZsyNp7t?zh4o+53-^$lNXm8TpjG?8+Bg|AAdSs* zwe;SfFLk=r(2>-k9HJq1J++c@=8D-1eEW_Ui@XYT!d6IUvlaX7f+fAuR8i+gpV=4x zx=gR7J+(DrZb4{SlJ)9SeXEqujJ)z=jTpS|3hJX3$leRKz>jbWuQ-1gxZR>r5zovv z&?s!yajH2NQSEETy}XDM=s%cMPbGgj*Bcg(T2!fB{fe@+vAN_`Wn;8~KC-R<^Rnv3 z;{5M1eZ39^(is}9LwgHyMqV*a9DkCze9Q1W!u->j_M>wsGMisFVO!O9Vca?%?a6hx z>6%uv(Jx;5Vq{I_=hjnCbic*zjqON0{rT}%PQ=!GM+@?&9Q!nHTH^cGVk=uxUH3*VeSKY_t|RQj zwsn7-+TAG}iaRVe_!Izd{l**)*!3S7!3 ziKwo)vh^8vYMNIlReS50ba_jcML)X`Q+3?_1f~qJ%dl6r+aOhm^!h*zuDY3?>6OBQ zd)cpem^jbTV!7+bkmz-<8ze3LLvwe&DZ4V_dCc6y@V5O$4(nAaeA#*MZ&AzY4(f~i zq3Tw~(SJL*&MKa_x3C?FBTqq`K|$2P8kTZ6uQ~o;b3hj_g?neu5)7-q+~L2KTx_ z50ljM9;fXzvg-V7a!tJ!YG)qla>!b>r3BeoEm3Nsrstx5*xk=#%>%fnvJKcPV5>%b zc~oY%tL($b&?>E$Z-PQYLvr#RamQ0STHcO$2V!Ioe^u*wRCX{fWXHLXUD(EgPj|WX zR~DRqlBSB0Dl7V%;ILLK_u`|T&?-Wlj94H3-Z!b;v#Q-!J5BdCnsjpT-bP3?=EvIz z105ML?aK&1b(Z@N@1kUD3(q=(#iQ%zh1+7i~YvK-16NjqU zOvktT8c+UNqEux3$HKQ=W$^<|(6-jFy8sq$?9tHrAgQpMZN*KK%P z67}?;(d>I1tEew44Q~(F?MIrLa$a6MXmoM`-J!Z6dM#@c;}4Tr2Ki59H#z?Wl5TmnkOXtx)f|AO8FuKQF!>ZoeWMG_`HAOuiTt2Lq z>kgz6cWiXZchYe9u<^}?n$GnD#J*p*JNBDAxs175e0#V4OQ(W?+!VKmauqEpes!9= zOSGG}$H40^r5@fk*wX62wvlq~IH=XOR-6^3mnjyl0!2)V|imMqhJ$Ay$6r{Y@(zE&p5hg0k*=BLhhY-}Q2` z>R&F09P$hPWw6xrRbiz2@LJaF+%tW9TW!9dHr|GdS(Y$2LGRsxM>Vj(0ZxNxWNB(i zqhDQ$W0#n#aR?5hFFp9KM6VUD|MqcX@bPx1WBsj)d5=t4*Y9I)d}~hlzHIlb2voA( zbPZ+Fvt{Y)Li;9KZau&4=~ zv49zjcO4tkz{Xs2urc=;jOV$9@w{-bF@HW^&Jfjj&f{w%4i@GU?HCOjvMqFGj0KHL zrjohj$?=koegKb{2WT>V z6nRX3@cD5V3Z2D-L43(BEMKm!f&!G$#D^y!drC%3AFVNAwJ0nvICua@YN6p1oIyez z0FtaYEUGUBEPESLI4l=37iL8F;nEol8V82gLcr9((mj>s@1w2*v6!SD&szr$2{c8( zvC>1l1@NB`94L2OMS_wCOe=Z-X(P*vO=bq_S^Ckbbn=*lli;LwpmGL~Y{1GPg=PUx z({ZKKsCq^u5P(BOV2}hP=nIjU@zerT|8_A0$n5D$2_Aq#BKYeEfTWGUv&f|xf&Y4t zz?uk*CX!%_z>v@w5(cG-z>^RN9k>AHl(J7eVR39(EXG7NTNxQ!kUht1*_FkC*@NhZ zDU8O+1vrhVFK{|(up~5gsx(t51$m5H=TC8&O8Z}^3=4~Yt`09Rp&GHUAQ`bJzFr_4 zWV4Z;uP>cSazRiLSd1$Y)Qk&36N5rvHOW+<4m6I8bVbncu2>{-Ott)J`Sk*xZD#s# z$xI6E2VXo5k3qU15t=TpSOmlu+)-#Wa6wZkSPGg(b>USRe_A2FU}f3|bRK~1BfwnKjDw!31#)K^$=9bL{+hUIgGImluCiq7&NFVe1P>J z`Rj^GA%S-7Mds>}*=%ss7MTll0QF)z@X1G$1=9f_7g~H3C@j>G88W#1=%kXM9-hP? zGu?C*0yL>KSF$gItDtAdX2UF5TpG-l=EY_JR!p#4*hQoGeaalg@ ztpCvSPCORwe4;p^BfmnNiozXla6GMqLxC_?ep-b^VN%CTM2VHKB^1xtUSd&uD3a z=AYChG3nv}D@M8s{=k7Tjemy#MMd#kC}T5AFeHZNVQQ1pVFU&ZJc3{2O^ zx$Z2E+K*u**o?s&hN}JW7fd^mR0q+8Jio#O9lu|}@rPr z`f9w1zB-(LmOe#z-dtWC&I`E`8ih{@`wHODTqPyIP7NXf{F(TGXg`oK40;4UNCX-U zMM*&)7;^%{K{4U{7#0a>Rsh2YV>mPv4aG+X4$z$j!$7hB0(2NC9*`fyp+IbtAclkX zZ3xieph!@DjEIGztOPIurLL&~7P#v^cadMuhfa@Y4~IkQ-VM6RJ1DH1)HDe1i{Q+nQ zGyTDg4rclT-UwmF7G`W=#ujF5fv15PTbQwh8C&?@wgoPS41O7kBPjv>v<^Lp26@*( bfT#orYvOQu9(Uk8l9W(Z-n7+NQsVyr7&7YW diff --git a/tests/opencl/blackscholes/oclBlackScholes_common.h b/tests/opencl/blackscholes/oclBlackScholes_common.h deleted file mode 100644 index 70ec92da..00000000 --- a/tests/opencl/blackscholes/oclBlackScholes_common.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - - - -#include - - - -//////////////////////////////////////////////////////////////////////////////// -// Process an array of optN options on CPU -//////////////////////////////////////////////////////////////////////////////// -extern "C" void BlackScholesCPU( - float *h_Call, //Call option price - float *h_Put, //Put option price - float *h_S, //Current stock price - float *h_X, //Option strike price - float *h_T, //Option years - float R, //Riskless rate of return - float V, //Stock volatility - unsigned int optionCount -); - - -//////////////////////////////////////////////////////////////////////////////// -// OpenCL Black-Scholes kernel launcher -//////////////////////////////////////////////////////////////////////////////// -extern "C" void initBlackScholes(cl_context cxGPUContext, cl_command_queue cqParamCommandQue, const char **argv); - -extern "C" void closeBlackScholes(void); - -extern "C" void BlackScholes( - cl_command_queue cqCommandQueue, - cl_mem d_Call, //Call option price - cl_mem d_Put, //Put option price - cl_mem d_S, //Current stock price - cl_mem d_X, //Option strike price - cl_mem d_T, //Option years - cl_float R, //Riskless rate of return - cl_float V, //Stock volatility - cl_uint optionCount -); diff --git a/tests/opencl/blackscholes/oclBlackScholes_gold.cpp b/tests/opencl/blackscholes/oclBlackScholes_gold.cpp deleted file mode 100644 index 88d2473b..00000000 --- a/tests/opencl/blackscholes/oclBlackScholes_gold.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - - - -#include -#include "oclBlackScholes_common.h" - - - -/////////////////////////////////////////////////////////////////////////////// -// Rational approximation of cumulative normal distribution function -/////////////////////////////////////////////////////////////////////////////// -static double CND(double d){ - const double A1 = 0.31938153; - const double A2 = -0.356563782; - const double A3 = 1.781477937; - const double A4 = -1.821255978; - const double A5 = 1.330274429; - const double RSQRT2PI = 0.39894228040143267793994605993438; - - double - K = 1.0 / (1.0 + 0.2316419 * fabs(d)); - - double - cnd = RSQRT2PI * exp(- 0.5 * d * d) * - (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5))))); - - if(d > 0) - cnd = 1.0 - cnd; - - return cnd; -} - -/////////////////////////////////////////////////////////////////////////////// -// Black-Scholes formula for both call and put -/////////////////////////////////////////////////////////////////////////////// -static void BlackScholesBodyCPU( - float& call, //Call option price - float& put, //Put option price - float Sf, //Current stock price - float Xf, //Option strike price - float Tf, //Option years - float Rf, //Riskless rate of return - float Vf //Stock volatility -){ - double S = Sf, X = Xf, T = Tf, R = Rf, V = Vf; - - double sqrtT = sqrt(T); - double d1 = (log(S / X) + (R + 0.5 * V * V) * T) / (V * sqrtT); - double d2 = d1 - V * sqrtT; - double CNDD1 = CND(d1); - double CNDD2 = CND(d2); - - //Calculate Call and Put simultaneously - double expRT = exp(- R * T); - call = (float)(S * CNDD1 - X * expRT * CNDD2); - put = (float)(X * expRT * (1.0 - CNDD2) - S * (1.0 - CNDD1)); -} - -//////////////////////////////////////////////////////////////////////////////// -// Process an array of optN options -//////////////////////////////////////////////////////////////////////////////// -extern "C" void BlackScholesCPU( - float *h_Call, //Call option price - float *h_Put, //Put option price - float *h_S, //Current stock price - float *h_X, //Option strike price - float *h_T, //Option years - float R, //Riskless rate of return - float V, //Stock volatility - unsigned int optionCount -){ - for(unsigned int i = 0; i < optionCount; i++) - BlackScholesBodyCPU( - h_Call[i], - h_Put[i], - h_S[i], - h_X[i], - h_T[i], - R, - V - ); -} diff --git a/tests/opencl/blackscholes/oclBlackScholes_launcher.cpp b/tests/opencl/blackscholes/oclBlackScholes_launcher.cpp deleted file mode 100644 index abacb8da..00000000 --- a/tests/opencl/blackscholes/oclBlackScholes_launcher.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -#include -#include "oclBlackScholes_common.h" - -static cl_program cpBlackScholes; //OpenCL program -static cl_kernel ckBlackScholes; //OpenCL kernel -static cl_command_queue cqDefaultCommandQueue; - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (NULL == filename || NULL == data || 0 == size) - return CL_INVALID_VALUE; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return CL_INVALID_VALUE; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return CL_SUCCESS; -} - -extern "C" void initBlackScholes(cl_context cxGPUContext, cl_command_queue cqParamCommandQueue, const char **argv){ - cl_int ciErrNum; - size_t kernelLength; - - /*shrLog("...loading BlackScholes.cl\n"); - char *cPathAndName = shrFindFilePath("BlackScholes.cl", argv[0]); - shrCheckError(cPathAndName != NULL, shrTRUE); - char *cBlackScholes = oclLoadProgSource(cPathAndName, "// My comment\n", &kernelLength); - shrCheckError(cBlackScholes != NULL, shrTRUE);*/ - - shrLog("...creating BlackScholes program\n"); - //cpBlackScholes = clCreateProgramWithSource(cxGPUContext, 1, (const char **)&cBlackScholes, &kernelLength, &ciErrNum); - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - ciErrNum = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - shrCheckError(ciErrNum, CL_SUCCESS); - cl_device_id device_id = oclGetFirstDev(cxGPUContext); - cpBlackScholes = clCreateProgramWithBinary( - cxGPUContext, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &ciErrNum); - shrCheckError(ciErrNum, CL_SUCCESS); - - shrLog("...building BlackScholes program\n"); - ciErrNum = clBuildProgram(cpBlackScholes, 0, NULL, "-cl-fast-relaxed-math -Werror", NULL, NULL); - - if(ciErrNum != CL_BUILD_SUCCESS){ - shrLog("*** Compilation failure ***\n"); - - size_t deviceNum; - cl_device_id *cdDevices; - ciErrNum = clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &deviceNum); - shrCheckError(ciErrNum, CL_SUCCESS); - - cdDevices = (cl_device_id *)malloc(deviceNum * sizeof(cl_device_id)); - shrCheckError(cdDevices != NULL, shrTRUE); - - ciErrNum = clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, deviceNum * sizeof(cl_device_id), cdDevices, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - size_t logSize; - char *logTxt; - - ciErrNum = clGetProgramBuildInfo(cpBlackScholes, cdDevices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize); - shrCheckError(ciErrNum, CL_SUCCESS); - - logTxt = (char *)malloc(logSize); - shrCheckError(logTxt != NULL, shrTRUE); - - ciErrNum = clGetProgramBuildInfo(cpBlackScholes, cdDevices[0], CL_PROGRAM_BUILD_LOG, logSize, logTxt, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - shrLog("%s\n", logTxt); - shrLog("*** Exiting ***\n"); - free(logTxt); - free(cdDevices); - exit(1); - } - - //Save ptx code to separate file - oclLogPtx(cpBlackScholes, oclGetFirstDev(cxGPUContext), "BlackScholes.ptx"); - - shrLog("...creating BlackScholes kernels\n"); - ckBlackScholes = clCreateKernel(cpBlackScholes, "BlackScholes", &ciErrNum); - shrCheckError(ciErrNum, CL_SUCCESS); - - cqDefaultCommandQueue = cqParamCommandQueue; - //free(cBlackScholes); - //free(cPathAndName); -} - -extern "C" void closeBlackScholes(void){ - cl_int ciErrNum; - ciErrNum = clReleaseKernel(ckBlackScholes); - ciErrNum |= clReleaseProgram(cpBlackScholes); - shrCheckError(ciErrNum, CL_SUCCESS); -} - -//////////////////////////////////////////////////////////////////////////////// -// OpenCL Black-Scholes kernel launcher -//////////////////////////////////////////////////////////////////////////////// -extern "C" void BlackScholes( - cl_command_queue cqCommandQueue, - cl_mem d_Call, //Call option price - cl_mem d_Put, //Put option price - cl_mem d_S, //Current stock price - cl_mem d_X, //Option strike price - cl_mem d_T, //Option years - cl_float R, //Riskless rate of return - cl_float V, //Stock volatility - cl_uint optionCount -){ - cl_int ciErrNum; - - if(!cqCommandQueue) - cqCommandQueue = cqDefaultCommandQueue; - - ciErrNum = clSetKernelArg(ckBlackScholes, 0, sizeof(cl_mem), (void *)&d_Call); - ciErrNum |= clSetKernelArg(ckBlackScholes, 1, sizeof(cl_mem), (void *)&d_Put); - ciErrNum |= clSetKernelArg(ckBlackScholes, 2, sizeof(cl_mem), (void *)&d_S); - ciErrNum |= clSetKernelArg(ckBlackScholes, 3, sizeof(cl_mem), (void *)&d_X); - ciErrNum |= clSetKernelArg(ckBlackScholes, 4, sizeof(cl_mem), (void *)&d_T); - ciErrNum |= clSetKernelArg(ckBlackScholes, 5, sizeof(cl_float), (void *)&R); - ciErrNum |= clSetKernelArg(ckBlackScholes, 6, sizeof(cl_float), (void *)&V); - ciErrNum |= clSetKernelArg(ckBlackScholes, 7, sizeof(cl_uint), (void *)&optionCount); - shrCheckError(ciErrNum, CL_SUCCESS); - - //Run the kernel - size_t globalWorkSize = 16;//60 * 1024; - size_t localWorkSize = 16;//128; - ciErrNum = clEnqueueNDRangeKernel(cqCommandQueue, ckBlackScholes, 1, NULL, &globalWorkSize, &localWorkSize, 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); -} diff --git a/tests/opencl/blackscholes/oclUtils.cpp b/tests/opencl/blackscholes/oclUtils.cpp deleted file mode 100644 index 7a238b55..00000000 --- a/tests/opencl/blackscholes/oclUtils.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// Utilities specific to OpenCL samples in NVIDIA GPU Computing SDK -// ********************************************************************* - -#include -#include -#include -#include -#include -#include "oclUtils.h" - -////////////////////////////////////////////////////////////////////////////// -//! Gets the platform ID for NVIDIA if available, otherwise default -//! -//! @return the id -//! @param clSelectedPlatformID OpenCL platoform ID -////////////////////////////////////////////////////////////////////////////// -cl_int oclGetPlatformID(cl_platform_id* clSelectedPlatformID) -{ - char chBuffer[1024]; - cl_uint num_platforms; - cl_platform_id* clPlatformIDs; - cl_int ciErrNum; - *clSelectedPlatformID = NULL; - - // Get OpenCL platform count - ciErrNum = clGetPlatformIDs (0, NULL, &num_platforms); - if (ciErrNum != CL_SUCCESS) - { - shrLog(" Error %i in clGetPlatformIDs Call !!!\n\n", ciErrNum); - return -1000; - } - else - { - if(num_platforms == 0) - { - shrLog("No OpenCL platform found!\n\n"); - return -2000; - } - else - { - // if there's a platform or more, make space for ID's - if ((clPlatformIDs = (cl_platform_id*)malloc(num_platforms * sizeof(cl_platform_id))) == NULL) - { - shrLog("Failed to allocate memory for cl_platform ID's!\n\n"); - return -3000; - } - - // get platform info for each platform and trap the NVIDIA platform if found - ciErrNum = clGetPlatformIDs (num_platforms, clPlatformIDs, NULL); - for(cl_uint i = 0; i < num_platforms; ++i) - { - ciErrNum = clGetPlatformInfo (clPlatformIDs[i], CL_PLATFORM_NAME, 1024, &chBuffer, NULL); - if(ciErrNum == CL_SUCCESS) - { - if(strstr(chBuffer, "NVIDIA") != NULL) - { - *clSelectedPlatformID = clPlatformIDs[i]; - break; - } - } - } - - // default to zeroeth platform if NVIDIA not found - if(*clSelectedPlatformID == NULL) - { - shrLog("WARNING: NVIDIA OpenCL platform not found - defaulting to first platform!\n\n"); - *clSelectedPlatformID = clPlatformIDs[0]; - } - - free(clPlatformIDs); - } - } - - return CL_SUCCESS; -} - -////////////////////////////////////////////////////////////////////////////// -//! Print the device name -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -void oclPrintDevName(int iLogMode, cl_device_id device) -{ - char device_string[1024]; - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, "%s", device_string); -} - -////////////////////////////////////////////////////////////////////////////// -//! Print info about the device -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -void oclPrintDevInfo(int iLogMode, cl_device_id device) -{ - char device_string[1024]; - bool nv_device_attibute_query = false; - - // CL_DEVICE_NAME - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_NAME: \t\t\t%s\n", device_string); - - // CL_DEVICE_VENDOR - clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_VENDOR: \t\t\t%s\n", device_string); - - // CL_DRIVER_VERSION - clGetDeviceInfo(device, CL_DRIVER_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DRIVER_VERSION: \t\t\t%s\n", device_string); - - // CL_DEVICE_VERSION - clGetDeviceInfo(device, CL_DEVICE_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_VERSION: \t\t\t%s\n", device_string); - - // CL_DEVICE_OPENCL_C_VERSION (if CL_DEVICE_VERSION version > 1.0) - if(strncmp("OpenCL 1.0", device_string, 10) != 0) - { - // This code is unused for devices reporting OpenCL 1.0, but a def is needed anyway to allow compilation using v 1.0 headers - // This constant isn't #defined in 1.0 - #ifndef CL_DEVICE_OPENCL_C_VERSION - #define CL_DEVICE_OPENCL_C_VERSION 0x103D - #endif - - clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_OPENCL_C_VERSION: \t\t%s\n", device_string); - } - - // CL_DEVICE_TYPE - cl_device_type type; - clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(type), &type, NULL); - if( type & CL_DEVICE_TYPE_CPU ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_CPU"); - if( type & CL_DEVICE_TYPE_GPU ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_GPU"); - if( type & CL_DEVICE_TYPE_ACCELERATOR ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR"); - if( type & CL_DEVICE_TYPE_DEFAULT ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT"); - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_COMPUTE_UNITS:\t\t%u\n", compute_units); - - // CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS - size_t workitem_dims; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(workitem_dims), &workitem_dims, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:\t%u\n", workitem_dims); - - // CL_DEVICE_MAX_WORK_ITEM_SIZES - size_t workitem_size[3]; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(workitem_size), &workitem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%u / %u / %u \n", workitem_size[0], workitem_size[1], workitem_size[2]); - - // CL_DEVICE_MAX_WORK_GROUP_SIZE - size_t workgroup_size; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(workgroup_size), &workgroup_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_GROUP_SIZE:\t%u\n", workgroup_size); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_CLOCK_FREQUENCY:\t%u MHz\n", clock_frequency); - - // CL_DEVICE_ADDRESS_BITS - cl_uint addr_bits; - clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(addr_bits), &addr_bits, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_ADDRESS_BITS:\t\t%u\n", addr_bits); - - // CL_DEVICE_MAX_MEM_ALLOC_SIZE - cl_ulong max_mem_alloc_size; - clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(max_mem_alloc_size), &max_mem_alloc_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_MEM_ALLOC_SIZE:\t\t%u MByte\n", (unsigned int)(max_mem_alloc_size / (1024 * 1024))); - - // CL_DEVICE_GLOBAL_MEM_SIZE - cl_ulong mem_size; - clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_GLOBAL_MEM_SIZE:\t\t%u MByte\n", (unsigned int)(mem_size / (1024 * 1024))); - - // CL_DEVICE_ERROR_CORRECTION_SUPPORT - cl_bool error_correction_support; - clGetDeviceInfo(device, CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof(error_correction_support), &error_correction_support, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_ERROR_CORRECTION_SUPPORT:\t%s\n", error_correction_support == CL_TRUE ? "yes" : "no"); - - // CL_DEVICE_LOCAL_MEM_TYPE - cl_device_local_mem_type local_mem_type; - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_TYPE, sizeof(local_mem_type), &local_mem_type, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_LOCAL_MEM_TYPE:\t\t%s\n", local_mem_type == 1 ? "local" : "global"); - - // CL_DEVICE_LOCAL_MEM_SIZE - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_LOCAL_MEM_SIZE:\t\t%u KByte\n", (unsigned int)(mem_size / 1024)); - - // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE - clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t%u KByte\n", (unsigned int)(mem_size / 1024)); - - // CL_DEVICE_QUEUE_PROPERTIES - cl_command_queue_properties queue_properties; - clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(queue_properties), &queue_properties, NULL); - if( queue_properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) - shrLogEx(iLogMode, 0, " CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"); - if( queue_properties & CL_QUEUE_PROFILING_ENABLE ) - shrLogEx(iLogMode, 0, " CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_PROFILING_ENABLE"); - - // CL_DEVICE_IMAGE_SUPPORT - cl_bool image_support; - clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(image_support), &image_support, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_IMAGE_SUPPORT:\t\t%u\n", image_support); - - // CL_DEVICE_MAX_READ_IMAGE_ARGS - cl_uint max_read_image_args; - clGetDeviceInfo(device, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(max_read_image_args), &max_read_image_args, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_READ_IMAGE_ARGS:\t%u\n", max_read_image_args); - - // CL_DEVICE_MAX_WRITE_IMAGE_ARGS - cl_uint max_write_image_args; - clGetDeviceInfo(device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(max_write_image_args), &max_write_image_args, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WRITE_IMAGE_ARGS:\t%u\n", max_write_image_args); - - // CL_DEVICE_SINGLE_FP_CONFIG - cl_device_fp_config fp_config; - clGetDeviceInfo(device, CL_DEVICE_SINGLE_FP_CONFIG, sizeof(cl_device_fp_config), &fp_config, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_SINGLE_FP_CONFIG:\t\t%s%s%s%s%s%s\n", - fp_config & CL_FP_DENORM ? "denorms " : "", - fp_config & CL_FP_INF_NAN ? "INF-quietNaNs " : "", - fp_config & CL_FP_ROUND_TO_NEAREST ? "round-to-nearest " : "", - fp_config & CL_FP_ROUND_TO_ZERO ? "round-to-zero " : "", - fp_config & CL_FP_ROUND_TO_INF ? "round-to-inf " : "", - fp_config & CL_FP_FMA ? "fma " : ""); - - // CL_DEVICE_IMAGE2D_MAX_WIDTH, CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_DEPTH - size_t szMaxDims[5]; - shrLogEx(iLogMode, 0, "\n CL_DEVICE_IMAGE "); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &szMaxDims[0], NULL); - shrLogEx(iLogMode, 0, "\t\t\t2D_MAX_WIDTH\t %u\n", szMaxDims[0]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &szMaxDims[1], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t2D_MAX_HEIGHT\t %u\n", szMaxDims[1]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &szMaxDims[2], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_WIDTH\t %u\n", szMaxDims[2]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &szMaxDims[3], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_HEIGHT\t %u\n", szMaxDims[3]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &szMaxDims[4], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_DEPTH\t %u\n", szMaxDims[4]); - - // CL_DEVICE_EXTENSIONS: get device extensions, and if any then parse & log the string onto separate lines - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, sizeof(device_string), &device_string, NULL); - if (device_string != 0) - { - shrLogEx(iLogMode, 0, "\n CL_DEVICE_EXTENSIONS:"); - std::string stdDevString; - stdDevString = std::string(device_string); - size_t szOldPos = 0; - size_t szSpacePos = stdDevString.find(' ', szOldPos); // extensions string is space delimited - while (szSpacePos != stdDevString.npos) - { - if( strcmp("cl_nv_device_attribute_query", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()) == 0 ) - nv_device_attibute_query = true; - - if (szOldPos > 0) - { - shrLogEx(iLogMode, 0, "\t\t"); - } - shrLogEx(iLogMode, 0, "\t\t\t%s\n", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()); - - do { - szOldPos = szSpacePos + 1; - szSpacePos = stdDevString.find(' ', szOldPos); - } while (szSpacePos == szOldPos); - } - shrLogEx(iLogMode, 0, "\n"); - } - else - { - shrLogEx(iLogMode, 0, " CL_DEVICE_EXTENSIONS: None\n"); - } - - if(nv_device_attibute_query) - { - cl_uint compute_capability_major, compute_capability_minor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(cl_uint), &compute_capability_major, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, sizeof(cl_uint), &compute_capability_minor, NULL); - shrLogEx(iLogMode, 0, "\n CL_DEVICE_COMPUTE_CAPABILITY_NV:\t%u.%u\n", compute_capability_major, compute_capability_minor); - - shrLogEx(iLogMode, 0, " NUMBER OF MULTIPROCESSORS:\t\t%u\n", compute_units); // this is the same value reported by CL_DEVICE_MAX_COMPUTE_UNITS - shrLogEx(iLogMode, 0, " NUMBER OF CUDA CORES:\t\t\t%u\n", ConvertSMVer2Cores(compute_capability_major, compute_capability_minor) * compute_units); - - cl_uint regs_per_block; - clGetDeviceInfo(device, CL_DEVICE_REGISTERS_PER_BLOCK_NV, sizeof(cl_uint), ®s_per_block, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_REGISTERS_PER_BLOCK_NV:\t%u\n", regs_per_block); - - cl_uint warp_size; - clGetDeviceInfo(device, CL_DEVICE_WARP_SIZE_NV, sizeof(cl_uint), &warp_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_WARP_SIZE_NV:\t\t%u\n", warp_size); - - cl_bool gpu_overlap; - clGetDeviceInfo(device, CL_DEVICE_GPU_OVERLAP_NV, sizeof(cl_bool), &gpu_overlap, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_GPU_OVERLAP_NV:\t\t%s\n", gpu_overlap == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - - cl_bool exec_timeout; - clGetDeviceInfo(device, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, sizeof(cl_bool), &exec_timeout, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV:\t%s\n", exec_timeout == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - - cl_bool integrated_memory; - clGetDeviceInfo(device, CL_DEVICE_INTEGRATED_MEMORY_NV, sizeof(cl_bool), &integrated_memory, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_INTEGRATED_MEMORY_NV:\t%s\n", integrated_memory == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - } - - // CL_DEVICE_PREFERRED_VECTOR_WIDTH_ - shrLogEx(iLogMode, 0, " CL_DEVICE_PREFERRED_VECTOR_WIDTH_\t"); - cl_uint vec_width [6]; - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &vec_width[0], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof(cl_uint), &vec_width[1], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), &vec_width[2], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof(cl_uint), &vec_width[3], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint), &vec_width[4], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &vec_width[5], NULL); - shrLogEx(iLogMode, 0, "CHAR %u, SHORT %u, INT %u, LONG %u, FLOAT %u, DOUBLE %u\n\n\n", - vec_width[0], vec_width[1], vec_width[2], vec_width[3], vec_width[4], vec_width[5]); -} - -////////////////////////////////////////////////////////////////////////////// -//! Get and return device capability -//! -//! @return the 2 digit integer representation of device Cap (major minor). return -1 if NA -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -int oclGetDevCap(cl_device_id device) -{ - char cDevString[1024]; - bool bDevAttributeQuery = false; - int iDevArch = -1; - - // Get device extensions, and if any then search for cl_nv_device_attribute_query - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, sizeof(cDevString), &cDevString, NULL); - if (cDevString != 0) - { - std::string stdDevString; - stdDevString = std::string(cDevString); - size_t szOldPos = 0; - size_t szSpacePos = stdDevString.find(' ', szOldPos); // extensions string is space delimited - while (szSpacePos != stdDevString.npos) - { - if( strcmp("cl_nv_device_attribute_query", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()) == 0 ) - { - bDevAttributeQuery = true; - } - - do { - szOldPos = szSpacePos + 1; - szSpacePos = stdDevString.find(' ', szOldPos); - } while (szSpacePos == szOldPos); - } - } - - // if search succeeded, get device caps - if(bDevAttributeQuery) - { - cl_int iComputeCapMajor, iComputeCapMinor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(cl_uint), (void*)&iComputeCapMajor, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, sizeof(cl_uint), (void*)&iComputeCapMinor, NULL); - iDevArch = (10 * iComputeCapMajor) + iComputeCapMinor; - } - - return iDevArch; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the first device from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetFirstDev(cl_context cxGPUContext) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id first = cdDevices[0]; - free(cdDevices); - - return first; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of device with maximal FLOPS from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetMaxFlopsDev(cl_context cxGPUContext) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - size_t device_count = szParmDataBytes / sizeof(cl_device_id); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id max_flops_device = cdDevices[0]; - int max_flops = 0; - - size_t current_device = 0; - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - - max_flops = compute_units * clock_frequency; - ++current_device; - - while( current_device < device_count ) - { - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - - int flops = compute_units * clock_frequency; - if( flops > max_flops ) - { - max_flops = flops; - max_flops_device = cdDevices[current_device]; - } - ++current_device; - } - - free(cdDevices); - - return max_flops_device; -} - -////////////////////////////////////////////////////////////////////////////// -//! Loads a Program file and prepends the cPreamble to the code. -//! -//! @return the source string if succeeded, 0 otherwise -//! @param cFilename program filename -//! @param cPreamble code that is prepended to the loaded file, typically a set of #defines or a header -//! @param szFinalLength returned length of the code string -////////////////////////////////////////////////////////////////////////////// -char* oclLoadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength) -{ - // locals - FILE* pFileStream = NULL; - size_t szSourceLength; - - // open the OpenCL source code file - #ifdef _WIN32 // Windows version - if(fopen_s(&pFileStream, cFilename, "rb") != 0) - { - return NULL; - } - #else // Linux version - pFileStream = fopen(cFilename, "rb"); - if(pFileStream == 0) - { - return NULL; - } - #endif - - size_t szPreambleLength = strlen(cPreamble); - - // get the length of the source code - fseek(pFileStream, 0, SEEK_END); - szSourceLength = ftell(pFileStream); - fseek(pFileStream, 0, SEEK_SET); - - // allocate a buffer for the source code string and read it in - char* cSourceString = (char *)malloc(szSourceLength + szPreambleLength + 1); - memcpy(cSourceString, cPreamble, szPreambleLength); - if (fread((cSourceString) + szPreambleLength, szSourceLength, 1, pFileStream) != 1) - { - fclose(pFileStream); - free(cSourceString); - return 0; - } - - // close the file and return the total length of the combined (preamble + source) string - fclose(pFileStream); - if(szFinalLength != 0) - { - *szFinalLength = szSourceLength + szPreambleLength; - } - cSourceString[szSourceLength + szPreambleLength] = '\0'; - - return cSourceString; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxGPUContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetDev(cl_context cxGPUContext, unsigned int nr) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - - if( szParmDataBytes / sizeof(cl_device_id) <= nr ) { - return (cl_device_id)-1; - } - - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id device = cdDevices[nr]; - free(cdDevices); - - return device; -} - -////////////////////////////////////////////////////////////////////////////// -//! Get the binary (PTX) of the program associated with the device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param binary returned code -//! @param length length of returned code -////////////////////////////////////////////////////////////////////////////// -void oclGetProgBinary( cl_program cpProgram, cl_device_id cdDevice, char** binary, size_t* length) -{ - // Grab the number of devices associated witht the program - cl_uint num_devices; - clGetProgramInfo(cpProgram, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL); - - // Grab the device ids - cl_device_id* devices = (cl_device_id*) malloc(num_devices * sizeof(cl_device_id)); - clGetProgramInfo(cpProgram, CL_PROGRAM_DEVICES, num_devices * sizeof(cl_device_id), devices, 0); - - // Grab the sizes of the binaries - size_t* binary_sizes = (size_t*)malloc(num_devices * sizeof(size_t)); - clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, num_devices * sizeof(size_t), binary_sizes, NULL); - - // Now get the binaries - char** ptx_code = (char**) malloc(num_devices * sizeof(char*)); - for( unsigned int i=0; i= 0 && index < errorCount) ? errorString[index] : "Unspecified Error"; -} - -// Helper function to get OpenCL image format string (channel order and type) from constant -// ********************************************************************* -const char* oclImageFormatString(cl_uint uiImageFormat) -{ - // cl_channel_order - if (uiImageFormat == CL_R)return "CL_R"; - if (uiImageFormat == CL_A)return "CL_A"; - if (uiImageFormat == CL_RG)return "CL_RG"; - if (uiImageFormat == CL_RA)return "CL_RA"; - if (uiImageFormat == CL_RGB)return "CL_RGB"; - if (uiImageFormat == CL_RGBA)return "CL_RGBA"; - if (uiImageFormat == CL_BGRA)return "CL_BGRA"; - if (uiImageFormat == CL_ARGB)return "CL_ARGB"; - if (uiImageFormat == CL_INTENSITY)return "CL_INTENSITY"; - if (uiImageFormat == CL_LUMINANCE)return "CL_LUMINANCE"; - - // cl_channel_type - if (uiImageFormat == CL_SNORM_INT8)return "CL_SNORM_INT8"; - if (uiImageFormat == CL_SNORM_INT16)return "CL_SNORM_INT16"; - if (uiImageFormat == CL_UNORM_INT8)return "CL_UNORM_INT8"; - if (uiImageFormat == CL_UNORM_INT16)return "CL_UNORM_INT16"; - if (uiImageFormat == CL_UNORM_SHORT_565)return "CL_UNORM_SHORT_565"; - if (uiImageFormat == CL_UNORM_SHORT_555)return "CL_UNORM_SHORT_555"; - if (uiImageFormat == CL_UNORM_INT_101010)return "CL_UNORM_INT_101010"; - if (uiImageFormat == CL_SIGNED_INT8)return "CL_SIGNED_INT8"; - if (uiImageFormat == CL_SIGNED_INT16)return "CL_SIGNED_INT16"; - if (uiImageFormat == CL_SIGNED_INT32)return "CL_SIGNED_INT32"; - if (uiImageFormat == CL_UNSIGNED_INT8)return "CL_UNSIGNED_INT8"; - if (uiImageFormat == CL_UNSIGNED_INT16)return "CL_UNSIGNED_INT16"; - if (uiImageFormat == CL_UNSIGNED_INT32)return "CL_UNSIGNED_INT32"; - if (uiImageFormat == CL_HALF_FLOAT)return "CL_HALF_FLOAT"; - if (uiImageFormat == CL_FLOAT)return "CL_FLOAT"; - - // unknown constant - return "Unknown"; -} diff --git a/tests/opencl/blackscholes/oclUtils.h b/tests/opencl/blackscholes/oclUtils.h deleted file mode 100644 index 2b109e18..00000000 --- a/tests/opencl/blackscholes/oclUtils.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -#ifndef OCL_UTILS_H -#define OCL_UTILS_H - -// ********************************************************************* -// Utilities specific to OpenCL samples in NVIDIA GPU Computing SDK -// ********************************************************************* - -// Common headers: Cross-API utililties and OpenCL header -#include - -// All OpenCL headers -#if defined (__APPLE__) || defined(MACOSX) - #include -#else - #include -#endif - -// Includes -#include -#include -#include - -// For systems with CL_EXT that are not updated with these extensions, we copied these -// extensions from -#ifndef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV - /* cl_nv_device_attribute_query extension - no extension #define since it has no functions */ - #define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000 - #define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001 - #define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002 - #define CL_DEVICE_WARP_SIZE_NV 0x4003 - #define CL_DEVICE_GPU_OVERLAP_NV 0x4004 - #define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005 - #define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006 -#endif - -// reminders for build output window and log -#ifdef _WIN32 - #pragma message ("Note: including shrUtils.h") - #pragma message ("Note: including opencl.h") -#endif - -// SDK Revision # -#define OCL_SDKREVISION "7027912" - -// Error and Exit Handling Macros... -// ********************************************************************* -// Full error handling macro with Cleanup() callback (if supplied)... -// (Companion Inline Function lower on page) -#define oclCheckErrorEX(a, b, c) __oclCheckErrorEX(a, b, c, __FILE__ , __LINE__) - -// Short version without Cleanup() callback pointer -// Both Input (a) and Reference (b) are specified as args -#define oclCheckError(a, b) oclCheckErrorEX(a, b, 0) - -////////////////////////////////////////////////////////////////////////////// -//! Gets the platform ID for NVIDIA if available, otherwise default to platform 0 -//! -//! @return the id -//! @param clSelectedPlatformID OpenCL platform ID -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_int oclGetPlatformID(cl_platform_id* clSelectedPlatformID); - -////////////////////////////////////////////////////////////////////////////// -//! Print info about the device -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclPrintDevInfo(int iLogMode, cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Get and return device capability -//! -//! @return the 2 digit integer representation of device Cap (major minor). return -1 if NA -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" int oclGetDevCap(cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Print the device name -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclPrintDevName(int iLogMode, cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the first device from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetFirstDev(cl_context cxGPUContext); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxGPUContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetDev(cl_context cxGPUContext, unsigned int device_idx); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of device with maximal FLOPS from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetMaxFlopsDev(cl_context cxGPUContext); - -////////////////////////////////////////////////////////////////////////////// -//! Loads a Program file and prepends the cPreamble to the code. -//! -//! @return the source string if succeeded, 0 otherwise -//! @param cFilename program filename -//! @param cPreamble code that is prepended to the loaded file, typically a set of #defines or a header -//! @param szFinalLength returned length of the code string -////////////////////////////////////////////////////////////////////////////// -extern "C" char* oclLoadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength); - -////////////////////////////////////////////////////////////////////////////// -//! Get the binary (PTX) of the program associated with the device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param binary returned code -//! @param length length of returned code -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclGetProgBinary( cl_program cpProgram, cl_device_id cdDevice, char** binary, size_t* length); - -////////////////////////////////////////////////////////////////////////////// -//! Get and log the binary (PTX) from the OpenCL compiler for the requested program & device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param const char* cPtxFileName optional PTX file name -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclLogPtx(cl_program cpProgram, cl_device_id cdDevice, const char* cPtxFileName); - -////////////////////////////////////////////////////////////////////////////// -//! Get and log the Build Log from the OpenCL compiler for the requested program & device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclLogBuildInfo(cl_program cpProgram, cl_device_id cdDevice); - -// Helper function for De-allocating cl objects -// ********************************************************************* -extern "C" void oclDeleteMemObjs(cl_mem* cmMemObjs, int iNumObjs); - -// Helper function to get OpenCL error string from constant -// ********************************************************************* -extern "C" const char* oclErrorString(cl_int error); - -// Helper function to get OpenCL image format string (channel order and type) from constant -// ********************************************************************* -extern "C" const char* oclImageFormatString(cl_uint uiImageFormat); - -// companion inline function for error checking and exit on error WITH Cleanup Callback (if supplied) -// ********************************************************************* -inline void __oclCheckErrorEX(cl_int iSample, cl_int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) -{ - // An error condition is defined by the sample/test value not equal to the reference - if (iReference != iSample) - { - // If the sample/test value isn't equal to the ref, it's an error by defnition, so override 0 sample/test value - iSample = (iSample == 0) ? -9999 : iSample; - - // Log the error info - shrLog("\n !!! Error # %i (%s) at line %i , in file %s !!!\n\n", iSample, oclErrorString(iSample), iLine, cFile); - - // Cleanup and exit, or just exit if no cleanup function pointer provided. Use iSample (error code in this case) as process exit code. - if (pCleanup != NULL) - { - pCleanup(iSample); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "Exiting...\n"); - exit(iSample); - } - } -} - -#endif \ No newline at end of file diff --git a/tests/opencl/blackscholes/shrQATest.h b/tests/opencl/blackscholes/shrQATest.h deleted file mode 100644 index 245cf8dc..00000000 --- a/tests/opencl/blackscholes/shrQATest.h +++ /dev/null @@ -1,238 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -#ifndef SHR_QATEST_H -#define SHR_QATEST_H - -// ********************************************************************* -// Generic utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// OS dependent includes -#ifdef _WIN32 - #pragma message ("Note: including windows.h") - #pragma message ("Note: including math.h") - #pragma message ("Note: including assert.h") - #pragma message ("Note: including time.h") - -// Headers needed for Windows - #include - #include -#else - // Headers needed for Linux - #include - #include - #include - #include - #include - #include - #include - #include - #include -#endif - -#ifndef STRCASECMP -#ifdef _WIN32 -#define STRCASECMP _stricmp -#else -#define STRCASECMP strcasecmp -#endif -#endif - -#ifndef STRNCASECMP -#ifdef _WIN32 -#define STRNCASECMP _strnicmp -#else -#define STRNCASECMP strncasecmp -#endif -#endif - - -// Standardized QA Start/Finish for CUDA SDK tests -#define shrQAStart(a, b) __shrQAStart(a, b) -#define shrQAFinish(a, b, c) __shrQAFinish(a, b, c) -#define shrQAFinish2(a, b, c, d) __shrQAFinish2(a, b, c, d) - -inline int findExeNameStart(const char *exec_name) -{ - int exename_start = (int)strlen(exec_name); - - while( (exename_start > 0) && - (exec_name[exename_start] != '\\') && - (exec_name[exename_start] != '/') ) - { - exename_start--; - } - if (exec_name[exename_start] == '\\' || - exec_name[exename_start] == '/') - { - return exename_start+1; - } else { - return exename_start; - } -} - -inline int __shrQAStart(int argc, char **argv) -{ - bool bQATest = false; - // First clear the output buffer - fflush(stdout); - fflush(stdout); - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - char *string_argv = &argv[i][string_start]; - - if (!STRCASECMP(string_argv, "qatest")) { - bQATest = true; - } - } - - // We don't want to print the entire path, so we search for the first - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& RUNNING %s", &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] starting...\n", &(argv[0][exename_start])); - } - fflush(stdout); - printf("\n"); fflush(stdout); - return exename_start; -} - -enum eQAstatus { - QA_FAILED = 0, - QA_PASSED = 1, - QA_WAIVED = 2 -}; - -inline void __ExitInTime(int seconds) -{ - fprintf(stdout, "> exiting in %d seconds: ", seconds); - fflush(stdout); - time_t t; - int count; - for (t=time(0)+seconds, count=seconds; time(0) < t; count--) { - fprintf(stdout, "%d...", count); -#ifdef WIN32 - Sleep(1000); -#else - sleep(1); -#endif - } - fprintf(stdout,"done!\n\n"); - fflush(stdout); -} - - -inline void __shrQAFinish(int argc, const char **argv, int iStatus) -{ - // By default QATest is disabled and NoPrompt is Enabled (times out at seconds passed into __ExitInTime() ) - bool bQATest = false, bNoPrompt = true, bQuitInTime = true; - const char *sStatus[] = { "FAILED", "PASSED", "WAIVED", NULL }; - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - - const char *string_argv = &argv[i][string_start]; - if (!STRCASECMP(string_argv, "qatest")) { - bQATest = true; - } - // For SDK individual samples that don't specify -noprompt or -prompt, - // a 3 second delay will happen before exiting, giving a user time to view results - if (!STRCASECMP(string_argv, "noprompt") || !STRCASECMP(string_argv, "help")) { - bNoPrompt = true; - bQuitInTime = false; - } - if (!STRCASECMP(string_argv, "prompt")) { - bNoPrompt = false; - bQuitInTime = false; - } - } - - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& %s %s", sStatus[iStatus], &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] test results...\n%s\n", &(argv[0][exename_start]), sStatus[iStatus]); - } - fflush(stdout); - printf("\n"); fflush(stdout); - if (bQuitInTime) { - __ExitInTime(3); - } else { - if (!bNoPrompt) { - fprintf(stdout, "\nPress to exit...\n"); - fflush(stdout); - getchar(); - } - } -} - -inline void __shrQAFinish2(bool bQATest, int argc, const char **argv, int iStatus) -{ - bool bQuitInTime = true; - const char *sStatus[] = { "FAILED", "PASSED", "WAIVED", NULL }; - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - - const char *string_argv = &argv[i][string_start]; - // For SDK individual samples that don't specify -noprompt or -prompt, - // a 3 second delay will happen before exiting, giving a user time to view results - if (!STRCASECMP(string_argv, "noprompt") || !STRCASECMP(string_argv, "help")) { - bQuitInTime = false; - } - if (!STRCASECMP(string_argv, "prompt")) { - bQuitInTime = false; - } - } - - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& %s %s", sStatus[iStatus], &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] test results...\n%s\n", &(argv[0][exename_start]), sStatus[iStatus]); - } - fflush(stdout); - - if (bQuitInTime) { - __ExitInTime(3); - } -} - -inline void shrQAFinishExit(int argc, const char **argv, int iStatus) -{ - __shrQAFinish(argc, argv, iStatus); - - exit(iStatus ? EXIT_SUCCESS : EXIT_FAILURE); -} - -inline void shrQAFinishExit2(bool bQAtest, int argc, const char **argv, int iStatus) -{ - __shrQAFinish2(bQAtest, argc, argv, iStatus); - - exit(iStatus ? EXIT_SUCCESS : EXIT_FAILURE); -} - -#endif \ No newline at end of file diff --git a/tests/opencl/blackscholes/shrUtils.cpp b/tests/opencl/blackscholes/shrUtils.cpp deleted file mode 100644 index cf0d2c3e..00000000 --- a/tests/opencl/blackscholes/shrUtils.cpp +++ /dev/null @@ -1,1954 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// Generic Utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// includes -#include -#include -#include -#include -#include "shrUtils.h" -#include "cmd_arg_reader.h" - -// size of PGM file header -const unsigned int PGMHeaderSize = 0x40; -#define MIN_EPSILON_ERROR 1e-3f - -// Deallocate memory allocated within shrUtils -// ********************************************************************* -void shrFree(void* ptr) -{ - if( NULL != ptr) free( ptr); -} - -// Helper function to init data arrays -// ********************************************************************* -void shrFillArray(float* pfData, int iSize) -{ - int i; - const float fScale = 1.0f / (float)RAND_MAX; - for (i = 0; i < iSize; ++i) - { - pfData[i] = fScale * rand(); - } -} - -// Helper function to print data arrays -// ********************************************************************* -void shrPrintArray(float* pfData, int iSize) -{ - int i; - for (i = 0; i < iSize; ++i) - { - shrLog("%d: %.3f\n", i, pfData[i]); - } -} - -// Helper function to return precision delta time for 3 counters since last call based upon host high performance counter -// ********************************************************************* -double shrDeltaT(int iCounterID = 0) -{ - // local var for computation of microseconds since last call - double DeltaT; - - #ifdef _WIN32 // Windows version of precision host timer - - // Variables that need to retain state between calls - static LARGE_INTEGER liOldCount0 = {0, 0}; - static LARGE_INTEGER liOldCount1 = {0, 0}; - static LARGE_INTEGER liOldCount2 = {0, 0}; - - // locals for new count, new freq and new time delta - LARGE_INTEGER liNewCount, liFreq; - if (QueryPerformanceFrequency(&liFreq)) - { - // Get new counter reading - QueryPerformanceCounter(&liNewCount); - - // Update the requested timer - switch (iCounterID) - { - case 0: - { - // Calculate time difference for timer 0. (zero when called the first time) - DeltaT = liOldCount0.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount0.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount0 = liNewCount; - - break; - } - case 1: - { - // Calculate time difference for timer 1. (zero when called the first time) - DeltaT = liOldCount1.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount1.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount1 = liNewCount; - - break; - } - case 2: - { - // Calculate time difference for timer 2. (zero when called the first time) - DeltaT = liOldCount2.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount2.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount2 = liNewCount; - - break; - } - default: - { - // Requested counter ID out of range - return -9999.0; - } - } - - // Returns time difference in seconds sunce the last call - return DeltaT; - } - else - { - // No high resolution performance counter - return -9999.0; - } - #else // Linux version of precision host timer. See http://www.informit.com/articles/article.aspx?p=23618&seqNum=8 - static struct timeval _NewTime; // new wall clock time (struct representation in seconds and microseconds) - static struct timeval _OldTime0; // old wall clock time 0(struct representation in seconds and microseconds) - static struct timeval _OldTime1; // old wall clock time 1(struct representation in seconds and microseconds) - static struct timeval _OldTime2; // old wall clock time 2(struct representation in seconds and microseconds) - - // Get new counter reading - gettimeofday(&_NewTime, NULL); - - switch (iCounterID) - { - case 0: - { - // Calculate time difference for timer 0. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime0.tv_sec + 1.0e-6 * (double)_OldTime0.tv_usec); - - // Reset old time 0 to new - _OldTime0.tv_sec = _NewTime.tv_sec; - _OldTime0.tv_usec = _NewTime.tv_usec; - - break; - } - case 1: - { - // Calculate time difference for timer 1. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime1.tv_sec + 1.0e-6 * (double)_OldTime1.tv_usec); - - // Reset old time 1 to new - _OldTime1.tv_sec = _NewTime.tv_sec; - _OldTime1.tv_usec = _NewTime.tv_usec; - - break; - } - case 2: - { - // Calculate time difference for timer 2. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime2.tv_sec + 1.0e-6 * (double)_OldTime2.tv_usec); - - // Reset old time 2 to new - _OldTime2.tv_sec = _NewTime.tv_sec; - _OldTime2.tv_usec = _NewTime.tv_usec; - - break; - } - default: - { - // Requested counter ID out of range - return -9999.0; - } - } - - // Returns time difference in seconds sunce the last call - return DeltaT; - #endif -} - -// Optional LogFileName Override function -// ********************************************************************* -char* cLogFilePathAndName = NULL; -void shrSetLogFileName (const char* cOverRideName) -{ - if( cLogFilePathAndName != NULL ) { - free(cLogFilePathAndName); - } - cLogFilePathAndName = (char*) malloc(strlen(cOverRideName) + 1); - #ifdef WIN32 - strcpy_s(cLogFilePathAndName, strlen(cOverRideName) + 1, cOverRideName); - #else - strcpy(cLogFilePathAndName, cOverRideName); - #endif - return; -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -static int shrLogV(int iLogMode, int iErrNum, const char* cFormatString, va_list vaArgList) -{ - static FILE* pFileStream0 = NULL; - static FILE* pFileStream1 = NULL; - size_t szNumWritten = 0; - char cFileMode [3]; - - // if the sample log file is closed and the call incudes a "write-to-file", open file for writing - if ((pFileStream0 == NULL) && (iLogMode & LOGFILE)) - { - // if the default filename has not been overriden, set to default - if (cLogFilePathAndName == NULL) - { - shrSetLogFileName(DEFAULTLOGFILE); - } - - #ifdef _WIN32 // Windows version - // set the file mode - if (iLogMode & APPENDMODE) // append to prexisting file contents - { - sprintf_s (cFileMode, 3, "a+"); - } - else // replace prexisting file contents - { - sprintf_s (cFileMode, 3, "w"); - } - - // open the individual sample log file in the requested mode - errno_t err = fopen_s(&pFileStream0, cLogFilePathAndName, cFileMode); - - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (err != 0) - { - if (pFileStream0) - { - fclose (pFileStream0); - } - return -err; - } - #else // Linux & Mac version - // set the file mode - if (iLogMode & APPENDMODE) // append to prexisting file contents - { - sprintf (cFileMode, "a+"); - } - else // replace prexisting file contents - { - sprintf (cFileMode, "w"); - } - - // open the file in the requested mode - if ((pFileStream0 = fopen(cLogFilePathAndName, cFileMode)) == 0) - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (pFileStream0) - { - fclose (pFileStream0); - } - return -1; - } - #endif - } - - // if the master log file is closed and the call incudes a "write-to-file" and MASTER, open master logfile file for writing - if ((pFileStream1 == NULL) && (iLogMode & LOGFILE) && (iLogMode & MASTER)) - { - #ifdef _WIN32 // Windows version - // open the master log file in append mode - errno_t err = fopen_s(&pFileStream1, MASTERLOGFILE, "a+"); - - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (err != 0) - { - if (pFileStream1) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid -// return -err; - } - #else // Linux & Mac version - - // open the file in the requested mode - if ((pFileStream1 = fopen(MASTERLOGFILE, "a+")) == 0) - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (pFileStream1) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid -// return -1; - } - #endif - - // If master log file length has become excessive, empty/reopen - if (iLogMode != LOGCONSOLE) - { - fseek(pFileStream1, 0L, SEEK_END); - if (ftell(pFileStream1) > 50000L) - { - fclose (pFileStream1); - #ifdef _WIN32 // Windows version - fopen_s(&pFileStream1, MASTERLOGFILE, "w"); - #else - pFileStream1 = fopen(MASTERLOGFILE, "w"); - #endif - } - } - } - - // Handle special Error Message code - if (iLogMode & ERRORMSG) - { - // print string to console if flagged - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf ("\n !!! Error # %i at ", iErrNum); // console - } - // print string to file if flagged - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, "\n !!! Error # %i at ", iErrNum); // sample log file - } - } - - // Vars used for variable argument processing - const char* pStr; - const char* cArg; - int iArg; - double dArg; - unsigned int uiArg; - std::string sFormatSpec; - const std::string sFormatChars = " -+#0123456789.dioufnpcsXxEeGgAa"; - const std::string sTypeChars = "dioufnpcsXxEeGgAa"; - char cType = 'c'; - - // Start at the head of the string and scan to the null at the end - for (pStr = cFormatString; *pStr; ++pStr) - { - // Check if the current character is not a formatting specifier ('%') - if (*pStr != '%') - { - // character is not '%', so print it verbatim to console and/or files as flagged - if (iLogMode & LOGCONSOLE) - { - szNumWritten = putc(*pStr, stdout); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = putc(*pStr, pFileStream0); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = putc(*pStr, pFileStream1); // master log file - } - } - } - else - { - // character is '%', so skip over it and read the full format specifier for the argument - ++pStr; - sFormatSpec = '%'; - - // special handling for string of %%%% - bool bRepeater = (*pStr == '%'); - if (bRepeater) - { - cType = '%'; - } - - // chars after the '%' are part of format if on list of constants... scan until that isn't true or NULL is found - while (pStr && ((sFormatChars.find(*pStr) != std::string::npos) || bRepeater)) - { - sFormatSpec += *pStr; - - // If the char is a type specifier, trap it and stop scanning - // (a type specifier char is always the last in the format except for string of %%%) - if (sTypeChars.find(*pStr) != std::string::npos) - { - cType = *pStr; - break; - } - - // Special handling for string of %%% - // If a string of %%% was started and then it ends, break (There won't be a typical type specifier) - if (bRepeater && (*pStr != '%')) - { - break; - } - - pStr++; - } - - // Now handle the arg according to type - switch (cType) - { - case '%': // special handling for string of %%%% - { - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str()); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str()); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str()); // master log file - } - } - continue; - } - case 'c': // single byte char - case 's': // string of single byte chars - { - // Set cArg as the next value in list and print to console and/or files if flagged - cArg = va_arg(vaArgList, char*); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), cArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), cArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), cArg); // master log file - } - } - continue; - } - case 'd': // signed decimal integer - case 'i': // signed decimal integer - { - // set iArg as the next value in list and print to console and/or files if flagged - iArg = va_arg(vaArgList, int); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), iArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), iArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), iArg); // master log file - } - } - continue; - } - case 'u': // unsigned decimal integer - case 'o': // unsigned octal integer - case 'x': // unsigned hexadecimal integer using "abcdef" - case 'X': // unsigned hexadecimal integer using "ABCDEF" - { - // set uiArg as the next value in list and print to console and/or files if flagged - uiArg = va_arg(vaArgList, unsigned int); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), uiArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), uiArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), uiArg); // master log file - } - } - continue; - } - case 'f': // float/double - case 'e': // scientific double/float - case 'E': // scientific double/float - case 'g': // scientific double/float - case 'G': // scientific double/float - case 'a': // signed hexadecimal double precision float - case 'A': // signed hexadecimal double precision float - { - // set dArg as the next value in list and print to console and/or files if flagged - dArg = va_arg(vaArgList, double); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), dArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), dArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), dArg); // master log file - } - } - continue; - } - default: - { - // print arg of unknown/unsupported type to console and/or file if flagged - if (iLogMode & LOGCONSOLE) // console - { - szNumWritten = putc(*pStr, stdout); - } - if (iLogMode & LOGFILE) - { - szNumWritten = putc(*pStr, pFileStream0); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = putc(*pStr, pFileStream1); // master log file - } - } - } - } - } - } - - // end the sample log with a horizontal line if closing - if (iLogMode & CLOSELOG) - { - if (iLogMode & LOGCONSOLE) - { - printf(HDASHLINE); - } - if (iLogMode & LOGFILE) - { - fprintf(pFileStream0, HDASHLINE); - } - } - - // flush console and/or file buffers if updated - if (iLogMode & LOGCONSOLE) - { - fflush(stdout); - } - if (iLogMode & LOGFILE) - { - fflush (pFileStream0); - - // if the master log file has been updated, flush it too - if (iLogMode & MASTER) - { - fflush (pFileStream1); - } - } - - // If the log file is open and the caller requests "close file", then close and NULL file handle - if ((pFileStream0) && (iLogMode & CLOSELOG)) - { - fclose (pFileStream0); - pFileStream0 = NULL; - } - if ((pFileStream1) && (iLogMode & CLOSELOG)) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - - // return error code or OK - if (iLogMode & ERRORMSG) - { - return iErrNum; - } - else - { - return 0; - } -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -int shrLogEx(int iLogMode = LOGCONSOLE, int iErrNum = 0, const char* cFormatString = "", ...) -{ - va_list vaArgList; - - // Prepare variable agument list - va_start(vaArgList, cFormatString); - int ret = shrLogV(iLogMode, iErrNum, cFormatString, vaArgList); - - // end variable argument handler - va_end(vaArgList); - - return ret; -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -int shrLog(const char* cFormatString = "", ...) -{ - va_list vaArgList; - - // Prepare variable agument list - va_start(vaArgList, cFormatString); - int ret = shrLogV(LOGBOTH, 0, cFormatString, vaArgList); - - // end variable argument handler - va_end(vaArgList); - - return ret; -} - -////////////////////////////////////////////////////////////////////////////// -//! Find the path for a file assuming that -//! files are found in the searchPath. -//! -//! @return the path if succeeded, otherwise 0 -//! @param filename name of the file -//! @param executable_path optional absolute path of the executable -////////////////////////////////////////////////////////////////////////////// -char* shrFindFilePath(const char* filename, const char* executable_path) -{ - // defines a variable that is replaced with the name of the executable - - // Typical relative search paths to locate needed companion files (e.g. sample input data, or JIT source files) - // The origin for the relative search may be the .exe file, a .bat file launching an .exe, a browser .exe launching the .exe or .bat, etc - const char* searchPath[] = - { - "./", // same dir - "./data/", // "/data/" subdir - "./src/", // "/src/" subdir - "./src//data/", // "/src//data/" subdir - "./inc/", // "/inc/" subdir - "../", // up 1 in tree - "../data/", // up 1 in tree, "/data/" subdir - "../src/", // up 1 in tree, "/src/" subdir - "../inc/", // up 1 in tree, "/inc/" subdir - "../OpenCL/src//", // up 1 in tree, "/OpenCL/src//" subdir - "../OpenCL/src//data/", // up 1 in tree, "/OpenCL/src//data/" subdir - "../OpenCL/src//src/", // up 1 in tree, "/OpenCL/src//src/" subdir - "../OpenCL/src//inc/", // up 1 in tree, "/OpenCL/src//inc/" subdir - "../C/src//", // up 1 in tree, "/C/src//" subdir - "../C/src//data/", // up 1 in tree, "/C/src//data/" subdir - "../C/src//src/", // up 1 in tree, "/C/src//src/" subdir - "../C/src//inc/", // up 1 in tree, "/C/src//inc/" subdir - "../DirectCompute/src//", // up 1 in tree, "/DirectCompute/src//" subdir - "../DirectCompute/src//data/", // up 1 in tree, "/DirectCompute/src//data/" subdir - "../DirectCompute/src//src/", // up 1 in tree, "/DirectCompute/src//src/" subdir - "../DirectCompute/src//inc/", // up 1 in tree, "/DirectCompute/src//inc/" subdir - "../../", // up 2 in tree - "../../data/", // up 2 in tree, "/data/" subdir - "../../src/", // up 2 in tree, "/src/" subdir - "../../inc/", // up 2 in tree, "/inc/" subdir - "../../../", // up 3 in tree - "../../../src//", // up 3 in tree, "/src//" subdir - "../../../src//data/", // up 3 in tree, "/src//data/" subdir - "../../../src//src/", // up 3 in tree, "/src//src/" subdir - "../../../src//inc/", // up 3 in tree, "/src//inc/" subdir - "../../../sandbox//", // up 3 in tree, "/sandbox//" subdir - "../../../sandbox//data/", // up 3 in tree, "/sandbox//data/" subdir - "../../../sandbox//src/", // up 3 in tree, "/sandbox//src/" subdir - "../../../sandbox//inc/" // up 3 in tree, "/sandbox//inc/" subdir - }; - - // Extract the executable name - std::string executable_name; - if (executable_path != 0) - { - executable_name = std::string(executable_path); - - #ifdef _WIN32 - // Windows path delimiter - size_t delimiter_pos = executable_name.find_last_of('\\'); - executable_name.erase(0, delimiter_pos + 1); - - if (executable_name.rfind(".exe") != string::npos) - { - // we strip .exe, only if the .exe is found - executable_name.resize(executable_name.size() - 4); - } - #else - // Linux & OSX path delimiter - size_t delimiter_pos = executable_name.find_last_of('/'); - executable_name.erase(0,delimiter_pos+1); - #endif - - } - - // Loop over all search paths and return the first hit - for( unsigned int i = 0; i < sizeof(searchPath)/sizeof(char*); ++i ) - { - std::string path(searchPath[i]); - size_t executable_name_pos = path.find(""); - - // If there is executable_name variable in the searchPath - // replace it with the value - if(executable_name_pos != std::string::npos) - { - if(executable_path != 0) - { - path.replace(executable_name_pos, strlen(""), executable_name); - - } - else - { - // Skip this path entry if no executable argument is given - continue; - } - } - - // Test if the file exists - path.append(filename); - std::fstream fh(path.c_str(), std::fstream::in); - if (fh.good()) - { - // File found - // returning an allocated array here for backwards compatibility reasons - char* file_path = (char*) malloc(path.length() + 1); - #ifdef _WIN32 - strcpy_s(file_path, path.length() + 1, path.c_str()); - #else - strcpy(file_path, path.c_str()); - #endif - return file_path; - } - } - - // File not found - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -//! Read file \filename and return the data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -shrReadFile( const char* filename, T** data, unsigned int* len, bool verbose) -{ - // check input arguments - ARGCHECK(NULL != filename); - ARGCHECK(NULL != len); - - // intermediate storage for the data read - std::vector data_read; - - // open file for reading - std::fstream fh( filename, std::fstream::in); - // check if filestream is valid - if(!fh.good()) - { - if (verbose) - std::cerr << "shrReadFile() : Opening file failed." << std::endl; - return shrFALSE; - } - - // read all data elements - T token; - while( fh.good()) - { - fh >> token; - data_read.push_back( token); - } - - // the last element is read twice - data_read.pop_back(); - - // check if reading result is consistent - if( ! fh.eof()) - { - if (verbose) - std::cerr << "WARNING : readData() : reading file might have failed." - << std::endl; - } - - fh.close(); - - // check if the given handle is already initialized - if( NULL != *data) - { - if( *len != data_read.size()) - { - std::cerr << "shrReadFile() : Initialized memory given but " - << "size mismatch with signal read " - << "(data read / data init = " << (unsigned int)data_read.size() - << " / " << *len << ")" << std::endl; - - return shrFALSE; - } - } - else - { - // allocate storage for the data read - *data = (T*) malloc( sizeof(T) * data_read.size()); - // store signal size - *len = static_cast( data_read.size()); - } - - // copy data - memcpy( *data, &data_read.front(), sizeof(T) * data_read.size()); - - return shrTRUE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -shrWriteFile( const char* filename, const T* data, unsigned int len, - const T epsilon, bool verbose) -{ - ARGCHECK(NULL != filename); - ARGCHECK(NULL != data); - - // open file for writing - std::fstream fh( filename, std::fstream::out); - // check if filestream is valid - if(!fh.good()) - { - if (verbose) - std::cerr << "shrWriteFile() : Opening file failed." << std::endl; - return shrFALSE; - } - - // first write epsilon - fh << "# " << epsilon << "\n"; - - // write data - for( unsigned int i = 0; (i < len) && (fh.good()); ++i) - { - fh << data[i] << ' '; - } - - // Check if writing succeeded - if( ! fh.good()) - { - if (verbose) - std::cerr << "shrWriteFile() : Writing file failed." << std::endl; - return shrFALSE; - } - - // file ends with nl - fh << std::endl; - - return shrTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg single precision floating point data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg double precision floating point data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg integer data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg unsigned integer data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileui( const char* filename, unsigned int** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg char / byte data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg unsigned char / byte data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileub( const char* filename, unsigned char** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for single precision floating point data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len, - const float epsilon, bool verbose) -{ - return shrWriteFile( filename, data, len, epsilon, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for double precision floating point data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFiled( const char* filename, const double* data, unsigned int len, - const double epsilon, bool verbose) -{ - return shrWriteFile( filename, data, len, epsilon, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for integer data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, 0, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for unsigned integer data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileui( const char* filename,const unsigned int* data,unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileub( const char* filename, const unsigned char* data, - unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for unsigned byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileb( const char* filename,const unsigned char* data,unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -////////////////////////////////////////////////////////////////////////////// -//! Load PGM or PPM file -//! @note if data == NULL then the necessary memory is allocated in the -//! function and w and h are initialized to the size of the image -//! @return shrTRUE if the file loading succeeded, otherwise shrFALSE -//! @param file name of the file to load -//! @param data handle to the memory for the image file data -//! @param w width of the image -//! @param h height of the image -//! @param channels number of channels in image -////////////////////////////////////////////////////////////////////////////// -shrBOOL loadPPM(const char* file, unsigned char** data, - unsigned int *w, unsigned int *h, unsigned int *channels) -{ - FILE* fp = 0; - - #ifdef _WIN32 - // open the file for binary read - errno_t err; - if ((err = fopen_s(&fp, file, "rb")) != 0) - #else - // open the file for binary read - if ((fp = fopen(file, "rb")) == 0) - #endif - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : Failed to open file: " << file << std::endl; - return shrFALSE; - } - - // check header - char header[PGMHeaderSize]; - if ((fgets( header, PGMHeaderSize, fp) == NULL) && ferror(fp)) - { - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl; - *channels = 0; - return shrFALSE; - } - - if (strncmp(header, "P5", 2) == 0) - { - *channels = 1; - } - else if (strncmp(header, "P6", 2) == 0) - { - *channels = 3; - } - else - { - std::cerr << "loadPPM() : File is not a PPM or PGM image" << std::endl; - *channels = 0; - return shrFALSE; - } - - // parse header, read maxval, width and height - unsigned int width = 0; - unsigned int height = 0; - unsigned int maxval = 0; - unsigned int i = 0; - while(i < 3) - { - if ((fgets(header, PGMHeaderSize, fp) == NULL) && ferror(fp)) - { - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl; - return shrFALSE; - } - if(header[0] == '#') continue; - - #ifdef _WIN32 - if(i == 0) - { - i += sscanf_s(header, "%u %u %u", &width, &height, &maxval); - } - else if (i == 1) - { - i += sscanf_s(header, "%u %u", &height, &maxval); - } - else if (i == 2) - { - i += sscanf_s(header, "%u", &maxval); - } - #else - if(i == 0) - { - i += sscanf(header, "%u %u %u", &width, &height, &maxval); - } - else if (i == 1) - { - i += sscanf(header, "%u %u", &height, &maxval); - } - else if (i == 2) - { - i += sscanf(header, "%u", &maxval); - } - #endif - } - - // check if given handle for the data is initialized - if(NULL != *data) - { - if (*w != width || *h != height) - { - fclose(fp); - std::cerr << "loadPPM() : Invalid image dimensions." << std::endl; - return shrFALSE; - } - } - else - { - *data = (unsigned char*)malloc( sizeof(unsigned char) * width * height * *channels); - *w = width; - *h = height; - } - - // read and close file - if (fread(*data, sizeof(unsigned char), width * height * *channels, fp) != width * height * *channels) - { - fclose(fp); - std::cerr << "loadPPM() : Invalid image." << std::endl; - return shrFALSE; - } - fclose(fp); - - return shrTRUE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Write / Save PPM or PGM file -//! @note Internal usage only -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -////////////////////////////////////////////////////////////////////////////// -shrBOOL savePPM( const char* file, unsigned char *data, - unsigned int w, unsigned int h, unsigned int channels) -{ - ARGCHECK(NULL != data); - ARGCHECK(w > 0); - ARGCHECK(h > 0); - - std::fstream fh( file, std::fstream::out | std::fstream::binary ); - if( fh.bad()) - { - std::cerr << "savePPM() : Opening file failed." << std::endl; - return shrFALSE; - } - - if (channels == 1) - { - fh << "P5\n"; - } - else if (channels == 3) { - fh << "P6\n"; - } - else { - std::cerr << "savePPM() : Invalid number of channels." << std::endl; - return shrFALSE; - } - - fh << w << "\n" << h << "\n" << 0xff << std::endl; - - for( unsigned int i = 0; (i < (w*h*channels)) && fh.good(); ++i) - { - fh << data[i]; - } - fh.flush(); - - if( fh.bad()) - { - std::cerr << "savePPM() : Writing data failed." << std::endl; - return shrFALSE; - } - fh.close(); - - return shrTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Load PPM image file (with unsigned char as data element type), padding 4th component -//! @return shrTrue if reading the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrLoadPPM4ub( const char* file, unsigned char** OutData, - unsigned int *w, unsigned int *h) -{ - // Load file data into a temporary buffer with automatic allocation - unsigned char* cLocalData = 0; - unsigned int channels; - shrBOOL bLoadOK = loadPPM(file, &cLocalData, w, h, &channels); // this allocates cLocalData, which must be freed later - - // If the data loaded OK from file to temporary buffer, then go ahead with padding and transfer - if (shrTRUE == bLoadOK) - { - // if the receiving buffer is null, allocate it... caller must free this - int size = *w * *h; - if (*OutData == NULL) - { - *OutData = (unsigned char*)malloc(sizeof(unsigned char) * size * 4); - } - - // temp pointers for incrementing - unsigned char* cTemp = cLocalData; - unsigned char* cOutPtr = *OutData; - - // transfer data, padding 4th element - for(int i=0; i( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type unsigned int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv, - const char* arg_name, unsigned int* val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const int* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type float -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv, - const char* arg_name, float* val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const float* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type string -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv, - const char* arg_name, char** val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const std::string* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - - // allocate memory for the string - *val = (char*)malloc(sizeof(char) * (v->length() + 1)); - - // copy from string to c_str - #ifdef WIN32 - strcpy_s(*val, v->length() + 1, v->c_str()); - #else - strcpy(*val, v->c_str()); - #endif - ret_val = shrTRUE; - } - else { - // fail safe - *val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string."<< - std::endl; - } - - return ret_val; - -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareData( const T* reference, const T* data, const unsigned int len, - const S epsilon, const float threshold) -{ - ARGCHECK( epsilon >= 0); - - bool result = true; - unsigned int error_count = 0; - - for( unsigned int i = 0; i < len; ++i) { - - T diff = reference[i] - data[i]; - bool comp = (diff <= epsilon) && (diff >= -epsilon); - result &= comp; - - error_count += !comp; - -#ifdef _DEBUG - if( ! comp) - { - std::cerr << "ERROR, i = " << i << ",\t " - << reference[i] << " / " - << data[i] - << " (reference / data)\n"; - } -#endif - } - - if (threshold == 0.0f) { - return (result) ? shrTRUE : shrFALSE; - } else { - return (len*threshold > error_count) ? shrTRUE : shrFALSE; - } -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareDataAsFloat( const T* reference, const T* data, const unsigned int len, - const S epsilon) -{ - ARGCHECK(epsilon >= 0); - - // If we set epsilon to be 0, let's set a minimum threshold - float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR ); - int error_count = 0; - bool result = true; - - for( unsigned int i = 0; i < len; ++i) { - float diff = fabs((float)reference[i] - (float)data[i]); - bool comp = (diff < max_error); - result &= comp; - - if( ! comp) - { - error_count++; -#ifdef _DEBUG - if (error_count < 50) { - shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)0x%02x / (data)0x%02x / (diff)%d\n", max_error, i, reference[i], data[i], (unsigned int)diff); - } -#endif - } - } - if (error_count) { - shrLog("\n Total # of errors = %d\n", error_count); - } - return (error_count == 0) ? shrTRUE : shrFALSE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//! @param epsilon threshold % of (# of bytes) for pass/fail -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareDataAsFloatThreshold( const T* reference, const T* data, const unsigned int len, - const S epsilon, const float threshold) -{ - ARGCHECK(epsilon >= 0); - - // If we set epsilon to be 0, let's set a minimum threshold - float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR); - int error_count = 0; - bool result = true; - - for( unsigned int i = 0; i < len; ++i) { - float diff = fabs((float)reference[i] - (float)data[i]); - bool comp = (diff < max_error); - result &= comp; - - if( ! comp) - { - error_count++; -//#ifdef _DEBUG - if (error_count < 50) { - shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)%f / (data)%f / (diff)%f\n", max_error, i, reference[i], data[i], diff); - } -//#endif - } - } - - if (threshold == 0.0f) { - if (error_count) { - shrLog("\n Total # of errors = %d\n", error_count); - } - return (error_count == 0) ? shrTRUE : shrFALSE; - } else { - - if (error_count) { - shrLog("\n %.2f(%%) of bytes mismatched (count=%d)\n", (float)error_count*100/(float)len, error_count); - } - - return ((len*threshold > error_count) ? shrTRUE : shrFALSE); - } -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparef( const float* reference, const float* data, - const unsigned int len ) -{ - const float epsilon = 0.0; - return compareData( reference, data, len, epsilon, 0.0f ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparei( const int* reference, const int* data, - const unsigned int len ) -{ - const int epsilon = 0; - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned integer arrays, with epsilon and threshold -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data, - const unsigned int len ) -{ - const int epsilon = 0; - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays (inc Threshold for # of pixel we can have errors) -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, -//! otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon ) -{ - return compareDataAsFloat( reference, data, len, epsilon ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparefe( const float* reference, const float* data, - const unsigned int len, const float epsilon ) -{ - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality and a -//! threshold for # pixel errors -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparefet( const float* reference, const float* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays using L2-norm with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareL2fe( const float* reference, const float* data, - const unsigned int len, const float epsilon ) -{ - ARGCHECK(epsilon >= 0); - - float error = 0; - float ref = 0; - - for( unsigned int i = 0; i < len; ++i) { - - float diff = reference[i] - data[i]; - error += diff * diff; - ref += reference[i] * reference[i]; - } - - float normRef = sqrtf(ref); - if (fabs(ref) < 1e-7) { -#ifdef _DEBUG - std::cerr << "ERROR, reference l2-norm is 0\n"; -#endif - return shrFALSE; - } - float normError = sqrtf(error); - error = normError / normRef; - bool result = error < epsilon; -#ifdef _DEBUG - if( ! result) - { - std::cerr << "ERROR, l2-norm error " - << error << " is greater than epsilon " << epsilon << "\n"; - } -#endif - - return result ? shrTRUE : shrFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PPM image files with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! @param verboseErrors output details of image mismatch to std::cerr -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold) -{ - unsigned char* src_data = NULL; - unsigned char* ref_data = NULL; - unsigned long error_count = 0; - unsigned int ref_width, ref_height; - unsigned int src_width, src_height; - - // Check sample and reference file pointers - if (src_file == NULL || ref_file == NULL) { - shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n"); - return shrFALSE; - } - shrLog("\n> shrComparePPM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file); - - // Load the ref image file - if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE) - { - shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file); - return shrFALSE; - } - - // Load the sample image file - if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE) - { - shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file); - return shrFALSE; - } - - // check to see if image dimensions match - if(src_height != ref_height || src_width != ref_width) - { - shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ", - src_width, src_height, ref_width, ref_height); - return shrFALSE; - } - - // compare the images - if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE) - { - error_count=1; - } - - shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!"); - return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PGM image files with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold) -{ - unsigned char* src_data = NULL; - unsigned char* ref_data = NULL; - unsigned long error_count = 0; - unsigned int ref_width, ref_height; - unsigned int src_width, src_height; - - // Check sample and reference file pointers - if (src_file == NULL || ref_file == NULL) { - shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n"); - return shrFALSE; - } - shrLog("\n> shrComparePGM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file); - - // Load the ref image file - if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE) - { - shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file); - return shrFALSE; - } - - // Load the sample image file - if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE) - { - shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file); - return shrFALSE; - } - - // check to see if image dimensions match - if(src_height != ref_height || src_width != ref_width) - { - shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ", - src_width, src_height, ref_width, ref_height); - return shrFALSE; - } - - // compare the images - if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE) - { - error_count=1; - } - - shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!"); - return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass -} - -// Load raw data from disk -unsigned char* shrLoadRawFile(const char* filename, size_t size) -{ - FILE *fp = NULL; - #ifdef WIN32 - errno_t err; - if ((err = fopen_s(&fp, filename, "rb")) != 0) - #else - if ((fp = fopen(filename, "rb")) == NULL) - #endif - { - shrLog(" Error opening file '%s' !!!\n", filename); - return 0; - } - - unsigned char* data = (unsigned char*)malloc(size); - size_t read = fread(data, 1, size, fp); - fclose(fp); - - shrLog(" Read '%s', %d bytes\n", filename, read); - - return data; -} - -// Round Up Division function -size_t shrRoundUp(int group_size, int global_size) -{ - int r = global_size % group_size; - if(r == 0) - { - return global_size; - } else - { - return global_size + group_size - r; - } -} \ No newline at end of file diff --git a/tests/opencl/blackscholes/shrUtils.h b/tests/opencl/blackscholes/shrUtils.h deleted file mode 100644 index 0f2795d4..00000000 --- a/tests/opencl/blackscholes/shrUtils.h +++ /dev/null @@ -1,642 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -#ifndef SHR_UTILS_H -#define SHR_UTILS_H - -// ********************************************************************* -// Generic utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// reminders for output window and build log -#ifdef _WIN32 - #pragma message ("Note: including windows.h") - #pragma message ("Note: including math.h") - #pragma message ("Note: including assert.h") -#endif - -// OS dependent includes -#ifdef _WIN32 - // Headers needed for Windows - #include -#else - // Headers needed for Linux - #include - #include - #include - #include - #include - #include - #include -#endif - -// Other headers needed for both Windows and Linux -#include -#include -#include -#include -#include - -// Un-comment the following #define to enable profiling code in SDK apps -//#define GPU_PROFILING - -// Beginning of GPU Architecture definitions -inline int ConvertSMVer2Cores(int major, int minor) -{ - // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM - typedef struct { - int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version - int Cores; - } sSMtoCores; - - sSMtoCores nGpuArchCoresPerSM[] = - { { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class - { 0x11, 8 }, // Tesla Generation (SM 1.1) G8x class - { 0x12, 8 }, // Tesla Generation (SM 1.2) G9x class - { 0x13, 8 }, // Tesla Generation (SM 1.3) GT200 class - { 0x20, 32 }, // Fermi Generation (SM 2.0) GF100 class - { 0x21, 48 }, // Fermi Generation (SM 2.1) GF10x class - { 0x30, 192}, // Fermi Generation (SM 3.0) GK10x class - { -1, -1 } - }; - - int index = 0; - while (nGpuArchCoresPerSM[index].SM != -1) { - if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor) ) { - return nGpuArchCoresPerSM[index].Cores; - } - index++; - } - printf("MapSMtoCores SM %d.%d is undefined (please update to the latest SDK)!\n", major, minor); - return -1; -} -// end of GPU Architecture definitions - - -// Defines and enum for use with logging functions -// ********************************************************************* -#define DEFAULTLOGFILE "SdkConsoleLog.txt" -#define MASTERLOGFILE "SdkMasterLog.csv" -enum LOGMODES -{ - LOGCONSOLE = 1, // bit to signal "log to console" - LOGFILE = 2, // bit to signal "log to file" - LOGBOTH = 3, // convenience union of first 2 bits to signal "log to both" - APPENDMODE = 4, // bit to set "file append" mode instead of "replace mode" on open - MASTER = 8, // bit to signal master .csv log output - ERRORMSG = 16, // bit to signal "pre-pend Error" - CLOSELOG = 32 // bit to close log file, if open, after any requested file write -}; -#define HDASHLINE "-----------------------------------------------------------\n" - -// Standardized boolean -enum shrBOOL -{ - shrFALSE = 0, - shrTRUE = 1 -}; - -// Standardized MAX, MIN and CLAMP -#define MAX(a, b) ((a > b) ? a : b) -#define MIN(a, b) ((a < b) ? a : b) -#define CLAMP(a, b, c) MIN(MAX(a, b), c) // double sided clip of input a -#define TOPCLAMP(a, b) (a < b ? a:b) // single top side clip of input a - -// Error and Exit Handling Macros... -// ********************************************************************* -// Full error handling macro with Cleanup() callback (if supplied)... -// (Companion Inline Function lower on page) -#define shrCheckErrorEX(a, b, c) __shrCheckErrorEX(a, b, c, __FILE__ , __LINE__) - -// Short version without Cleanup() callback pointer -// Both Input (a) and Reference (b) are specified as args -#define shrCheckError(a, b) shrCheckErrorEX(a, b, 0) - -// Standardized Exit Macro for leaving main()... extended version -// (Companion Inline Function lower on page) -#define shrExitEX(a, b, c) __shrExitEX(a, b, c) - -// Standardized Exit Macro for leaving main()... short version -// (Companion Inline Function lower on page) -#define shrEXIT(a, b) __shrExitEX(a, b, EXIT_SUCCESS) - -// Simple argument checker macro -#define ARGCHECK(a) if((a) != shrTRUE)return shrFALSE - -// Define for user-customized error handling -#define STDERROR "file %s, line %i\n\n" , __FILE__ , __LINE__ - -// Function to deallocate memory allocated within shrUtils -// ********************************************************************* -extern "C" void shrFree(void* ptr); - -// ********************************************************************* -// Helper function to log standardized information to Console, to File or to both -//! Examples: shrLogEx(LOGBOTH, 0, "Function A\n"); -//! : shrLogEx(LOGBOTH | ERRORMSG, ciErrNum, STDERROR); -//! -//! Automatically opens file and stores handle if needed and not done yet -//! Closes file and nulls handle on request -//! -//! @param 0 iLogMode: LOGCONSOLE, LOGFILE, LOGBOTH, APPENDMODE, MASTER, ERRORMSG, CLOSELOG. -//! LOGFILE and LOGBOTH may be | 'd with APPENDMODE to select file append mode instead of overwrite mode -//! LOGFILE and LOGBOTH may be | 'd with CLOSELOG to "write and close" -//! First 3 options may be | 'd with MASTER to enable independent write to master data log file -//! First 3 options may be | 'd with ERRORMSG to start line with standard error message -//! @param 2 dValue: -//! Positive val = double value for time in secs to be formatted to 6 decimals. -//! Negative val is an error code and this give error preformatting. -//! @param 3 cFormatString: String with formatting specifiers like printf or fprintf. -//! ALL printf flags, width, precision and type specifiers are supported with this exception: -//! Wide char type specifiers intended for wprintf (%S and %C) are NOT supported -//! Single byte char type specifiers (%s and %c) ARE supported -//! @param 4... variable args: like printf or fprintf. Must match format specifer type above. -//! @return 0 if OK, negative value on error or if error occurs or was passed in. -// ********************************************************************* -extern "C" int shrLogEx(int iLogMode, int iErrNum, const char* cFormatString, ...); - -// Short version of shrLogEx defaulting to shrLogEx(LOGBOTH, 0, -// ********************************************************************* -extern "C" int shrLog(const char* cFormatString, ...); - -// ********************************************************************* -// Delta timer function for up to 3 independent timers using host high performance counters -// Maintains state for 3 independent counters -//! Example: double dElapsedTime = shrDeltaTime(0); -//! -//! @param 0 iCounterID: Which timer to check/reset. (0, 1, 2) -//! @return delta time of specified counter since last call in seconds. Otherwise -9999.0 if error -// ********************************************************************* -extern "C" double shrDeltaT(int iCounterID); - -// Optional LogFileNameOverride function -// ********************************************************************* -extern "C" void shrSetLogFileName (const char* cOverRideName); - -// Helper function to init data arrays -// ********************************************************************* -extern "C" void shrFillArray(float* pfData, int iSize); - -// Helper function to print data arrays -// ********************************************************************* -extern "C" void shrPrintArray(float* pfData, int iSize); - -//////////////////////////////////////////////////////////////////////////// -//! Find the path for a filename -//! @return the path if succeeded, otherwise 0 -//! @param filename name of the file -//! @param executablePath optional absolute path of the executable -//////////////////////////////////////////////////////////////////////////// -extern "C" char* shrFindFilePath(const char* filename, const char* executablePath); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing single precision floating point data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing double precision floating point data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing integer data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing unsigned integer data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileui( const char* filename, unsigned int** data, - unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing char / byte data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing unsigned char / byte data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileub( const char* filename, unsigned char** data, - unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing single precision floating point -//! data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len, - const float epsilon, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing double precision floating point -//! data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFiled( const char* filename, const float* data, unsigned int len, - const double epsilon, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing integer data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing unsigned integer data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileui( const char* filename, const unsigned int* data, - unsigned int len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing char / byte data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing unsigned char / byte data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileub( const char* filename, const unsigned char* data, - unsigned int len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Load PPM image file (with unsigned char as data element type), padding -//! 4th component -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param OutData handle to the data read -//! @param w width of the image -//! @param h height of the image -//! -//! Note: If *OutData is NULL this function allocates buffer that must be freed by caller -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrLoadPPM4ub(const char* file, unsigned char** OutData, - unsigned int *w, unsigned int *h); - -//////////////////////////////////////////////////////////////////////////// -//! Save PPM image file (with unsigned char as data element type, padded to -//! 4 bytes) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrSavePPM4ub( const char* file, unsigned char *data, - unsigned int w, unsigned int h); - -//////////////////////////////////////////////////////////////////////////////// -//! Save PGM image file (with unsigned char as data element type) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrSavePGMub( const char* file, unsigned char *data, - unsigned int w, unsigned int h); - -//////////////////////////////////////////////////////////////////////////// -//! Load PGM image file (with unsigned char as data element type) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrLoadPGMub( const char* file, unsigned char** data, - unsigned int *w,unsigned int *h); - -//////////////////////////////////////////////////////////////////////////// -// Command line arguments: General notes -// * All command line arguments begin with '--' followed by the token; -// token and value are seperated by '='; example --samples=50 -// * Arrays have the form --model=[one.obj,two.obj,three.obj] -// (without whitespaces) -//////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////// -//! Check if command line argument \a flag-name is given -//! @return shrTRUE if command line argument \a flag_name has been given, -//! otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param flag_name name of command line flag -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCheckCmdLineFlag( const int argc, const char** argv, - const char* flag_name); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumenti( const int argc, const char** argv, - const char* arg_name, int* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type unsigned int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv, - const char* arg_name, unsigned int* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type float -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv, - const char* arg_name, float* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type string -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv, - const char* arg_name, char** val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument list those element are strings -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val command line argument list -//! @param len length of the list / number of elements -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentListstr( const int argc, const char** argv, - const char* arg_name, char** val, - unsigned int* len); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparef( const float* reference, const float* data, - const unsigned int len); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparei( const int* reference, const int* data, - const unsigned int len ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned integer arrays, with epsilon and threshold -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param threshold tolerance % # of comparison errors (0.15f = 15%) -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned char arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data, - const unsigned int len ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integers with a tolernance for # of byte errors -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//! @param threshold tolerance % # of comparison errors (0.15f = 15%) -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays witha n epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparefe( const float* reference, const float* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality and a -//! threshold for # pixel errors -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparefet( const float* reference, const float* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays using L2-norm with an epsilon tolerance for -//! equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareL2fe( const float* reference, const float* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PPM image files with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! $param verboseErrors output details of image mismatch to std::err -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PGM image files with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! $param verboseErrors output details of image mismatch to std::err -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold); - -extern "C" unsigned char* shrLoadRawFile(const char* filename, size_t size); - -extern "C" size_t shrRoundUp(int group_size, int global_size); - -// companion inline function for error checking and exit on error WITH Cleanup Callback (if supplied) -// ********************************************************************* -inline void __shrCheckErrorEX(int iSample, int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) -{ - if (iReference != iSample) - { - shrLogEx(LOGBOTH | ERRORMSG, iSample, "line %i , in file %s !!!\n\n" , iLine, cFile); - if (pCleanup != NULL) - { - pCleanup(EXIT_FAILURE); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "Exiting...\n"); - exit(EXIT_FAILURE); - } - } -} - -// Standardized Exit -// ********************************************************************* -inline void __shrExitEX(int argc, const char** argv, int iExitCode) -{ -#ifdef WIN32 - if (!shrCheckCmdLineFlag(argc, argv, "noprompt") && !shrCheckCmdLineFlag(argc, argv, "qatest")) -#else - if (shrCheckCmdLineFlag(argc, argv, "prompt") && !shrCheckCmdLineFlag(argc, argv, "qatest")) -#endif - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "\nPress to Quit...\n"); - getchar(); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "%s Exiting...\n", argv[0]); - } - fflush(stderr); - exit(iExitCode); -} - -#endif \ No newline at end of file diff --git a/tests/opencl/common.mk b/tests/opencl/common.mk deleted file mode 100644 index cfb436a6..00000000 --- a/tests/opencl/common.mk +++ /dev/null @@ -1,120 +0,0 @@ -XLEN ?= 32 -TOOLDIR ?= /opt - -TARGET ?= opaesim - -XRT_SYN_DIR ?= ../../../hw/syn/xilinx/xrt -XRT_DEVICE_INDEX ?= 0 - -ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv64-gnu-toolchain -VX_CFLAGS += -march=rv64imafd -mabi=lp64d -K_CFLAGS += -march=rv64imafd -mabi=ilp64d -STARTUP_ADDR ?= 0x180000000 -else -RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv-gnu-toolchain -VX_CFLAGS += -march=rv32imaf -mabi=ilp32f -K_CFLAGS += -march=rv32imaf -mabi=ilp32f -STARTUP_ADDR ?= 0x80000000 -endif - -RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf -RISCV_SYSROOT ?= $(RISCV_TOOLCHAIN_PATH)/$(RISCV_PREFIX) - -POCL_CC_PATH ?= $(TOOLDIR)/pocl/compiler -POCL_RT_PATH ?= $(TOOLDIR)/pocl/runtime - -VORTEX_RT_PATH ?= $(realpath ../../../runtime) -VORTEX_KN_PATH ?= $(realpath ../../../kernel) - -FPGA_BIN_DIR ?= $(VORTEX_RT_PATH)/opae - -LLVM_VORTEX ?= $(TOOLDIR)/llvm-vortex -LLVM_POCL ?= $(TOOLDIR)/llvm-vortex - -K_CFLAGS += -v -O3 --sysroot=$(RISCV_SYSROOT) --gcc-toolchain=$(RISCV_TOOLCHAIN_PATH) -Xclang -target-feature -Xclang +vortex -K_CFLAGS += -fno-rtti -fno-exceptions -nostartfiles -fdata-sections -ffunction-sections -K_CFLAGS += -I$(VORTEX_KN_PATH)/include -DNDEBUG -DLLVM_VOTEX -K_LDFLAGS += -Wl,-Bstatic,--gc-sections,-T$(VORTEX_KN_PATH)/linker/vx_link$(XLEN).ld,--defsym=STARTUP_ADDR=$(STARTUP_ADDR) $(VORTEX_KN_PATH)/libvortexrt.a -lm - -CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -CXXFLAGS += -Wno-deprecated-declarations -Wno-unused-parameter -Wno-narrowing -CXXFLAGS += -pthread -CXXFLAGS += -I$(POCL_RT_PATH)/include - -ifdef HOSTGPU - CXXFLAGS += -DHOSTGPU - LDFLAGS += -lOpenCL -else - LDFLAGS += -L$(VORTEX_RT_PATH)/stub -lvortex $(POCL_RT_PATH)/lib/libOpenCL.so -endif - -# Debugigng -ifdef DEBUG - CXXFLAGS += -g -O0 -else - CXXFLAGS += -O2 -DNDEBUG -endif - -ifeq ($(TARGET), fpga) - OPAE_DRV_PATHS ?= libopae-c.so -else -ifeq ($(TARGET), asesim) - OPAE_DRV_PATHS ?= libopae-c-ase.so -else -ifeq ($(TARGET), opaesim) - OPAE_DRV_PATHS ?= libopae-c-sim.so -endif -endif -endif - -OBJS := $(addsuffix .o, $(notdir $(SRCS))) - -all: $(PROJECT) kernel.pocl - -kernel.pocl: kernel.cl - LD_LIBRARY_PATH=$(LLVM_POCL)/lib:$(POCL_CC_PATH)/lib:$(LLVM_VORTEX)/lib:$(LD_LIBRARY_PATH) LLVM_PREFIX=$(LLVM_VORTEX) POCL_DEBUG=all POCL_VORTEX_CFLAGS="$(K_CFLAGS)" POCL_VORTEX_LDFLAGS="$(K_LDFLAGS)" $(POCL_CC_PATH)/bin/poclcc -o kernel.pocl kernel.cl - -%.cc.o: %.cc - $(CXX) $(CXXFLAGS) -c $< -o $@ - -%.cpp.o: %.cpp - $(CXX) $(CXXFLAGS) -c $< -o $@ - -%.c.o: %.c - $(CC) $(CXXFLAGS) -c $< -o $@ - -$(PROJECT): $(OBJS) - $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ - -run-hostgpu: $(PROJECT) kernel.pocl - ./$(PROJECT) $(OPTS) - -run-simx: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_RT_PATH)/simx:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) - -run-rtlsim: $(PROJECT) kernel.pocl - LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_RT_PATH)/rtlsim:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) - -run-opae: $(PROJECT) kernel.pocl - SCOPE_JSON_PATH=$(FPGA_BIN_DIR)/scope.json OPAE_DRV_PATHS=$(OPAE_DRV_PATHS) LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_RT_PATH)/opae:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) - -run-xrt: $(PROJECT) kernel.pocl -ifeq ($(TARGET), hw) - SCOPE_JSON_PATH=$(FPGA_BIN_DIR)/scope.json XRT_INI_PATH=$(XRT_SYN_DIR)/xrt.ini EMCONFIG_PATH=$(FPGA_BIN_DIR) XRT_DEVICE_INDEX=$(XRT_DEVICE_INDEX) XRT_XCLBIN_PATH=$(FPGA_BIN_DIR)/vortex_afu.xclbin LD_LIBRARY_PATH=$(XILINX_XRT)/lib:$(POCL_RT_PATH)/lib:$(VORTEX_RT_PATH)/xrt:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) -else - XCL_EMULATION_MODE=$(TARGET) XRT_INI_PATH=$(XRT_SYN_DIR)/xrt.ini EMCONFIG_PATH=$(FPGA_BIN_DIR) XRT_DEVICE_INDEX=$(XRT_DEVICE_INDEX) XRT_XCLBIN_PATH=$(FPGA_BIN_DIR)/vortex_afu.xclbin LD_LIBRARY_PATH=$(XILINX_XRT)/lib:$(POCL_RT_PATH)/lib:$(VORTEX_RT_PATH)/xrt:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) -endif - -.depend: $(SRCS) - $(CXX) $(CXXFLAGS) -MM $^ > .depend; - -clean: - rm -rf $(PROJECT) *.o .depend - -clean-all: clean - rm -rf *.dump *.pocl - -ifneq ($(MAKECMDGOALS),clean) - -include .depend -endif diff --git a/tests/opencl/convolution/Makefile b/tests/opencl/convolution/Makefile deleted file mode 100644 index 42a577d2..00000000 --- a/tests/opencl/convolution/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = convolution - -SRCS = main.cc - -OPTS ?= -n32 - -include ../common.mk diff --git a/tests/opencl/convolution/kernel.cl b/tests/opencl/convolution/kernel.cl deleted file mode 100644 index 2ef31040..00000000 --- a/tests/opencl/convolution/kernel.cl +++ /dev/null @@ -1,32 +0,0 @@ -__kernel void conv3x3(__global float* output, - __global float* input, - __global float* weights, - const int width, - const int height) -{ - int x = get_global_id(0); - int y = get_global_id(1); - - // Adjust for padded borders - int paddedWidth = width + 2; - int paddedX = x + 1; - int paddedY = y + 1; - - // Compute the convolution sum - float sum = 0.0f; - - sum += input[(paddedY - 1) * paddedWidth + (paddedX - 1)] * weights[0]; // Top-left - sum += input[(paddedY - 1) * paddedWidth + paddedX] * weights[1]; // Top-center - sum += input[(paddedY - 1) * paddedWidth + (paddedX + 1)] * weights[2]; // Top-right - - sum += input[paddedY * paddedWidth + (paddedX - 1)] * weights[3]; // Middle-left - sum += input[paddedY * paddedWidth + paddedX] * weights[4]; // Center - sum += input[paddedY * paddedWidth + (paddedX + 1)] * weights[5]; // Middle-right - - sum += input[(paddedY + 1) * paddedWidth + (paddedX - 1)] * weights[6]; // Bottom-left - sum += input[(paddedY + 1) * paddedWidth + paddedX] * weights[7]; // Bottom-center - sum += input[(paddedY + 1) * paddedWidth + (paddedX + 1)] * weights[8]; // Bottom-right - - // Store the result in the output array - output[y * width + x] = sum; -} \ No newline at end of file diff --git a/tests/opencl/convolution/main.cc b/tests/opencl/convolution/main.cc deleted file mode 100644 index dded468f..00000000 --- a/tests/opencl/convolution/main.cc +++ /dev/null @@ -1,285 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FLOAT_ULP 6 - -#define KERNEL_NAME "conv3x3" - -#define CL_CHECK(_expr) \ - do { \ - cl_int _err = _expr; \ - if (_err == CL_SUCCESS) \ - break; \ - printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ - cleanup(); \ - exit(-1); \ - } while (0) - -#define CL_CHECK2(_expr) \ - ({ \ - cl_int _err = CL_INVALID_VALUE; \ - decltype(_expr) _ret = _expr; \ - if (_err != CL_SUCCESS) { \ - printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ - cleanup(); \ - exit(-1); \ - } \ - _ret; \ - }) - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - -static int write_operand_file(const char* filename, void* data, size_t size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "wb"); - if (NULL == fp) { - fprintf(stderr, "Failed to write operand data.\n"); - return -1; - } - - size_t wsize = fwrite(data, size, 1, fp); - if (wsize != 1) { - fprintf(stderr, "Failed to write operand data.\n"); - return -1; - } - - fclose(fp); - - return 0; -} - -static bool compare_equal(float a, float b) { - union fi_t { float f; int32_t i; }; - fi_t fa, fb; - fa.f = a; - fb.f = b; - auto d = std::abs(fa.i - fb.i); - return d <= FLOAT_ULP; -} - -static void convolution_cpu(float *O, float *I, float *W, int32_t width, int32_t height) { - int paddedWidth = width + 2; - for (int32_t y = 0; y < height; ++y) { - for (int32_t x = 0; x < width; ++x) { - int paddedY = y + 1; - int paddedX = x + 1; - float sum = 0.0f; - for (int32_t ky = -1; ky <= 1; ++ky) { - for (int32_t kx = -1; kx <= 1; ++kx) { - int32_t iy = paddedY + ky; - int32_t ix = paddedX + kx; - float value = I[iy * paddedWidth + ix]; - float weight = W[(ky + 1) * 3 + (kx + 1)]; - sum += value * weight; - } - } - O[y * width + x] = sum; - } - } -} - -cl_device_id device_id = NULL; -cl_context context = NULL; -cl_command_queue commandQueue = NULL; -cl_program program = NULL; -cl_kernel kernel = NULL; -cl_mem i_memobj = NULL; -cl_mem w_memobj = NULL; -cl_mem o_memobj = NULL; -uint8_t* kernel_bin = NULL; - -static void cleanup() { - if (commandQueue) clReleaseCommandQueue(commandQueue); - if (kernel) clReleaseKernel(kernel); - if (program) clReleaseProgram(program); - if (i_memobj) clReleaseMemObject(i_memobj); - if (w_memobj) clReleaseMemObject(w_memobj); - if (o_memobj) clReleaseMemObject(o_memobj); - if (context) clReleaseContext(context); - if (device_id) clReleaseDevice(device_id); - if (kernel_bin) free(kernel_bin); -} - -int size = 32; - -static void show_usage() { - printf("Usage: [-n size] [-h: help]\n"); -} - -static void parse_args(int argc, char **argv) { - int c; - while ((c = getopt(argc, argv, "n:h?")) != -1) { - switch (c) { - case 'n': - size = atoi(optarg); - break; - case 'h': - case '?': { - show_usage(); - exit(0); - } break; - default: - show_usage(); - exit(-1); - } - } -} - -int main (int argc, char **argv) { - // parse command arguments - parse_args(argc, argv); - - printf("Matrix size=%d\n", size); - - uint32_t o_points = size * size; - uint32_t i_points = (size+2) * (size+2); - uint32_t w_points = 3 * 3; - - cl_platform_id platform_id; - size_t kernel_size; - - // Getting platform and device information - CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); - CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); - - printf("Create context\n"); - context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); - - char device_string[1024]; - clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - printf("Using device: %s\n", device_string); - - printf("Allocate device buffers\n"); - size_t i_nbytes = i_points * sizeof(float); - size_t w_nbytes = w_points * sizeof(float); - size_t o_nbytes = o_points * sizeof(float); - i_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, i_nbytes, NULL, &_err)); - w_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, w_nbytes, NULL, &_err)); - o_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, o_nbytes, NULL, &_err)); - - printf("Create program from kernel source\n"); -#ifdef HOSTGPU - if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) - return -1; - program = CL_CHECK2(clCreateProgramWithSource( - context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); -#else - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; - program = CL_CHECK2(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); -#endif - if (program == NULL) { - cleanup(); - return -1; - } - - // Build program - CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); - - // Create kernel - kernel = CL_CHECK2(clCreateKernel(program, KERNEL_NAME, &_err)); - - size_t global_size[2] = {size, size}; - - // Set kernel arguments - CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&o_memobj)); - CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&i_memobj)); - CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&w_memobj)); - CL_CHECK(clSetKernelArg(kernel, 3, sizeof(uint32_t), &size)); - CL_CHECK(clSetKernelArg(kernel, 4, sizeof(uint32_t), &size)); - - // Allocate memories for input arrays and output arrays. - std::vector h_i(i_points); - std::vector h_w(w_points); - std::vector h_o(o_points, 0.0f); - - // Generate input values - for (int32_t y = -1; y < size+1; ++y) { - for (int32_t x = -1; x < size+1; ++x) { - if (x >= 0 && x < size && y >= 0 && y < size) { - h_i[(y+1) * (size+2) + (x+1)] = static_cast(rand()) / RAND_MAX; - } else { - h_i[(y+1) * (size+2) + (x+1)] = 0; - } - } - } - for (uint32_t i = 0; i < w_points; ++i) { - h_w[i] = static_cast(rand()) / RAND_MAX; - } - - // NOTE(hansung): Dump operand buffer to a file - if (write_operand_file("convolution.input.input.bin", h_i.data(), i_nbytes) != 0) - return EXIT_FAILURE; - if (write_operand_file("convolution.input.weights.bin", h_w.data(), w_nbytes) != 0) - return EXIT_FAILURE; - - // Creating command queue - commandQueue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - - printf("Upload source buffers\n"); - CL_CHECK(clEnqueueWriteBuffer(commandQueue, i_memobj, CL_TRUE, 0, i_nbytes, h_i.data(), 0, NULL, NULL)); - CL_CHECK(clEnqueueWriteBuffer(commandQueue, w_memobj, CL_TRUE, 0, w_nbytes, h_w.data(), 0, NULL, NULL)); - - printf("Execute the kernel\n"); - auto time_start = std::chrono::high_resolution_clock::now(); - CL_CHECK(clEnqueueNDRangeKernel(commandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL)); - CL_CHECK(clFinish(commandQueue)); - auto time_end = std::chrono::high_resolution_clock::now(); - double elapsed = std::chrono::duration_cast(time_end - time_start).count(); - printf("Elapsed time: %lg ms\n", elapsed); - - printf("Download destination buffer\n"); - CL_CHECK(clEnqueueReadBuffer(commandQueue, o_memobj, CL_TRUE, 0, o_nbytes, h_o.data(), 0, NULL, NULL)); - - printf("Verify result\n"); - std::vector ref_vec(o_points); - convolution_cpu(ref_vec.data(), h_i.data(), h_w.data(), size, size); - int errors = 0; - for (uint32_t i = 0; i < o_points; ++i) { - if (!compare_equal(h_o[i], ref_vec[i])) { - if (errors < 100) - printf("*** error: [%d] expected=%f, actual=%f\n", i, ref_vec[i], h_o[i]); - ++errors; - } - } - if (errors != 0) { - printf("FAILED! - %d errors\n", errors); - } else { - printf("PASSED!\n"); - } - - // Clean up - cleanup(); - - return errors; -} diff --git a/tests/opencl/dotproduct/DotProduct.cl b/tests/opencl/dotproduct/DotProduct.cl deleted file mode 100644 index dce00ec6..00000000 --- a/tests/opencl/dotproduct/DotProduct.cl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - - __kernel void DotProduct (__global float* a, __global float* b, __global float* c, int iNumElements) -{ - // find position in global arrays - int iGID = get_global_id(0); - - // bound check (equivalent to the limit on a 'for' loop for standard/serial C code - if (iGID >= iNumElements) - { - return; - } - - // process - int iInOffset = iGID << 2; - c[iGID] = a[iInOffset] * b[iInOffset] - + a[iInOffset + 1] * b[iInOffset + 1] - + a[iInOffset + 2] * b[iInOffset + 2] - + a[iInOffset + 3] * b[iInOffset + 3]; -} diff --git a/tests/opencl/dotproduct/Makefile b/tests/opencl/dotproduct/Makefile deleted file mode 100644 index 02f71828..00000000 --- a/tests/opencl/dotproduct/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = dotproduct - -SRCS = main.cc oclUtils.cpp shrUtils.cpp cmd_arg_reader.cpp - -OPTS ?= -n64 - -include ../common.mk diff --git a/tests/opencl/dotproduct/cmd_arg_reader.cpp b/tests/opencl/dotproduct/cmd_arg_reader.cpp deleted file mode 100644 index 9b7f91ef..00000000 --- a/tests/opencl/dotproduct/cmd_arg_reader.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -/* CUda UTility Library */ - -// includes, file -#include "cmd_arg_reader.h" - -// includes, system -#include - -// internal unnamed namespace - -namespace -{ - // types, internal (class, enum, struct, union, typedef) - - // variables, internal - -} // namespace { - -// variables, exported - -/*static*/ CmdArgReader* CmdArgReader::self; -/*static*/ char** CmdArgReader::rargv; -/*static*/ int CmdArgReader::rargc; - -// functions, exported - -//////////////////////////////////////////////////////////////////////////////// -//! Public construction interface -//! @return a handle to the class instance -//! @param argc number of command line arguments (as given to main()) -//! @param argv command line argument string (as given to main()) -//////////////////////////////////////////////////////////////////////////////// -/*static*/ void -CmdArgReader::init( const int argc, const char** argv) -{ - if ( NULL != self) - { - return; - } - - // command line arguments - if (( 0 == argc) || ( 0 == argv)) - { - LOGIC_EXCEPTION( "No command line arguments given."); - } - - self = new CmdArgReader(); - - self->createArgsMaps( argc, argv); - - rargc = argc; - rargv = const_cast( argv); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, default -//////////////////////////////////////////////////////////////////////////////// -CmdArgReader::CmdArgReader() : - args(), - unprocessed(), - iter(), - iter_unprocessed() -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Destructor -//////////////////////////////////////////////////////////////////////////////// -CmdArgReader::~CmdArgReader() -{ - for( iter = args.begin(); iter != args.end(); ++iter) - { - if( *(iter->second.first) == typeid( int)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( bool)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::string)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::vector< std::string>) ) - { - delete static_cast< std::vector< std::string>* >( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::vector) ) - { - delete static_cast< std::vector* >( iter->second.second); - break; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read args as token value pair into map for better processing (Even the -//! values remain strings until the parameter values is requested by the -//! program.) -//! @param argc the argument count (as given to 'main') -//! @param argv the char* array containing the command line arguments -//////////////////////////////////////////////////////////////////////////////// -void -CmdArgReader::createArgsMaps( const int argc, const char** argv) { - - std::string token; - std::string val_str; - - std::map< std::string, std::string> args; - - std::string::size_type pos; - std::string arg; - for( int i=1; i - inline const T* getArgHelper( const std::string& name); - - //! Check if a command line argument with name \a name exists - //! @return true if a command line argument of name \a name exists, - //! otherwise false - //! @param name the name of the requested argument - inline bool existArgHelper( const std::string& name) const; - - //! Read args as token value pair into map for better processing - //! (Even the values remain strings until the parameter values is - //! requested by the program.) - //! @param argc the argument count (as given to 'main') - //! @param argv the char* array containing the command line arguments - void createArgsMaps( const int argc, const char** argv); - - //! Helper for "casting" the strings from the map with the unprocessed - //! values to the correct - //! data type. - //! @return true if conversion succeeded, otherwise false - //! @param element the value as string - //! @param val the value as type T - template - static inline bool convertToT( const std::string& element, T& val); - -public: - - // typedefs internal - - //! container for a processed command line argument - //! typeid is used to easily be able to decide if a re-requested token-value - //! pair match the type of the first conversion - typedef std::pair< const std::type_info*, void*> ValType; - //! map of already converted values - typedef std::map< std::string, ValType > ArgsMap; - //! iterator for the map of already converted values - typedef ArgsMap::iterator ArgsMapIter; - typedef ArgsMap::const_iterator ConstArgsMapIter; - - //! map of unprocessed (means unconverted) token-value pairs - typedef std::map< std::string, std::string> UnpMap; - //! iterator for the map of unprocessed (means unconverted) token-value pairs - typedef std::map< std::string, std::string>::iterator UnpMapIter; - -private: - -#ifdef _WIN32 -# pragma warning( disable: 4251) -#endif - - //! rargc original value of argc - static int rargc; - - //! rargv contains command line arguments in raw format - static char** rargv; - - //! args Map containing the already converted token-value pairs - ArgsMap args; - - //! args Map containing the unprocessed / unconverted token-value pairs - UnpMap unprocessed; - - //! iter Iterator for the map with the already converted token-value - //! pairs (to avoid frequent reallocation) - ArgsMapIter iter; - - //! iter Iterator for the map with the unconverted token-value - //! pairs (to avoid frequent reallocation) - UnpMapIter iter_unprocessed; - -#ifdef _WIN32 -# pragma warning( default: 4251) -#endif - -private: - - //! Constructor, copy (not implemented) - CmdArgReader( const CmdArgReader&); - - //! Assignment operator (not implemented) - CmdArgReader& operator=( const CmdArgReader&); -}; - -// variables, exported (extern) - -// functions, inlined (inline) - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line argument arrays -//! @note This function is used each type for which no template specialization -//! exist (which will cause errors if the type does not fulfill the std::vector -//! interface). -//////////////////////////////////////////////////////////////////////////////// -template -/*static*/ inline bool -CmdArgReader::convertToT( const std::string& element, T& val) -{ - // preallocate storage - val.resize( std::count( element.begin(), element.end(), ',') + 1); - - unsigned int i = 0; - std::string::size_type pos_start = 1; // leave array prefix '[' - std::string::size_type pos_end = 0; - - // do for all elements of the comma seperated list - while( std::string::npos != ( pos_end = element.find(',', pos_end+1)) ) - { - // convert each element by the appropriate function - if ( ! convertToT< typename T::value_type >( - std::string( element, pos_start, pos_end - pos_start), val[i])) - { - return false; - } - - pos_start = pos_end + 1; - ++i; - } - - std::string tmp1( element, pos_start, element.length() - pos_start - 1); - - // process last element (leave array postfix ']') - if ( ! convertToT< typename T::value_type >( std::string( element, - pos_start, - element.length() - pos_start - 1), - val[i])) - { - return false; - } - - // possible to process all elements? - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type int -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, int& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type float -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, float& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type double -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, double& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type string -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, - std::string& val) -{ - val = element; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type bool -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, bool& val) -{ - // check if value is given as string-type { true | false } - if ( "true" == element) - { - val = true; - return true; - } - else if ( "false" == element) - { - val = false; - return true; - } - // check if argument is given as integer { 0 | 1 } - else - { - int tmp; - if ( convertToT( element, tmp)) - { - if ( 1 == tmp) - { - val = true; - return true; - } - else if ( 0 == tmp) - { - val = false; - return true; - } - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of the command line argument with given name -//! @return A const handle to the requested argument. If the argument does -//! not exist or if it is not from type T NULL is returned -//! @param T the type of the argument requested -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -template -/*static*/ const T* -CmdArgReader::getArg( const std::string& name) -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getArg(): CmdArgReader not initialized."); - return NULL; - } - - return self->getArgHelper( name); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Check if a command line argument with the given name exists -//! @return true if a command line argument with name \a name exists, -//! otherwise false -//! @param name name of the command line argument in question -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline bool -CmdArgReader::existArg( const std::string& name) -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getArg(): CmdArgReader not initialized."); - return false; - } - - return self->existArgHelper( name); -} - -//////////////////////////////////////////////////////////////////////////////// -//! @brief Get the value of the command line argument with given name -//! @return A const handle to the requested argument. If the argument does -//! not exist or if it is not from type T NULL is returned -//! @param T the type of the argument requested -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -template -const T* -CmdArgReader::getArgHelper( const std::string& name) -{ - // check if argument already processed and stored in correct type - if ( args.end() != (iter = args.find( name))) - { - if ( (*(iter->second.first)) == typeid( T) ) - { - return (T*) iter->second.second; - } - } - else - { - T* tmp = new T; - - // check the array with unprocessed values - if ( unprocessed.end() != (iter_unprocessed = unprocessed.find( name))) - { - // try to "cast" the string to the type requested - if ( convertToT< T >( iter_unprocessed->second, *tmp)) - { - // add the token element pair to map of already converted values - args[name] = std::make_pair( &(typeid( T)), (void*) tmp); - - return tmp; - } - } - - // not used while not inserted into the map -> cleanup - delete tmp; - } - - // failed, argument not available - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Check if a command line argument with name \a name exists -//! @return true if a command line argument of name \a name exists, -//! otherwise false -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -inline bool -CmdArgReader::existArgHelper( const std::string& name) const -{ - bool ret_val = false; - - // check if argument already processed and stored in correct type - if( args.end() != args.find( name)) - { - ret_val = true; - } - else - { - - // check the array with unprocessed values - if ( unprocessed.end() != unprocessed.find( name)) - { - ret_val = true; - } - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the original / raw argc program argument -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline int& -CmdArgReader::getRArgc() -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getRArgc(): CmdArgReader not initialized."); - } - - return rargc; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the original / raw argv program argument -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline char**& -CmdArgReader::getRArgv() -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getRArgc(): CmdArgReader not initialized."); - } - - return rargv; -} - -// functions, exported (extern) - -#endif // #ifndef _CMDARGREADER_H_ diff --git a/tests/opencl/dotproduct/exception.h b/tests/opencl/dotproduct/exception.h deleted file mode 100644 index e4650d99..00000000 --- a/tests/opencl/dotproduct/exception.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -/* CUda UTility Library */ -#ifndef _EXCEPTION_H_ -#define _EXCEPTION_H_ - -// includes, system -#include -#include -#include -#include - -//! Exception wrapper. -//! @param Std_Exception Exception out of namespace std for easy typing. -template -class Exception : public Std_Exception -{ -public: - - //! @brief Static construction interface - //! @return Alwayss throws ( Located_Exception) - //! @param file file in which the Exception occurs - //! @param line line in which the Exception occurs - //! @param detailed details on the code fragment causing the Exception - static void throw_it( const char* file, - const int line, - const char* detailed = "-" ); - - //! Static construction interface - //! @return Alwayss throws ( Located_Exception) - //! @param file file in which the Exception occurs - //! @param line line in which the Exception occurs - //! @param detailed details on the code fragment causing the Exception - static void throw_it( const char* file, - const int line, - const std::string& detailed); - - //! Destructor - virtual ~Exception() throw(); - -private: - - //! Constructor, default (private) - Exception(); - - //! Constructor, standard - //! @param str string returned by what() - Exception( const std::string& str); - -}; - -//////////////////////////////////////////////////////////////////////////////// -//! Exception handler function for arbitrary exceptions -//! @param ex exception to handle -//////////////////////////////////////////////////////////////////////////////// -template -inline void -handleException( const Exception_Typ& ex) -{ - std::cerr << ex.what() << std::endl; - - exit( EXIT_FAILURE); -} - -//! Convenience macros - -//! Exception caused by dynamic program behavior, e.g. file does not exist -#define RUNTIME_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//! Logic exception in program, e.g. an assert failed -#define LOGIC_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//! Out of range exception -#define RANGE_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//////////////////////////////////////////////////////////////////////////////// -//! Implementation - -// includes, system -#include - -//////////////////////////////////////////////////////////////////////////////// -//! Static construction interface. -//! @param Exception causing code fragment (file and line) and detailed infos. -//////////////////////////////////////////////////////////////////////////////// -/*static*/ template -void -Exception:: -throw_it( const char* file, const int line, const char* detailed) -{ - std::stringstream s; - - // Quiet heavy-weight but exceptions are not for - // performance / release versions - s << "Exception in file '" << file << "' in line " << line << "\n" - << "Detailed description: " << detailed << "\n"; - - throw Exception( s.str()); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Static construction interface. -//! @param Exception causing code fragment (file and line) and detailed infos. -//////////////////////////////////////////////////////////////////////////////// -/*static*/ template -void -Exception:: -throw_it( const char* file, const int line, const std::string& msg) -{ - throw_it( file, line, msg.c_str()); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, default (private). -//////////////////////////////////////////////////////////////////////////////// -template -Exception::Exception() : - Exception("Unknown Exception.\n") -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, standard (private). -//! String returned by what(). -//////////////////////////////////////////////////////////////////////////////// -template -Exception::Exception( const std::string& s) : - Std_Exception( s) -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Destructor -//////////////////////////////////////////////////////////////////////////////// -template -Exception::~Exception() throw() { } - -// functions, exported - -#endif // #ifndef _EXCEPTION_H_ - diff --git a/tests/opencl/dotproduct/kernel.cl b/tests/opencl/dotproduct/kernel.cl deleted file mode 100644 index a0f01334..00000000 --- a/tests/opencl/dotproduct/kernel.cl +++ /dev/null @@ -1,22 +0,0 @@ -__kernel void DotProduct (__global float* a, __global float* b, __global float* c, int iNumElements) -{ - // find position in global arrays - int iGID = get_global_id(0); - - // bound check (equivalent to the limit on a 'for' loop for standard/serial C code - //printf("%d, %d\n", iGID, iNumElements); - if (iGID >= iNumElements) - { - return; - } - - // process - int iInOffset = iGID << 2; - c[iGID] = a[iInOffset] * b[iInOffset] - + a[iInOffset + 1] * b[iInOffset + 1] - + a[iInOffset + 2] * b[iInOffset + 2] - + a[iInOffset + 3] * b[iInOffset + 3]; - //float cc = c[iGID]; - - //printf("c[%d]=%f\n", iGID, cc); -} \ No newline at end of file diff --git a/tests/opencl/dotproduct/main.cc b/tests/opencl/dotproduct/main.cc deleted file mode 100644 index 9116c5e3..00000000 --- a/tests/opencl/dotproduct/main.cc +++ /dev/null @@ -1,267 +0,0 @@ -////////////////////////////////////////////////////////////////////////// -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// oclDotProduct Notes: -// -// A simple OpenCL API demo application that implements a -// vector dot product computation between 2 float arrays. -// -// Runs computations with OpenCL on the GPU device and then checks results -// against basic host CPU/C++ computation. -// -// Uses 'shr' and 'ocl' functions from oclUtils and shrUtils libraries for compactness. -// But these are NOT required libs for OpenCL developement in general. -// ********************************************************************* - -// standard utilities and systems includes - -#include "oclUtils.h" -#include "shrQATest.h" - -// Name of the file with the source code for the computation kernel -// ********************************************************************* -const char* cSourceFile = "kernel.pocl"; - -// Host buffers for demo -// ********************************************************************* -void *srcA, *srcB, *dst; // Host buffers for OpenCL test -void* Golden; // Host buffer for host golden processing cross check - -// OpenCL Vars -cl_platform_id cpPlatform; // OpenCL platform -cl_device_id *cdDevices; // OpenCL device -cl_context cxGPUContext; // OpenCL context -cl_command_queue cqCommandQueue;// OpenCL command que -cl_program program; // OpenCL program -cl_kernel ckKernel; // OpenCL kernel -cl_mem cmDevSrcA; // OpenCL device source buffer A -cl_mem cmDevSrcB; // OpenCL device source buffer B -cl_mem cmDevDst; // OpenCL device destination buffer -size_t szGlobalWorkSize; // Total # of work items in the 1D range -size_t szLocalWorkSize; // # of work items in the 1D work group -size_t szParmDataBytes; // Byte size of context information -size_t szKernelLength; // Byte size of kernel code -cl_int ciErrNum; // Error code var -char* cPathAndName = NULL; // var for full paths to data, src, etc. -char* cSourceCL = NULL; // Buffer to hold source for compilation -const char* cExecutableName = NULL; - -// demo config vars -int iNumElements= 1024; // Length of float arrays to process (odd # for illustration) -shrBOOL bNoPrompt = shrFALSE; - -// Forward Declarations -// ********************************************************************* -void DotProductHost(const float* pfData1, const float* pfData2, float* pfResult, int iNumElements); -void Cleanup (int iExitCode); -void (*pCleanup)(int) = &Cleanup; - -int *gp_argc = NULL; -char ***gp_argv = NULL; - -// Main function -// ********************************************************************* -int main(int argc, char **argv) -{ - gp_argc = &argc; - gp_argv = &argv; - - shrQAStart(argc, argv); - - cl_uint uiNumComputeUnits; - - ciErrNum = clGetPlatformIDs(1, &cpPlatform, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - - cl_uint uiNumDevices = 1; - cdDevices = (cl_device_id *)malloc(uiNumDevices * sizeof(cl_device_id)); - cl_uint uiTargetDevice = 0; - ciErrNum = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_DEFAULT, 1, &cdDevices[uiTargetDevice], NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - - - // Get command line device options and config accordingly - shrLog(" # of Devices Available = %u\n", uiNumDevices); - if(shrGetCmdLineArgumentu(argc, (const char**)argv, "device", &uiTargetDevice)== shrTRUE) - { - uiTargetDevice = CLAMP(uiTargetDevice, 0, (uiNumDevices - 1)); - } - shrLog(" Using Device %u: ", uiTargetDevice); - oclPrintDevName(LOGBOTH, cdDevices[uiTargetDevice]); - ciErrNum = clGetDeviceInfo(cdDevices[uiTargetDevice], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(uiNumComputeUnits), &uiNumComputeUnits, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, NULL); - shrLog("\n # of Compute Units = %u\n", uiNumComputeUnits); - - // get command line arg for quick test, if provided - bNoPrompt = shrCheckCmdLineFlag(argc, (const char**)argv, "noprompt"); - - // start logs - cExecutableName = argv[0]; - shrSetLogFileName ("oclDotProduct.txt"); - shrLog("%s Starting...\n\n# of float elements per Array \t= %u\n", argv[0], iNumElements); - - // set and log Global and Local work size dimensions - szLocalWorkSize = 16; - szGlobalWorkSize = shrRoundUp((int)szLocalWorkSize, iNumElements); // rounded up to the nearest multiple of the LocalWorkSize - shrLog("Global Work Size \t\t= %u\nLocal Work Size \t\t= %u\n# of Work Groups \t\t= %u\n\n", - szGlobalWorkSize, szLocalWorkSize, (szGlobalWorkSize % szLocalWorkSize + szGlobalWorkSize/szLocalWorkSize)); - - // Allocate and initialize host arrays - shrLog( "Allocate and Init Host Mem...\n"); - srcA = (void *)malloc(sizeof(cl_float4) * szGlobalWorkSize); - srcB = (void *)malloc(sizeof(cl_float4) * szGlobalWorkSize); - dst = (void *)malloc(sizeof(cl_float) * szGlobalWorkSize); - Golden = (void *)malloc(sizeof(cl_float) * iNumElements); - shrFillArray((float*)srcA, 4 * iNumElements); - shrFillArray((float*)srcB, 4 * iNumElements); - - // Get the NVIDIA platform - ciErrNum = oclGetPlatformID(&cpPlatform); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Get a GPU device - ciErrNum = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_DEFAULT, 1, &cdDevices[uiTargetDevice], NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Create the context - cxGPUContext = clCreateContext(0, 1, &cdDevices[uiTargetDevice], NULL, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Create a command-queue - shrLog("clCreateCommandQueue...\n"); - cqCommandQueue = clCreateCommandQueue(cxGPUContext, cdDevices[uiTargetDevice], 0, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Allocate the OpenCL buffer memory objects for source and result on the device GMEM - shrLog("clCreateBuffer (SrcA, SrcB and Dst in Device GMEM)...\n"); - cmDevSrcA = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize * 4, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cmDevSrcB = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize * 4, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cmDevDst = clCreateBuffer(cxGPUContext, CL_MEM_WRITE_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Read the OpenCL kernel in from source file - shrLog("oclLoadProgSource (%s)...\n", cSourceFile); - cPathAndName = shrFindFilePath(cSourceFile, argv[0]); - oclCheckErrorEX(cPathAndName != NULL, shrTRUE, pCleanup); - cSourceCL = oclLoadProgSource(cPathAndName, "", &szKernelLength); - oclCheckErrorEX(cSourceCL != NULL, shrTRUE, pCleanup); - - // Create the program - shrLog("clCreateProgramWithSource...\n"); - cl_int binary_status; - cl_program program = - clCreateProgramWithBinary(cxGPUContext, 1, cdDevices, &szKernelLength, (const uint8_t**)&cSourceCL, &binary_status, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - // Build the program with 'mad' Optimization option - #ifdef MAC - char* flags = "-cl-fast-relaxed-math -DMAC"; - #else - char* flags = "-cl-fast-relaxed-math"; - #endif - shrLog("clBuildProgram...\n"); - ciErrNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL); - if (ciErrNum != CL_SUCCESS) - { - // write out standard error, Build Log and PTX, then cleanup and exit - shrLogEx(LOGBOTH | ERRORMSG, ciErrNum, STDERROR); - oclLogBuildInfo(program, oclGetFirstDev(cxGPUContext)); - oclLogPtx(program, oclGetFirstDev(cxGPUContext), "oclDotProduct.ptx"); - Cleanup(EXIT_FAILURE); - } - - // Create the kernel - shrLog("clCreateKernel (nDotProduct)...\n"); - ckKernel = clCreateKernel(program, "DotProduct", &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Set the Argument values - shrLog("clSetKernelArg 0 - 3...\n\n"); - ciErrNum = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), (void*)&cmDevSrcA); - ciErrNum |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), (void*)&cmDevSrcB); - ciErrNum |= clSetKernelArg(ckKernel, 2, sizeof(cl_mem), (void*)&cmDevDst); - ciErrNum |= clSetKernelArg(ckKernel, 3, sizeof(cl_int), (void*)&iNumElements); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // -------------------------------------------------------- - // Core sequence... copy input data to GPU, compute, copy results back - - // Asynchronous write of data to GPU device - shrLog("clEnqueueWriteBuffer (SrcA and SrcB)...\n"); - ciErrNum = clEnqueueWriteBuffer(cqCommandQueue, cmDevSrcA, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize * 4, srcA, 0, NULL, NULL); - ciErrNum |= clEnqueueWriteBuffer(cqCommandQueue, cmDevSrcB, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize * 4, srcB, 0, NULL, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Launch kernel - shrLog("clEnqueueNDRangeKernel (DotProduct)...\n"); - ciErrNum = clEnqueueNDRangeKernel(cqCommandQueue, ckKernel, 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Read back results and check accumulated errors - shrLog("clEnqueueReadBuffer (Dst)...\n\n"); - ciErrNum = clEnqueueReadBuffer(cqCommandQueue, cmDevDst, CL_TRUE, 0, sizeof(cl_float) * szGlobalWorkSize, dst, 0, NULL, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Compute and compare results for golden-host and report errors and pass/fail - shrLog("Comparing against Host/C++ computation...\n\n"); - DotProductHost ((const float*)srcA, (const float*)srcB, (float*)Golden, iNumElements); - shrBOOL bMatch = shrComparefet((const float*)Golden, (const float*)dst, (unsigned int)iNumElements, 0.0f, 0); - - // Cleanup and leave - Cleanup (EXIT_SUCCESS); - - return (bMatch == shrTRUE) ? 0 : 1; -} - -// "Golden" Host processing dot product function for comparison purposes -// ********************************************************************* -void DotProductHost(const float* pfData1, const float* pfData2, float* pfResult, int iNumElements) -{ - int i, j, k; - for (i = 0, j = 0; i < iNumElements; i++) - { - pfResult[i] = 0.0f; - for (k = 0; k < 4; k++, j++) - { - pfResult[i] += pfData1[j] * pfData2[j]; - } - } -} - -// Cleanup and exit code -// ********************************************************************* -void Cleanup(int iExitCode) -{ - // Cleanup allocated objects - shrLog("Starting Cleanup...\n\n"); - if(cPathAndName)free(cPathAndName); - if(cSourceCL)free(cSourceCL); - if(ckKernel)clReleaseKernel(ckKernel); - if(program)clReleaseProgram(program); - if(cqCommandQueue)clReleaseCommandQueue(cqCommandQueue); - if(cxGPUContext)clReleaseContext(cxGPUContext); - if (cmDevSrcA)clReleaseMemObject(cmDevSrcA); - if (cmDevSrcB)clReleaseMemObject(cmDevSrcB); - if (cmDevDst)clReleaseMemObject(cmDevDst); - - // Free host memory - free(srcA); - free(srcB); - free (dst); - free(Golden); - - if (cdDevices) free(cdDevices); - - shrQAFinishExit(*gp_argc, (const char **)*gp_argv, (iExitCode == EXIT_SUCCESS) ? QA_PASSED : QA_FAILED); -} \ No newline at end of file diff --git a/tests/opencl/dotproduct/oclUtils.cpp b/tests/opencl/dotproduct/oclUtils.cpp deleted file mode 100644 index 7a238b55..00000000 --- a/tests/opencl/dotproduct/oclUtils.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// Utilities specific to OpenCL samples in NVIDIA GPU Computing SDK -// ********************************************************************* - -#include -#include -#include -#include -#include -#include "oclUtils.h" - -////////////////////////////////////////////////////////////////////////////// -//! Gets the platform ID for NVIDIA if available, otherwise default -//! -//! @return the id -//! @param clSelectedPlatformID OpenCL platoform ID -////////////////////////////////////////////////////////////////////////////// -cl_int oclGetPlatformID(cl_platform_id* clSelectedPlatformID) -{ - char chBuffer[1024]; - cl_uint num_platforms; - cl_platform_id* clPlatformIDs; - cl_int ciErrNum; - *clSelectedPlatformID = NULL; - - // Get OpenCL platform count - ciErrNum = clGetPlatformIDs (0, NULL, &num_platforms); - if (ciErrNum != CL_SUCCESS) - { - shrLog(" Error %i in clGetPlatformIDs Call !!!\n\n", ciErrNum); - return -1000; - } - else - { - if(num_platforms == 0) - { - shrLog("No OpenCL platform found!\n\n"); - return -2000; - } - else - { - // if there's a platform or more, make space for ID's - if ((clPlatformIDs = (cl_platform_id*)malloc(num_platforms * sizeof(cl_platform_id))) == NULL) - { - shrLog("Failed to allocate memory for cl_platform ID's!\n\n"); - return -3000; - } - - // get platform info for each platform and trap the NVIDIA platform if found - ciErrNum = clGetPlatformIDs (num_platforms, clPlatformIDs, NULL); - for(cl_uint i = 0; i < num_platforms; ++i) - { - ciErrNum = clGetPlatformInfo (clPlatformIDs[i], CL_PLATFORM_NAME, 1024, &chBuffer, NULL); - if(ciErrNum == CL_SUCCESS) - { - if(strstr(chBuffer, "NVIDIA") != NULL) - { - *clSelectedPlatformID = clPlatformIDs[i]; - break; - } - } - } - - // default to zeroeth platform if NVIDIA not found - if(*clSelectedPlatformID == NULL) - { - shrLog("WARNING: NVIDIA OpenCL platform not found - defaulting to first platform!\n\n"); - *clSelectedPlatformID = clPlatformIDs[0]; - } - - free(clPlatformIDs); - } - } - - return CL_SUCCESS; -} - -////////////////////////////////////////////////////////////////////////////// -//! Print the device name -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -void oclPrintDevName(int iLogMode, cl_device_id device) -{ - char device_string[1024]; - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, "%s", device_string); -} - -////////////////////////////////////////////////////////////////////////////// -//! Print info about the device -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -void oclPrintDevInfo(int iLogMode, cl_device_id device) -{ - char device_string[1024]; - bool nv_device_attibute_query = false; - - // CL_DEVICE_NAME - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_NAME: \t\t\t%s\n", device_string); - - // CL_DEVICE_VENDOR - clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_VENDOR: \t\t\t%s\n", device_string); - - // CL_DRIVER_VERSION - clGetDeviceInfo(device, CL_DRIVER_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DRIVER_VERSION: \t\t\t%s\n", device_string); - - // CL_DEVICE_VERSION - clGetDeviceInfo(device, CL_DEVICE_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_VERSION: \t\t\t%s\n", device_string); - - // CL_DEVICE_OPENCL_C_VERSION (if CL_DEVICE_VERSION version > 1.0) - if(strncmp("OpenCL 1.0", device_string, 10) != 0) - { - // This code is unused for devices reporting OpenCL 1.0, but a def is needed anyway to allow compilation using v 1.0 headers - // This constant isn't #defined in 1.0 - #ifndef CL_DEVICE_OPENCL_C_VERSION - #define CL_DEVICE_OPENCL_C_VERSION 0x103D - #endif - - clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_OPENCL_C_VERSION: \t\t%s\n", device_string); - } - - // CL_DEVICE_TYPE - cl_device_type type; - clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(type), &type, NULL); - if( type & CL_DEVICE_TYPE_CPU ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_CPU"); - if( type & CL_DEVICE_TYPE_GPU ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_GPU"); - if( type & CL_DEVICE_TYPE_ACCELERATOR ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR"); - if( type & CL_DEVICE_TYPE_DEFAULT ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT"); - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_COMPUTE_UNITS:\t\t%u\n", compute_units); - - // CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS - size_t workitem_dims; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(workitem_dims), &workitem_dims, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:\t%u\n", workitem_dims); - - // CL_DEVICE_MAX_WORK_ITEM_SIZES - size_t workitem_size[3]; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(workitem_size), &workitem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%u / %u / %u \n", workitem_size[0], workitem_size[1], workitem_size[2]); - - // CL_DEVICE_MAX_WORK_GROUP_SIZE - size_t workgroup_size; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(workgroup_size), &workgroup_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_GROUP_SIZE:\t%u\n", workgroup_size); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_CLOCK_FREQUENCY:\t%u MHz\n", clock_frequency); - - // CL_DEVICE_ADDRESS_BITS - cl_uint addr_bits; - clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(addr_bits), &addr_bits, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_ADDRESS_BITS:\t\t%u\n", addr_bits); - - // CL_DEVICE_MAX_MEM_ALLOC_SIZE - cl_ulong max_mem_alloc_size; - clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(max_mem_alloc_size), &max_mem_alloc_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_MEM_ALLOC_SIZE:\t\t%u MByte\n", (unsigned int)(max_mem_alloc_size / (1024 * 1024))); - - // CL_DEVICE_GLOBAL_MEM_SIZE - cl_ulong mem_size; - clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_GLOBAL_MEM_SIZE:\t\t%u MByte\n", (unsigned int)(mem_size / (1024 * 1024))); - - // CL_DEVICE_ERROR_CORRECTION_SUPPORT - cl_bool error_correction_support; - clGetDeviceInfo(device, CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof(error_correction_support), &error_correction_support, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_ERROR_CORRECTION_SUPPORT:\t%s\n", error_correction_support == CL_TRUE ? "yes" : "no"); - - // CL_DEVICE_LOCAL_MEM_TYPE - cl_device_local_mem_type local_mem_type; - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_TYPE, sizeof(local_mem_type), &local_mem_type, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_LOCAL_MEM_TYPE:\t\t%s\n", local_mem_type == 1 ? "local" : "global"); - - // CL_DEVICE_LOCAL_MEM_SIZE - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_LOCAL_MEM_SIZE:\t\t%u KByte\n", (unsigned int)(mem_size / 1024)); - - // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE - clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t%u KByte\n", (unsigned int)(mem_size / 1024)); - - // CL_DEVICE_QUEUE_PROPERTIES - cl_command_queue_properties queue_properties; - clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(queue_properties), &queue_properties, NULL); - if( queue_properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) - shrLogEx(iLogMode, 0, " CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"); - if( queue_properties & CL_QUEUE_PROFILING_ENABLE ) - shrLogEx(iLogMode, 0, " CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_PROFILING_ENABLE"); - - // CL_DEVICE_IMAGE_SUPPORT - cl_bool image_support; - clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(image_support), &image_support, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_IMAGE_SUPPORT:\t\t%u\n", image_support); - - // CL_DEVICE_MAX_READ_IMAGE_ARGS - cl_uint max_read_image_args; - clGetDeviceInfo(device, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(max_read_image_args), &max_read_image_args, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_READ_IMAGE_ARGS:\t%u\n", max_read_image_args); - - // CL_DEVICE_MAX_WRITE_IMAGE_ARGS - cl_uint max_write_image_args; - clGetDeviceInfo(device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(max_write_image_args), &max_write_image_args, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WRITE_IMAGE_ARGS:\t%u\n", max_write_image_args); - - // CL_DEVICE_SINGLE_FP_CONFIG - cl_device_fp_config fp_config; - clGetDeviceInfo(device, CL_DEVICE_SINGLE_FP_CONFIG, sizeof(cl_device_fp_config), &fp_config, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_SINGLE_FP_CONFIG:\t\t%s%s%s%s%s%s\n", - fp_config & CL_FP_DENORM ? "denorms " : "", - fp_config & CL_FP_INF_NAN ? "INF-quietNaNs " : "", - fp_config & CL_FP_ROUND_TO_NEAREST ? "round-to-nearest " : "", - fp_config & CL_FP_ROUND_TO_ZERO ? "round-to-zero " : "", - fp_config & CL_FP_ROUND_TO_INF ? "round-to-inf " : "", - fp_config & CL_FP_FMA ? "fma " : ""); - - // CL_DEVICE_IMAGE2D_MAX_WIDTH, CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_DEPTH - size_t szMaxDims[5]; - shrLogEx(iLogMode, 0, "\n CL_DEVICE_IMAGE "); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &szMaxDims[0], NULL); - shrLogEx(iLogMode, 0, "\t\t\t2D_MAX_WIDTH\t %u\n", szMaxDims[0]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &szMaxDims[1], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t2D_MAX_HEIGHT\t %u\n", szMaxDims[1]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &szMaxDims[2], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_WIDTH\t %u\n", szMaxDims[2]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &szMaxDims[3], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_HEIGHT\t %u\n", szMaxDims[3]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &szMaxDims[4], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_DEPTH\t %u\n", szMaxDims[4]); - - // CL_DEVICE_EXTENSIONS: get device extensions, and if any then parse & log the string onto separate lines - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, sizeof(device_string), &device_string, NULL); - if (device_string != 0) - { - shrLogEx(iLogMode, 0, "\n CL_DEVICE_EXTENSIONS:"); - std::string stdDevString; - stdDevString = std::string(device_string); - size_t szOldPos = 0; - size_t szSpacePos = stdDevString.find(' ', szOldPos); // extensions string is space delimited - while (szSpacePos != stdDevString.npos) - { - if( strcmp("cl_nv_device_attribute_query", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()) == 0 ) - nv_device_attibute_query = true; - - if (szOldPos > 0) - { - shrLogEx(iLogMode, 0, "\t\t"); - } - shrLogEx(iLogMode, 0, "\t\t\t%s\n", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()); - - do { - szOldPos = szSpacePos + 1; - szSpacePos = stdDevString.find(' ', szOldPos); - } while (szSpacePos == szOldPos); - } - shrLogEx(iLogMode, 0, "\n"); - } - else - { - shrLogEx(iLogMode, 0, " CL_DEVICE_EXTENSIONS: None\n"); - } - - if(nv_device_attibute_query) - { - cl_uint compute_capability_major, compute_capability_minor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(cl_uint), &compute_capability_major, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, sizeof(cl_uint), &compute_capability_minor, NULL); - shrLogEx(iLogMode, 0, "\n CL_DEVICE_COMPUTE_CAPABILITY_NV:\t%u.%u\n", compute_capability_major, compute_capability_minor); - - shrLogEx(iLogMode, 0, " NUMBER OF MULTIPROCESSORS:\t\t%u\n", compute_units); // this is the same value reported by CL_DEVICE_MAX_COMPUTE_UNITS - shrLogEx(iLogMode, 0, " NUMBER OF CUDA CORES:\t\t\t%u\n", ConvertSMVer2Cores(compute_capability_major, compute_capability_minor) * compute_units); - - cl_uint regs_per_block; - clGetDeviceInfo(device, CL_DEVICE_REGISTERS_PER_BLOCK_NV, sizeof(cl_uint), ®s_per_block, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_REGISTERS_PER_BLOCK_NV:\t%u\n", regs_per_block); - - cl_uint warp_size; - clGetDeviceInfo(device, CL_DEVICE_WARP_SIZE_NV, sizeof(cl_uint), &warp_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_WARP_SIZE_NV:\t\t%u\n", warp_size); - - cl_bool gpu_overlap; - clGetDeviceInfo(device, CL_DEVICE_GPU_OVERLAP_NV, sizeof(cl_bool), &gpu_overlap, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_GPU_OVERLAP_NV:\t\t%s\n", gpu_overlap == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - - cl_bool exec_timeout; - clGetDeviceInfo(device, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, sizeof(cl_bool), &exec_timeout, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV:\t%s\n", exec_timeout == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - - cl_bool integrated_memory; - clGetDeviceInfo(device, CL_DEVICE_INTEGRATED_MEMORY_NV, sizeof(cl_bool), &integrated_memory, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_INTEGRATED_MEMORY_NV:\t%s\n", integrated_memory == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - } - - // CL_DEVICE_PREFERRED_VECTOR_WIDTH_ - shrLogEx(iLogMode, 0, " CL_DEVICE_PREFERRED_VECTOR_WIDTH_\t"); - cl_uint vec_width [6]; - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &vec_width[0], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof(cl_uint), &vec_width[1], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), &vec_width[2], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof(cl_uint), &vec_width[3], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint), &vec_width[4], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &vec_width[5], NULL); - shrLogEx(iLogMode, 0, "CHAR %u, SHORT %u, INT %u, LONG %u, FLOAT %u, DOUBLE %u\n\n\n", - vec_width[0], vec_width[1], vec_width[2], vec_width[3], vec_width[4], vec_width[5]); -} - -////////////////////////////////////////////////////////////////////////////// -//! Get and return device capability -//! -//! @return the 2 digit integer representation of device Cap (major minor). return -1 if NA -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -int oclGetDevCap(cl_device_id device) -{ - char cDevString[1024]; - bool bDevAttributeQuery = false; - int iDevArch = -1; - - // Get device extensions, and if any then search for cl_nv_device_attribute_query - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, sizeof(cDevString), &cDevString, NULL); - if (cDevString != 0) - { - std::string stdDevString; - stdDevString = std::string(cDevString); - size_t szOldPos = 0; - size_t szSpacePos = stdDevString.find(' ', szOldPos); // extensions string is space delimited - while (szSpacePos != stdDevString.npos) - { - if( strcmp("cl_nv_device_attribute_query", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()) == 0 ) - { - bDevAttributeQuery = true; - } - - do { - szOldPos = szSpacePos + 1; - szSpacePos = stdDevString.find(' ', szOldPos); - } while (szSpacePos == szOldPos); - } - } - - // if search succeeded, get device caps - if(bDevAttributeQuery) - { - cl_int iComputeCapMajor, iComputeCapMinor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(cl_uint), (void*)&iComputeCapMajor, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, sizeof(cl_uint), (void*)&iComputeCapMinor, NULL); - iDevArch = (10 * iComputeCapMajor) + iComputeCapMinor; - } - - return iDevArch; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the first device from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetFirstDev(cl_context cxGPUContext) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id first = cdDevices[0]; - free(cdDevices); - - return first; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of device with maximal FLOPS from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetMaxFlopsDev(cl_context cxGPUContext) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - size_t device_count = szParmDataBytes / sizeof(cl_device_id); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id max_flops_device = cdDevices[0]; - int max_flops = 0; - - size_t current_device = 0; - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - - max_flops = compute_units * clock_frequency; - ++current_device; - - while( current_device < device_count ) - { - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - - int flops = compute_units * clock_frequency; - if( flops > max_flops ) - { - max_flops = flops; - max_flops_device = cdDevices[current_device]; - } - ++current_device; - } - - free(cdDevices); - - return max_flops_device; -} - -////////////////////////////////////////////////////////////////////////////// -//! Loads a Program file and prepends the cPreamble to the code. -//! -//! @return the source string if succeeded, 0 otherwise -//! @param cFilename program filename -//! @param cPreamble code that is prepended to the loaded file, typically a set of #defines or a header -//! @param szFinalLength returned length of the code string -////////////////////////////////////////////////////////////////////////////// -char* oclLoadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength) -{ - // locals - FILE* pFileStream = NULL; - size_t szSourceLength; - - // open the OpenCL source code file - #ifdef _WIN32 // Windows version - if(fopen_s(&pFileStream, cFilename, "rb") != 0) - { - return NULL; - } - #else // Linux version - pFileStream = fopen(cFilename, "rb"); - if(pFileStream == 0) - { - return NULL; - } - #endif - - size_t szPreambleLength = strlen(cPreamble); - - // get the length of the source code - fseek(pFileStream, 0, SEEK_END); - szSourceLength = ftell(pFileStream); - fseek(pFileStream, 0, SEEK_SET); - - // allocate a buffer for the source code string and read it in - char* cSourceString = (char *)malloc(szSourceLength + szPreambleLength + 1); - memcpy(cSourceString, cPreamble, szPreambleLength); - if (fread((cSourceString) + szPreambleLength, szSourceLength, 1, pFileStream) != 1) - { - fclose(pFileStream); - free(cSourceString); - return 0; - } - - // close the file and return the total length of the combined (preamble + source) string - fclose(pFileStream); - if(szFinalLength != 0) - { - *szFinalLength = szSourceLength + szPreambleLength; - } - cSourceString[szSourceLength + szPreambleLength] = '\0'; - - return cSourceString; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxGPUContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetDev(cl_context cxGPUContext, unsigned int nr) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - - if( szParmDataBytes / sizeof(cl_device_id) <= nr ) { - return (cl_device_id)-1; - } - - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id device = cdDevices[nr]; - free(cdDevices); - - return device; -} - -////////////////////////////////////////////////////////////////////////////// -//! Get the binary (PTX) of the program associated with the device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param binary returned code -//! @param length length of returned code -////////////////////////////////////////////////////////////////////////////// -void oclGetProgBinary( cl_program cpProgram, cl_device_id cdDevice, char** binary, size_t* length) -{ - // Grab the number of devices associated witht the program - cl_uint num_devices; - clGetProgramInfo(cpProgram, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL); - - // Grab the device ids - cl_device_id* devices = (cl_device_id*) malloc(num_devices * sizeof(cl_device_id)); - clGetProgramInfo(cpProgram, CL_PROGRAM_DEVICES, num_devices * sizeof(cl_device_id), devices, 0); - - // Grab the sizes of the binaries - size_t* binary_sizes = (size_t*)malloc(num_devices * sizeof(size_t)); - clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, num_devices * sizeof(size_t), binary_sizes, NULL); - - // Now get the binaries - char** ptx_code = (char**) malloc(num_devices * sizeof(char*)); - for( unsigned int i=0; i= 0 && index < errorCount) ? errorString[index] : "Unspecified Error"; -} - -// Helper function to get OpenCL image format string (channel order and type) from constant -// ********************************************************************* -const char* oclImageFormatString(cl_uint uiImageFormat) -{ - // cl_channel_order - if (uiImageFormat == CL_R)return "CL_R"; - if (uiImageFormat == CL_A)return "CL_A"; - if (uiImageFormat == CL_RG)return "CL_RG"; - if (uiImageFormat == CL_RA)return "CL_RA"; - if (uiImageFormat == CL_RGB)return "CL_RGB"; - if (uiImageFormat == CL_RGBA)return "CL_RGBA"; - if (uiImageFormat == CL_BGRA)return "CL_BGRA"; - if (uiImageFormat == CL_ARGB)return "CL_ARGB"; - if (uiImageFormat == CL_INTENSITY)return "CL_INTENSITY"; - if (uiImageFormat == CL_LUMINANCE)return "CL_LUMINANCE"; - - // cl_channel_type - if (uiImageFormat == CL_SNORM_INT8)return "CL_SNORM_INT8"; - if (uiImageFormat == CL_SNORM_INT16)return "CL_SNORM_INT16"; - if (uiImageFormat == CL_UNORM_INT8)return "CL_UNORM_INT8"; - if (uiImageFormat == CL_UNORM_INT16)return "CL_UNORM_INT16"; - if (uiImageFormat == CL_UNORM_SHORT_565)return "CL_UNORM_SHORT_565"; - if (uiImageFormat == CL_UNORM_SHORT_555)return "CL_UNORM_SHORT_555"; - if (uiImageFormat == CL_UNORM_INT_101010)return "CL_UNORM_INT_101010"; - if (uiImageFormat == CL_SIGNED_INT8)return "CL_SIGNED_INT8"; - if (uiImageFormat == CL_SIGNED_INT16)return "CL_SIGNED_INT16"; - if (uiImageFormat == CL_SIGNED_INT32)return "CL_SIGNED_INT32"; - if (uiImageFormat == CL_UNSIGNED_INT8)return "CL_UNSIGNED_INT8"; - if (uiImageFormat == CL_UNSIGNED_INT16)return "CL_UNSIGNED_INT16"; - if (uiImageFormat == CL_UNSIGNED_INT32)return "CL_UNSIGNED_INT32"; - if (uiImageFormat == CL_HALF_FLOAT)return "CL_HALF_FLOAT"; - if (uiImageFormat == CL_FLOAT)return "CL_FLOAT"; - - // unknown constant - return "Unknown"; -} diff --git a/tests/opencl/dotproduct/oclUtils.h b/tests/opencl/dotproduct/oclUtils.h deleted file mode 100644 index b0f49108..00000000 --- a/tests/opencl/dotproduct/oclUtils.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -#ifndef OCL_UTILS_H -#define OCL_UTILS_H - -// ********************************************************************* -// Utilities specific to OpenCL samples in NVIDIA GPU Computing SDK -// ********************************************************************* - -// Common headers: Cross-API utililties and OpenCL header -#include "shrUtils.h" - -// All OpenCL headers -#if defined (__APPLE__) || defined(MACOSX) - #include -#else - #include -#endif - -// Includes -#include -#include -#include - -// For systems with CL_EXT that are not updated with these extensions, we copied these -// extensions from -#ifndef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV - /* cl_nv_device_attribute_query extension - no extension #define since it has no functions */ - #define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000 - #define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001 - #define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002 - #define CL_DEVICE_WARP_SIZE_NV 0x4003 - #define CL_DEVICE_GPU_OVERLAP_NV 0x4004 - #define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005 - #define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006 -#endif - -// reminders for build output window and log -#ifdef _WIN32 - #pragma message ("Note: including shrUtils.h") - #pragma message ("Note: including opencl.h") -#endif - -// SDK Revision # -#define OCL_SDKREVISION "7027912" - -// Error and Exit Handling Macros... -// ********************************************************************* -// Full error handling macro with Cleanup() callback (if supplied)... -// (Companion Inline Function lower on page) -#define oclCheckErrorEX(a, b, c) __oclCheckErrorEX(a, b, c, __FILE__ , __LINE__) - -// Short version without Cleanup() callback pointer -// Both Input (a) and Reference (b) are specified as args -#define oclCheckError(a, b) oclCheckErrorEX(a, b, 0) - -////////////////////////////////////////////////////////////////////////////// -//! Gets the platform ID for NVIDIA if available, otherwise default to platform 0 -//! -//! @return the id -//! @param clSelectedPlatformID OpenCL platform ID -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_int oclGetPlatformID(cl_platform_id* clSelectedPlatformID); - -////////////////////////////////////////////////////////////////////////////// -//! Print info about the device -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclPrintDevInfo(int iLogMode, cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Get and return device capability -//! -//! @return the 2 digit integer representation of device Cap (major minor). return -1 if NA -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" int oclGetDevCap(cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Print the device name -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclPrintDevName(int iLogMode, cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the first device from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetFirstDev(cl_context cxGPUContext); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxGPUContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetDev(cl_context cxGPUContext, unsigned int device_idx); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of device with maximal FLOPS from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetMaxFlopsDev(cl_context cxGPUContext); - -////////////////////////////////////////////////////////////////////////////// -//! Loads a Program file and prepends the cPreamble to the code. -//! -//! @return the source string if succeeded, 0 otherwise -//! @param cFilename program filename -//! @param cPreamble code that is prepended to the loaded file, typically a set of #defines or a header -//! @param szFinalLength returned length of the code string -////////////////////////////////////////////////////////////////////////////// -extern "C" char* oclLoadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength); - -////////////////////////////////////////////////////////////////////////////// -//! Get the binary (PTX) of the program associated with the device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param binary returned code -//! @param length length of returned code -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclGetProgBinary( cl_program cpProgram, cl_device_id cdDevice, char** binary, size_t* length); - -////////////////////////////////////////////////////////////////////////////// -//! Get and log the binary (PTX) from the OpenCL compiler for the requested program & device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param const char* cPtxFileName optional PTX file name -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclLogPtx(cl_program cpProgram, cl_device_id cdDevice, const char* cPtxFileName); - -////////////////////////////////////////////////////////////////////////////// -//! Get and log the Build Log from the OpenCL compiler for the requested program & device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclLogBuildInfo(cl_program cpProgram, cl_device_id cdDevice); - -// Helper function for De-allocating cl objects -// ********************************************************************* -extern "C" void oclDeleteMemObjs(cl_mem* cmMemObjs, int iNumObjs); - -// Helper function to get OpenCL error string from constant -// ********************************************************************* -extern "C" const char* oclErrorString(cl_int error); - -// Helper function to get OpenCL image format string (channel order and type) from constant -// ********************************************************************* -extern "C" const char* oclImageFormatString(cl_uint uiImageFormat); - -// companion inline function for error checking and exit on error WITH Cleanup Callback (if supplied) -// ********************************************************************* -inline void __oclCheckErrorEX(cl_int iSample, cl_int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) -{ - // An error condition is defined by the sample/test value not equal to the reference - if (iReference != iSample) - { - // If the sample/test value isn't equal to the ref, it's an error by defnition, so override 0 sample/test value - iSample = (iSample == 0) ? -9999 : iSample; - - // Log the error info - shrLog("\n !!! Error # %i (%s) at line %i , in file %s !!!\n\n", iSample, oclErrorString(iSample), iLine, cFile); - - // Cleanup and exit, or just exit if no cleanup function pointer provided. Use iSample (error code in this case) as process exit code. - if (pCleanup != NULL) - { - pCleanup(iSample); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "Exiting...\n"); - exit(iSample); - } - } -} - -#endif \ No newline at end of file diff --git a/tests/opencl/dotproduct/shrQATest.h b/tests/opencl/dotproduct/shrQATest.h deleted file mode 100644 index 245cf8dc..00000000 --- a/tests/opencl/dotproduct/shrQATest.h +++ /dev/null @@ -1,238 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -#ifndef SHR_QATEST_H -#define SHR_QATEST_H - -// ********************************************************************* -// Generic utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// OS dependent includes -#ifdef _WIN32 - #pragma message ("Note: including windows.h") - #pragma message ("Note: including math.h") - #pragma message ("Note: including assert.h") - #pragma message ("Note: including time.h") - -// Headers needed for Windows - #include - #include -#else - // Headers needed for Linux - #include - #include - #include - #include - #include - #include - #include - #include - #include -#endif - -#ifndef STRCASECMP -#ifdef _WIN32 -#define STRCASECMP _stricmp -#else -#define STRCASECMP strcasecmp -#endif -#endif - -#ifndef STRNCASECMP -#ifdef _WIN32 -#define STRNCASECMP _strnicmp -#else -#define STRNCASECMP strncasecmp -#endif -#endif - - -// Standardized QA Start/Finish for CUDA SDK tests -#define shrQAStart(a, b) __shrQAStart(a, b) -#define shrQAFinish(a, b, c) __shrQAFinish(a, b, c) -#define shrQAFinish2(a, b, c, d) __shrQAFinish2(a, b, c, d) - -inline int findExeNameStart(const char *exec_name) -{ - int exename_start = (int)strlen(exec_name); - - while( (exename_start > 0) && - (exec_name[exename_start] != '\\') && - (exec_name[exename_start] != '/') ) - { - exename_start--; - } - if (exec_name[exename_start] == '\\' || - exec_name[exename_start] == '/') - { - return exename_start+1; - } else { - return exename_start; - } -} - -inline int __shrQAStart(int argc, char **argv) -{ - bool bQATest = false; - // First clear the output buffer - fflush(stdout); - fflush(stdout); - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - char *string_argv = &argv[i][string_start]; - - if (!STRCASECMP(string_argv, "qatest")) { - bQATest = true; - } - } - - // We don't want to print the entire path, so we search for the first - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& RUNNING %s", &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] starting...\n", &(argv[0][exename_start])); - } - fflush(stdout); - printf("\n"); fflush(stdout); - return exename_start; -} - -enum eQAstatus { - QA_FAILED = 0, - QA_PASSED = 1, - QA_WAIVED = 2 -}; - -inline void __ExitInTime(int seconds) -{ - fprintf(stdout, "> exiting in %d seconds: ", seconds); - fflush(stdout); - time_t t; - int count; - for (t=time(0)+seconds, count=seconds; time(0) < t; count--) { - fprintf(stdout, "%d...", count); -#ifdef WIN32 - Sleep(1000); -#else - sleep(1); -#endif - } - fprintf(stdout,"done!\n\n"); - fflush(stdout); -} - - -inline void __shrQAFinish(int argc, const char **argv, int iStatus) -{ - // By default QATest is disabled and NoPrompt is Enabled (times out at seconds passed into __ExitInTime() ) - bool bQATest = false, bNoPrompt = true, bQuitInTime = true; - const char *sStatus[] = { "FAILED", "PASSED", "WAIVED", NULL }; - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - - const char *string_argv = &argv[i][string_start]; - if (!STRCASECMP(string_argv, "qatest")) { - bQATest = true; - } - // For SDK individual samples that don't specify -noprompt or -prompt, - // a 3 second delay will happen before exiting, giving a user time to view results - if (!STRCASECMP(string_argv, "noprompt") || !STRCASECMP(string_argv, "help")) { - bNoPrompt = true; - bQuitInTime = false; - } - if (!STRCASECMP(string_argv, "prompt")) { - bNoPrompt = false; - bQuitInTime = false; - } - } - - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& %s %s", sStatus[iStatus], &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] test results...\n%s\n", &(argv[0][exename_start]), sStatus[iStatus]); - } - fflush(stdout); - printf("\n"); fflush(stdout); - if (bQuitInTime) { - __ExitInTime(3); - } else { - if (!bNoPrompt) { - fprintf(stdout, "\nPress to exit...\n"); - fflush(stdout); - getchar(); - } - } -} - -inline void __shrQAFinish2(bool bQATest, int argc, const char **argv, int iStatus) -{ - bool bQuitInTime = true; - const char *sStatus[] = { "FAILED", "PASSED", "WAIVED", NULL }; - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - - const char *string_argv = &argv[i][string_start]; - // For SDK individual samples that don't specify -noprompt or -prompt, - // a 3 second delay will happen before exiting, giving a user time to view results - if (!STRCASECMP(string_argv, "noprompt") || !STRCASECMP(string_argv, "help")) { - bQuitInTime = false; - } - if (!STRCASECMP(string_argv, "prompt")) { - bQuitInTime = false; - } - } - - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& %s %s", sStatus[iStatus], &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] test results...\n%s\n", &(argv[0][exename_start]), sStatus[iStatus]); - } - fflush(stdout); - - if (bQuitInTime) { - __ExitInTime(3); - } -} - -inline void shrQAFinishExit(int argc, const char **argv, int iStatus) -{ - __shrQAFinish(argc, argv, iStatus); - - exit(iStatus ? EXIT_SUCCESS : EXIT_FAILURE); -} - -inline void shrQAFinishExit2(bool bQAtest, int argc, const char **argv, int iStatus) -{ - __shrQAFinish2(bQAtest, argc, argv, iStatus); - - exit(iStatus ? EXIT_SUCCESS : EXIT_FAILURE); -} - -#endif \ No newline at end of file diff --git a/tests/opencl/dotproduct/shrUtils.cpp b/tests/opencl/dotproduct/shrUtils.cpp deleted file mode 100644 index cf0d2c3e..00000000 --- a/tests/opencl/dotproduct/shrUtils.cpp +++ /dev/null @@ -1,1954 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// Generic Utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// includes -#include -#include -#include -#include -#include "shrUtils.h" -#include "cmd_arg_reader.h" - -// size of PGM file header -const unsigned int PGMHeaderSize = 0x40; -#define MIN_EPSILON_ERROR 1e-3f - -// Deallocate memory allocated within shrUtils -// ********************************************************************* -void shrFree(void* ptr) -{ - if( NULL != ptr) free( ptr); -} - -// Helper function to init data arrays -// ********************************************************************* -void shrFillArray(float* pfData, int iSize) -{ - int i; - const float fScale = 1.0f / (float)RAND_MAX; - for (i = 0; i < iSize; ++i) - { - pfData[i] = fScale * rand(); - } -} - -// Helper function to print data arrays -// ********************************************************************* -void shrPrintArray(float* pfData, int iSize) -{ - int i; - for (i = 0; i < iSize; ++i) - { - shrLog("%d: %.3f\n", i, pfData[i]); - } -} - -// Helper function to return precision delta time for 3 counters since last call based upon host high performance counter -// ********************************************************************* -double shrDeltaT(int iCounterID = 0) -{ - // local var for computation of microseconds since last call - double DeltaT; - - #ifdef _WIN32 // Windows version of precision host timer - - // Variables that need to retain state between calls - static LARGE_INTEGER liOldCount0 = {0, 0}; - static LARGE_INTEGER liOldCount1 = {0, 0}; - static LARGE_INTEGER liOldCount2 = {0, 0}; - - // locals for new count, new freq and new time delta - LARGE_INTEGER liNewCount, liFreq; - if (QueryPerformanceFrequency(&liFreq)) - { - // Get new counter reading - QueryPerformanceCounter(&liNewCount); - - // Update the requested timer - switch (iCounterID) - { - case 0: - { - // Calculate time difference for timer 0. (zero when called the first time) - DeltaT = liOldCount0.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount0.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount0 = liNewCount; - - break; - } - case 1: - { - // Calculate time difference for timer 1. (zero when called the first time) - DeltaT = liOldCount1.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount1.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount1 = liNewCount; - - break; - } - case 2: - { - // Calculate time difference for timer 2. (zero when called the first time) - DeltaT = liOldCount2.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount2.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount2 = liNewCount; - - break; - } - default: - { - // Requested counter ID out of range - return -9999.0; - } - } - - // Returns time difference in seconds sunce the last call - return DeltaT; - } - else - { - // No high resolution performance counter - return -9999.0; - } - #else // Linux version of precision host timer. See http://www.informit.com/articles/article.aspx?p=23618&seqNum=8 - static struct timeval _NewTime; // new wall clock time (struct representation in seconds and microseconds) - static struct timeval _OldTime0; // old wall clock time 0(struct representation in seconds and microseconds) - static struct timeval _OldTime1; // old wall clock time 1(struct representation in seconds and microseconds) - static struct timeval _OldTime2; // old wall clock time 2(struct representation in seconds and microseconds) - - // Get new counter reading - gettimeofday(&_NewTime, NULL); - - switch (iCounterID) - { - case 0: - { - // Calculate time difference for timer 0. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime0.tv_sec + 1.0e-6 * (double)_OldTime0.tv_usec); - - // Reset old time 0 to new - _OldTime0.tv_sec = _NewTime.tv_sec; - _OldTime0.tv_usec = _NewTime.tv_usec; - - break; - } - case 1: - { - // Calculate time difference for timer 1. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime1.tv_sec + 1.0e-6 * (double)_OldTime1.tv_usec); - - // Reset old time 1 to new - _OldTime1.tv_sec = _NewTime.tv_sec; - _OldTime1.tv_usec = _NewTime.tv_usec; - - break; - } - case 2: - { - // Calculate time difference for timer 2. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime2.tv_sec + 1.0e-6 * (double)_OldTime2.tv_usec); - - // Reset old time 2 to new - _OldTime2.tv_sec = _NewTime.tv_sec; - _OldTime2.tv_usec = _NewTime.tv_usec; - - break; - } - default: - { - // Requested counter ID out of range - return -9999.0; - } - } - - // Returns time difference in seconds sunce the last call - return DeltaT; - #endif -} - -// Optional LogFileName Override function -// ********************************************************************* -char* cLogFilePathAndName = NULL; -void shrSetLogFileName (const char* cOverRideName) -{ - if( cLogFilePathAndName != NULL ) { - free(cLogFilePathAndName); - } - cLogFilePathAndName = (char*) malloc(strlen(cOverRideName) + 1); - #ifdef WIN32 - strcpy_s(cLogFilePathAndName, strlen(cOverRideName) + 1, cOverRideName); - #else - strcpy(cLogFilePathAndName, cOverRideName); - #endif - return; -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -static int shrLogV(int iLogMode, int iErrNum, const char* cFormatString, va_list vaArgList) -{ - static FILE* pFileStream0 = NULL; - static FILE* pFileStream1 = NULL; - size_t szNumWritten = 0; - char cFileMode [3]; - - // if the sample log file is closed and the call incudes a "write-to-file", open file for writing - if ((pFileStream0 == NULL) && (iLogMode & LOGFILE)) - { - // if the default filename has not been overriden, set to default - if (cLogFilePathAndName == NULL) - { - shrSetLogFileName(DEFAULTLOGFILE); - } - - #ifdef _WIN32 // Windows version - // set the file mode - if (iLogMode & APPENDMODE) // append to prexisting file contents - { - sprintf_s (cFileMode, 3, "a+"); - } - else // replace prexisting file contents - { - sprintf_s (cFileMode, 3, "w"); - } - - // open the individual sample log file in the requested mode - errno_t err = fopen_s(&pFileStream0, cLogFilePathAndName, cFileMode); - - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (err != 0) - { - if (pFileStream0) - { - fclose (pFileStream0); - } - return -err; - } - #else // Linux & Mac version - // set the file mode - if (iLogMode & APPENDMODE) // append to prexisting file contents - { - sprintf (cFileMode, "a+"); - } - else // replace prexisting file contents - { - sprintf (cFileMode, "w"); - } - - // open the file in the requested mode - if ((pFileStream0 = fopen(cLogFilePathAndName, cFileMode)) == 0) - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (pFileStream0) - { - fclose (pFileStream0); - } - return -1; - } - #endif - } - - // if the master log file is closed and the call incudes a "write-to-file" and MASTER, open master logfile file for writing - if ((pFileStream1 == NULL) && (iLogMode & LOGFILE) && (iLogMode & MASTER)) - { - #ifdef _WIN32 // Windows version - // open the master log file in append mode - errno_t err = fopen_s(&pFileStream1, MASTERLOGFILE, "a+"); - - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (err != 0) - { - if (pFileStream1) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid -// return -err; - } - #else // Linux & Mac version - - // open the file in the requested mode - if ((pFileStream1 = fopen(MASTERLOGFILE, "a+")) == 0) - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (pFileStream1) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid -// return -1; - } - #endif - - // If master log file length has become excessive, empty/reopen - if (iLogMode != LOGCONSOLE) - { - fseek(pFileStream1, 0L, SEEK_END); - if (ftell(pFileStream1) > 50000L) - { - fclose (pFileStream1); - #ifdef _WIN32 // Windows version - fopen_s(&pFileStream1, MASTERLOGFILE, "w"); - #else - pFileStream1 = fopen(MASTERLOGFILE, "w"); - #endif - } - } - } - - // Handle special Error Message code - if (iLogMode & ERRORMSG) - { - // print string to console if flagged - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf ("\n !!! Error # %i at ", iErrNum); // console - } - // print string to file if flagged - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, "\n !!! Error # %i at ", iErrNum); // sample log file - } - } - - // Vars used for variable argument processing - const char* pStr; - const char* cArg; - int iArg; - double dArg; - unsigned int uiArg; - std::string sFormatSpec; - const std::string sFormatChars = " -+#0123456789.dioufnpcsXxEeGgAa"; - const std::string sTypeChars = "dioufnpcsXxEeGgAa"; - char cType = 'c'; - - // Start at the head of the string and scan to the null at the end - for (pStr = cFormatString; *pStr; ++pStr) - { - // Check if the current character is not a formatting specifier ('%') - if (*pStr != '%') - { - // character is not '%', so print it verbatim to console and/or files as flagged - if (iLogMode & LOGCONSOLE) - { - szNumWritten = putc(*pStr, stdout); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = putc(*pStr, pFileStream0); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = putc(*pStr, pFileStream1); // master log file - } - } - } - else - { - // character is '%', so skip over it and read the full format specifier for the argument - ++pStr; - sFormatSpec = '%'; - - // special handling for string of %%%% - bool bRepeater = (*pStr == '%'); - if (bRepeater) - { - cType = '%'; - } - - // chars after the '%' are part of format if on list of constants... scan until that isn't true or NULL is found - while (pStr && ((sFormatChars.find(*pStr) != std::string::npos) || bRepeater)) - { - sFormatSpec += *pStr; - - // If the char is a type specifier, trap it and stop scanning - // (a type specifier char is always the last in the format except for string of %%%) - if (sTypeChars.find(*pStr) != std::string::npos) - { - cType = *pStr; - break; - } - - // Special handling for string of %%% - // If a string of %%% was started and then it ends, break (There won't be a typical type specifier) - if (bRepeater && (*pStr != '%')) - { - break; - } - - pStr++; - } - - // Now handle the arg according to type - switch (cType) - { - case '%': // special handling for string of %%%% - { - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str()); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str()); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str()); // master log file - } - } - continue; - } - case 'c': // single byte char - case 's': // string of single byte chars - { - // Set cArg as the next value in list and print to console and/or files if flagged - cArg = va_arg(vaArgList, char*); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), cArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), cArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), cArg); // master log file - } - } - continue; - } - case 'd': // signed decimal integer - case 'i': // signed decimal integer - { - // set iArg as the next value in list and print to console and/or files if flagged - iArg = va_arg(vaArgList, int); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), iArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), iArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), iArg); // master log file - } - } - continue; - } - case 'u': // unsigned decimal integer - case 'o': // unsigned octal integer - case 'x': // unsigned hexadecimal integer using "abcdef" - case 'X': // unsigned hexadecimal integer using "ABCDEF" - { - // set uiArg as the next value in list and print to console and/or files if flagged - uiArg = va_arg(vaArgList, unsigned int); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), uiArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), uiArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), uiArg); // master log file - } - } - continue; - } - case 'f': // float/double - case 'e': // scientific double/float - case 'E': // scientific double/float - case 'g': // scientific double/float - case 'G': // scientific double/float - case 'a': // signed hexadecimal double precision float - case 'A': // signed hexadecimal double precision float - { - // set dArg as the next value in list and print to console and/or files if flagged - dArg = va_arg(vaArgList, double); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), dArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), dArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), dArg); // master log file - } - } - continue; - } - default: - { - // print arg of unknown/unsupported type to console and/or file if flagged - if (iLogMode & LOGCONSOLE) // console - { - szNumWritten = putc(*pStr, stdout); - } - if (iLogMode & LOGFILE) - { - szNumWritten = putc(*pStr, pFileStream0); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = putc(*pStr, pFileStream1); // master log file - } - } - } - } - } - } - - // end the sample log with a horizontal line if closing - if (iLogMode & CLOSELOG) - { - if (iLogMode & LOGCONSOLE) - { - printf(HDASHLINE); - } - if (iLogMode & LOGFILE) - { - fprintf(pFileStream0, HDASHLINE); - } - } - - // flush console and/or file buffers if updated - if (iLogMode & LOGCONSOLE) - { - fflush(stdout); - } - if (iLogMode & LOGFILE) - { - fflush (pFileStream0); - - // if the master log file has been updated, flush it too - if (iLogMode & MASTER) - { - fflush (pFileStream1); - } - } - - // If the log file is open and the caller requests "close file", then close and NULL file handle - if ((pFileStream0) && (iLogMode & CLOSELOG)) - { - fclose (pFileStream0); - pFileStream0 = NULL; - } - if ((pFileStream1) && (iLogMode & CLOSELOG)) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - - // return error code or OK - if (iLogMode & ERRORMSG) - { - return iErrNum; - } - else - { - return 0; - } -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -int shrLogEx(int iLogMode = LOGCONSOLE, int iErrNum = 0, const char* cFormatString = "", ...) -{ - va_list vaArgList; - - // Prepare variable agument list - va_start(vaArgList, cFormatString); - int ret = shrLogV(iLogMode, iErrNum, cFormatString, vaArgList); - - // end variable argument handler - va_end(vaArgList); - - return ret; -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -int shrLog(const char* cFormatString = "", ...) -{ - va_list vaArgList; - - // Prepare variable agument list - va_start(vaArgList, cFormatString); - int ret = shrLogV(LOGBOTH, 0, cFormatString, vaArgList); - - // end variable argument handler - va_end(vaArgList); - - return ret; -} - -////////////////////////////////////////////////////////////////////////////// -//! Find the path for a file assuming that -//! files are found in the searchPath. -//! -//! @return the path if succeeded, otherwise 0 -//! @param filename name of the file -//! @param executable_path optional absolute path of the executable -////////////////////////////////////////////////////////////////////////////// -char* shrFindFilePath(const char* filename, const char* executable_path) -{ - // defines a variable that is replaced with the name of the executable - - // Typical relative search paths to locate needed companion files (e.g. sample input data, or JIT source files) - // The origin for the relative search may be the .exe file, a .bat file launching an .exe, a browser .exe launching the .exe or .bat, etc - const char* searchPath[] = - { - "./", // same dir - "./data/", // "/data/" subdir - "./src/", // "/src/" subdir - "./src//data/", // "/src//data/" subdir - "./inc/", // "/inc/" subdir - "../", // up 1 in tree - "../data/", // up 1 in tree, "/data/" subdir - "../src/", // up 1 in tree, "/src/" subdir - "../inc/", // up 1 in tree, "/inc/" subdir - "../OpenCL/src//", // up 1 in tree, "/OpenCL/src//" subdir - "../OpenCL/src//data/", // up 1 in tree, "/OpenCL/src//data/" subdir - "../OpenCL/src//src/", // up 1 in tree, "/OpenCL/src//src/" subdir - "../OpenCL/src//inc/", // up 1 in tree, "/OpenCL/src//inc/" subdir - "../C/src//", // up 1 in tree, "/C/src//" subdir - "../C/src//data/", // up 1 in tree, "/C/src//data/" subdir - "../C/src//src/", // up 1 in tree, "/C/src//src/" subdir - "../C/src//inc/", // up 1 in tree, "/C/src//inc/" subdir - "../DirectCompute/src//", // up 1 in tree, "/DirectCompute/src//" subdir - "../DirectCompute/src//data/", // up 1 in tree, "/DirectCompute/src//data/" subdir - "../DirectCompute/src//src/", // up 1 in tree, "/DirectCompute/src//src/" subdir - "../DirectCompute/src//inc/", // up 1 in tree, "/DirectCompute/src//inc/" subdir - "../../", // up 2 in tree - "../../data/", // up 2 in tree, "/data/" subdir - "../../src/", // up 2 in tree, "/src/" subdir - "../../inc/", // up 2 in tree, "/inc/" subdir - "../../../", // up 3 in tree - "../../../src//", // up 3 in tree, "/src//" subdir - "../../../src//data/", // up 3 in tree, "/src//data/" subdir - "../../../src//src/", // up 3 in tree, "/src//src/" subdir - "../../../src//inc/", // up 3 in tree, "/src//inc/" subdir - "../../../sandbox//", // up 3 in tree, "/sandbox//" subdir - "../../../sandbox//data/", // up 3 in tree, "/sandbox//data/" subdir - "../../../sandbox//src/", // up 3 in tree, "/sandbox//src/" subdir - "../../../sandbox//inc/" // up 3 in tree, "/sandbox//inc/" subdir - }; - - // Extract the executable name - std::string executable_name; - if (executable_path != 0) - { - executable_name = std::string(executable_path); - - #ifdef _WIN32 - // Windows path delimiter - size_t delimiter_pos = executable_name.find_last_of('\\'); - executable_name.erase(0, delimiter_pos + 1); - - if (executable_name.rfind(".exe") != string::npos) - { - // we strip .exe, only if the .exe is found - executable_name.resize(executable_name.size() - 4); - } - #else - // Linux & OSX path delimiter - size_t delimiter_pos = executable_name.find_last_of('/'); - executable_name.erase(0,delimiter_pos+1); - #endif - - } - - // Loop over all search paths and return the first hit - for( unsigned int i = 0; i < sizeof(searchPath)/sizeof(char*); ++i ) - { - std::string path(searchPath[i]); - size_t executable_name_pos = path.find(""); - - // If there is executable_name variable in the searchPath - // replace it with the value - if(executable_name_pos != std::string::npos) - { - if(executable_path != 0) - { - path.replace(executable_name_pos, strlen(""), executable_name); - - } - else - { - // Skip this path entry if no executable argument is given - continue; - } - } - - // Test if the file exists - path.append(filename); - std::fstream fh(path.c_str(), std::fstream::in); - if (fh.good()) - { - // File found - // returning an allocated array here for backwards compatibility reasons - char* file_path = (char*) malloc(path.length() + 1); - #ifdef _WIN32 - strcpy_s(file_path, path.length() + 1, path.c_str()); - #else - strcpy(file_path, path.c_str()); - #endif - return file_path; - } - } - - // File not found - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -//! Read file \filename and return the data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -shrReadFile( const char* filename, T** data, unsigned int* len, bool verbose) -{ - // check input arguments - ARGCHECK(NULL != filename); - ARGCHECK(NULL != len); - - // intermediate storage for the data read - std::vector data_read; - - // open file for reading - std::fstream fh( filename, std::fstream::in); - // check if filestream is valid - if(!fh.good()) - { - if (verbose) - std::cerr << "shrReadFile() : Opening file failed." << std::endl; - return shrFALSE; - } - - // read all data elements - T token; - while( fh.good()) - { - fh >> token; - data_read.push_back( token); - } - - // the last element is read twice - data_read.pop_back(); - - // check if reading result is consistent - if( ! fh.eof()) - { - if (verbose) - std::cerr << "WARNING : readData() : reading file might have failed." - << std::endl; - } - - fh.close(); - - // check if the given handle is already initialized - if( NULL != *data) - { - if( *len != data_read.size()) - { - std::cerr << "shrReadFile() : Initialized memory given but " - << "size mismatch with signal read " - << "(data read / data init = " << (unsigned int)data_read.size() - << " / " << *len << ")" << std::endl; - - return shrFALSE; - } - } - else - { - // allocate storage for the data read - *data = (T*) malloc( sizeof(T) * data_read.size()); - // store signal size - *len = static_cast( data_read.size()); - } - - // copy data - memcpy( *data, &data_read.front(), sizeof(T) * data_read.size()); - - return shrTRUE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -shrWriteFile( const char* filename, const T* data, unsigned int len, - const T epsilon, bool verbose) -{ - ARGCHECK(NULL != filename); - ARGCHECK(NULL != data); - - // open file for writing - std::fstream fh( filename, std::fstream::out); - // check if filestream is valid - if(!fh.good()) - { - if (verbose) - std::cerr << "shrWriteFile() : Opening file failed." << std::endl; - return shrFALSE; - } - - // first write epsilon - fh << "# " << epsilon << "\n"; - - // write data - for( unsigned int i = 0; (i < len) && (fh.good()); ++i) - { - fh << data[i] << ' '; - } - - // Check if writing succeeded - if( ! fh.good()) - { - if (verbose) - std::cerr << "shrWriteFile() : Writing file failed." << std::endl; - return shrFALSE; - } - - // file ends with nl - fh << std::endl; - - return shrTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg single precision floating point data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg double precision floating point data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg integer data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg unsigned integer data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileui( const char* filename, unsigned int** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg char / byte data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg unsigned char / byte data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileub( const char* filename, unsigned char** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for single precision floating point data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len, - const float epsilon, bool verbose) -{ - return shrWriteFile( filename, data, len, epsilon, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for double precision floating point data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFiled( const char* filename, const double* data, unsigned int len, - const double epsilon, bool verbose) -{ - return shrWriteFile( filename, data, len, epsilon, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for integer data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, 0, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for unsigned integer data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileui( const char* filename,const unsigned int* data,unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileub( const char* filename, const unsigned char* data, - unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for unsigned byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileb( const char* filename,const unsigned char* data,unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -////////////////////////////////////////////////////////////////////////////// -//! Load PGM or PPM file -//! @note if data == NULL then the necessary memory is allocated in the -//! function and w and h are initialized to the size of the image -//! @return shrTRUE if the file loading succeeded, otherwise shrFALSE -//! @param file name of the file to load -//! @param data handle to the memory for the image file data -//! @param w width of the image -//! @param h height of the image -//! @param channels number of channels in image -////////////////////////////////////////////////////////////////////////////// -shrBOOL loadPPM(const char* file, unsigned char** data, - unsigned int *w, unsigned int *h, unsigned int *channels) -{ - FILE* fp = 0; - - #ifdef _WIN32 - // open the file for binary read - errno_t err; - if ((err = fopen_s(&fp, file, "rb")) != 0) - #else - // open the file for binary read - if ((fp = fopen(file, "rb")) == 0) - #endif - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : Failed to open file: " << file << std::endl; - return shrFALSE; - } - - // check header - char header[PGMHeaderSize]; - if ((fgets( header, PGMHeaderSize, fp) == NULL) && ferror(fp)) - { - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl; - *channels = 0; - return shrFALSE; - } - - if (strncmp(header, "P5", 2) == 0) - { - *channels = 1; - } - else if (strncmp(header, "P6", 2) == 0) - { - *channels = 3; - } - else - { - std::cerr << "loadPPM() : File is not a PPM or PGM image" << std::endl; - *channels = 0; - return shrFALSE; - } - - // parse header, read maxval, width and height - unsigned int width = 0; - unsigned int height = 0; - unsigned int maxval = 0; - unsigned int i = 0; - while(i < 3) - { - if ((fgets(header, PGMHeaderSize, fp) == NULL) && ferror(fp)) - { - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl; - return shrFALSE; - } - if(header[0] == '#') continue; - - #ifdef _WIN32 - if(i == 0) - { - i += sscanf_s(header, "%u %u %u", &width, &height, &maxval); - } - else if (i == 1) - { - i += sscanf_s(header, "%u %u", &height, &maxval); - } - else if (i == 2) - { - i += sscanf_s(header, "%u", &maxval); - } - #else - if(i == 0) - { - i += sscanf(header, "%u %u %u", &width, &height, &maxval); - } - else if (i == 1) - { - i += sscanf(header, "%u %u", &height, &maxval); - } - else if (i == 2) - { - i += sscanf(header, "%u", &maxval); - } - #endif - } - - // check if given handle for the data is initialized - if(NULL != *data) - { - if (*w != width || *h != height) - { - fclose(fp); - std::cerr << "loadPPM() : Invalid image dimensions." << std::endl; - return shrFALSE; - } - } - else - { - *data = (unsigned char*)malloc( sizeof(unsigned char) * width * height * *channels); - *w = width; - *h = height; - } - - // read and close file - if (fread(*data, sizeof(unsigned char), width * height * *channels, fp) != width * height * *channels) - { - fclose(fp); - std::cerr << "loadPPM() : Invalid image." << std::endl; - return shrFALSE; - } - fclose(fp); - - return shrTRUE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Write / Save PPM or PGM file -//! @note Internal usage only -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -////////////////////////////////////////////////////////////////////////////// -shrBOOL savePPM( const char* file, unsigned char *data, - unsigned int w, unsigned int h, unsigned int channels) -{ - ARGCHECK(NULL != data); - ARGCHECK(w > 0); - ARGCHECK(h > 0); - - std::fstream fh( file, std::fstream::out | std::fstream::binary ); - if( fh.bad()) - { - std::cerr << "savePPM() : Opening file failed." << std::endl; - return shrFALSE; - } - - if (channels == 1) - { - fh << "P5\n"; - } - else if (channels == 3) { - fh << "P6\n"; - } - else { - std::cerr << "savePPM() : Invalid number of channels." << std::endl; - return shrFALSE; - } - - fh << w << "\n" << h << "\n" << 0xff << std::endl; - - for( unsigned int i = 0; (i < (w*h*channels)) && fh.good(); ++i) - { - fh << data[i]; - } - fh.flush(); - - if( fh.bad()) - { - std::cerr << "savePPM() : Writing data failed." << std::endl; - return shrFALSE; - } - fh.close(); - - return shrTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Load PPM image file (with unsigned char as data element type), padding 4th component -//! @return shrTrue if reading the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrLoadPPM4ub( const char* file, unsigned char** OutData, - unsigned int *w, unsigned int *h) -{ - // Load file data into a temporary buffer with automatic allocation - unsigned char* cLocalData = 0; - unsigned int channels; - shrBOOL bLoadOK = loadPPM(file, &cLocalData, w, h, &channels); // this allocates cLocalData, which must be freed later - - // If the data loaded OK from file to temporary buffer, then go ahead with padding and transfer - if (shrTRUE == bLoadOK) - { - // if the receiving buffer is null, allocate it... caller must free this - int size = *w * *h; - if (*OutData == NULL) - { - *OutData = (unsigned char*)malloc(sizeof(unsigned char) * size * 4); - } - - // temp pointers for incrementing - unsigned char* cTemp = cLocalData; - unsigned char* cOutPtr = *OutData; - - // transfer data, padding 4th element - for(int i=0; i( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type unsigned int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv, - const char* arg_name, unsigned int* val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const int* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type float -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv, - const char* arg_name, float* val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const float* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type string -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv, - const char* arg_name, char** val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const std::string* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - - // allocate memory for the string - *val = (char*)malloc(sizeof(char) * (v->length() + 1)); - - // copy from string to c_str - #ifdef WIN32 - strcpy_s(*val, v->length() + 1, v->c_str()); - #else - strcpy(*val, v->c_str()); - #endif - ret_val = shrTRUE; - } - else { - // fail safe - *val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string."<< - std::endl; - } - - return ret_val; - -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareData( const T* reference, const T* data, const unsigned int len, - const S epsilon, const float threshold) -{ - ARGCHECK( epsilon >= 0); - - bool result = true; - unsigned int error_count = 0; - - for( unsigned int i = 0; i < len; ++i) { - - T diff = reference[i] - data[i]; - bool comp = (diff <= epsilon) && (diff >= -epsilon); - result &= comp; - - error_count += !comp; - -#ifdef _DEBUG - if( ! comp) - { - std::cerr << "ERROR, i = " << i << ",\t " - << reference[i] << " / " - << data[i] - << " (reference / data)\n"; - } -#endif - } - - if (threshold == 0.0f) { - return (result) ? shrTRUE : shrFALSE; - } else { - return (len*threshold > error_count) ? shrTRUE : shrFALSE; - } -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareDataAsFloat( const T* reference, const T* data, const unsigned int len, - const S epsilon) -{ - ARGCHECK(epsilon >= 0); - - // If we set epsilon to be 0, let's set a minimum threshold - float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR ); - int error_count = 0; - bool result = true; - - for( unsigned int i = 0; i < len; ++i) { - float diff = fabs((float)reference[i] - (float)data[i]); - bool comp = (diff < max_error); - result &= comp; - - if( ! comp) - { - error_count++; -#ifdef _DEBUG - if (error_count < 50) { - shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)0x%02x / (data)0x%02x / (diff)%d\n", max_error, i, reference[i], data[i], (unsigned int)diff); - } -#endif - } - } - if (error_count) { - shrLog("\n Total # of errors = %d\n", error_count); - } - return (error_count == 0) ? shrTRUE : shrFALSE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//! @param epsilon threshold % of (# of bytes) for pass/fail -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareDataAsFloatThreshold( const T* reference, const T* data, const unsigned int len, - const S epsilon, const float threshold) -{ - ARGCHECK(epsilon >= 0); - - // If we set epsilon to be 0, let's set a minimum threshold - float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR); - int error_count = 0; - bool result = true; - - for( unsigned int i = 0; i < len; ++i) { - float diff = fabs((float)reference[i] - (float)data[i]); - bool comp = (diff < max_error); - result &= comp; - - if( ! comp) - { - error_count++; -//#ifdef _DEBUG - if (error_count < 50) { - shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)%f / (data)%f / (diff)%f\n", max_error, i, reference[i], data[i], diff); - } -//#endif - } - } - - if (threshold == 0.0f) { - if (error_count) { - shrLog("\n Total # of errors = %d\n", error_count); - } - return (error_count == 0) ? shrTRUE : shrFALSE; - } else { - - if (error_count) { - shrLog("\n %.2f(%%) of bytes mismatched (count=%d)\n", (float)error_count*100/(float)len, error_count); - } - - return ((len*threshold > error_count) ? shrTRUE : shrFALSE); - } -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparef( const float* reference, const float* data, - const unsigned int len ) -{ - const float epsilon = 0.0; - return compareData( reference, data, len, epsilon, 0.0f ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparei( const int* reference, const int* data, - const unsigned int len ) -{ - const int epsilon = 0; - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned integer arrays, with epsilon and threshold -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data, - const unsigned int len ) -{ - const int epsilon = 0; - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays (inc Threshold for # of pixel we can have errors) -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, -//! otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon ) -{ - return compareDataAsFloat( reference, data, len, epsilon ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparefe( const float* reference, const float* data, - const unsigned int len, const float epsilon ) -{ - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality and a -//! threshold for # pixel errors -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparefet( const float* reference, const float* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays using L2-norm with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareL2fe( const float* reference, const float* data, - const unsigned int len, const float epsilon ) -{ - ARGCHECK(epsilon >= 0); - - float error = 0; - float ref = 0; - - for( unsigned int i = 0; i < len; ++i) { - - float diff = reference[i] - data[i]; - error += diff * diff; - ref += reference[i] * reference[i]; - } - - float normRef = sqrtf(ref); - if (fabs(ref) < 1e-7) { -#ifdef _DEBUG - std::cerr << "ERROR, reference l2-norm is 0\n"; -#endif - return shrFALSE; - } - float normError = sqrtf(error); - error = normError / normRef; - bool result = error < epsilon; -#ifdef _DEBUG - if( ! result) - { - std::cerr << "ERROR, l2-norm error " - << error << " is greater than epsilon " << epsilon << "\n"; - } -#endif - - return result ? shrTRUE : shrFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PPM image files with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! @param verboseErrors output details of image mismatch to std::cerr -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold) -{ - unsigned char* src_data = NULL; - unsigned char* ref_data = NULL; - unsigned long error_count = 0; - unsigned int ref_width, ref_height; - unsigned int src_width, src_height; - - // Check sample and reference file pointers - if (src_file == NULL || ref_file == NULL) { - shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n"); - return shrFALSE; - } - shrLog("\n> shrComparePPM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file); - - // Load the ref image file - if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE) - { - shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file); - return shrFALSE; - } - - // Load the sample image file - if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE) - { - shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file); - return shrFALSE; - } - - // check to see if image dimensions match - if(src_height != ref_height || src_width != ref_width) - { - shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ", - src_width, src_height, ref_width, ref_height); - return shrFALSE; - } - - // compare the images - if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE) - { - error_count=1; - } - - shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!"); - return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PGM image files with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold) -{ - unsigned char* src_data = NULL; - unsigned char* ref_data = NULL; - unsigned long error_count = 0; - unsigned int ref_width, ref_height; - unsigned int src_width, src_height; - - // Check sample and reference file pointers - if (src_file == NULL || ref_file == NULL) { - shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n"); - return shrFALSE; - } - shrLog("\n> shrComparePGM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file); - - // Load the ref image file - if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE) - { - shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file); - return shrFALSE; - } - - // Load the sample image file - if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE) - { - shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file); - return shrFALSE; - } - - // check to see if image dimensions match - if(src_height != ref_height || src_width != ref_width) - { - shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ", - src_width, src_height, ref_width, ref_height); - return shrFALSE; - } - - // compare the images - if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE) - { - error_count=1; - } - - shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!"); - return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass -} - -// Load raw data from disk -unsigned char* shrLoadRawFile(const char* filename, size_t size) -{ - FILE *fp = NULL; - #ifdef WIN32 - errno_t err; - if ((err = fopen_s(&fp, filename, "rb")) != 0) - #else - if ((fp = fopen(filename, "rb")) == NULL) - #endif - { - shrLog(" Error opening file '%s' !!!\n", filename); - return 0; - } - - unsigned char* data = (unsigned char*)malloc(size); - size_t read = fread(data, 1, size, fp); - fclose(fp); - - shrLog(" Read '%s', %d bytes\n", filename, read); - - return data; -} - -// Round Up Division function -size_t shrRoundUp(int group_size, int global_size) -{ - int r = global_size % group_size; - if(r == 0) - { - return global_size; - } else - { - return global_size + group_size - r; - } -} \ No newline at end of file diff --git a/tests/opencl/dotproduct/shrUtils.h b/tests/opencl/dotproduct/shrUtils.h deleted file mode 100644 index f0c08ab4..00000000 --- a/tests/opencl/dotproduct/shrUtils.h +++ /dev/null @@ -1,642 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -#ifndef SHR_UTILS_H -#define SHR_UTILS_H - -// ********************************************************************* -// Generic utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// reminders for output window and build log -#ifdef _WIN32 - #pragma message ("Note: including windows.h") - #pragma message ("Note: including math.h") - #pragma message ("Note: including assert.h") -#endif - -// OS dependent includes -#ifdef _WIN32 - // Headers needed for Windows - #include -#else - // Headers needed for Linux - #include - #include - #include - #include - #include - #include - #include -#endif - -// Other headers needed for both Windows and Linux -#include -#include -#include -#include -#include - -// Un-comment the following #define to enable profiling code in SDK apps -//#define GPU_PROFILING - -// Beginning of GPU Architecture definitions -inline int ConvertSMVer2Cores(int major, int minor) -{ - // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM - typedef struct { - int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version - int Cores; - } sSMtoCores; - - sSMtoCores nGpuArchCoresPerSM[] = - { { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class - { 0x11, 8 }, // Tesla Generation (SM 1.1) G8x class - { 0x12, 8 }, // Tesla Generation (SM 1.2) G9x class - { 0x13, 8 }, // Tesla Generation (SM 1.3) GT200 class - { 0x20, 32 }, // Fermi Generation (SM 2.0) GF100 class - { 0x21, 48 }, // Fermi Generation (SM 2.1) GF10x class - { 0x30, 192}, // Fermi Generation (SM 3.0) GK10x class - { -1, -1 } - }; - - int index = 0; - while (nGpuArchCoresPerSM[index].SM != -1) { - if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor) ) { - return nGpuArchCoresPerSM[index].Cores; - } - index++; - } - printf("MapSMtoCores SM %d.%d is undefined (please update to the latest SDK)!\n", major, minor); - return -1; -} -// end of GPU Architecture definitions - - -// Defines and enum for use with logging functions -// ********************************************************************* -#define DEFAULTLOGFILE "SdkConsoleLog.txt" -#define MASTERLOGFILE "SdkMasterLog.csv" -enum LOGMODES -{ - LOGCONSOLE = 1, // bit to signal "log to console" - LOGFILE = 2, // bit to signal "log to file" - LOGBOTH = 3, // convenience union of first 2 bits to signal "log to both" - APPENDMODE = 4, // bit to set "file append" mode instead of "replace mode" on open - MASTER = 8, // bit to signal master .csv log output - ERRORMSG = 16, // bit to signal "pre-pend Error" - CLOSELOG = 32 // bit to close log file, if open, after any requested file write -}; -#define HDASHLINE "-----------------------------------------------------------\n" - -// Standardized boolean -enum shrBOOL -{ - shrFALSE = 0, - shrTRUE = 1 -}; - -// Standardized MAX, MIN and CLAMP -#define MAX(a, b) ((a > b) ? a : b) -#define MIN(a, b) ((a < b) ? a : b) -#define CLAMP(a, b, c) MIN(MAX(a, b), c) // double sided clip of input a -#define TOPCLAMP(a, b) (a < b ? a:b) // single top side clip of input a - -// Error and Exit Handling Macros... -// ********************************************************************* -// Full error handling macro with Cleanup() callback (if supplied)... -// (Companion Inline Function lower on page) -#define shrCheckErrorEX(a, b, c) __shrCheckErrorEX(a, b, c, __FILE__ , __LINE__) - -// Short version without Cleanup() callback pointer -// Both Input (a) and Reference (b) are specified as args -#define shrCheckError(a, b) shrCheckErrorEX(a, b, 0) - -// Standardized Exit Macro for leaving main()... extended version -// (Companion Inline Function lower on page) -#define shrExitEX(a, b, c) __shrExitEX(a, b, c) - -// Standardized Exit Macro for leaving main()... short version -// (Companion Inline Function lower on page) -#define shrEXIT(a, b) __shrExitEX(a, b, EXIT_SUCCESS) - -// Simple argument checker macro -#define ARGCHECK(a) if((a) != shrTRUE)return shrFALSE - -// Define for user-customized error handling -#define STDERROR "file %s, line %i\n\n" , __FILE__ , __LINE__ - -// Function to deallocate memory allocated within shrUtils -// ********************************************************************* -extern "C" void shrFree(void* ptr); - -// ********************************************************************* -// Helper function to log standardized information to Console, to File or to both -//! Examples: shrLogEx(LOGBOTH, 0, "Function A\n"); -//! : shrLogEx(LOGBOTH | ERRORMSG, ciErrNum, STDERROR); -//! -//! Automatically opens file and stores handle if needed and not done yet -//! Closes file and nulls handle on request -//! -//! @param 0 iLogMode: LOGCONSOLE, LOGFILE, LOGBOTH, APPENDMODE, MASTER, ERRORMSG, CLOSELOG. -//! LOGFILE and LOGBOTH may be | 'd with APPENDMODE to select file append mode instead of overwrite mode -//! LOGFILE and LOGBOTH may be | 'd with CLOSELOG to "write and close" -//! First 3 options may be | 'd with MASTER to enable independent write to master data log file -//! First 3 options may be | 'd with ERRORMSG to start line with standard error message -//! @param 2 dValue: -//! Positive val = double value for time in secs to be formatted to 6 decimals. -//! Negative val is an error code and this give error preformatting. -//! @param 3 cFormatString: String with formatting specifiers like printf or fprintf. -//! ALL printf flags, width, precision and type specifiers are supported with this exception: -//! Wide char type specifiers intended for wprintf (%S and %C) are NOT supported -//! Single byte char type specifiers (%s and %c) ARE supported -//! @param 4... variable args: like printf or fprintf. Must match format specifer type above. -//! @return 0 if OK, negative value on error or if error occurs or was passed in. -// ********************************************************************* -extern "C" int shrLogEx(int iLogMode, int iErrNum, const char* cFormatString, ...); - -// Short version of shrLogEx defaulting to shrLogEx(LOGBOTH, 0, -// ********************************************************************* -extern "C" int shrLog(const char* cFormatString, ...); - -// ********************************************************************* -// Delta timer function for up to 3 independent timers using host high performance counters -// Maintains state for 3 independent counters -//! Example: double dElapsedTime = shrDeltaTime(0); -//! -//! @param 0 iCounterID: Which timer to check/reset. (0, 1, 2) -//! @return delta time of specified counter since last call in seconds. Otherwise -9999.0 if error -// ********************************************************************* -extern "C" double shrDeltaT(int iCounterID); - -// Optional LogFileNameOverride function -// ********************************************************************* -extern "C" void shrSetLogFileName (const char* cOverRideName); - -// Helper function to init data arrays -// ********************************************************************* -extern "C" void shrFillArray(float* pfData, int iSize); - -// Helper function to print data arrays -// ********************************************************************* -extern "C" void shrPrintArray(float* pfData, int iSize); - -//////////////////////////////////////////////////////////////////////////// -//! Find the path for a filename -//! @return the path if succeeded, otherwise 0 -//! @param filename name of the file -//! @param executablePath optional absolute path of the executable -//////////////////////////////////////////////////////////////////////////// -extern "C" char* shrFindFilePath(const char* filename, const char* executablePath); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing single precision floating point data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing double precision floating point data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing integer data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing unsigned integer data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileui( const char* filename, unsigned int** data, - unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing char / byte data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing unsigned char / byte data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileub( const char* filename, unsigned char** data, - unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing single precision floating point -//! data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len, - const float epsilon, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing double precision floating point -//! data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFiled( const char* filename, const float* data, unsigned int len, - const double epsilon, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing integer data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing unsigned integer data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileui( const char* filename, const unsigned int* data, - unsigned int len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing char / byte data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing unsigned char / byte data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileub( const char* filename, const unsigned char* data, - unsigned int len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Load PPM image file (with unsigned char as data element type), padding -//! 4th component -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param OutData handle to the data read -//! @param w width of the image -//! @param h height of the image -//! -//! Note: If *OutData is NULL this function allocates buffer that must be freed by caller -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrLoadPPM4ub(const char* file, unsigned char** OutData, - unsigned int *w, unsigned int *h); - -//////////////////////////////////////////////////////////////////////////// -//! Save PPM image file (with unsigned char as data element type, padded to -//! 4 bytes) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrSavePPM4ub( const char* file, unsigned char *data, - unsigned int w, unsigned int h); - -//////////////////////////////////////////////////////////////////////////////// -//! Save PGM image file (with unsigned char as data element type) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrSavePGMub( const char* file, unsigned char *data, - unsigned int w, unsigned int h); - -//////////////////////////////////////////////////////////////////////////// -//! Load PGM image file (with unsigned char as data element type) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrLoadPGMub( const char* file, unsigned char** data, - unsigned int *w,unsigned int *h); - -//////////////////////////////////////////////////////////////////////////// -// Command line arguments: General notes -// * All command line arguments begin with '--' followed by the token; -// token and value are seperated by '='; example --samples=50 -// * Arrays have the form --model=[one.obj,two.obj,three.obj] -// (without whitespaces) -//////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////// -//! Check if command line argument \a flag-name is given -//! @return shrTRUE if command line argument \a flag_name has been given, -//! otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param flag_name name of command line flag -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCheckCmdLineFlag( const int argc, const char** argv, - const char* flag_name); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumenti( const int argc, const char** argv, - const char* arg_name, int* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type unsigned int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv, - const char* arg_name, unsigned int* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type float -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv, - const char* arg_name, float* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type string -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv, - const char* arg_name, char** val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument list those element are strings -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val command line argument list -//! @param len length of the list / number of elements -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentListstr( const int argc, const char** argv, - const char* arg_name, char** val, - unsigned int* len); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparef( const float* reference, const float* data, - const unsigned int len); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparei( const int* reference, const int* data, - const unsigned int len ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned integer arrays, with epsilon and threshold -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param threshold tolerance % # of comparison errors (0.15f = 15%) -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned char arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data, - const unsigned int len ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integers with a tolernance for # of byte errors -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//! @param threshold tolerance % # of comparison errors (0.15f = 15%) -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays witha n epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparefe( const float* reference, const float* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality and a -//! threshold for # pixel errors -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparefet( const float* reference, const float* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays using L2-norm with an epsilon tolerance for -//! equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareL2fe( const float* reference, const float* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PPM image files with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! $param verboseErrors output details of image mismatch to std::err -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PGM image files with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! $param verboseErrors output details of image mismatch to std::err -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold); - -extern "C" unsigned char* shrLoadRawFile(const char* filename, size_t size); - -extern "C" size_t shrRoundUp(int group_size, int global_size); - -// companion inline function for error checking and exit on error WITH Cleanup Callback (if supplied) -// ********************************************************************* -inline void __shrCheckErrorEX(int iSample, int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) -{ - if (iReference != iSample) - { - shrLogEx(LOGBOTH | ERRORMSG, iSample, "line %i , in file %s !!!\n\n" , iLine, cFile); - if (pCleanup != NULL) - { - pCleanup(EXIT_FAILURE); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "Exiting...\n"); - exit(EXIT_FAILURE); - } - } -} - -// Standardized Exit -// ********************************************************************* -inline void __shrExitEX(int argc, const char** argv, int iExitCode) -{ -#ifdef WIN32 - if (!shrCheckCmdLineFlag(argc, argv, "noprompt") && !shrCheckCmdLineFlag(argc, argv, "qatest")) -#else - if (shrCheckCmdLineFlag(argc, argv, "prompt") && !shrCheckCmdLineFlag(argc, argv, "qatest")) -#endif - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "\nPress to Quit...\n"); - getchar(); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "%s Exiting...\n", argv[0]); - } - fflush(stderr); - exit(iExitCode); -} - -#endif diff --git a/tests/opencl/flops/.depend b/tests/opencl/flops/.depend deleted file mode 100644 index 6f7bdaac..00000000 --- a/tests/opencl/flops/.depend +++ /dev/null @@ -1,8 +0,0 @@ -main.o: main.cc \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/opencl.h \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/cl.h \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/cl_version.h \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/cl_platform.h \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/cl_gl.h \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/cl_ext.h \ - /scratch/hansung/build/pocl-vortex2/runtime/include/CL/cl_ext_pocl.h diff --git a/tests/opencl/flops/.gitignore b/tests/opencl/flops/.gitignore deleted file mode 100644 index 3ca9b5b2..00000000 --- a/tests/opencl/flops/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -flops -*.o -*.bin* -*.pocl -*.dump -*.vcd diff --git a/tests/opencl/flops/Makefile b/tests/opencl/flops/Makefile deleted file mode 100644 index a3301c6f..00000000 --- a/tests/opencl/flops/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = flops - -SRCS = main.cc - -OPTS ?= -n64 - -include ../common.mk diff --git a/tests/opencl/flops/kernel.cl b/tests/opencl/flops/kernel.cl deleted file mode 100644 index 181e1171..00000000 --- a/tests/opencl/flops/kernel.cl +++ /dev/null @@ -1,13 +0,0 @@ -__kernel void flops (__global volatile const float *src, - __global volatile float *dst, - __local volatile float *smem) -{ - int gid = get_global_id(0); - float f = 0.0f; - float incr = src[0]; - __attribute__((opencl_unroll_hint(16))) - for (int i = 0; i < 5000; i++) { - f += incr; - } - dst[gid] = f; -} diff --git a/tests/opencl/flops/main.cc b/tests/opencl/flops/main.cc deleted file mode 100644 index ebab1825..00000000 --- a/tests/opencl/flops/main.cc +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define KERNEL_NAME "flops" - -#define CL_CHECK(_expr) \ - do { \ - cl_int _err = _expr; \ - if (_err == CL_SUCCESS) \ - break; \ - printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ - cleanup(); \ - exit(-1); \ - } while (0) - -#define CL_CHECK2(_expr) \ - ({ \ - cl_int _err = CL_INVALID_VALUE; \ - decltype(_expr) _ret = _expr; \ - if (_err != CL_SUCCESS) { \ - printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ - cleanup(); \ - exit(-1); \ - } \ - _ret; \ - }) - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - -static int write_operand_file(const char* filename, void* data, size_t size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "wb"); - if (NULL == fp) { - fprintf(stderr, "Failed to write operand data.\n"); - return -1; - } - - size_t wsize = fwrite(data, size, 1, fp); - if (wsize != 1) { - fprintf(stderr, "Failed to write operand data.\n"); - return -1; - } - - fclose(fp); - - return 0; -} - -static bool almost_equal(float a, float b, int ulp = 4) { - union fi_t { int i; float f; }; - fi_t fa, fb; - fa.f = a; - fb.f = b; - return std::abs(fa.i - fb.i) <= ulp; -} - -cl_device_id device_id = NULL; -cl_context context = NULL; -cl_command_queue commandQueue = NULL; -cl_program program = NULL; -cl_kernel kernel = NULL; -cl_mem src_memobj = NULL; -cl_mem dst_memobj = NULL; -float *h_src = NULL; -float *h_dst = NULL; -uint8_t *kernel_bin = NULL; - -static void cleanup() { - if (commandQueue) clReleaseCommandQueue(commandQueue); - if (kernel) clReleaseKernel(kernel); - if (program) clReleaseProgram(program); - if (src_memobj) clReleaseMemObject(src_memobj); - if (dst_memobj) clReleaseMemObject(dst_memobj); - if (context) clReleaseContext(context); - if (device_id) clReleaseDevice(device_id); - - if (kernel_bin) free(kernel_bin); - if (h_src) free(h_src); - if (h_dst) free(h_dst); -} - -int size = 64; - -static void show_usage() { - printf("Usage: [-n size] [-h: help]\n"); -} - -static void parse_args(int argc, char **argv) { - int c; - while ((c = getopt(argc, argv, "n:h?")) != -1) { - switch (c) { - case 'n': - size = atoi(optarg); - break; - case 'h': - case '?': { - show_usage(); - exit(0); - } break; - default: - show_usage(); - exit(-1); - } - } - - printf("Workload size=%d\n", size); -} - -int main (int argc, char **argv) { - // parse command arguments - parse_args(argc, argv); - - cl_platform_id platform_id; - size_t kernel_size; - cl_int binary_status; - - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; - - // Getting platform and device information - CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); - CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); - - printf("Create context\n"); - context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); - - printf("Allocate device buffers\n"); - size_t nbytes = size * sizeof(float); - src_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); - dst_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); - - printf("Create program from kernel source\n"); - cl_int _err; - program = clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err); - if (program == NULL) { - cleanup(); - return -1; - } - - // Build program - CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); - - // Create kernel - kernel = CL_CHECK2(clCreateKernel(program, KERNEL_NAME, &_err)); - - // store entire array to sharedmem - size_t local_size = size; - - // Set kernel arguments - CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&src_memobj)); - CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&dst_memobj)); - CL_CHECK(clSetKernelArg(kernel, 2, local_size*sizeof(float), NULL)); - - // Allocate memories for input arrays and output arrays. - h_src = (float*)malloc(nbytes); - h_dst = (float*)malloc(nbytes); - - // Initialize values for array members. - for (int i = 0; i < size; ++i) { - h_src[i] = sinf(i)*sinf(i); - h_dst[i] = 0xdeadbeef; - //printf("*** [%d]: h_src=%f, h_dst=%f\n", i, h_src[i], h_dst[i]); - } - - // NOTE(hansung): Dump operand buffer to a file - if (write_operand_file("flops.input.src.bin", h_src, nbytes) != 0) - return EXIT_FAILURE; - - // Creating command queue - commandQueue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - - printf("Upload source buffers\n"); - CL_CHECK(clEnqueueWriteBuffer(commandQueue, src_memobj, CL_TRUE, 0, nbytes, h_src, 0, NULL, NULL)); - - printf("Execute the kernel\n"); - size_t global_work_size[1] = {size}; - size_t local_work_size[1] = {1}; - auto time_start = std::chrono::high_resolution_clock::now(); - CL_CHECK(clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, global_work_size, local_work_size, 0, NULL, NULL)); - CL_CHECK(clFinish(commandQueue)); - auto time_end = std::chrono::high_resolution_clock::now(); - double elapsed = std::chrono::duration_cast(time_end - time_start).count(); - printf("Elapsed time: %lg ms\n", elapsed); - - printf("Download destination buffer\n"); - CL_CHECK(clEnqueueReadBuffer(commandQueue, dst_memobj, CL_TRUE, 0, nbytes, h_dst, 0, NULL, NULL)); - - printf("Verify result\n"); - int errors = 0; - for (int i = 0; i < size; ++i) { - float ref = h_src[i]; - if (!almost_equal(h_dst[i], ref)) { - if (errors < 100) - printf("*** error: [%d] expected=%f, actual=%f, src=%f\n", i, ref, h_dst[i], h_src[i]); - ++errors; - } - } - if (0 == errors) { - printf("PASSED!\n"); - } else { - printf("FAILED! - %d errors\n", errors); - } - - // Clean up - cleanup(); - - return errors; -} diff --git a/tests/opencl/guassian/Makefile b/tests/opencl/guassian/Makefile deleted file mode 100644 index f858333a..00000000 --- a/tests/opencl/guassian/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = guassian - -SRCS = main.cc clutils.cpp utils.cpp - -OPTS ?= - -include ../common.mk diff --git a/tests/opencl/guassian/OriginalParallel.c b/tests/opencl/guassian/OriginalParallel.c deleted file mode 100755 index 6a899b68..00000000 --- a/tests/opencl/guassian/OriginalParallel.c +++ /dev/null @@ -1,241 +0,0 @@ -/*----------------------------------------------------------- -** ge_p.c -- The program is to solve a linear system Ax = b -** by using Gaussian Elimination. The algorithm on page 101 -** ("Foundations of Parallel Programming") is used. -** The sequential version is ge_s.c. This parallel -** implementation converts three independent for() loops -** into three Fans. Use the data file ge_3.dat to verify -** the correction of the output. -** -** Written by Andreas Kura, 02/15/95 -** Modified by Chong-wei Xu, /04/20/95 -**----------------------------------------------------------- -*/ -#include -#include - -int Size, t; -float **a, *b; -BEGIN_SHARED_DECL - float **m; -END_SHARED_DECL; -FILE *fp; - -void InitProblemOnce(); -void InitPerRun(); -void ForwardSub(); -void Fan1(); -void Fan2(); -void Fan3(); -void InitMat(); -void InitAry(); -void PrintMat(); -void PrintAry(); - -main () -{ - InitializeUs(); - MakeSharedVariables; /* to make SHARED m */ - - InitProblemOnce(); - InitPerRun(); - ForwardSub(); - - printf("The result of matrix m is: \n"); - PrintMat(SHARED m, Size, Size); - printf("The result of matrix a is: \n"); - PrintMat(a, Size, Size); - printf("The result of array b is: \n"); - PrintAry(b, Size); -} - -/*------------------------------------------------------ -** InitProblemOnce -- Initialize all of matrices and -** vectors by opening a data file specified by the user. -** -** We used dynamic array **a, *b, and **m to allocate -** the memory storages. -**------------------------------------------------------ -*/ -void InitProblemOnce() -{ - char filename[30]; - - printf("Enter the data file name: "); - scanf("%s", filename); - printf("The file name is: %s\n", filename); - - fp = fopen(filename, "r"); - - fscanf(fp, "%d", &Size); - a = (float **) UsAllocScatterMatrix(Size, Size, sizeof(float)); - /* - a = (float **) malloc(Size * sizeof(float *)); - for (i=0; i -#include -#include -#include - -#include - -#include "clutils.h" -#include "utils.h" - - -// The following variables have file scope to simplify -// the utility functions - -//! All discoverable OpenCL platforms -static cl_platform_id* platforms = NULL; -static cl_uint numPlatforms; - -//! All discoverable OpenCL devices (one pointer per platform) -static cl_device_id* devices = NULL; -static cl_uint* numDevices = NULL; - -//! The chosen OpenCL platform -static cl_platform_id platform = NULL; - -//! The chosen OpenCL device -static cl_device_id device = NULL; - -//! OpenCL context -static cl_context context = NULL; - -//! OpenCL command queue -static cl_command_queue commandQueue = NULL; -static cl_command_queue commandQueueProf = NULL; -static cl_command_queue commandQueueNoProf = NULL; - -//! Global status of events -static bool eventsEnabled = false; - -//------------------------------------------------------- -// Initialization and Cleanup -//------------------------------------------------------- - -//! Initialize OpenCl environment on one device -/*! - Init function for one device. Looks for supported devices and creates a context - \return returns a context initialized -*/ -/*cl_context cl_init(char devicePreference) -{ - cl_int status; - - // Discover and populate the platforms - status = clGetPlatformIDs(0, NULL, &numPlatforms); - cl_errChk(status, "Getting platform IDs", true); - if (numPlatforms > 0) - { - // Get all the platforms - platforms = (cl_platform_id*)alloc(numPlatforms * - sizeof(cl_platform_id)); - - status = clGetPlatformIDs(numPlatforms, platforms, NULL); - cl_errChk(status, "Getting platform IDs", true); - } - else - { - // If no platforms are available, we shouldn't continue - printf("No OpenCL platforms found\n"); - exit(-1); - } - - // Allocate space for the device lists and lengths - numDevices = (cl_uint*)alloc(sizeof(cl_uint)*numPlatforms); - devices = (cl_device_id**)alloc(sizeof(cl_device_id*)*numPlatforms); - - // If a device preference was supplied, we'll limit the search of devices - // based on type - cl_device_type deviceType = CL_DEVICE_TYPE_ALL; - if(devicePreference == 'c') { - deviceType = CL_DEVICE_TYPE_CPU; - } - if(devicePreference == 'g') { - deviceType = CL_DEVICE_TYPE_GPU; - } - - // Traverse the platforms array printing information and - // populating devices - for(unsigned int i = 0; i < numPlatforms ; i++) - { - // Print out some basic info about the platform - char* platformName = NULL; - char* platformVendor = NULL; - - platformName = cl_getPlatformName(platforms[i]); - platformVendor = cl_getPlatformVendor(platforms[i]); - - status = clGetDeviceIDs(platforms[i], deviceType, 0, NULL, &numDevices[i]); - cl_errChk(status, "Getting device IDs", false); - if(status != CL_SUCCESS) { - printf("This is a known NVIDIA bug (if platform == AMD then die)\n"); - printf("Setting number of devices to 0 and continuing\n"); - numDevices[i] = 0; - } - - printf("Platform %d (%d devices):\n", i, numDevices[i]); - printf("\tName: %s\n", platformName); - printf("\tVendor: %s\n", platformVendor); - - free(platformName); - free(platformVendor); - - // Populate OpenCL devices if any exist - if(numDevices[i] != 0) - { - // Allocate an array of devices of size "numDevices" - devices[i] = (cl_device_id*)alloc(sizeof(cl_device_id)*numDevices[i]); - - // Populate Arrray with devices - status = clGetDeviceIDs(platforms[i], deviceType, numDevices[i], - devices[i], NULL); - cl_errChk(status, "Getting device IDs", true); - } - - // Print some information about each device - for( unsigned int j = 0; j < numDevices[i]; j++) - { - char* deviceName = NULL; - char* deviceVendor = NULL; - - printf("\tDevice %d:\n", j); - - deviceName = cl_getDeviceName(devices[i][j]); - deviceVendor = cl_getDeviceVendor(devices[i][j]); - - printf("\t\tName: %s\n", deviceName); - printf("\t\tVendor: %s\n", deviceVendor); - - free(deviceName); - free(deviceVendor); - } - } - - // Hard-code in the platform/device to use, or uncomment 'scanf' - // to decide at runtime - cl_uint chosen_platform, chosen_device; - // UNCOMMENT the following two lines to manually select device each time - //printf("Enter Platform and Device No (Seperated by Space) \n"); - //scanf("%d %d", &chosen_platform, &chosen_device); - chosen_platform = 0; - chosen_device = 0; - printf("Using Platform %d, Device %d \n", chosen_platform, chosen_device); - - // Do a sanity check of platform/device selection - if(chosen_platform >= numPlatforms || - chosen_device >= numDevices[chosen_platform]) { - printf("Invalid platform/device combination\n"); - exit(-1); - } - - // Set the selected platform and device - platform = platforms[chosen_platform]; - device = devices[chosen_platform][chosen_device]; - - // Create the context - cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, - (cl_context_properties)(platform), 0}; - context = clCreateContext(cps, 1, &device, NULL, NULL, &status); - cl_errChk(status, "Creating context", true); - - // Create the command queue - commandQueueProf = clCreateCommandQueue(context, device, - CL_QUEUE_PROFILING_ENABLE, &status); - cl_errChk(status, "creating command queue", true); - - commandQueueNoProf = clCreateCommandQueue(context, device, 0, &status); - cl_errChk(status, "creating command queue", true); - - if(eventsEnabled) { - printf("Profiling enabled\n"); - commandQueue = commandQueueProf; - } - else { - printf("Profiling disabled\n"); - commandQueue = commandQueueNoProf; - } - - return context; -}*/ - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - - -cl_context cl_init_context(int platform, int dev,int quiet) { - int printInfo=1; - if (platform >= 0 && dev >= 0) printInfo = 0; - cl_int status; - // Used to iterate through the platforms and devices, respectively - - // These will hold the platform and device we select (can potentially be - // multiple, but we're just doing one for now) - // cl_platform_id platform = NULL; - - /*status = clGetPlatformIDs(0, NULL, &numPlatforms); - if (printInfo) printf("Number of platforms detected:%d\n", numPlatforms); - - // Print some information about the available platforms - cl_platform_id *platforms = NULL; - cl_device_id * devices = NULL; - if (numPlatforms > 0) - { - // get all the platforms - platforms = (cl_platform_id*)malloc(numPlatforms * - sizeof(cl_platform_id)); - status = clGetPlatformIDs(numPlatforms, platforms, NULL); - - // Traverse the platforms array - if (printInfo) printf("Checking For OpenCl Compatible Devices\n"); - for(unsigned int i = 0; i < numPlatforms ; i++) - { - char pbuf[100]; - if (printInfo) printf("Platform %d:\t", i); - status = clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, - sizeof(pbuf), pbuf, NULL); - if (printInfo) printf("Vendor: %s\n", pbuf); - - //unsigned int numDevices; - - status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &numDevices); - if(cl_errChk(status, "checking for devices",true)) - exit(1); - if(numDevices == 0) { - printf("There are no devices for Platform %d\n",i); - exit(0); - } - else - { - if (printInfo) printf("\tNo of devices for Platform %d is %u\n",i, numDevices); - //! Allocate an array of devices of size "numDevices" - devices = (cl_device_id*)malloc(sizeof(cl_device_id)*numDevices); - //! Populate Arrray with devices - status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, numDevices, - devices, NULL); - if(cl_errChk(status, "getting device IDs",true)) { - exit(1); - } - } - for( unsigned int j = 0; j < numDevices; j++) - { - char dbuf[100]; - char deviceStr[100]; - if (printInfo) printf("\tDevice: %d\t", j); - status = clGetDeviceInfo(devices[j], CL_DEVICE_VENDOR, sizeof(dbuf), - deviceStr, NULL); - cl_errChk(status, "Getting Device Info\n",true); - if (printInfo) printf("Vendor: %s", deviceStr); - status = clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof(dbuf), - dbuf, NULL); - if (printInfo) printf("\n\t\tName: %s\n", dbuf); - } - } - } - else - { - // If no platforms are available, we're sunk! - printf("No OpenCL platforms found\n"); - exit(0); - } - - int platform_touse; - unsigned int device_touse; - if (printInfo) printf("Enter Platform and Device No (Seperated by Space) \n"); - if (printInfo) scanf("%d %d", &platform_touse, &device_touse); - else { - platform_touse = platform; - device_touse = dev; - } - if (!quiet) printf("Using Platform %d \t Device No %d \n",platform_touse, device_touse); - - //! Recheck how many devices does our chosen platform have - status = clGetDeviceIDs(platforms[platform_touse], CL_DEVICE_TYPE_ALL, 0, NULL, &numDevices); - - if(device_touse > numDevices) - { - printf("Invalid Device Number\n"); - exit(1); - } - - //! Populate devices array with all the visible devices of our chosen platform - devices = (cl_device_id *)malloc(sizeof(cl_device_id)*numDevices); - status = clGetDeviceIDs(platforms[platform_touse], - CL_DEVICE_TYPE_ALL, numDevices, - devices, NULL); - if(cl_errChk(status,"Error in Getting Devices\n",true)) exit(1); - - - //!Check if Device requested is a CPU or a GPU - cl_device_type dtype; - device = devices[device_touse]; - status = clGetDeviceInfo(devices[device_touse], - CL_DEVICE_TYPE, - sizeof(dtype), - (void *)&dtype, - NULL); - if(cl_errChk(status,"Error in Getting Device Info\n",true)) exit(1); - if(dtype == CL_DEVICE_TYPE_GPU) { - if (!quiet) printf("Creating GPU Context\n\n"); - } - else if (dtype == CL_DEVICE_TYPE_CPU) { - if (!quiet) printf("Creating CPU Context\n\n"); - } - else perror("This Context Type Not Supported\n"); - - cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, - (cl_context_properties)(platforms[platform_touse]), 0}; - - cl_context_properties *cprops = cps; - - context = clCreateContextFromType( - cprops, (cl_device_type)dtype, - NULL, NULL, &status); - if(cl_errChk(status, "creating Context",true)) { - exit(1); - }*/ - - // Getting platform and device information - - numPlatforms = 1; - platforms = (cl_platform_id*)malloc(numPlatforms * sizeof(cl_platform_id)); - - numDevices = (cl_uint*)malloc(sizeof(cl_uint)*numPlatforms); - numDevices[0] = 1; - devices = (cl_device_id*)malloc(sizeof(cl_device_id)*numDevices[0]); - - int platform_touse = 0; - int device_touse = 0; - - status = clGetPlatformIDs(numPlatforms, platforms, NULL); - cl_errChk(status, "Oops!", true); - status = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_DEFAULT, numDevices[0], devices, NULL); - cl_errChk(status, "Oops!", true); - context = clCreateContext(NULL, numDevices[0], devices, NULL, NULL, &status); - cl_errChk(status, "Oops!", true); - - device=devices[device_touse]; - -#ifdef PROFILING - - commandQueue = clCreateCommandQueue(context, - devices[device_touse], CL_QUEUE_PROFILING_ENABLE, &status); - -#else - - commandQueue = clCreateCommandQueue(context, - devices[device_touse], 0, &status); - -#endif // PROFILING - - if(cl_errChk(status, "creating command queue",true)) { - exit(1); - } - return context; -} -/*! - Release all resources that the user doesn't have access to. -*/ -void cl_cleanup() -{ - cl_int status; - - // Free the command queue - if (commandQueue) { - status = clReleaseCommandQueue(commandQueue); - cl_errChk(status, "Oops!", true); - printf("clReleaseCommandQueue()\n"); - } - - // Free the context - if (context) { - status = clReleaseContext(context); - cl_errChk(status, "Oops!", true); - printf("clReleaseContext()\n"); - } - - for (cl_uint p = 0; p < numPlatforms; ++p) { - for (cl_uint d = 0; d < numDevices[p]; ++d) { - status = clReleaseDevice(devices[d]); - cl_errChk(status, "Oops!", true); - printf("clReleaseDevice()\n"); - } - } - - free(devices); - free(numDevices); - free(platforms); -} - -//! Release a kernel object -/*! - \param mem The kernel object to release -*/ -void cl_freeKernel(cl_kernel kernel) -{ - cl_int status; - - if(kernel != NULL) { - status = clReleaseKernel(kernel); - cl_errChk(status, "Releasing kernel object", true); - printf("clReleaseKernel()\n"); - } -} - -//! Release memory allocated on the device -/*! - \param mem The device pointer to release -*/ -void cl_freeMem(cl_mem mem) -{ - cl_int status; - - if(mem != NULL) { - status = clReleaseMemObject(mem); - cl_errChk(status, "Releasing mem object", true); - printf("clReleaseMemObject()\n"); - } -} - -//! Release a program object -/*! - \param mem The program object to release -*/ -void cl_freeProgram(cl_program program) -{ - cl_int status; - - if(program != NULL) { - status = clReleaseProgram(program); - cl_errChk(status, "Releasing program object", true); - printf("clReleaseProgram()\n"); - } -} - -//! Returns a reference to the command queue -/*! - Returns a reference to the command queue \n - Used for any OpenCl call that needs the command queue declared in clutils.cpp -*/ -cl_command_queue cl_getCommandQueue() -{ - return commandQueue; -} - -//------------------------------------------------------- -// Synchronization functions -//------------------------------------------------------- - -/*! - Wait till all pending commands in queue are finished -*/ -void cl_sync() -{ - clFinish(commandQueue); -} - - -//------------------------------------------------------- -// Memory allocation -//------------------------------------------------------- - -//! Allocate a buffer on a device -/*! - \param mem_size Size of memory in bytes - \param flags Optional cl_mem_flags - \return Returns a cl_mem object that points to device memory -*/ -cl_mem cl_allocBuffer(size_t mem_size, cl_mem_flags flags) -{ - cl_mem mem; - cl_int status; - - /*! - Logging information for keeping track of device memory - */ - static int allocationCount = 1; - static size_t allocationSize = 0; - - allocationCount++; - allocationSize += mem_size; - - mem = clCreateBuffer(context, flags, mem_size, NULL, &status); - - cl_errChk(status, "creating buffer", true); - - return mem; -} - -//! Allocate constant memory on device -/*! - \param mem_size Size of memory in bytes - \param host_ptr Host pointer that contains the data - \return Returns a cl_mem object that points to device memory -*/ -cl_mem cl_allocBufferConst(size_t mem_size, void* host_ptr) -{ - cl_mem mem; - cl_int status; - - mem = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, - mem_size, host_ptr, &status); - cl_errChk(status, "Error creating const mem buffer", true); - - return mem; -} - -//! Allocate a buffer on device pinning the host memory at host_ptr -/*! - \param mem_size Size of memory in bytes - \return Returns a cl_mem object that points to pinned memory on the host -*/ -cl_mem cl_allocBufferPinned(size_t mem_size) -{ - cl_mem mem; - cl_int status; - - mem = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, - mem_size, NULL, &status); - cl_errChk(status, "Error allocating pinned memory", true); - - return mem; -} - -//! Allocate an image on a device -/*! - \param height Number of rows in the image - \param width Number of columns in the image - \param elemSize Size of the elements in the image - \param flags Optional cl_mem_flags - \return Returns a cl_mem object that points to device memory -*/ -cl_mem cl_allocImage(size_t height, size_t width, char type, cl_mem_flags flags) -{ - cl_mem mem; - cl_int status; - - size_t elemSize = 0; - - cl_image_format format; - format.image_channel_order = CL_R; - - switch(type) { - case 'f': - elemSize = sizeof(float); - format.image_channel_data_type = CL_FLOAT; - break; - case 'i': - elemSize = sizeof(int); - format.image_channel_data_type = CL_SIGNED_INT32; - break; - default: - printf("Error creating image: Unsupported image type.\n"); - exit(-1); - } - - /*! - Logging information for keeping track of device memory - */ - static int allocationCount = 1; - static size_t allocationSize = 0; - - allocationCount++; - allocationSize += height*width*elemSize; - - // Create the image - mem = clCreateImage2D(context, flags, &format, width, height, 0, NULL, &status); - - //cl_errChk(status, "creating image", true); - if(status != CL_SUCCESS) { - printf("Error creating image: Images may not be supported for this device.\n"); - printSupportedImageFormats(); - getchar(); - exit(-1); - } - - return mem; -} - - -//------------------------------------------------------- -// Data transfers -//------------------------------------------------------- - - -// Copy and map a buffer -void* cl_copyAndMapBuffer(cl_mem dst, cl_mem src, size_t size) { - - void* ptr; // Pointer to the pinned memory that will be returned - - cl_copyBufferToBuffer(dst, src, size); - - ptr = cl_mapBuffer(dst, size, CL_MAP_READ); - - return ptr; -} - -// Copy a buffer -void cl_copyBufferToBuffer(cl_mem dst, cl_mem src, size_t size) -{ - cl_int status; - status = clEnqueueCopyBuffer(commandQueue, src, dst, 0, 0, size, 0, NULL, - NULL); - cl_errChk(status, "Copying buffer", true); - -} - -//! Copy a buffer to the device -/*! - \param dst Valid device pointer - \param src Host pointer that contains the data - \param mem_size Size of data to copy - \param blocking Blocking or non-blocking operation -*/ -void cl_copyBufferToDevice(cl_mem dst, void* src, size_t mem_size, cl_bool blocking) -{ - cl_int status; - status = clEnqueueWriteBuffer(commandQueue, dst, blocking, 0, - mem_size, src, 0, NULL, NULL); - cl_errChk(status, "Writing buffer", true); - -} - -//! Copy a buffer to the host -/*! - \param dst Valid host pointer - \param src Device pointer that contains the data - \param mem_size Size of data to copy - \param blocking Blocking or non-blocking operation -*/ -void cl_copyBufferToHost(void* dst, cl_mem src, size_t mem_size, cl_bool blocking) -{ - cl_int status; - status = clEnqueueReadBuffer(commandQueue, src, blocking, 0, - mem_size, dst, 0, NULL, NULL); - cl_errChk(status, "Reading buffer", true); - -} - -//! Copy a buffer to a 2D image -/*! - \param src Valid device buffer - \param dst Empty device image - \param mem_size Size of data to copy -*/ -void cl_copyBufferToImage(cl_mem buffer, cl_mem image, int height, int width) -{ - size_t origin[3] = {0, 0, 0}; - size_t region[3] = {width, height, 1}; - - cl_int status; - status = clEnqueueCopyBufferToImage(commandQueue, buffer, image, 0, - origin, region, 0, NULL, NULL); - cl_errChk(status, "Copying buffer to image", true); - -} - -// Copy data to an image on the device -/*! - \param dst Valid device pointer - \param src Host pointer that contains the data - \param height Height of the image - \param width Width of the image -*/ -void cl_copyImageToDevice(cl_mem dst, void* src, size_t height, size_t width) -{ - cl_int status; - size_t origin[3] = {0, 0, 0}; - size_t region[3] = {width, height, 1}; - - status = clEnqueueWriteImage(commandQueue, dst, CL_TRUE, origin, - region, 0, 0, src, 0, NULL, NULL); - cl_errChk(status, "Writing image", true); -} - -//! Copy an image to the host -/*! - \param dst Valid host pointer - \param src Device pointer that contains the data - \param height Height of the image - \param width Width of the image -*/ -void cl_copyImageToHost(void* dst, cl_mem src, size_t height, size_t width) -{ - cl_int status; - size_t origin[3] = {0, 0, 0}; - size_t region[3] = {width, height, 1}; - - status = clEnqueueReadImage(commandQueue, src, CL_TRUE, origin, - region, 0, 0, dst, 0, NULL, NULL); - cl_errChk(status, "Reading image", true); -} - -//! Map a buffer into a host address -/*! - \param mem cl_mem object - \param mem_size Size of memory in bytes - \param flags Optional cl_mem_flags - \return Returns a host pointer that points to the mapped region -*/ -void *cl_mapBuffer(cl_mem mem, size_t mem_size, cl_mem_flags flags) -{ - cl_int status; - void *ptr; - - ptr = (void *)clEnqueueMapBuffer(commandQueue, mem, CL_TRUE, flags, - 0, mem_size, 0, NULL, NULL, &status); - - cl_errChk(status, "Error mapping a buffer", true); - - return ptr; -} - -//! Unmap a buffer or image -/*! - \param mem cl_mem object - \param ptr A host pointer that points to the mapped region -*/ -void cl_unmapBuffer(cl_mem mem, void *ptr) -{ - - // TODO It looks like AMD doesn't support profiling unmapping yet. Leaving the - // commented code here until it's supported - - cl_int status; - - status = clEnqueueUnmapMemObject(commandQueue, mem, ptr, 0, NULL, NULL); - - cl_errChk(status, "Error unmapping a buffer or image", true); -} - -void cl_writeToZCBuffer(cl_mem mem, void* data, size_t size) -{ - - void* ptr; - - ptr = cl_mapBuffer(mem, size, CL_MAP_WRITE); - - memcpy(ptr, data, size); - - cl_unmapBuffer(mem, ptr); -} - -//------------------------------------------------------- -// Program and kernels -//------------------------------------------------------- - -//! Convert source code file into cl_program -/*! -Compile Opencl source file into a cl_program. The cl_program will be made into a kernel in PrecompileKernels() - -\param kernelPath Filename of OpenCl code -\param compileoptions Compilation options -\param verbosebuild Switch to enable verbose Output -*/ -cl_program cl_compileProgram(char* kernelPath, char* compileoptions, bool verbosebuild ) -{ - cl_int status; - FILE *fp = NULL; - char *source = NULL; - long int size; - - /*printf("\t%s\n", kernelPath); - - // Determine the size of the source file -#ifdef _WIN32 - fopen_s(&fp, kernelPath, "rb"); -#else - fp = fopen(kernelPath, "rb"); -#endif - if(!fp) { - printf("Could not open kernel file\n"); - exit(-1); - } - status = fseek(fp, 0, SEEK_END); - if(status != 0) { - printf("Error seeking to end of file\n"); - exit(-1); - } - size = ftell(fp); - if(size < 0) { - printf("Error getting file position\n"); - exit(-1); - } - rewind(fp); - - // Allocate enough space for the source code - source = (char *)alloc(size + 1); - - // fill with NULLs (just for fun) - for (int i = 0; i < size+1; i++) { - source[i] = '\0'; - } - - // Read in the source code - fread(source, 1, size, fp); - source[size] = '\0';*/ - - // read kernel binary from file - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - int err = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - cl_errChk(err, "read_kernel_file", true); - - // Create the program object - //cl_program clProgramReturn = clCreateProgramWithSource(context, 1, (const char **)&source, NULL, &status); - cl_program clProgramReturn = clCreateProgramWithBinary( - context, 1, devices, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &status); - free(kernel_bin); - cl_errChk(status, "Creating program", true); - - //free(source); - //fclose(fp); - - // Try to compile the program - status = clBuildProgram(clProgramReturn, 0, NULL, compileoptions, NULL, NULL); - if(cl_errChk(status, "Building program", false) || verbosebuild == 1) - { - - cl_build_status build_status; - - clGetProgramBuildInfo(clProgramReturn, device, CL_PROGRAM_BUILD_STATUS, - sizeof(cl_build_status), &build_status, NULL); - - if(build_status == CL_SUCCESS && verbosebuild == 0) { - return clProgramReturn; - } - - //char *build_log; - size_t ret_val_size; - printf("Device: %p",device); - clGetProgramBuildInfo(clProgramReturn, device, CL_PROGRAM_BUILD_LOG, 0, - NULL, &ret_val_size); - - char *build_log = (char*)alloc(ret_val_size+1); - - clGetProgramBuildInfo(clProgramReturn, device, CL_PROGRAM_BUILD_LOG, - ret_val_size+1, build_log, NULL); - - // to be careful, terminate with \0 - // there's no information in the reference whether the string is 0 - // terminated or not - build_log[ret_val_size] = '\0'; - - printf("Build log:\n %s...\n", build_log); - if(build_status != CL_SUCCESS) { - getchar(); - exit(-1); - } - else - return clProgramReturn; - } - - // print the ptx information - // printBinaries(clProgram); - - return clProgramReturn; -} - -//! Create a kernel from compiled source -/*! -Create a kernel from compiled source - -\param program Compiled OpenCL program -\param kernel_name Name of the kernel in the program -\return Returns a cl_kernel object for the specified kernel -*/ -cl_kernel cl_createKernel(cl_program program, const char* kernel_name) { - - cl_kernel kernel; - cl_int status; - - kernel = clCreateKernel(program, kernel_name, &status); - cl_errChk(status, "Creating kernel", true); - - return kernel; -} - -//! Set an argument for a OpenCL kernel -/*! -Set an argument for a OpenCL kernel - -\param kernel The kernel for which the argument is being set -\param index The argument index -\param size The size of the argument -\param data A pointer to the argument -*/ -void cl_setKernelArg(cl_kernel kernel, unsigned int index, size_t size, - void* data) -{ - cl_int status; - status = clSetKernelArg(kernel, index, size, data); - - cl_errChk(status, "Setting kernel arg", true); -} - - -//------------------------------------------------------- -// Profiling/events -//------------------------------------------------------- - - -//! Time kernel execution using cl_event -/*! - Prints out the time taken between the start and end of an event - \param event_time -*/ -double cl_computeExecTime(cl_event event_time) -{ - cl_int status; - cl_ulong starttime; - cl_ulong endtime; - - double elapsed; - - status = clGetEventProfilingInfo(event_time, CL_PROFILING_COMMAND_START, - sizeof(cl_ulong), &starttime, NULL); - cl_errChk(status, "profiling start", true); - - status = clGetEventProfilingInfo(event_time, CL_PROFILING_COMMAND_END, - sizeof(cl_ulong), &endtime, NULL); - cl_errChk(status, "profiling end", true); - - // Convert to ms - elapsed = (double)(endtime-starttime)/1000000.0; - - return elapsed; -} - -//! Compute the elapsed time between two timer values -double cl_computeTime(cl_time start, cl_time end) -{ -#ifdef _WIN32 - __int64 freq; - int status; - - status = QueryPerformanceFrequency((LARGE_INTEGER*)&freq); - if(status == 0) { - perror("QueryPerformanceFrequency"); - exit(-1); - } - - // Return time in ms - return double(end-start)/(double(freq)/1000.0); -#else - - return end-start; -#endif -} - -//! Grab the current time using a system-specific timer -void cl_getTime(cl_time* time) -{ - -#ifdef _WIN32 - int status = QueryPerformanceCounter((LARGE_INTEGER*)time); - if(status == 0) { - perror("QueryPerformanceCounter"); - exit(-1); - } -#else - // Use gettimeofday to get the current time - struct timeval curTime; - gettimeofday(&curTime, NULL); - - // Convert timeval into double - *time = curTime.tv_sec * 1000 + (double)curTime.tv_usec/1000; -#endif -} - - - -//------------------------------------------------------- -// Error handling -//------------------------------------------------------- - -//! OpenCl error code list -/*! - An array of character strings used to give the error corresponding to the error code \n - - The error code is the index within this array -*/ -char *cl_errs[MAX_ERR_VAL] = { - (char *)"CL_SUCCESS", // 0 - (char *)"CL_DEVICE_NOT_FOUND", //-1 - (char *)"CL_DEVICE_NOT_AVAILABLE", //-2 - (char *)"CL_COMPILER_NOT_AVAILABLE", //-3 - (char *)"CL_MEM_OBJECT_ALLOCATION_FAILURE", //-4 - (char *)"CL_OUT_OF_RESOURCES", //-5 - (char *)"CL_OUT_OF_HOST_MEMORY", //-6 - (char *)"CL_PROFILING_INFO_NOT_AVAILABLE", //-7 - (char *)"CL_MEM_COPY_OVERLAP", //-8 - (char *)"CL_IMAGE_FORMAT_MISMATCH", //-9 - (char *)"CL_IMAGE_FORMAT_NOT_SUPPORTED", //-10 - (char *)"CL_BUILD_PROGRAM_FAILURE", //-11 - (char *)"CL_MAP_FAILURE", //-12 - (char *)"", //-13 - (char *)"", //-14 - (char *)"", //-15 - (char *)"", //-16 - (char *)"", //-17 - (char *)"", //-18 - (char *)"", //-19 - (char *)"", //-20 - (char *)"", //-21 - (char *)"", //-22 - (char *)"", //-23 - (char *)"", //-24 - (char *)"", //-25 - (char *)"", //-26 - (char *)"", //-27 - (char *)"", //-28 - (char *)"", //-29 - (char *)"CL_INVALID_VALUE", //-30 - (char *)"CL_INVALID_DEVICE_TYPE", //-31 - (char *)"CL_INVALID_PLATFORM", //-32 - (char *)"CL_INVALID_DEVICE", //-33 - (char *)"CL_INVALID_CONTEXT", //-34 - (char *)"CL_INVALID_QUEUE_PROPERTIES", //-35 - (char *)"CL_INVALID_COMMAND_QUEUE", //-36 - (char *)"CL_INVALID_HOST_PTR", //-37 - (char *)"CL_INVALID_MEM_OBJECT", //-38 - (char *)"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR", //-39 - (char *)"CL_INVALID_IMAGE_SIZE", //-40 - (char *)"CL_INVALID_SAMPLER", //-41 - (char *)"CL_INVALID_BINARY", //-42 - (char *)"CL_INVALID_BUILD_OPTIONS", //-43 - (char *)"CL_INVALID_PROGRAM", //-44 - (char *)"CL_INVALID_PROGRAM_EXECUTABLE", //-45 - (char *)"CL_INVALID_KERNEL_NAME", //-46 - (char *)"CL_INVALID_KERNEL_DEFINITION", //-47 - (char *)"CL_INVALID_KERNEL", //-48 - (char *)"CL_INVALID_ARG_INDEX", //-49 - (char *)"CL_INVALID_ARG_VALUE", //-50 - (char *)"CL_INVALID_ARG_SIZE", //-51 - (char *)"CL_INVALID_KERNEL_ARGS", //-52 - (char *)"CL_INVALID_WORK_DIMENSION ", //-53 - (char *)"CL_INVALID_WORK_GROUP_SIZE", //-54 - (char *)"CL_INVALID_WORK_ITEM_SIZE", //-55 - (char *)"CL_INVALID_GLOBAL_OFFSET", //-56 - (char *)"CL_INVALID_EVENT_WAIT_LIST", //-57 - (char *)"CL_INVALID_EVENT", //-58 - (char *)"CL_INVALID_OPERATION", //-59 - (char *)"CL_INVALID_GL_OBJECT", //-60 - (char *)"CL_INVALID_BUFFER_SIZE", //-61 - (char *)"CL_INVALID_MIP_LEVEL", //-62 - (char *)"CL_INVALID_GLOBAL_WORK_SIZE"}; //-63 - -//! OpenCl Error checker -/*! -Checks for error code as per cl_int returned by OpenCl -\param status Error value as cl_int -\param msg User provided error message -\return True if Error Seen, False if no error -*/ -int cl_errChk(const cl_int status, const char * msg, bool exitOnErr) -{ - - if(status != CL_SUCCESS) { - printf("OpenCL Error: %d %s %s\n", status, cl_errs[-status], msg); - - if(exitOnErr) { - exit(-1); - } - - return true; - } - return false; -} - -// Queries the supported image formats for the device and prints -// them to the screen - void printSupportedImageFormats() -{ - cl_uint numFormats; - cl_int status; - - status = clGetSupportedImageFormats(context, 0, CL_MEM_OBJECT_IMAGE2D, - 0, NULL, &numFormats); - cl_errChk(status, "getting supported image formats", true); - - cl_image_format* imageFormats = NULL; - imageFormats = (cl_image_format*)alloc(sizeof(cl_image_format)*numFormats); - - status = clGetSupportedImageFormats(context, 0, CL_MEM_OBJECT_IMAGE2D, - numFormats, imageFormats, NULL); - - printf("There are %d supported image formats\n", numFormats); - - cl_uint orders[]={CL_R, CL_A, CL_INTENSITY, CL_LUMINANCE, CL_RG, - CL_RA, CL_RGB, CL_RGBA, CL_ARGB, CL_BGRA}; - char *orderstr[]={(char *)"CL_R", (char *)"CL_A",(char *)"CL_INTENSITY", (char *)"CL_LUMINANCE", (char *)"CL_RG", - (char *)"CL_RA", (char *)"CL_RGB", (char *)"CL_RGBA", (char *)"CL_ARGB", (char *)"CL_BGRA"}; - - cl_uint types[]={ - CL_SNORM_INT8 , CL_SNORM_INT16, CL_UNORM_INT8, CL_UNORM_INT16, - CL_UNORM_SHORT_565, CL_UNORM_SHORT_555, CL_UNORM_INT_101010,CL_SIGNED_INT8, - CL_SIGNED_INT16, CL_SIGNED_INT32, CL_UNSIGNED_INT8, CL_UNSIGNED_INT16, - CL_UNSIGNED_INT32, CL_HALF_FLOAT, CL_FLOAT}; - - char * typesstr[]={ - (char *)"CL_SNORM_INT8" ,(char *)"CL_SNORM_INT16",(char *)"CL_UNORM_INT8",(char *)"CL_UNORM_INT16", - (char *)"CL_UNORM_SHORT_565",(char *)"CL_UNORM_SHORT_555",(char *)"CL_UNORM_INT_101010", - (char *)"CL_SIGNED_INT8",(char *)"CL_SIGNED_INT16",(char *)"CL_SIGNED_INT32",(char *)"CL_UNSIGNED_INT8", - (char *)"CL_UNSIGNED_INT16",(char *)"CL_UNSIGNED_INT32",(char *)"CL_HALF_FLOAT",(char *)"CL_FLOAT"}; - - printf("Supported Formats:\n"); - for(int i = 0; i < (int)numFormats; i++) { - printf("\tFormat %d: ", i); - - for(int j = 0; j < (int)(sizeof(orders)/sizeof(cl_int)); j++) { - if(imageFormats[i].image_channel_order == orders[j]) { - printf("%s, ", orderstr[j]); - } - } - for(int j = 0; j < (int)(sizeof(types)/sizeof(cl_int)); j++) { - if(imageFormats[i].image_channel_data_type == types[j]) { - printf("%s, ", typesstr[j]); - } - } - printf("\n"); - } - - free(imageFormats); -} - - -//------------------------------------------------------- -// Platform and device information -//------------------------------------------------------- - -//! Returns true if AMD is the device vendor -bool cl_deviceIsAMD(cl_device_id dev) { - - bool retval = false; - - char* vendor = cl_getDeviceVendor(dev); - - if(strncmp(vendor, "Advanced", 8) == 0) { - retval = true; - } - - free(vendor); - - return retval; -} - -//! Returns true if NVIDIA is the device vendor -bool cl_deviceIsNVIDIA(cl_device_id dev) { - - bool retval = false; - - char* vendor = cl_getDeviceVendor(dev); - - if(strncmp(vendor, "NVIDIA", 6) == 0) { - retval = true; - } - - free(vendor); - - return retval; -} - -//! Returns true if NVIDIA is the device vendor -bool cl_platformIsNVIDIA(cl_platform_id plat) { - - bool retval = false; - - char* vendor = cl_getPlatformVendor(plat); - - if(strncmp(vendor, "NVIDIA", 6) == 0) { - retval = true; - } - - free(vendor); - - return retval; -} - -//! Get the name of the vendor for a device -char* cl_getDeviceDriverVersion(cl_device_id dev) -{ - cl_int status; - size_t devInfoSize; - char* devInfoStr = NULL; - - // If dev is NULL, set it to the default device - if(dev == NULL) { - dev = device; - } - - // Print the vendor - status = clGetDeviceInfo(dev, CL_DRIVER_VERSION, 0, - NULL, &devInfoSize); - cl_errChk(status, "Getting vendor name", true); - - devInfoStr = (char*)alloc(devInfoSize); - - status = clGetDeviceInfo(dev, CL_DRIVER_VERSION, devInfoSize, - devInfoStr, NULL); - cl_errChk(status, "Getting vendor name", true); - - return devInfoStr; -} - -//! The the name of the device as supplied by the OpenCL implementation -char* cl_getDeviceName(cl_device_id dev) -{ - cl_int status; - size_t devInfoSize; - char* devInfoStr = NULL; - - // If dev is NULL, set it to the default device - if(dev == NULL) { - dev = device; - } - - // Print the name - status = clGetDeviceInfo(dev, CL_DEVICE_NAME, 0, - NULL, &devInfoSize); - cl_errChk(status, "Getting device name", true); - - devInfoStr = (char*)alloc(devInfoSize); - - status = clGetDeviceInfo(dev, CL_DEVICE_NAME, devInfoSize, - devInfoStr, NULL); - cl_errChk(status, "Getting device name", true); - - return(devInfoStr); -} - -//! Get the name of the vendor for a device -char* cl_getDeviceVendor(cl_device_id dev) -{ - cl_int status; - size_t devInfoSize; - char* devInfoStr = NULL; - - // If dev is NULL, set it to the default device - if(dev == NULL) { - dev = device; - } - - // Print the vendor - status = clGetDeviceInfo(dev, CL_DEVICE_VENDOR, 0, - NULL, &devInfoSize); - cl_errChk(status, "Getting vendor name", true); - - devInfoStr = (char*)alloc(devInfoSize); - - status = clGetDeviceInfo(dev, CL_DEVICE_VENDOR, devInfoSize, - devInfoStr, NULL); - cl_errChk(status, "Getting vendor name", true); - - return devInfoStr; -} - -//! Get the name of the vendor for a device -char* cl_getDeviceVersion(cl_device_id dev) -{ - cl_int status; - size_t devInfoSize; - char* devInfoStr = NULL; - - // If dev is NULL, set it to the default device - if(dev == NULL) { - dev = device; - } - - // Print the vendor - status = clGetDeviceInfo(dev, CL_DEVICE_VERSION, 0, - NULL, &devInfoSize); - cl_errChk(status, "Getting vendor name", true); - - devInfoStr = (char*)alloc(devInfoSize); - - status = clGetDeviceInfo(dev, CL_DEVICE_VERSION, devInfoSize, - devInfoStr, NULL); - cl_errChk(status, "Getting vendor name", true); - - return devInfoStr; -} - -//! The the name of the device as supplied by the OpenCL implementation -char* cl_getPlatformName(cl_platform_id platform) -{ - cl_int status; - size_t platformInfoSize; - char* platformInfoStr = NULL; - - // Print the name - status = clGetPlatformInfo(platform, CL_PLATFORM_NAME, 0, - NULL, &platformInfoSize); - cl_errChk(status, "Getting platform name", true); - - platformInfoStr = (char*)alloc(platformInfoSize); - - status = clGetPlatformInfo(platform, CL_PLATFORM_NAME, platformInfoSize, - platformInfoStr, NULL); - cl_errChk(status, "Getting platform name", true); - - return(platformInfoStr); -} - -//! The the name of the device as supplied by the OpenCL implementation -char* cl_getPlatformVendor(cl_platform_id platform) -{ - cl_int status; - size_t platformInfoSize; - char* platformInfoStr = NULL; - - // Print the name - status = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, 0, - NULL, &platformInfoSize); - cl_errChk(status, "Getting platform name", true); - - platformInfoStr = (char*)alloc(platformInfoSize); - - status = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, platformInfoSize, - platformInfoStr, NULL); - cl_errChk(status, "Getting platform name", true); - - return(platformInfoStr); -} - -//------------------------------------------------------- -// Utility functions -//------------------------------------------------------- - -//! Take a string and an int, and return a string -char* catStringWithInt(const char* string, int integer) { - - if(integer > 99999) { - printf("Can't handle event identifiers with 6 digits\n"); - exit(-1); - } - - // 5 characters for the identifier, 1 for the null terminator - int strLen = strlen(string)+5+1; - char* eventStr = (char*)alloc(sizeof(char)*strLen); - - char tmp[6]; - - strcpy(eventStr, string); - strncat(eventStr, itoa_portable(integer, tmp, 10), 5); - - return eventStr; -} - -/** - ** C++ version 0.4 char* style "itoa": - ** Written by Lukás Chmela - ** Released under GPLv3. - **/ -//portable itoa function -char* itoa_portable(int value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - int tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - //Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - - return result; -} \ No newline at end of file diff --git a/tests/opencl/guassian/clutils.h b/tests/opencl/guassian/clutils.h deleted file mode 100755 index 51177d07..00000000 --- a/tests/opencl/guassian/clutils.h +++ /dev/null @@ -1,281 +0,0 @@ -/****************************************************************************\ - * Copyright (c) 2011, Advanced Micro Devices, Inc. * - * All rights reserved. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions * - * are met: * - * * - * Redistributions of source code must retain the above copyright notice, * - * this list of conditions and the following disclaimer. * - * * - * Redistributions in binary form must reproduce the above copyright notice, * - * this list of conditions and the following disclaimer in the documentation * - * and/or other materials provided with the distribution. * - * * - * Neither the name of the copyright holder nor the names of its contributors * - * may be used to endorse or promote products derived from this software * - * without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * * - * If you use the software (in whole or in part), you shall adhere to all * - * applicable U.S., European, and other export laws, including but not * - * limited to the U.S. Export Administration Regulations (“EAR”), (15 C.F.R. * - * Sections 730 through 774), and E.U. Council Regulation (EC) No 1334/2000 * - * of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, you * - * hereby certify that, except pursuant to a license granted by the United * - * States Department of Commerce Bureau of Industry and Security or as * - * otherwise permitted pursuant to a License Exception under the U.S. Export * - * Administration Regulations ("EAR"), you will not (1) export, re-export or * - * release to a national of a country in Country Groups D:1, E:1 or E:2 any * - * restricted technology, software, or source code you receive hereunder, * - * or (2) export to Country Groups D:1, E:1 or E:2 the direct product of such * - * technology or software, if such foreign produced direct product is subject * - * to national security controls as identified on the Commerce Control List * - *(currently found in Supplement 1 to Part 774 of EAR). For the most current * - * Country Group listings, or for additional information about the EAR or * - * your obligations under those regulations, please refer to the U.S. Bureau * - * of Industry and Security’s website at http://www.bis.doc.gov/. * - \****************************************************************************/ - -#ifndef __CL_UTILS_H__ -#define __CL_UTILS_H__ - -#include - -// The cl_time type is OS specific -#ifdef _WIN32 -#include -#include -typedef __int64 cl_time; -#else -#include -typedef double cl_time; -#endif - -//------------------------------------------------------- -// Initialization and Cleanup -//------------------------------------------------------- - -// Detects platforms and devices, creates context and command queue -cl_context cl_init(char devicePreference='\0'); - -// Creates a context given a platform and a device -cl_context cl_init_context(int platform,int dev,int quiet=0); - -// Releases resources used by clutils -void cl_cleanup(); - -// Releases a kernel object -void cl_freeKernel(cl_kernel kernel); - -// Releases a memory object -void cl_freeMem(cl_mem mem); - -// Releases a program object -void cl_freeProgram(cl_program program); - -// Returns the global command queue -cl_command_queue cl_getCommandQueue(); - - -//------------------------------------------------------- -// Synchronization functions -//------------------------------------------------------- - -// Performs a clFinish on the command queue -void cl_sync(); - - -//------------------------------------------------------- -// Memory allocation -//------------------------------------------------------- - -// Allocates a regular buffer on the device -cl_mem cl_allocBuffer(size_t mem_size, - cl_mem_flags flags = CL_MEM_READ_WRITE); - -// XXX I don't think this does exactly what we want it to do -// Allocates a read-only buffer and transfers the data -cl_mem cl_allocBufferConst(size_t mem_size, void* host_ptr); - -// Allocates pinned memory on the host -cl_mem cl_allocBufferPinned(size_t mem_size); - -// Allocates an image on the device -cl_mem cl_allocImage(size_t height, size_t width, char type, - cl_mem_flags flags = CL_MEM_READ_WRITE); - - - -//------------------------------------------------------- -// Data transfers -//------------------------------------------------------- - -// Copies a buffer from the device to pinned memory on the host and -// maps it so it can be read -void* cl_copyAndMapBuffer(cl_mem dst, cl_mem src, size_t size); - -// Copies from one buffer to another -void cl_copyBufferToBuffer(cl_mem dst, cl_mem src, size_t size); - -// Copies data to a buffer on the device -void cl_copyBufferToDevice(cl_mem dst, void *src, size_t mem_size, - cl_bool blocking = CL_TRUE); - -// Copies data to an image on the device -void cl_copyImageToDevice(cl_mem dst, void* src, size_t height, size_t width); - -// Copies an image from the device to the host -void cl_copyImageToHost(void* dst, cl_mem src, size_t height, size_t width); - -// Copies data from a device buffer to the host -void cl_copyBufferToHost(void *dst, cl_mem src, size_t mem_size, - cl_bool blocking = CL_TRUE); - -// Copies data from a buffer on the device to an image on the device -void cl_copyBufferToImage(cl_mem src, cl_mem dst, int height, int width); - -// Maps a buffer -void* cl_mapBuffer(cl_mem mem, size_t mem_size, cl_mem_flags flags); - -// Unmaps a buffer -void cl_unmapBuffer(cl_mem mem, void *ptr); - -// Writes data to a zero-copy buffer on the device -void cl_writeToZCBuffer(cl_mem mem, void* data, size_t size); - -//------------------------------------------------------- -// Program and kernels -//------------------------------------------------------- - -// Compiles a program -cl_program cl_compileProgram(char* kernelPath, char* compileoptions, - bool verboseoptions = 0); - -// Creates a kernel -cl_kernel cl_createKernel(cl_program program, const char* kernelName); - - -// Sets a kernel argument -void cl_setKernelArg(cl_kernel kernel, unsigned int index, size_t size, - void* data); - - -//------------------------------------------------------- -// Profiling/events -//------------------------------------------------------- - -// Computes the execution time (start to end) for an event -double cl_computeExecTime(cl_event); - -// Compute the elapsed time between two CPU timer values -double cl_computeTime(cl_time start, cl_time end); - -// Creates an event from CPU timers -void cl_createUserEvent(cl_time start, cl_time end, char* desc); - -// Disable logging of events -void cl_disableEvents(); - -// Enable logging of events -void cl_enableEvents(); - -// Query the current system time -void cl_getTime(cl_time* time); - -// Calls a function which prints events to the terminal -void cl_printEvents(); - -// Calls a function which writes the events to a file -void cl_writeEventsToFile(char* path); - - -//------------------------------------------------------- -// Error handling -//------------------------------------------------------- - -// Compare a status value to CL_SUCCESS and optionally exit on error -int cl_errChk(const cl_int status, const char *msg, bool exitOnErr); - -// Queries the supported image formats for the device and prints -// them to the screen -void printSupportedImageFormats(); - -//------------------------------------------------------- -// Platform and device information -//------------------------------------------------------- - -bool cl_deviceIsAMD(cl_device_id dev=NULL); -bool cl_deviceIsNVIDIA(cl_device_id dev=NULL); -bool cl_platformIsNVIDIA(cl_platform_id plat=NULL); -char* cl_getDeviceDriverVersion(cl_device_id dev=NULL); -char* cl_getDeviceName(cl_device_id dev=NULL); -char* cl_getDeviceVendor(cl_device_id dev=NULL); -char* cl_getDeviceVersion(cl_device_id dev=NULL); -char* cl_getPlatformName(cl_platform_id platform); -char* cl_getPlatformVendor(cl_platform_id platform); - -//------------------------------------------------------- -// Utility functions -//------------------------------------------------------- - -char* catStringWithInt(const char* str, int integer); - -char* itoa_portable(int value, char* result, int base); - -//------------------------------------------------------- -// Data types -//------------------------------------------------------- -typedef struct{ - int x; - int y; -} int2; - -typedef struct{ - float x; - float y; -}float2; - -typedef struct{ - float x; - float y; - float z; - float w; -}float4; - -//------------------------------------------------------- -// Defines -//------------------------------------------------------- - -#define MAX_ERR_VAL 64 - -#define NUM_PROGRAMS 7 - -#define NUM_KERNELS 13 -#define KERNEL_INIT_DET 0 -#define KERNEL_BUILD_DET 1 -#define KERNEL_SURF_DESC 2 -#define KERNEL_NORM_DESC 3 -#define KERNEL_NON_MAX_SUP 4 -#define KERNEL_GET_ORIENT1 5 -#define KERNEL_GET_ORIENT2 6 -#define KERNEL_NN 7 -#define KERNEL_SCAN 8 -#define KERNEL_SCAN4 9 -#define KERNEL_TRANSPOSE 10 -#define KERNEL_SCANIMAGE 11 -#define KERNEL_TRANSPOSEIMAGE 12 - -#endif diff --git a/tests/opencl/guassian/gaussianElim.h b/tests/opencl/guassian/gaussianElim.h deleted file mode 100755 index 5d905d7e..00000000 --- a/tests/opencl/guassian/gaussianElim.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _GAUSSIANELIM -#define _GAUSSIANELIM - -#include -#include -#include -#include -#include -#include -#include - -#include "clutils.h" - -// All OpenCL headers -#if defined (__APPLE__) || defined(MACOSX) - #include -#else - #include -#endif - -float *OpenClGaussianElimination( - cl_context context, - int timing); - -void printUsage(); -int parseCommandline(int argc, char *argv[], char* filename, - int *q, int *t, int *p, int *d); - -void InitPerRun(int size,float *m); -void ForwardSub(cl_context context, float *a, float *b, float *m, int size,int timing); -void BackSub(float *a, float *b, float *finalVec, int size); -void Fan1(float *m, float *a, int Size, int t); -void Fan2(float *m, float *a, float *b,int Size, int j1, int t); -//void Fan3(float *m, float *b, int Size, int t); -void InitMat(FILE *fp, int size, float *ary, int nrow, int ncol); -void InitAry(FILE *fp, float *ary, int ary_size); -void PrintMat(float *ary, int size, int nrow, int ncolumn); -void PrintAry(float *ary, int ary_size); -float eventTime(cl_event event,cl_command_queue command_queue); -#endif diff --git a/tests/opencl/guassian/gettimeofday.cpp b/tests/opencl/guassian/gettimeofday.cpp deleted file mode 100755 index a0486593..00000000 --- a/tests/opencl/guassian/gettimeofday.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "stdio.h" -#include -#include -#include -//using namespace System; -using namespace std; - -#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) - #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 -#else - #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL -#endif - -struct timezone -{ - int tz_minuteswest; /* minutes W of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - - -// Definition of a gettimeofday function - int gettimeofday(struct timeval *tv, struct timezone *tz) -{ -// Define a structure to receive the current Windows filetime - FILETIME ft; - -// Initialize the present time to 0 and the timezone to UTC - unsigned __int64 tmpres = 0; - static int tzflag = 0; - - if (NULL != tv) - { - GetSystemTimeAsFileTime(&ft); - -// The GetSystemTimeAsFileTime returns the number of 100 nanosecond -// intervals since Jan 1, 1601 in a structure. Copy the high bits to -// the 64 bit tmpres, shift it left by 32 then or in the low 32 bits. - tmpres |= ft.dwHighDateTime; - tmpres <<= 32; - tmpres |= ft.dwLowDateTime; - -// Convert to microseconds by dividing by 10 - tmpres /= 10; - -// The Unix epoch starts on Jan 1 1970. Need to subtract the difference -// in seconds from Jan 1 1601. - tmpres -= DELTA_EPOCH_IN_MICROSECS; - -// Finally change microseconds to seconds and place in the seconds value. -// The modulus picks up the microseconds. - tv->tv_sec = (long)(tmpres / 1000000UL); - tv->tv_usec = (long)(tmpres % 1000000UL); - } - - if (NULL != tz) - { - if (!tzflag) - { - _tzset(); - tzflag++; - } - -// Adjust for the timezone west of Greenwich - long seconds_diff; - _get_timezone(&seconds_diff); - tz->tz_minuteswest = seconds_diff / 60; - int hours_offset; - _get_daylight(&hours_offset); - tz->tz_dsttime = hours_offset; - } - - return 0; -} - diff --git a/tests/opencl/guassian/gettimeofday.h b/tests/opencl/guassian/gettimeofday.h deleted file mode 100755 index 8db1f7a9..00000000 --- a/tests/opencl/guassian/gettimeofday.h +++ /dev/null @@ -1,17 +0,0 @@ - -#ifdef _WIN32 -#include -/** -Based on code seen at. - -http://www.winehq.org/pipermail/wine-devel/2003-June/018082.html - -http://msdn.microsoft.com/en-us/library/ms740560 - -*/ -int gettimeofday(struct timeval *tv, struct timezone *tz); -#else -#include -#endif - - diff --git a/tests/opencl/guassian/kernel.cl b/tests/opencl/guassian/kernel.cl deleted file mode 100755 index c370e9b2..00000000 --- a/tests/opencl/guassian/kernel.cl +++ /dev/null @@ -1,49 +0,0 @@ -//#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable - -typedef struct latLong - { - float lat; - float lng; - } LatLong; - -__kernel void Fan1(__global float *m_dev, - __global float *a_dev, - __global float *b_dev, - const int size, - const int t) { - int globalId = get_global_id(0); - - if (globalId < size-1-t) { - *(m_dev + size * (globalId + t + 1)+t) = *(a_dev + size * (globalId + t + 1) + t) / *(a_dev + size * t + t); - } -} - - -__kernel void Fan2(__global float *m_dev, - __global float *a_dev, - __global float *b_dev, - const int size, - const int t) { - int globalId = get_global_id(0); - - int globalIdx = get_global_id(0); - int globalIdy = get_global_id(1); - if (globalIdx < size-1-t && globalIdy < size-t) { - a_dev[size*(globalIdx+1+t)+(globalIdy+t)] -= m_dev[size*(globalIdx+1+t)+t] * a_dev[size*t+(globalIdy+t)]; - - if(globalIdy == 0){ - b_dev[globalIdx+1+t] -= m_dev[size*(globalIdx+1+t)+(globalIdy+t)] * b_dev[t]; - } - } -// One dimensional -// int globalIdx = globalId % size; -// int globalIdy = globalId / size; -// -// if (globalIdx < size-1-t && globalIdy < size-t) { -// a_dev[size*(globalIdx+1+t)+(globalIdy+t)] -= m_dev[size*(globalIdx+1+t)+t] * a_dev[size*t+(globalIdy+t)]; -// } -// if(globalIdy == 0){ -// b_dev[globalIdx+1+t] -= m_dev[size*(globalIdx+1+t)+(globalIdy+t)] * b_dev[t]; -// } - -} diff --git a/tests/opencl/guassian/main.cc b/tests/opencl/guassian/main.cc deleted file mode 100755 index a221a267..00000000 --- a/tests/opencl/guassian/main.cc +++ /dev/null @@ -1,420 +0,0 @@ -#ifndef __GAUSSIAN_ELIMINATION__ -#define __GAUSSIAN_ELIMINATION__ - -#include "gaussianElim.h" - -cl_context context = NULL; - -int main(int argc, char *argv[]) { - printf("enter demo main\n"); - float *a = NULL, *b = NULL, *finalVec = NULL; - float *m = NULL; - int size; - - FILE *fp; - - // args - char filename[100]; - int quiet = 0, timing = 0, platform = -1, device = -1; - - // parse command line - if (parseCommandline(argc, argv, filename, &quiet, &timing, &platform, - &device)) { - printUsage(); - return 0; - } - - context = cl_init_context(platform, device, quiet); - - fp = fopen(filename, "r"); - fscanf(fp, "%d", &size); - - a = (float *)malloc(size * size * sizeof(float)); - - InitMat(fp, size, a, size, size); - // printf("The input matrix a is:\n"); - // PrintMat(a, size, size, size); - b = (float *)malloc(size * sizeof(float)); - - InitAry(fp, b, size); - // printf("The input array b is:\n"); - // PrintAry(b, size); - - // create the solution matrix - m = (float *)malloc(size * size * sizeof(float)); - - // create a new vector to hold the final answer - finalVec = (float *)malloc(size * sizeof(float)); - - InitPerRun(size, m); - - // begin timing - - // run kernels - ForwardSub(context, a, b, m, size, timing); - - // end timing - if (!quiet) { - printf("The result of matrix m is: \n"); - - PrintMat(m, size, size, size); - printf("The result of matrix a is: \n"); - PrintMat(a, size, size, size); - printf("The result of array b is: \n"); - PrintAry(b, size); - - BackSub(a, b, finalVec, size); - printf("The final solution is: \n"); - PrintAry(finalVec, size); - } - - fclose(fp); - free(m); - free(a); - free(b); - free(finalVec); - // OpenClGaussianElimination(context,timing); - - cl_cleanup(); - - printf("Passed!\n"); - return 0; -} - -/*------------------------------------------------------ - ** ForwardSub() -- Forward substitution of Gaussian - ** elimination. - **------------------------------------------------------ - */ -void ForwardSub(cl_context context, float *a, float *b, float *m, int size, - int timing) { - // 1. set up kernels - cl_kernel fan1_kernel, fan2_kernel; - cl_int status = 0; - cl_program gaussianElim_program; - cl_event writeEvent, kernelEvent, readEvent; - float writeTime = 0, readTime = 0, kernelTime = 0; - float writeMB = 0, readMB = 0; - - gaussianElim_program = cl_compileProgram((char *)"gaussianElim_kernels.cl", NULL); - - fan1_kernel = clCreateKernel(gaussianElim_program, "Fan1", &status); - status = cl_errChk(status, (char *)"Error Creating Fan1 kernel", true); - if (status) - exit(1); - - fan2_kernel = clCreateKernel(gaussianElim_program, "Fan2", &status); - status = cl_errChk(status, (char *)"Error Creating Fan2 kernel", true); - if (status) - exit(1); - - // 2. set up memory on device and send ipts data to device - - cl_mem a_dev, b_dev, m_dev; - - cl_int error = 0; - - a_dev = clCreateBuffer(context, CL_MEM_READ_WRITE, - sizeof(float) * size * size, NULL, &error); - - b_dev = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) * size, NULL, - &error); - - m_dev = clCreateBuffer(context, CL_MEM_READ_WRITE, - sizeof(float) * size * size, NULL, &error); - - cl_command_queue command_queue = cl_getCommandQueue(); - - error = clEnqueueWriteBuffer(command_queue, a_dev, - 1, // change to 0 for nonblocking write - 0, // offset - sizeof(float) * size * size, a, 0, NULL, - &writeEvent); - - if (timing) - writeTime += eventTime(writeEvent, command_queue); - clReleaseEvent(writeEvent); - - error = clEnqueueWriteBuffer(command_queue, b_dev, - 1, // change to 0 for nonblocking write - 0, // offset - sizeof(float) * size, b, 0, NULL, &writeEvent); - if (timing) - writeTime += eventTime(writeEvent, command_queue); - clReleaseEvent(writeEvent); - - error = clEnqueueWriteBuffer(command_queue, - m_dev, - 1, // change to 0 for nonblocking write - 0, // offset - sizeof(float) * size * size, m, 0, NULL, - &writeEvent); - if (timing) - writeTime += eventTime(writeEvent, command_queue); - clReleaseEvent(writeEvent); - writeMB = (float)(sizeof(float) * size * (size + size + 1) / 1e6); - - // 3. Determine block sizes - size_t globalWorksizeFan1[1]; - size_t globalWorksizeFan2[2]; - - globalWorksizeFan1[0] = size; - globalWorksizeFan2[0] = size; - globalWorksizeFan2[1] = size; - - int t; - // 4. Setup and Run kernels - for (t = 0; t < (size - 1); t++) { - // kernel args - cl_int argchk; - argchk = clSetKernelArg(fan1_kernel, 0, sizeof(cl_mem), (void *)&m_dev); - argchk |= clSetKernelArg(fan1_kernel, 1, sizeof(cl_mem), (void *)&a_dev); - argchk |= clSetKernelArg(fan1_kernel, 2, sizeof(cl_mem), (void *)&b_dev); - argchk |= clSetKernelArg(fan1_kernel, 3, sizeof(int), (void *)&size); - argchk |= clSetKernelArg(fan1_kernel, 4, sizeof(int), (void *)&t); - - cl_errChk(argchk, "ERROR in Setting Fan1 kernel args", true); - - // launch kernel - error = - clEnqueueNDRangeKernel(command_queue, fan1_kernel, 1, 0, - globalWorksizeFan1, NULL, 0, NULL, &kernelEvent); - - cl_errChk(error, "ERROR in Executing Fan1 Kernel", true); - if (timing) { - // printf("here1a\n"); - kernelTime += eventTime(kernelEvent, command_queue); - // printf("here1b\n"); - } - clReleaseEvent(kernelEvent); - // Fan1<<>>(m_cuda,a_cuda,Size,t); - // cudaThreadSynchronize(); - - // kernel args - argchk = clSetKernelArg(fan2_kernel, 0, sizeof(cl_mem), (void *)&m_dev); - argchk |= clSetKernelArg(fan2_kernel, 1, sizeof(cl_mem), (void *)&a_dev); - argchk |= clSetKernelArg(fan2_kernel, 2, sizeof(cl_mem), (void *)&b_dev); - argchk |= clSetKernelArg(fan2_kernel, 3, sizeof(int), (void *)&size); - argchk |= clSetKernelArg(fan2_kernel, 4, sizeof(int), (void *)&t); - - cl_errChk(argchk, "ERROR in Setting Fan2 kernel args", true); - - // launch kernel - error = - clEnqueueNDRangeKernel(command_queue, fan2_kernel, 2, 0, - globalWorksizeFan2, NULL, 0, NULL, &kernelEvent); - - cl_errChk(error, "ERROR in Executing Fan1 Kernel", true); - if (timing) { - // printf("here2a\n"); - kernelTime += eventTime(kernelEvent, command_queue); - // printf("here2b\n"); - } - clReleaseEvent(kernelEvent); - // Fan2<<>>(m_cuda,a_cuda,b_cuda,Size,Size-t,t); - // cudaThreadSynchronize(); - } - // 5. transfer data off of device - error = - clEnqueueReadBuffer(command_queue, a_dev, - 1, // change to 0 for nonblocking write - 0, // offset - sizeof(float) * size * size, a, 0, NULL, &readEvent); - - cl_errChk(error, "ERROR with clEnqueueReadBuffer", true); - if (timing) - readTime += eventTime(readEvent, command_queue); - clReleaseEvent(readEvent); - - error = clEnqueueReadBuffer(command_queue, b_dev, - 1, // change to 0 for nonblocking write - 0, // offset - sizeof(float) * size, b, 0, NULL, &readEvent); - cl_errChk(error, "ERROR with clEnqueueReadBuffer", true); - if (timing) - readTime += eventTime(readEvent, command_queue); - clReleaseEvent(readEvent); - - error = - clEnqueueReadBuffer(command_queue, m_dev, - 1, // change to 0 for nonblocking write - 0, // offset - sizeof(float) * size * size, m, 0, NULL, &readEvent); - - cl_errChk(error, "ERROR with clEnqueueReadBuffer", true); - if (timing) - readTime += eventTime(readEvent, command_queue); - clReleaseEvent(readEvent); - readMB = (float)(sizeof(float) * size * (size + size + 1) / 1e6); - - if (timing) { - printf("Matrix Size\tWrite(s) [size]\t\tKernel(s)\tRead(s) " - "[size]\t\tTotal(s)\n"); - printf("%dx%d \t", size, size); - - printf("%f [%.2fMB]\t", writeTime, writeMB); - - printf("%f\t", kernelTime); - - printf("%f [%.2fMB]\t", readTime, readMB); - - printf("%f\n\n", writeTime + kernelTime + readTime); - } - - cl_freeMem(a_dev); - cl_freeMem(b_dev); - cl_freeMem(m_dev); - cl_freeKernel(fan1_kernel); - cl_freeKernel(fan2_kernel); - cl_freeProgram(gaussianElim_program); -} - -float eventTime(cl_event event, cl_command_queue command_queue) { - cl_int error = 0; - cl_ulong eventStart, eventEnd; - clFinish(command_queue); - error = clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, - sizeof(cl_ulong), &eventStart, NULL); - cl_errChk(error, "ERROR in Event Profiling.", true); - error = clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, - sizeof(cl_ulong), &eventEnd, NULL); - cl_errChk(error, "ERROR in Event Profiling.", true); - - return (float)((eventEnd - eventStart) / 1e9); -} - -int parseCommandline(int argc, char *argv[], char *filename, int *q, int *t, - int *p, int *d) { - int i; - // if (argc < 2) return 1; // error - strncpy(filename, "matrix4.txt", 100); - char flag; - - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-') { // flag - flag = argv[i][1]; - switch (flag) { - case 'h': // help - return 1; - break; - case 'q': // quiet - *q = 1; - break; - case 't': // timing - *t = 1; - break; - case 'p': // platform - i++; - *p = atoi(argv[i]); - break; - case 'd': // device - i++; - *d = atoi(argv[i]); - break; - } - } - } - if ((*d >= 0 && *p < 0) || - (*p >= 0 && - *d < 0)) // both p and d must be specified if either are specified - return 1; - return 0; -} - -void printUsage() { - printf("Gaussian Elimination Usage\n"); - printf("\n"); - printf("gaussianElimination [filename] [-hqt] [-p [int] -d [int]]\n"); - printf("\n"); - printf("example:\n"); - printf("$ ./gaussianElimination matrix4.txt\n"); - printf("\n"); - printf("filename the filename that holds the matrix data\n"); - printf("\n"); - printf("-h Display the help file\n"); - printf("-q Quiet mode. Suppress all text output.\n"); - printf("-t Print timing information.\n"); - printf("\n"); - printf("-p [int] Choose the platform (must choose both platform and " - "device)\n"); - printf("-d [int] Choose the device (must choose both platform and " - "device)\n"); - printf("\n"); - printf("\n"); - printf("Notes: 1. The filename is required as the first parameter.\n"); - printf(" 2. If you declare either the device or the platform,\n"); - printf(" you must declare both.\n\n"); -} - -/*------------------------------------------------------ - ** InitPerRun() -- Initialize the contents of the - ** multipier matrix **m - **------------------------------------------------------ - */ -void InitPerRun(int size, float *m) { - int i; - for (i = 0; i < size * size; i++) - *(m + i) = 0.0; -} -void BackSub(float *a, float *b, float *finalVec, int size) { - // solve "bottom up" - int i, j; - for (i = 0; i < size; i++) { - finalVec[size - i - 1] = b[size - i - 1]; - for (j = 0; j < i; j++) { - finalVec[size - i - 1] -= *(a + size * (size - i - 1) + (size - j - 1)) * - finalVec[size - j - 1]; - } - finalVec[size - i - 1] = - finalVec[size - i - 1] / *(a + size * (size - i - 1) + (size - i - 1)); - } -} -void InitMat(FILE *fp, int size, float *ary, int nrow, int ncol) { - int i, j; - - for (i = 0; i < nrow; i++) { - for (j = 0; j < ncol; j++) { - fscanf(fp, "%f", ary + size * i + j); - } - } -} -/*------------------------------------------------------ - ** InitAry() -- Initialize the array (vector) by reading - ** data from the data file - **------------------------------------------------------ - */ -void InitAry(FILE *fp, float *ary, int ary_size) { - int i; - - for (i = 0; i < ary_size; i++) { - fscanf(fp, "%f", &ary[i]); - } -} -/*------------------------------------------------------ - ** PrintMat() -- Print the contents of the matrix - **------------------------------------------------------ - */ -void PrintMat(float *ary, int size, int nrow, int ncol) { - int i, j; - - for (i = 0; i < nrow; i++) { - for (j = 0; j < ncol; j++) { - printf("%8.2f ", *(ary + size * i + j)); - } - printf("\n"); - } - printf("\n"); -} - -/*------------------------------------------------------ - ** PrintAry() -- Print the contents of the array (vector) - **------------------------------------------------------ - */ -void PrintAry(float *ary, int ary_size) { - int i; - for (i = 0; i < ary_size; i++) { - printf("%.2f ", ary[i]); - } - printf("\n\n"); -} -#endif diff --git a/tests/opencl/guassian/matrix4.txt b/tests/opencl/guassian/matrix4.txt deleted file mode 100755 index abf30b49..00000000 --- a/tests/opencl/guassian/matrix4.txt +++ /dev/null @@ -1,11 +0,0 @@ -4 - --0.6 -0.5 0.7 0.3 --0.3 -0.9 0.3 0.7 --0.4 -0.5 -0.3 -0.8 -0.0 -0.1 0.2 0.9 - --0.85 -0.68 0.24 -0.53 - -0.7 0.0 -0.4 -0.5 - diff --git a/tests/opencl/guassian/run b/tests/opencl/guassian/run deleted file mode 100755 index 31683b1b..00000000 --- a/tests/opencl/guassian/run +++ /dev/null @@ -1 +0,0 @@ -./gaussian ../../data/gaussian/matrix4.txt \ No newline at end of file diff --git a/tests/opencl/guassian/utils.cpp b/tests/opencl/guassian/utils.cpp deleted file mode 100755 index b0f9115f..00000000 --- a/tests/opencl/guassian/utils.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/****************************************************************************\ - * Copyright (c) 2011, Advanced Micro Devices, Inc. * - * All rights reserved. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions * - * are met: * - * * - * Redistributions of source code must retain the above copyright notice, * - * this list of conditions and the following disclaimer. * - * * - * Redistributions in binary form must reproduce the above copyright notice, * - * this list of conditions and the following disclaimer in the documentation * - * and/or other materials provided with the distribution. * - * * - * Neither the name of the copyright holder nor the names of its contributors * - * may be used to endorse or promote products derived from this software * - * without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * * - * If you use the software (in whole or in part), you shall adhere to all * - * applicable U.S., European, and other export laws, including but not * - * limited to the U.S. Export Administration Regulations (“EAR”), (15 C.F.R. * - * Sections 730 through 774), and E.U. Council Regulation (EC) No 1334/2000 * - * of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, you * - * hereby certify that, except pursuant to a license granted by the United * - * States Department of Commerce Bureau of Industry and Security or as * - * otherwise permitted pursuant to a License Exception under the U.S. Export * - * Administration Regulations ("EAR"), you will not (1) export, re-export or * - * release to a national of a country in Country Groups D:1, E:1 or E:2 any * - * restricted technology, software, or source code you receive hereunder, * - * or (2) export to Country Groups D:1, E:1 or E:2 the direct product of such * - * technology or software, if such foreign produced direct product is subject * - * to national security controls as identified on the Commerce Control List * - *(currently found in Supplement 1 to Part 774 of EAR). For the most current * - * Country Group listings, or for additional information about the EAR or * - * your obligations under those regulations, please refer to the U.S. Bureau * - * of Industry and Security’s website at http://www.bis.doc.gov/. * - \****************************************************************************/ - -#include -#include -#include -#include - -#include "utils.h" - -static bool usingImages = true; - -//! A wrapper for malloc that checks the return value -void* alloc(size_t size) { - - void* ptr = NULL; - ptr = malloc(size); - if(ptr == NULL) { - perror("malloc"); - exit(-1); - } - - return ptr; -} - -// This function checks to make sure a file exists before we open it -void checkFile(char* filename) -{ - - struct stat fileStatus; - if(stat(filename, &fileStatus) != 0) { - printf("Error opening file: %s\n", filename); - exit(-1); - } - else { - if(!(S_IFREG & fileStatus.st_mode)) { - printf("File %s is not a regular file\n", filename); - exit(-1); - } - } -} - - -// This function checks to make sure a directory exists -void checkDir(char* dirpath) -{ - - struct stat fileStatus; - if(stat(dirpath, &fileStatus) != 0) { - printf("Directory does not exist: %s\n", dirpath); - exit(-1); - } - else { - if(!(S_IFDIR & fileStatus.st_mode)) { - printf("Directory was not provided: %s\n", dirpath); - exit(-1); - } - } -} - -// Parse the command line arguments -void parseArguments(int argc, char** argv, char** input, char** events, - char** ipts, char* devicePref, bool* verifyResults) -{ - - for(int i = 2; i < argc; i++) { - if(strcmp(argv[i], "-d") == 0) { // Event dump found - if(i == argc-1) { - printf("Usage: -e Needs directory path\n"); - exit(-1); - } - devicePref[0] = argv[i+1][0]; - i++; - continue; - } - if(strcmp(argv[i], "-e") == 0) { // Event dump found - if(i == argc-1) { - printf("Usage: -e Needs directory path\n"); - exit(-1); - } - *events = argv[i+1]; - i++; - continue; - } - if(strcmp(argv[i], "-i") == 0) { // Input found - if(i == argc-1) { - printf("Usage: -i Needs directory path\n"); - exit(-1); - } - *input = argv[i+1]; - i++; - continue; - } - if(strcmp(argv[i], "-l") == 0) { // Ipts dump found - if(i == argc-1) { - printf("Usage: -l Needs directory path\n"); - exit(-1); - } - *ipts = argv[i+1]; - i++; - continue; - } - if(strcmp(argv[i], "-n") == 0) { // Don't use OpenCL images - setUsingImages(false); - continue; - } - if(strcmp(argv[i], "-v") == 0) { // Verify results - *verifyResults = true; - continue; - } - } -} - - -// This function that takes a positive integer 'value' and returns -// the nearest multiple of 'multiple' (used for padding columns) -unsigned int roundUp(unsigned int value, unsigned int multiple) { - - unsigned int remainder = value % multiple; - - // Make the value a multiple of multiple - if(remainder != 0) { - value += (multiple-remainder); - } - - return value; -} - - -// Concatenate two strings and return a pointer to the new string -char* smartStrcat(char* str1, char* str2) -{ - char* newStr = NULL; - - newStr = (char*)alloc((strlen(str1)+strlen(str2)+1)*sizeof(char)); - - strcpy(newStr, str1); - strcat(newStr, str2); - - return newStr; -} - - -// Set the value of using images to true if they are being -// used, or false if they are not -void setUsingImages(bool val) -{ - usingImages = val; -} - - -// Return whether or not images are being used -bool isUsingImages() -{ - return usingImages; -} diff --git a/tests/opencl/guassian/utils.h b/tests/opencl/guassian/utils.h deleted file mode 100755 index 1e901ced..00000000 --- a/tests/opencl/guassian/utils.h +++ /dev/null @@ -1,84 +0,0 @@ -/****************************************************************************\ - * Copyright (c) 2011, Advanced Micro Devices, Inc. * - * All rights reserved. * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions * - * are met: * - * * - * Redistributions of source code must retain the above copyright notice, * - * this list of conditions and the following disclaimer. * - * * - * Redistributions in binary form must reproduce the above copyright notice, * - * this list of conditions and the following disclaimer in the documentation * - * and/or other materials provided with the distribution. * - * * - * Neither the name of the copyright holder nor the names of its contributors * - * may be used to endorse or promote products derived from this software * - * without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * * - * If you use the software (in whole or in part), you shall adhere to all * - * applicable U.S., European, and other export laws, including but not * - * limited to the U.S. Export Administration Regulations (“EAR”), (15 C.F.R. * - * Sections 730 through 774), and E.U. Council Regulation (EC) No 1334/2000 * - * of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, you * - * hereby certify that, except pursuant to a license granted by the United * - * States Department of Commerce Bureau of Industry and Security or as * - * otherwise permitted pursuant to a License Exception under the U.S. Export * - * Administration Regulations ("EAR"), you will not (1) export, re-export or * - * release to a national of a country in Country Groups D:1, E:1 or E:2 any * - * restricted technology, software, or source code you receive hereunder, * - * or (2) export to Country Groups D:1, E:1 or E:2 the direct product of such * - * technology or software, if such foreign produced direct product is subject * - * to national security controls as identified on the Commerce Control List * - *(currently found in Supplement 1 to Part 774 of EAR). For the most current * - * Country Group listings, or for additional information about the EAR or * - * your obligations under those regulations, please refer to the U.S. Bureau * - * of Industry and Security’s website at http://www.bis.doc.gov/. * - \****************************************************************************/ - -#ifndef _UTILS_ -#define _UTILS_ - -// Wrapper for malloc -void* alloc(size_t size); - -// Checks for existence of directory -void checkDir(char* dirpath); - -// Check for existence of file -void checkFile(char* filename); - -// Parse the input command line options to the program -void parseArguments(int argc, char** argv, char** input, char** events, - char** ipts, char* devicePref, bool* verifyResults); - - -// Print the program usage information -void printUsage(); - -// Rounds up size to the nearest multiple of multiple -unsigned int roundUp(unsigned int value, unsigned int multiple); - -// Concatenate two strings, creating a new one -char* smartStrcat(char* str1, char* str2); - -// Set the value of usingImages -void setUsingImages(bool val); - -// Return whether or not images are being used -bool isUsingImages(); - -#endif diff --git a/tests/opencl/kmeans/.gitignore b/tests/opencl/kmeans/.gitignore deleted file mode 100644 index b70c69e3..00000000 --- a/tests/opencl/kmeans/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -kmeans - diff --git a/tests/opencl/kmeans/Makefile b/tests/opencl/kmeans/Makefile deleted file mode 100644 index e1f16b68..00000000 --- a/tests/opencl/kmeans/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = kmeans - -SRCS = main.cc read_input.c rmse.c kmeans_clustering.c cluster.c getopt.c - -OPTS ?= - -include ../common.mk diff --git a/tests/opencl/kmeans/cluster.c b/tests/opencl/kmeans/cluster.c deleted file mode 100755 index bc3c7c59..00000000 --- a/tests/opencl/kmeans/cluster.c +++ /dev/null @@ -1,155 +0,0 @@ -/*****************************************************************************/ -/*IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. */ -/*By downloading, copying, installing or using the software you agree */ -/*to this license. If you do not agree to this license, do not download, */ -/*install, copy or use the software. */ -/* */ -/* */ -/*Copyright (c) 2005 Northwestern University */ -/*All rights reserved. */ - -/*Redistribution of the software in source and binary forms, */ -/*with or without modification, is permitted provided that the */ -/*following conditions are met: */ -/* */ -/*1 Redistributions of source code must retain the above copyright */ -/* notice, this list of conditions and the following disclaimer. */ -/* */ -/*2 Redistributions in binary form must reproduce the above copyright */ -/* notice, this list of conditions and the following disclaimer in the */ -/* documentation and/or other materials provided with the distribution.*/ -/* */ -/*3 Neither the name of Northwestern University nor the names of its */ -/* contributors may be used to endorse or promote products derived */ -/* from this software without specific prior written permission. */ -/* */ -/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS */ -/*IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */ -/*TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT AND */ -/*FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL */ -/*NORTHWESTERN UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, */ -/*INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ -/*(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR */ -/*SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ -/*HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */ -/*STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */ -/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ -/*POSSIBILITY OF SUCH DAMAGE. */ -/******************************************************************************/ - -/*************************************************************************/ -/** File: cluster.c **/ -/** Description: Takes as input a file, containing 1 data point per **/ -/** per line, and performs a fuzzy c-means clustering **/ -/** on the data. Fuzzy clustering is performed using **/ -/** min to max clusters and the clustering that gets **/ -/** the best score according to a compactness and **/ -/** separation criterion are returned. **/ -/** Author: Brendan McCane **/ -/** James Cook University of North Queensland. **/ -/** Australia. email: mccane@cs.jcu.edu.au **/ -/** **/ -/** Edited by: Jay Pisharath, Wei-keng Liao **/ -/** Northwestern University. **/ -/** **/ -/** ================================================================ **/ -/** **/ -/** Edited by: Shuai Che, David Tarjan, Sang-Ha Lee **/ -/** University of Virginia **/ -/** **/ -/** Description: No longer supports fuzzy c-means clustering; **/ -/** only regular k-means clustering. **/ -/** No longer performs "validity" function to analyze **/ -/** compactness and separation crietria; instead **/ -/** calculate root mean squared error. **/ -/** **/ -/*************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include "kmeans.h" - -float min_rmse_ref = FLT_MAX; -extern double wtime(void); - /* reference min_rmse value */ - -/*---< cluster() >-----------------------------------------------------------*/ -int cluster(int npoints, /* number of data points */ - int nfeatures, /* number of attributes for each point */ - float **features, /* array: [npoints][nfeatures] */ - int min_nclusters, /* range of min to max number of clusters */ - int max_nclusters, - float threshold, /* loop terminating factor */ - int *best_nclusters, /* out: number between min and max with lowest RMSE */ - float ***cluster_centres, /* out: [best_nclusters][nfeatures] */ - float *min_rmse, /* out: minimum RMSE */ - int isRMSE, /* calculate RMSE */ - int nloops /* number of iteration for each number of clusters */ - ) -{ - int nclusters; /* number of clusters k */ - int index =0; /* number of iteration to reach the best RMSE */ - int rmse; /* RMSE for each clustering */ - int *membership; /* which cluster a data point belongs to */ - float **tmp_cluster_centres; /* hold coordinates of cluster centers */ - int i; - - /* allocate memory for membership */ - membership = (int*) malloc(npoints * sizeof(int)); - - /* sweep k from min to max_nclusters to find the best number of clusters */ - for(nclusters = min_nclusters; nclusters <= max_nclusters; nclusters++) - { - if (nclusters > npoints) break; /* cannot have more clusters than points */ - - /* allocate device memory, invert data array (@ kmeans_cuda.cu) */ - allocate(npoints, nfeatures, nclusters, features); - - /* iterate nloops times for each number of clusters */ - for(i = 0; i < nloops; i++) - { - /* initialize initial cluster centers, CUDA calls (@ kmeans_cuda.cu) */ - tmp_cluster_centres = kmeans_clustering(features, - nfeatures, - npoints, - nclusters, - threshold, - membership); - - if (*cluster_centres) { - free((*cluster_centres)[0]); - free(*cluster_centres); - } - *cluster_centres = tmp_cluster_centres; - - - /* find the number of clusters with the best RMSE */ - if(isRMSE) - { - rmse = rms_err(features, - nfeatures, - npoints, - tmp_cluster_centres, - nclusters); - - if(rmse < min_rmse_ref){ - min_rmse_ref = rmse; //update reference min RMSE - *min_rmse = min_rmse_ref; //update return min RMSE - *best_nclusters = nclusters; //update optimum number of clusters - index = i; //update number of iteration to reach best RMSE - } - } - } - - deallocateMemory(); /* free device memory (@ kmeans_cuda.cu) */ - } - - free(membership); - - return index; -} - diff --git a/tests/opencl/kmeans/getopt.c b/tests/opencl/kmeans/getopt.c deleted file mode 100755 index de98d917..00000000 --- a/tests/opencl/kmeans/getopt.c +++ /dev/null @@ -1,1184 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to drepper@gnu.org - before changing it! - Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in . - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -# define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -# ifndef const -# define const -# endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -# include -# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -# define ELIDE_CODE -# endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -# include -# include -#endif /* GNU C library. */ - -#ifdef VMS -# include -# if HAVE_STRING_H - 0 -# include -# endif -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. */ -# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC -# include -# ifndef _ -# define _(msgid) gettext (msgid) -# endif -# else -# define _(msgid) (msgid) -# endif -# if defined _LIBC && defined USE_IN_LIBIO -# include -# endif -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -# include -# define my_index strchr -#else - -//# if HAVE_STRING_H || WIN32 /* Pete Wilson mod 7/28/02 */ -# include -//# else -//# include -//# endif - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -#ifndef getenv -extern char *getenv (); -#endif - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -# if (!defined __STDC__ || !__STDC__) && !defined strlen -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -# endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Stored original parameters. - XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ -extern int __libc_argc; -extern char **__libc_argv; - -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -# ifdef USE_NONOPTION_FLAGS -/* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; - -static int nonoption_flags_max_len; -static int nonoption_flags_len; -# endif - -# ifdef USE_NONOPTION_FLAGS -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -# else -# define SWAP_FLAGS(ch1, ch2) -# endif -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -#if defined __STDC__ && __STDC__ -static void exchange (char **); -#endif - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - -#if defined _LIBC && defined USE_NONOPTION_FLAGS - /* First make sure the handling of the `__getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } - } -#endif - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined __STDC__ && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#if defined _LIBC && defined USE_NONOPTION_FLAGS - if (posixly_correct == NULL - && argc == __libc_argc && argv == __libc_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - int print_errors = opterr; - if (optstring[0] == ':') - print_errors = 0; - - if (argc < 1) - return -1; - - optarg = NULL; - - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ -#if defined _LIBC && defined USE_NONOPTION_FLAGS -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else if (long_only - || pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); -#endif - } - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif - - if (argv[optind - 1][1] == '-') - { - /* --option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("\ -%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); -#else - fprintf (stderr, _("\ -%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); -#endif - } - else - { - /* +option or -option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("\ -%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], - pfound->name); -#else - fprintf (stderr, _("\ -%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); -#endif - } - -#if defined _LIBC && defined USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#endif - } - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); -#endif - } - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif - - if (argv[optind][1] == '-') - { - /* --option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); -#else - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); -#endif - } - else - { - /* +option or -option */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); -#else - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); -#endif - } - -#if defined _LIBC && defined USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#endif - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; -#endif - - if (posixly_correct) - { - /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: illegal option -- %c\n"), - argv[0], c); -#else - fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); -#endif - } - else - { -#if defined _LIBC && defined USE_IN_LIBIO - __asprintf (&buf, _("%s: invalid option -- %c\n"), - argv[0], c); -#else - fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); -#endif - } - -#if defined _LIBC && defined USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#endif - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("%s: option requires an argument -- %c\n"), - argv[0], c); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); -#endif - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); -#endif - } - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); -#endif - } - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (print_errors) - { -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, _("\ -%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); -#endif - } - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ -#if defined _LIBC && defined USE_IN_LIBIO - char *buf; - - __asprintf (&buf, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); - - free (buf); -#else - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); -#endif - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ - - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ \ No newline at end of file diff --git a/tests/opencl/kmeans/getopt.h b/tests/opencl/kmeans/getopt.h deleted file mode 100755 index 2a2e7577..00000000 --- a/tests/opencl/kmeans/getopt.h +++ /dev/null @@ -1,191 +0,0 @@ - - -/* getopt.h */ -/* Declarations for getopt. - Copyright (C) 1989-1994, 1996-1999, 2001 Free Software - Foundation, Inc. This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute - it and/or modify it under the terms of the GNU Lesser - General Public License as published by the Free Software - Foundation; either version 2.1 of the License, or - (at your option) any later version. - - The GNU C Library is distributed in the hope that it will - be useful, but WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A - PARTICULAR PURPOSE. See the GNU Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with the GNU C Library; if not, write - to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA. */ - - - - - -#ifndef _GETOPT_H - -#ifndef __need_getopt -# define _GETOPT_H 1 -#endif - -/* If __GNU_LIBRARY__ is not already defined, either we are being used - standalone, or this is the first header included in the source file. - If we are being used with glibc, we need to include , but - that does not exist if we are standalone. So: if __GNU_LIBRARY__ is - not defined, include , which will pull in for us - if it's from glibc. (Why ctype.h? It's guaranteed to exist and it - doesn't flood the namespace with stuff the way some other headers do.) */ -#if !defined __GNU_LIBRARY__ -# include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -#ifndef __need_getopt -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -# if (defined __STDC__ && __STDC__) || defined __cplusplus - const char *name; -# else - char *name; -# endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - - -/* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ - -#if (defined __STDC__ && __STDC__) || defined __cplusplus -# ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); -# else /* not __GNU_LIBRARY__ */ -extern int getopt (); -# endif /* __GNU_LIBRARY__ */ - -# ifndef __need_getopt -extern int getopt_long (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); -extern int getopt_long_only (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only); -# endif -#else /* not __STDC__ */ -extern int getopt (); -# ifndef __need_getopt -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -# endif -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -/* Make sure we later can get all the definitions and declarations. */ -#undef __need_getopt - -#endif /* getopt.h */ - diff --git a/tests/opencl/kmeans/kernel.cl b/tests/opencl/kmeans/kernel.cl deleted file mode 100755 index 81089878..00000000 --- a/tests/opencl/kmeans/kernel.cl +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef FLT_MAX -#define FLT_MAX 3.40282347e+38 -#endif - -__kernel void -kmeans_kernel_c(__global float *feature, - __global float *clusters, - __global int *membership, - int npoints, - int nclusters, - int nfeatures, - int offset, - int size - ) -{ - unsigned int point_id = get_global_id(0); - int index = 0; - //const unsigned int point_id = get_global_id(0); - if (point_id < npoints) - { - float min_dist=FLT_MAX; - for (int i=0; i < nclusters; i++) { - - float dist = 0; - float ans = 0; - for (int l=0; l -#include -#include -#include -#include "kmeans.h" - -#define RANDOM_MAX 2147483647 - -extern double wtime(void); - -/*----< kmeans_clustering() >---------------------------------------------*/ -float** kmeans_clustering(float **feature, /* in: [npoints][nfeatures] */ - int nfeatures, - int npoints, - int nclusters, - float threshold, - int *membership) /* out: [npoints] */ -{ - int i, j, n = 0; /* counters */ - int loop=0, temp; - int *new_centers_len; /* [nclusters]: no. of points in each cluster */ - float delta; /* if the point moved */ - float **clusters; /* out: [nclusters][nfeatures] */ - float **new_centers; /* [nclusters][nfeatures] */ - - int *initial; /* used to hold the index of points not yet selected - prevents the "birthday problem" of dual selection (?) - considered holding initial cluster indices, but changed due to - possible, though unlikely, infinite loops */ - int initial_points; - int c = 0; - - /* nclusters should never be > npoints - that would guarantee a cluster without points */ - if (nclusters > npoints) - nclusters = npoints; - - /* allocate space for and initialize returning variable clusters[] */ - clusters = (float**) malloc(nclusters * sizeof(float*)); - clusters[0] = (float*) malloc(nclusters * nfeatures * sizeof(float)); - for (i=1; i= 0; i++) { - //n = (int)rand() % initial_points; - - for (j=0; j 0) - clusters[i][j] = new_centers[i][j] / new_centers_len[i]; /* take average i.e. sum/n */ - new_centers[i][j] = 0.0; /* set back to 0 */ - } - new_centers_len[i] = 0; /* set back to 0 */ - } - c++; - } while ((delta > threshold) && (loop++ < 500)); /* makes sure loop terminates */ - printf("iterated %d times\n", c); - free(new_centers[0]); - free(new_centers); - free(new_centers_len); - free(initial); - - return clusters; -} - diff --git a/tests/opencl/kmeans/main.cc b/tests/opencl/kmeans/main.cc deleted file mode 100755 index 20ad1765..00000000 --- a/tests/opencl/kmeans/main.cc +++ /dev/null @@ -1,401 +0,0 @@ -#include "kmeans.h" -#include -#include -#include -#include -#include -#include - -#ifdef WIN -#include -#else -#include -#include -double gettime() { - struct timeval t; - gettimeofday(&t, NULL); - return t.tv_sec + t.tv_usec * 1e-6; -} -#endif - -#ifdef NV -#include -#else -#include -#endif - -#ifndef FLT_MAX -#define FLT_MAX 3.40282347e+38 -#endif - -#ifdef RD_WG_SIZE_0_0 -#define BLOCK_SIZE RD_WG_SIZE_0_0 -#elif defined(RD_WG_SIZE_0) -#define BLOCK_SIZE RD_WG_SIZE_0 -#elif defined(RD_WG_SIZE) -#define BLOCK_SIZE RD_WG_SIZE -#else -#define BLOCK_SIZE 256 -#endif - -#ifdef RD_WG_SIZE_1_0 -#define BLOCK_SIZE2 RD_WG_SIZE_1_0 -#elif defined(RD_WG_SIZE_1) -#define BLOCK_SIZE2 RD_WG_SIZE_1 -#elif defined(RD_WG_SIZE) -#define BLOCK_SIZE2 RD_WG_SIZE -#else -#define BLOCK_SIZE2 256 -#endif - -// local variables -static cl_context context; -static cl_command_queue cmd_queue; -static cl_device_type device_type; -static cl_device_id *device_list; -static cl_int num_devices; - -static int initialize(int use_gpu) { - cl_int result; - size_t size; - - /*// create OpenCL context - cl_platform_id platform_id; - if (clGetPlatformIDs(1, &platform_id, NULL) != CL_SUCCESS) { - printf("ERROR: clGetPlatformIDs(1,*,0) failed\n"); - return -1; - } - cl_context_properties ctxprop[] = {CL_CONTEXT_PLATFORM, - (cl_context_properties)platform_id, 0}; - device_type = use_gpu ? CL_DEVICE_TYPE_GPU : CL_DEVICE_TYPE_CPU; - context = clCreateContextFromType(ctxprop, device_type, NULL, NULL, NULL); - if (!context) { - printf("ERROR: clCreateContextFromType(%s) failed\n", - use_gpu ? "GPU" : "CPU"); - return -1; - } - - // get the list of GPUs - result = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); - num_devices = (int)(size / sizeof(cl_device_id)); - - if (result != CL_SUCCESS || num_devices < 1) { - printf("ERROR: clGetContextInfo() failed\n"); - return -1; - } - device_list = new cl_device_id[num_devices]; - if (!device_list) { - printf("ERROR: new cl_device_id[] failed\n"); - return -1; - } - result = - clGetContextInfo(context, CL_CONTEXT_DEVICES, size, device_list, NULL); - if (result != CL_SUCCESS) { - printf("ERROR: clGetContextInfo() failed\n"); - return -1; - }*/ - - cl_platform_id platform_id; - num_devices = 1; - device_list = new cl_device_id[num_devices]; - - result = clGetPlatformIDs(1, &platform_id, NULL); - result = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, device_list, NULL); - context = clCreateContext(NULL, 1, device_list, NULL, NULL, &result); - - // create command queue for the first device - cmd_queue = clCreateCommandQueue(context, device_list[0], 0, &result); - if (!cmd_queue || result != CL_SUCCESS) { - printf("ERROR: clCreateCommandQueue() failed\n"); - return -1; - } - - return 0; -} - -static int shutdown() { - // release resources - if (cmd_queue) - clReleaseCommandQueue(cmd_queue); - if (context) - clReleaseContext(context); - if (device_list) - delete [] device_list; - - // reset all variables - cmd_queue = 0; - context = 0; - device_list = 0; - num_devices = 0; - device_type = 0; - - return 0; -} - -cl_mem d_feature; -cl_mem d_feature_swap; -cl_mem d_cluster; -cl_mem d_membership; - -cl_kernel kernel; -cl_kernel kernel_s; -cl_kernel kernel2; - -int *membership_OCL; -int *membership_d; -float *feature_d; -float *clusters_d; -float *center_d; - - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - - -int allocate(int n_points, int n_features, int n_clusters, float **feature) { - /*int sourcesize = 1024 * 1024; - char *source = (char *)calloc(sourcesize, sizeof(char)); - if (!source) { - printf("ERROR: calloc(%d) failed\n", sourcesize); - return -1; - } - - // read the kernel core source - char *tempchar = "./kmeans.cl"; - FILE *fp = fopen(tempchar, "rb"); - if (!fp) { - printf("ERROR: unable to open '%s'\n", tempchar); - return -1; - } - fread(source + strlen(source), sourcesize, 1, fp); - fclose(fp);*/ - - // OpenCL initialization - int use_gpu = 1; - if (initialize(use_gpu)) - return -1; - - // compile kernel - cl_int err = 0; - //const char *slist[2] = {source, 0}; - //cl_program prog = clCreateProgramWithSource(context, 1, slist, NULL, &err); - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - err = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - if (err != CL_SUCCESS) { - printf("ERROR: read_kernel_file() => %d\n", err); - return -1; - } - - cl_program prog = clCreateProgramWithBinary( - context, 1, device_list, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateProgramWithBinary() => %d\n", err); - return -1; - } - - free(kernel_bin); - - err = clBuildProgram(prog, 1, &device_list[0], NULL, NULL, NULL); - { // show warnings/errors - // static char log[65536]; memset(log, 0, sizeof(log)); - // cl_device_id device_id = 0; - // err = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(device_id), - //&device_id, NULL); - // clGetProgramBuildInfo(prog, device_id, CL_PROGRAM_BUILD_LOG, - // sizeof(log)-1, log, NULL); - // if(err || strstr(log,"warning:") || strstr(log, "error:")) - // printf("<<<<\n%s\n>>>>\n", log); - } - if (err != CL_SUCCESS) { - printf("ERROR: clBuildProgram() => %d\n", err); - return -1; - } - - char *kernel_kmeans_c = "kmeans_kernel_c"; - char *kernel_swap = "kmeans_swap"; - - kernel_s = clCreateKernel(prog, kernel_kmeans_c, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateKernel() 0 => %d\n", err); - return -1; - } - - kernel2 = clCreateKernel(prog, kernel_swap, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateKernel() 0 => %d\n", err); - return -1; - } - - clReleaseProgram(prog); - - d_feature = clCreateBuffer(context, CL_MEM_READ_WRITE, - n_points * n_features * sizeof(float), NULL, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateBuffer d_feature (size:%d) => %d\n", - n_points * n_features, err); - return -1; - } - - d_feature_swap = - clCreateBuffer(context, CL_MEM_READ_WRITE, - n_points * n_features * sizeof(float), NULL, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateBuffer d_feature_swap (size:%d) => %d\n", - n_points * n_features, err); - return -1; - } - - d_cluster = - clCreateBuffer(context, CL_MEM_READ_WRITE, - n_clusters * n_features * sizeof(float), NULL, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateBuffer d_cluster (size:%d) => %d\n", - n_clusters * n_features, err); - return -1; - } - - d_membership = clCreateBuffer(context, CL_MEM_READ_WRITE, - n_points * sizeof(int), NULL, &err); - if (err != CL_SUCCESS) { - printf("ERROR: clCreateBuffer d_membership (size:%d) => %d\n", n_points, - err); - return -1; - } - - // write buffers - err = clEnqueueWriteBuffer(cmd_queue, d_feature, 1, 0, - n_points * n_features * sizeof(float), feature[0], - 0, 0, 0); - if (err != CL_SUCCESS) { - printf("ERROR: clEnqueueWriteBuffer d_feature (size:%d) => %d\n", - n_points * n_features, err); - return -1; - } - - clSetKernelArg(kernel2, 0, sizeof(void *), (void *)&d_feature); - clSetKernelArg(kernel2, 1, sizeof(void *), (void *)&d_feature_swap); - clSetKernelArg(kernel2, 2, sizeof(cl_int), (void *)&n_points); - clSetKernelArg(kernel2, 3, sizeof(cl_int), (void *)&n_features); - - size_t global_work[3] = {n_points, 1, 1}; - /// Ke Wang adjustable local group size 2013/08/07 10:37:33 - size_t local_work_size = BLOCK_SIZE; // work group size is defined by - // RD_WG_SIZE_0 or RD_WG_SIZE_0_0 - // 2014/06/10 17:00:51 - if (global_work[0] % local_work_size != 0) - global_work[0] = (global_work[0] / local_work_size + 1) * local_work_size; - - err = clEnqueueNDRangeKernel(cmd_queue, kernel2, 1, NULL, global_work, - &local_work_size, 0, 0, 0); - if (err != CL_SUCCESS) { - printf("ERROR: clEnqueueNDRangeKernel()=>%d failed\n", err); - return -1; - } - - membership_OCL = (int *)malloc(n_points * sizeof(int)); - - return 0; -} - -void deallocateMemory() { - clReleaseMemObject(d_feature); - clReleaseMemObject(d_feature_swap); - clReleaseMemObject(d_cluster); - clReleaseMemObject(d_membership); - free(membership_OCL); -} - -int main(int argc, char **argv) { - printf("WG size of kernel_swap = %d, WG size of kernel_kmeans = %d \n", - BLOCK_SIZE, BLOCK_SIZE2); - setup(argc, argv); - shutdown(); -} - -int kmeansOCL(float **feature, /* in: [npoints][nfeatures] */ - int n_features, int n_points, int n_clusters, int *membership, - float **clusters, int *new_centers_len, float **new_centers) { - - int delta = 0; - int i, j, k; - cl_int err = 0; - - size_t global_work[3] = {n_points, 1, 1}; - - /// Ke Wang adjustable local group size 2013/08/07 10:37:33 - size_t local_work_size = BLOCK_SIZE2; // work group size is defined by - // RD_WG_SIZE_1 or RD_WG_SIZE_1_0 - // 2014/06/10 17:00:41 - if (global_work[0] % local_work_size != 0) - global_work[0] = (global_work[0] / local_work_size + 1) * local_work_size; - - err = clEnqueueWriteBuffer(cmd_queue, d_cluster, 1, 0, - n_clusters * n_features * sizeof(float), - clusters[0], 0, 0, 0); - if (err != CL_SUCCESS) { - printf("ERROR: clEnqueueWriteBuffer d_cluster (size:%d) => %d\n", n_points, - err); - return -1; - } - - int size = 0; - int offset = 0; - - clSetKernelArg(kernel_s, 0, sizeof(void *), (void *)&d_feature_swap); - clSetKernelArg(kernel_s, 1, sizeof(void *), (void *)&d_cluster); - clSetKernelArg(kernel_s, 2, sizeof(void *), (void *)&d_membership); - clSetKernelArg(kernel_s, 3, sizeof(cl_int), (void *)&n_points); - clSetKernelArg(kernel_s, 4, sizeof(cl_int), (void *)&n_clusters); - clSetKernelArg(kernel_s, 5, sizeof(cl_int), (void *)&n_features); - clSetKernelArg(kernel_s, 6, sizeof(cl_int), (void *)&offset); - clSetKernelArg(kernel_s, 7, sizeof(cl_int), (void *)&size); - - err = clEnqueueNDRangeKernel(cmd_queue, kernel_s, 1, NULL, global_work, - &local_work_size, 0, 0, 0); - if (err != CL_SUCCESS) { - printf("ERROR: clEnqueueNDRangeKernel()=>%d failed\n", err); - return -1; - } - clFinish(cmd_queue); - err = clEnqueueReadBuffer(cmd_queue, d_membership, 1, 0, - n_points * sizeof(int), membership_OCL, 0, 0, 0); - if (err != CL_SUCCESS) { - printf("ERROR: Memcopy Out\n"); - return -1; - } - - delta = 0; - for (i = 0; i < n_points; i++) { - int cluster_id = membership_OCL[i]; - new_centers_len[cluster_id]++; - if (membership_OCL[i] != membership[i]) { - delta++; - membership[i] = membership_OCL[i]; - } - for (j = 0; j < n_features; j++) { - new_centers[cluster_id][j] += feature[i][j]; - } - } - - return delta; -} diff --git a/tests/opencl/kmeans/read_input.c b/tests/opencl/kmeans/read_input.c deleted file mode 100755 index fa0dc586..00000000 --- a/tests/opencl/kmeans/read_input.c +++ /dev/null @@ -1,340 +0,0 @@ -/*****************************************************************************/ -/*IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. */ -/*By downloading, copying, installing or using the software you agree */ -/*to this license. If you do not agree to this license, do not download, */ -/*install, copy or use the software. */ -/* */ -/* */ -/*Copyright (c) 2005 Northwestern University */ -/*All rights reserved. */ - -/*Redistribution of the software in source and binary forms, */ -/*with or without modification, is permitted provided that the */ -/*following conditions are met: */ -/* */ -/*1 Redistributions of source code must retain the above copyright */ -/* notice, this list of conditions and the following disclaimer. */ -/* */ -/*2 Redistributions in binary form must reproduce the above copyright */ -/* notice, this list of conditions and the following disclaimer in the */ -/* documentation and/or other materials provided with the distribution.*/ -/* */ -/*3 Neither the name of Northwestern University nor the names of its */ -/* contributors may be used to endorse or promote products derived */ -/* from this software without specific prior written permission. */ -/* */ -/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS */ -/*IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */ -/*TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT AND */ -/*FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL */ -/*NORTHWESTERN UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, */ -/*INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ -/*(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR */ -/*SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ -/*HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */ -/*STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */ -/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ -/*POSSIBILITY OF SUCH DAMAGE. */ -/******************************************************************************/ - -/*************************************************************************/ -/** File: example.c **/ -/** Description: Takes as input a file: **/ -/** ascii file: containing 1 data point per line **/ -/** binary file: first int is the number of objects **/ -/** 2nd int is the no. of features of each **/ -/** object **/ -/** This example performs a fuzzy c-means clustering **/ -/** on the data. Fuzzy clustering is performed using **/ -/** min to max clusters and the clustering that gets **/ -/** the best score according to a compactness and **/ -/** separation criterion are returned. **/ -/** Author: Wei-keng Liao **/ -/** ECE Department Northwestern University **/ -/** email: wkliao@ece.northwestern.edu **/ -/** **/ -/** Edited by: Jay Pisharath **/ -/** Northwestern University. **/ -/** **/ -/** ================================================================ **/ -/** - * **/ -/** Edited by: Shuai Che, David Tarjan, Sang-Ha Lee - * **/ -/** University of Virginia - * **/ -/** - * **/ -/** Description: No longer supports fuzzy c-means clustering; - * **/ -/** only regular k-means clustering. - * **/ -/** No longer performs "validity" function to - * analyze **/ -/** compactness and separation crietria; instead - * **/ -/** calculate root mean squared error. - * **/ -/** **/ -/*************************************************************************/ -#define _CRT_SECURE_NO_DEPRECATE 1 - -#include "kmeans.h" -#include -#include -#include -#include -#include -#include -#include - -extern double wtime(void); - -/*---< usage() >------------------------------------------------------------*/ -void usage(char *argv0) { - char *help = "\nUsage: %s [switches] -i filename\n\n" - " -i filename :file containing data to be clustered\n" - " -m max_nclusters :maximum number of clusters allowed " - "[default=5]\n" - " -n min_nclusters :minimum number of clusters allowed " - "[default=5]\n" - " -t threshold :threshold value " - "[default=0.001]\n" - " -l nloops :iteration for each number of clusters " - "[default=1]\n" - " -b :input file is in binary format\n" - " -r :calculate RMSE " - "[default=off]\n" - " -o :output cluster center coordinates " - "[default=off]\n"; - fprintf(stderr, help, argv0); - exit(-1); -} - -/*---< main() >-------------------------------------------------------------*/ -int setup(int argc, char **argv) { - int opt; - extern char *optarg; - char *filename = 0; - float *buf; - char line[1024]; - int isBinaryFile = 0; - - float threshold = 0.001; /* default value */ - int max_nclusters = 5; /* default value */ - int min_nclusters = 5; /* default value */ - int best_nclusters = 0; - int nfeatures = 0; - int npoints = 0; - float len; - - float **features; - float **cluster_centres = NULL; - int i, j, index; - int nloops = 1; /* default value */ - - int isRMSE = 0; - float rmse; - - int isOutput = 0; - // float cluster_timing, io_timing; - - /* obtain command line arguments and change appropriate options */ - while ((opt = getopt(argc, argv, "i:t:m:n:l:bro")) != EOF) { - switch (opt) { - case 'i': - filename = optarg; - break; - case 'b': - isBinaryFile = 1; - break; - case 't': - threshold = atof(optarg); - break; - case 'm': - max_nclusters = atoi(optarg); - break; - case 'n': - min_nclusters = atoi(optarg); - break; - case 'r': - isRMSE = 1; - break; - case 'o': - isOutput = 1; - break; - case 'l': - nloops = atoi(optarg); - break; - case '?': - usage(argv[0]); - break; - default: - usage(argv[0]); - break; - } - } - - /* ============== I/O begin ==============*/ - /* get nfeatures and npoints */ - // io_timing = omp_get_wtime(); - - /*if (isBinaryFile) { // Binary file input - FILE *infile; - if ((infile = fopen("100", "r")) == NULL) { - fprintf(stderr, "Error: no such file (%s)\n", filename); - exit(1); - } - fread(&npoints, 1, sizeof(int), infile); - fread(&nfeatures, 1, sizeof(int), infile); - - // allocate space for features[][] and read attributes of all objects - buf = (float *)malloc(npoints * nfeatures * sizeof(float)); - features = (float **)malloc(npoints * sizeof(float *)); - features[0] = (float *)malloc(npoints * nfeatures * sizeof(float)); - for (i = 1; i < npoints; i++) { - features[i] = features[i - 1] + nfeatures; - } - fread(buf, 1, npoints * nfeatures * sizeof(float), infile); - fclose(infile); - } else { - FILE *infile; - if ((infile = fopen("100", "r")) == NULL) { - fprintf(stderr, "Error: no such file (%s)\n", filename); - exit(1); - } - while (fgets(line, 1024, infile) != NULL) - if (strtok(line, " \t\n") != 0) { - npoints++; - } - rewind(infile); - while (fgets(line, 1024, infile) != NULL) { - if (strtok(line, " \t\n") != 0) { - // ignore the id (first attribute): nfeatures = 1; - while (strtok(NULL, " ,\t\n") != NULL) - nfeatures++; - break; - } - } - - // allocate space for features[] and read attributes of all objects - buf = (float *)malloc(npoints * nfeatures * sizeof(float)); - features = (float **)malloc(npoints * sizeof(float *)); - features[0] = (float *)malloc(npoints * nfeatures * sizeof(float)); - for (i = 1; i < npoints; i++) - features[i] = features[i - 1] + nfeatures; - rewind(infile); - i = 0; - while (fgets(line, 1024, infile) != NULL) { - if (strtok(line, " \t\n") == NULL) - continue; - for (j = 0; j < nfeatures; j++) { - buf[i] = atof(strtok(NULL, " ,\t\n")); - i++; - } - } - fclose(infile); - }*/ - - npoints = 100; - nfeatures = 100; - buf = (float *)malloc(npoints * nfeatures * sizeof(float)); - features = (float **)malloc(npoints * sizeof(float *)); - features[0] = (float *)malloc(npoints * nfeatures * sizeof(float)); - for (i = 1; i < npoints; i++) { - features[i] = features[i - 1] + nfeatures; - } - for (i = 0; i < npoints * nfeatures; ++i) { - buf[i] = (i % 64); - } - - // io_timing = omp_get_wtime() - io_timing; - - printf("\nI/O completed\n"); - printf("\nNumber of objects: %d\n", npoints); - printf("Number of features: %d\n", nfeatures); - /* ============== I/O end ==============*/ - - // error check for clusters - if (npoints < min_nclusters) { - printf("Error: min_nclusters(%d) > npoints(%d) -- cannot proceed\n", - min_nclusters, npoints); - exit(0); - } - - srand(7); /* seed for future random number generator */ - memcpy( - features[0], buf, - npoints * nfeatures * - sizeof( - float)); /* now features holds 2-dimensional array of features */ - free(buf); - - /* ======================= core of the clustering ===================*/ - - // cluster_timing = omp_get_wtime(); /* Total clustering time */ - cluster_centres = NULL; - index = cluster(npoints, /* number of data points */ - nfeatures, /* number of features for each point */ - features, /* array: [npoints][nfeatures] */ - min_nclusters, /* range of min to max number of clusters */ - max_nclusters, threshold, /* loop termination factor */ - &best_nclusters, /* return: number between min and max */ - &cluster_centres, /* return: [best_nclusters][nfeatures] */ - &rmse, /* Root Mean Squared Error */ - isRMSE, /* calculate RMSE */ - nloops); /* number of iteration for each number of clusters */ - - // cluster_timing = omp_get_wtime() - cluster_timing; - - /* =============== Command Line Output =============== */ - - /* cluster center coordinates - :displayed only for when k=1*/ - if ((min_nclusters == max_nclusters) && (isOutput == 1)) { - printf("\n================= Centroid Coordinates =================\n"); - for (i = 0; i < max_nclusters; i++) { - printf("%d:", i); - for (j = 0; j < nfeatures; j++) { - printf(" %.2f", cluster_centres[i][j]); - } - printf("\n\n"); - } - } - - len = (float)((max_nclusters - min_nclusters + 1) * nloops); - - printf("Number of Iteration: %d\n", nloops); - // printf("Time for I/O: %.5fsec\n", io_timing); - // printf("Time for Entire Clustering: %.5fsec\n", cluster_timing); - - if (min_nclusters != max_nclusters) { - if (nloops != 1) { // range of k, multiple iteration - // printf("Average Clustering Time: %fsec\n", - // cluster_timing / len); - printf("Best number of clusters is %d\n", best_nclusters); - } else { // range of k, single iteration - // printf("Average Clustering Time: %fsec\n", - // cluster_timing / len); - printf("Best number of clusters is %d\n", best_nclusters); - } - } else { - if (nloops != 1) { // single k, multiple iteration - // printf("Average Clustering Time: %.5fsec\n", - // cluster_timing / nloops); - if (isRMSE) // if calculated RMSE - printf("Number of trials to approach the best RMSE of %.3f is %d\n", - rmse, index + 1); - } else { // single k, single iteration - if (isRMSE) // if calculated RMSE - printf("Root Mean Squared Error: %.3f\n", rmse); - } - } - - /* free up memory */ - free(cluster_centres[0]); - free(cluster_centres); - free(features[0]); - free(features); - return (0); -} diff --git a/tests/opencl/kmeans/rmse.c b/tests/opencl/kmeans/rmse.c deleted file mode 100755 index 03d614a6..00000000 --- a/tests/opencl/kmeans/rmse.c +++ /dev/null @@ -1,94 +0,0 @@ -/*************************************************************************/ -/** File: rmse.c **/ -/** Description: calculate root mean squared error of particular **/ -/** clustering. **/ -/** Author: Sang-Ha Lee **/ -/** University of Virginia. **/ -/** **/ -/** Note: euclid_dist_2() and find_nearest_point() adopted from **/ -/** Minebench code. **/ -/** **/ -/*************************************************************************/ - -#include -#include -#include -#include - -#include "kmeans.h" - -extern double wtime(void); - -/*----< euclid_dist_2() >----------------------------------------------------*/ -/* multi-dimensional spatial Euclid distance square */ -__inline -float euclid_dist_2(float *pt1, - float *pt2, - int numdims) -{ - int i; - float ans=0.0; - - for (i=0; i-----------------------------------------------*/ -__inline -int find_nearest_point(float *pt, /* [nfeatures] */ - int nfeatures, - float **pts, /* [npts][nfeatures] */ - int npts) -{ - int index, i; - float max_dist=FLT_MAX; - - /* find the cluster center id with min distance to pt */ - for (i=0; i-------------------------------------*/ -float rms_err (float **feature, /* [npoints][nfeatures] */ - int nfeatures, - int npoints, - float **cluster_centres, /* [nclusters][nfeatures] */ - int nclusters) -{ - int i; - int nearest_cluster_index; /* cluster center id with min distance to pt */ - float sum_euclid = 0.0; /* sum of Euclidean distance squares */ - float ret; /* return value */ - - /* calculate and sum the sqaure of euclidean distance*/ - #pragma omp parallel for \ - shared(feature,cluster_centres) \ - firstprivate(npoints,nfeatures,nclusters) \ - private(i, nearest_cluster_index) \ - schedule (static) - for (i=0; i -#include -#include -#include -#include -#include - -/*****************************************************************************/ -/* Memory management routines */ - -/* Free an array of owned strings. */ -void -pb_FreeStringArray(char **string_array) -{ - char **p; - - if (!string_array) return; - for (p = string_array; *p; p++) free(*p); - free(string_array); -} - -struct pb_PlatformParam * -pb_PlatformParam(char *name, char *version) -{ - if (name == NULL) { - fprintf(stderr, "pb_PlatformParam: Invalid argument\n"); - exit(-1); - } - - struct pb_PlatformParam *ret = - (struct pb_PlatformParam *)malloc(sizeof (struct pb_PlatformParam)); - - ret->name = name; - ret->version = version; - return ret; -} - -void -pb_FreePlatformParam(struct pb_PlatformParam *p) -{ - if (p == NULL) return; - - free(p->name); - free(p->version); - free(p); -} - -struct pb_DeviceParam * -pb_DeviceParam_index(int index) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_INDEX; - ret->index = index; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_cpu(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_CPU; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_gpu(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_GPU; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_accelerator(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_ACCELERATOR; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_name(char *name) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_NAME; - ret->name = name; - return ret; -} - -void -pb_FreeDeviceParam(struct pb_DeviceParam *p) -{ - if (p == NULL) return; - - switch(p->criterion) { - case pb_Device_NAME: - free(p->name); - break; - case pb_Device_INDEX: - case pb_Device_CPU: - case pb_Device_ACCELERATOR: - break; - default: - fprintf(stderr, "pb_FreeDeviceParam: Invalid argument\n"); - exit(-1); - } -} - -void -pb_FreeParameters(struct pb_Parameters *p) -{ - free(p->outFile); - pb_FreeStringArray(p->inpFiles); - pb_FreePlatformParam(p->platform); - pb_FreeDeviceParam(p->device); - free(p); -} - -/*****************************************************************************/ - -/* Parse a comma-delimited list of strings into an - * array of strings. */ -static char ** -read_string_array(char *in) -{ - char **ret; - int i; - int count; /* Number of items in the input */ - char *substring; /* Current substring within 'in' */ - - /* Count the number of items in the string */ - count = 1; - for (i = 0; in[i]; i++) if (in[i] == ',') count++; - - /* Allocate storage */ - ret = (char **)malloc((count + 1) * sizeof(char *)); - - /* Create copies of the strings from the list */ - substring = in; - for (i = 0; i < count; i++) { - char *substring_end; - int substring_length; - - /* Find length of substring */ - for (substring_end = substring; - (*substring_end != ',') && (*substring_end != 0); - substring_end++); - - substring_length = substring_end - substring; - - /* Allocate memory and copy the substring */ - ret[i] = (char *)malloc(substring_length + 1); - memcpy(ret[i], substring, substring_length); - ret[i][substring_length] = 0; - - /* go to next substring */ - substring = substring_end + 1; - } - ret[i] = NULL; /* Write the sentinel value */ - - return ret; -} - -static void -report_parse_error(const char *str) -{ - fputs(str, stderr); -} - -/* Interpret a string as a 'pb_DeviceParam' value. - * Return a pointer to a new value, or NULL on failure. - */ -static struct pb_DeviceParam * -read_device_param(char *str) -{ - /* Try different ways of interpreting 'device_string' until one works */ - - /* If argument is an integer, then interpret it as a device index */ - errno = 0; - char *end; - long device_int = strtol(str, &end, 10); - if (!errno) { - /* Negative numbers are not valid */ - if (device_int < 0 || device_int > INT_MAX) return NULL; - - return pb_DeviceParam_index(device_int); - } - - /* Match against predefined strings */ - if (strcmp(str, "CPU") == 0) - return pb_DeviceParam_cpu(); - if (strcmp(str, "GPU") == 0) - return pb_DeviceParam_gpu(); - if (strcmp(str, "ACCELERATOR") == 0) - return pb_DeviceParam_accelerator(); - - /* Assume any other string is a device name */ - return pb_DeviceParam_name(strdup(str)); -} - -/* Interpret a string as a 'pb_PlatformParam' value. - * Return a pointer to a new value, or NULL on failure. - */ -static struct pb_PlatformParam * -read_platform_param(char *str) -{ - int separator_index; /* Index of the '-' character separating - * name and version number. It's -1 if - * there's no '-' character. */ - - /* Find the last occurrence of '-' in 'str' */ - { - char *cur; - separator_index = -1; - for (cur = str; *cur; cur++) { - if (*cur == '-') separator_index = cur - str; - } - } - - /* The platform name is either the entire string, or all characters before - * the separator */ - int name_length = separator_index == -1 ? strlen(str) : separator_index; - char *name_str = (char *)malloc(name_length + 1); - memcpy(name_str, str, name_length); - name_str[name_length] = 0; - - /* The version is either NULL, or all characters after the separator */ - char *version_str; - if (separator_index == -1) { - version_str = NULL; - } - else { - const char *version_input_str = str + separator_index + 1; - int version_length = strlen(version_input_str); - - version_str = (char *)malloc(version_length + 1); - memcpy(version_str, version_input_str, version_length); - version_str[version_length] = 0; - } - - /* Create output structure */ - return pb_PlatformParam(name_str, version_str); -} - -/****************************************************************************/ -/* Argument parsing state */ - -/* Argument parsing state. - * - * Arguments that are interpreted by the argument parser are removed from - * the list. Variables 'argc' and 'argn' do not count arguments that have - * been removed. - * - * During argument parsing, the array of arguments is compacted, overwriting - * the erased arguments. Variable 'argv_put' points to the array element - * where the next argument will be written. Variable 'argv_get' points to - * the array element where the next argument will be read from. - */ -struct argparse { - int argc; /* Number of arguments. Mutable. */ - int argn; /* Current argument index. */ - char **argv_get; /* Argument value being read. */ - char **argv_put; /* Argument value being written. - * argv_put <= argv_get. */ -}; - -static void -initialize_argparse(struct argparse *ap, int argc, char **argv) -{ - ap->argc = argc; - ap->argn = 0; - ap->argv_get = ap->argv_put = argv; -} - -/* Finish argument parsing, without processing the remaining arguments. - * Write new argument count into _argc. */ -static void -finalize_argparse(struct argparse *ap, int *_argc, char **argv) -{ - /* Move the remaining arguments */ - for(; ap->argn < ap->argc; ap->argn++) - *ap->argv_put++ = *ap->argv_get++; - - /* Update the argument count */ - *_argc = ap->argc; - - /* Insert a terminating NULL */ - argv[ap->argc] = NULL; -} - -/* Delete the current argument. The argument will not be visible - * when argument parsing is done. */ -static void -delete_argument(struct argparse *ap) -{ - if (ap->argn >= ap->argc) { - fprintf(stderr, "delete_argument\n"); - } - ap->argc--; - ap->argv_get++; -} - -/* Go to the next argument. Also, move the current argument to its - * final location in argv. */ -static void -next_argument(struct argparse *ap) -{ - if (ap->argn >= ap->argc) { - fprintf(stderr, "next_argument\n"); - } - /* Move argument to its new location. */ - *ap->argv_put++ = *ap->argv_get++; - ap->argn++; -} - -static int -is_end_of_arguments(struct argparse *ap) -{ - return ap->argn == ap->argc; -} - -/* Get the current argument */ -static char * -get_argument(struct argparse *ap) -{ - return *ap->argv_get; -} - -/* Get the current argument, and also delete it */ -static char * -consume_argument(struct argparse *ap) -{ - char *ret = get_argument(ap); - delete_argument(ap); - return ret; -} - -/****************************************************************************/ - -/* The result of parsing a command-line argument */ -typedef enum { - ARGPARSE_OK, /* Success */ - ARGPARSE_ERROR, /* Error */ - ARGPARSE_DONE /* Success, and do not continue parsing */ -} result; - -typedef result parse_action(struct argparse *ap, struct pb_Parameters *params); - - -/* A command-line option */ -struct option { - char short_name; /* If not 0, the one-character - * name of this option */ - const char *long_name; /* If not NULL, the long name of this option */ - parse_action *action; /* What to do when this option occurs. - * Sentinel value is NULL. - */ -}; - -/* Output file - * - * -o FILE - */ -static result -parse_output_file(struct argparse *ap, struct pb_Parameters *params) -{ - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting file name after '-o'\n"); - return ARGPARSE_ERROR; - } - - /* Replace the output file name */ - free(params->outFile); - params->outFile = strdup(consume_argument(ap)); - - return ARGPARSE_OK; -} - -/* Input files - * - * -i FILE,FILE,... - */ -static result -parse_input_files(struct argparse *ap, struct pb_Parameters *params) -{ - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting file name after '-i'\n"); - return ARGPARSE_ERROR; - } - - /* Replace the input file list */ - pb_FreeStringArray(params->inpFiles); - params->inpFiles = read_string_array(consume_argument(ap)); - return ARGPARSE_OK; -} - -/* End of options - * - * -- - */ - -static result -parse_end_options(struct argparse *ap, struct pb_Parameters *params) -{ - return ARGPARSE_DONE; -} - -/* OpenCL device - * - * --device X - */ - -static result -parse_device(struct argparse *ap, struct pb_Parameters *params) -{ - /* Read the next argument, which specifies a device */ - - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting device specification after '--device'\n"); - return ARGPARSE_ERROR; - } - - char *device_string = consume_argument(ap); - struct pb_DeviceParam *device_param = read_device_param(device_string); - - if (!device_param) { - report_parse_error("Unrecognized device specification format on command line\n"); - return ARGPARSE_ERROR; - } - - /* Save the result */ - pb_FreeDeviceParam(params->device); - params->device = device_param; - - return ARGPARSE_OK; -} - -static result -parse_platform(struct argparse *ap, struct pb_Parameters *params) -{ - /* Read the next argument, which specifies a platform */ - - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting device specification after '--platform'\n"); - return ARGPARSE_ERROR; - } - - char *platform_string = consume_argument(ap); - struct pb_PlatformParam *platform_param = read_platform_param(platform_string); - - if (!platform_param) { - report_parse_error("Unrecognized platform specification format on command line\n"); - return ARGPARSE_ERROR; - } - - /* Save the result */ - pb_FreePlatformParam(params->platform); - params->platform = platform_param; - - return ARGPARSE_OK; -} - - -static struct option options[] = { - { 'o', NULL, &parse_output_file }, - { 'i', NULL, &parse_input_files }, - { '-', NULL, &parse_end_options }, - { 0, "device", &parse_device }, - { 0, "platform", &parse_platform }, - { 0, NULL, NULL } -}; - -static int -is_last_option(struct option *op) -{ - return op->action == NULL; -} - -/****************************************************************************/ - -/* Parse command-line parameters. - * Return zero on error, nonzero otherwise. - * On error, the other outputs may be invalid. - * - * The information collected from parameters is used to update - * 'ret'. 'ret' should be initialized. - * - * '_argc' and 'argv' are updated to contain only the unprocessed arguments. - */ -static int -pb_ParseParameters (struct pb_Parameters *ret, int *_argc, char **argv) -{ - char *err_message; - struct argparse ap; - - /* Each argument */ - initialize_argparse(&ap, *_argc, argv); - while(!is_end_of_arguments(&ap)) { - result arg_result; /* Result of parsing this option */ - char *arg = get_argument(&ap); - - /* Process this argument */ - if (arg[0] == '-') { - /* Single-character flag */ - if ((arg[1] != 0) && (arg[2] == 0)) { - delete_argument(&ap); /* This argument is consumed here */ - - /* Find a matching short option */ - struct option *op; - for (op = options; !is_last_option(op); op++) { - if (op->short_name == arg[1]) { - arg_result = (*op->action)(&ap, ret); - goto option_was_processed; - } - } - - /* No option matches */ - report_parse_error("Unexpected command-line parameter\n"); - arg_result = ARGPARSE_ERROR; - goto option_was_processed; - } - - /* Long flag */ - if (arg[1] == '-') { - delete_argument(&ap); /* This argument is consumed here */ - - /* Find a matching long option */ - struct option *op; - for (op = options; !is_last_option(op); op++) { - if (op->long_name && strcmp(&arg[2], op->long_name) == 0) { - arg_result = (*op->action)(&ap, ret); - goto option_was_processed; - } - } - - /* No option matches */ - report_parse_error("Unexpected command-line parameter\n"); - arg_result = ARGPARSE_ERROR; - goto option_was_processed; - } - } - else { - /* Other arguments are ignored */ - next_argument(&ap); - arg_result = ARGPARSE_OK; - goto option_was_processed; - } - - option_was_processed: - /* Decide what to do next based on 'arg_result' */ - switch(arg_result) { - case ARGPARSE_OK: - /* Continue processing */ - break; - - case ARGPARSE_ERROR: - /* Error exit from the function */ - return 0; - - case ARGPARSE_DONE: - /* Normal exit from the argument parsing loop */ - goto end_of_options; - } - } /* end for each argument */ - - /* If all arguments were processed, then normal exit from the loop */ - - end_of_options: - finalize_argparse(&ap, _argc, argv); - return 1; -} - -/*****************************************************************************/ -/* Other exported functions */ - -struct pb_Parameters * -pb_ReadParameters(int *_argc, char **argv) -{ - struct pb_Parameters *ret = - (struct pb_Parameters *)malloc(sizeof(struct pb_Parameters)); - - /* Initialize the parameters structure */ - ret->outFile = NULL; - ret->inpFiles = (char **)malloc(sizeof(char *)); - ret->inpFiles[0] = NULL; - ret->platform = NULL; - ret->device = NULL; - - /* Read parameters and update _argc, argv */ - if (!pb_ParseParameters(ret, _argc, argv)) { - /* Parse error */ - pb_FreeParameters(ret); - return NULL; - } - - return ret; -} - -int -pb_Parameters_CountInputs(struct pb_Parameters *p) -{ - int n; - - for (n = 0; p->inpFiles[n]; n++); - return n; -} - diff --git a/tests/opencl/lbm/gpu_info.c b/tests/opencl/lbm/gpu_info.c deleted file mode 100644 index 4d641f81..00000000 --- a/tests/opencl/lbm/gpu_info.c +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ -//#include -#include -#include -#include -#include - -#include "gpu_info.h" - -void compute_active_thread(size_t *thread, - size_t *grid, - int task, - int pad, - int major, - int minor, - int sm) -{ - int max_thread; - int max_block=8; - if(major==1) - { - if(minor>=2) - max_thread=1024; - else - max_thread=768; - } - else if(major==2) - max_thread=1536; - else - //newer GPU //keep using 2.0 - max_thread=1536; - - int _grid; - int _thread; - - if(task*pad>sm*max_thread) - { - _thread=max_thread/max_block; - _grid = ((task*pad+_thread-1)/_thread)*_thread; - } - else - { - _thread=pad; - _grid=task*pad; - } - - thread[0]=_thread; - grid[0]=_grid; -} diff --git a/tests/opencl/lbm/gpu_info.h b/tests/opencl/lbm/gpu_info.h deleted file mode 100644 index 5d433968..00000000 --- a/tests/opencl/lbm/gpu_info.h +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef __GPUINFOH__ -#define __GPUINFOH__ - -#ifdef __cplusplus -extern "C" { -#endif - -void compute_active_thread(size_t *thread, - size_t *grid, - int task, - int pad, - int major, - int minor, - int sm); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/lbm/kernel.cl b/tests/opencl/lbm/kernel.cl deleted file mode 100644 index 9afb4d56..00000000 --- a/tests/opencl/lbm/kernel.cl +++ /dev/null @@ -1,424 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef LBM_KERNEL_CL -#define LBM_KERNEL_CL - - -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -/*############################################################################*/ - -#ifndef _LAYOUT_CONFIG_H_ -#define _LAYOUT_CONFIG_H_ - -/*############################################################################*/ - -//Unchangeable settings: volume simulation size for the given example -#define SIZE_X (32) -#define SIZE_Y (32) -#define SIZE_Z (32) - -//Changeable settings -//Padding in each dimension -#define PADDING_X (8) -#define PADDING_Y (0) -#define PADDING_Z (4) - -//Pitch in each dimension -#define PADDED_X (SIZE_X+PADDING_X) -#define PADDED_Y (SIZE_Y+PADDING_Y) -#define PADDED_Z (SIZE_Z+PADDING_Z) - -#define TOTAL_CELLS (SIZE_X*SIZE_Y*SIZE_Z) -#define TOTAL_PADDED_CELLS (PADDED_X*PADDED_Y*PADDED_Z) - -//Flattening function -// This macro will be used to map a 3-D index and element to a value -// The macro below implements the equivalent of a 3-D array of -// 20-element structures in C standard layout. -#define CALC_INDEX(x,y,z,e) ( e + N_CELL_ENTRIES*\ - ((x)+(y)*PADDED_X+(z)*PADDED_X*PADDED_Y) ) - -#define MARGIN (CALC_INDEX(0, 0, 2, 0) - CALC_INDEX(0,0,0,0)) - -// Set this value to 1 for GATHER, or 0 for SCATTER -#if 1 -#define GATHER -#else -#define SCATTER -#endif - -//OpenCL block size (not trivially changeable here) -#define BLOCK_SIZE SIZE_X - -/*############################################################################*/ - -typedef enum {C = 0, - N, S, E, W, T, B, - NE, NW, SE, SW, - NT, NB, ST, SB, - ET, EB, WT, WB, - FLAGS, N_CELL_ENTRIES} CELL_ENTRIES; - -#define N_DISTR_FUNCS FLAGS - -typedef enum {OBSTACLE = 1 << 0, - ACCEL = 1 << 1, - IN_OUT_FLOW = 1 << 2} CELL_FLAGS; - -#endif /* _CONFIG_H_ */ - - -#ifndef _LBM_MARCOS_H -#define _LBM_MACROS_H_ - -#define OMEGA (1.95f) - -#define OUTPUT_PRECISION float - -#define BOOL int -#define TRUE (-1) -#define FALSE (0) - -#define DFL1 (1.0f/ 3.0f) -#define DFL2 (1.0f/18.0f) -#define DFL3 (1.0f/36.0f) - -/*############################################################################*/ - -typedef float* LBM_Grid;//float LBM_Grid[PADDED_Z*PADDED_Y*PADDED_X*N_CELL_ENTRIES]; -typedef LBM_Grid* LBM_GridPtr; - -/*############################################################################*/ - - -#define SWEEP_X __temp_x__ -#define SWEEP_Y __temp_y__ -#define SWEEP_Z __temp_z__ -#define SWEEP_VAR int __temp_x__, __temp_y__, __temp_z__; - -#define SWEEP_START(x1,y1,z1,x2,y2,z2) \ - for( __temp_z__ = z1; \ - __temp_z__ < z2; \ - __temp_z__++) { \ - for( __temp_y__ = 0; \ - __temp_y__ < SIZE_Y; \ - __temp_y__++) { \ - for(__temp_x__ = 0; \ - __temp_x__ < SIZE_X; \ - __temp_x__++) { \ - -#define SWEEP_END }}} - - -#define GRID_ENTRY(g,x,y,z,e) ((g)[CALC_INDEX( x, y, z, e)]) -#define GRID_ENTRY_SWEEP(g,dx,dy,dz,e) ((g)[CALC_INDEX((dx)+SWEEP_X, (dy)+SWEEP_Y, (dz)+SWEEP_Z, e)]) - -#define LOCAL(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, 0, e )) -#define NEIGHBOR_C(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, 0, e )) -#define NEIGHBOR_N(g,e) (GRID_ENTRY_SWEEP( g, 0, +1, 0, e )) -#define NEIGHBOR_S(g,e) (GRID_ENTRY_SWEEP( g, 0, -1, 0, e )) -#define NEIGHBOR_E(g,e) (GRID_ENTRY_SWEEP( g, +1, 0, 0, e )) -#define NEIGHBOR_W(g,e) (GRID_ENTRY_SWEEP( g, -1, 0, 0, e )) -#define NEIGHBOR_T(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, +1, e )) -#define NEIGHBOR_B(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, -1, e )) -#define NEIGHBOR_NE(g,e) (GRID_ENTRY_SWEEP( g, +1, +1, 0, e )) -#define NEIGHBOR_NW(g,e) (GRID_ENTRY_SWEEP( g, -1, +1, 0, e )) -#define NEIGHBOR_SE(g,e) (GRID_ENTRY_SWEEP( g, +1, -1, 0, e )) -#define NEIGHBOR_SW(g,e) (GRID_ENTRY_SWEEP( g, -1, -1, 0, e )) -#define NEIGHBOR_NT(g,e) (GRID_ENTRY_SWEEP( g, 0, +1, +1, e )) -#define NEIGHBOR_NB(g,e) (GRID_ENTRY_SWEEP( g, 0, +1, -1, e )) -#define NEIGHBOR_ST(g,e) (GRID_ENTRY_SWEEP( g, 0, -1, +1, e )) -#define NEIGHBOR_SB(g,e) (GRID_ENTRY_SWEEP( g, 0, -1, -1, e )) -#define NEIGHBOR_ET(g,e) (GRID_ENTRY_SWEEP( g, +1, 0, +1, e )) -#define NEIGHBOR_EB(g,e) (GRID_ENTRY_SWEEP( g, +1, 0, -1, e )) -#define NEIGHBOR_WT(g,e) (GRID_ENTRY_SWEEP( g, -1, 0, +1, e )) -#define NEIGHBOR_WB(g,e) (GRID_ENTRY_SWEEP( g, -1, 0, -1, e )) - - -#ifdef SCATTER - -#define SRC_C(g) (LOCAL( g, C )) -#define SRC_N(g) (LOCAL( g, N )) -#define SRC_S(g) (LOCAL( g, S )) -#define SRC_E(g) (LOCAL( g, E )) -#define SRC_W(g) (LOCAL( g, W )) -#define SRC_T(g) (LOCAL( g, T )) -#define SRC_B(g) (LOCAL( g, B )) -#define SRC_NE(g) (LOCAL( g, NE )) -#define SRC_NW(g) (LOCAL( g, NW )) -#define SRC_SE(g) (LOCAL( g, SE )) -#define SRC_SW(g) (LOCAL( g, SW )) -#define SRC_NT(g) (LOCAL( g, NT )) -#define SRC_NB(g) (LOCAL( g, NB )) -#define SRC_ST(g) (LOCAL( g, ST )) -#define SRC_SB(g) (LOCAL( g, SB )) -#define SRC_ET(g) (LOCAL( g, ET )) -#define SRC_EB(g) (LOCAL( g, EB )) -#define SRC_WT(g) (LOCAL( g, WT )) -#define SRC_WB(g) (LOCAL( g, WB )) - -#define DST_C(g) (NEIGHBOR_C ( g, C )) -#define DST_N(g) (NEIGHBOR_N ( g, N )) -#define DST_S(g) (NEIGHBOR_S ( g, S )) -#define DST_E(g) (NEIGHBOR_E ( g, E )) -#define DST_W(g) (NEIGHBOR_W ( g, W )) -#define DST_T(g) (NEIGHBOR_T ( g, T )) -#define DST_B(g) (NEIGHBOR_B ( g, B )) -#define DST_NE(g) (NEIGHBOR_NE( g, NE )) -#define DST_NW(g) (NEIGHBOR_NW( g, NW )) -#define DST_SE(g) (NEIGHBOR_SE( g, SE )) -#define DST_SW(g) (NEIGHBOR_SW( g, SW )) -#define DST_NT(g) (NEIGHBOR_NT( g, NT )) -#define DST_NB(g) (NEIGHBOR_NB( g, NB )) -#define DST_ST(g) (NEIGHBOR_ST( g, ST )) -#define DST_SB(g) (NEIGHBOR_SB( g, SB )) -#define DST_ET(g) (NEIGHBOR_ET( g, ET )) -#define DST_EB(g) (NEIGHBOR_EB( g, EB )) -#define DST_WT(g) (NEIGHBOR_WT( g, WT )) -#define DST_WB(g) (NEIGHBOR_WB( g, WB )) - -#else /* GATHER */ - -#define SRC_C(g) (NEIGHBOR_C ( g, C )) -#define SRC_N(g) (NEIGHBOR_S ( g, N )) -#define SRC_S(g) (NEIGHBOR_N ( g, S )) -#define SRC_E(g) (NEIGHBOR_W ( g, E )) -#define SRC_W(g) (NEIGHBOR_E ( g, W )) -#define SRC_T(g) (NEIGHBOR_B ( g, T )) -#define SRC_B(g) (NEIGHBOR_T ( g, B )) -#define SRC_NE(g) (NEIGHBOR_SW( g, NE )) -#define SRC_NW(g) (NEIGHBOR_SE( g, NW )) -#define SRC_SE(g) (NEIGHBOR_NW( g, SE )) -#define SRC_SW(g) (NEIGHBOR_NE( g, SW )) -#define SRC_NT(g) (NEIGHBOR_SB( g, NT )) -#define SRC_NB(g) (NEIGHBOR_ST( g, NB )) -#define SRC_ST(g) (NEIGHBOR_NB( g, ST )) -#define SRC_SB(g) (NEIGHBOR_NT( g, SB )) -#define SRC_ET(g) (NEIGHBOR_WB( g, ET )) -#define SRC_EB(g) (NEIGHBOR_WT( g, EB )) -#define SRC_WT(g) (NEIGHBOR_EB( g, WT )) -#define SRC_WB(g) (NEIGHBOR_ET( g, WB )) - -#define DST_C(g) (LOCAL( g, C )) -#define DST_N(g) (LOCAL( g, N )) -#define DST_S(g) (LOCAL( g, S )) -#define DST_E(g) (LOCAL( g, E )) -#define DST_W(g) (LOCAL( g, W )) -#define DST_T(g) (LOCAL( g, T )) -#define DST_B(g) (LOCAL( g, B )) -#define DST_NE(g) (LOCAL( g, NE )) -#define DST_NW(g) (LOCAL( g, NW )) -#define DST_SE(g) (LOCAL( g, SE )) -#define DST_SW(g) (LOCAL( g, SW )) -#define DST_NT(g) (LOCAL( g, NT )) -#define DST_NB(g) (LOCAL( g, NB )) -#define DST_ST(g) (LOCAL( g, ST )) -#define DST_SB(g) (LOCAL( g, SB )) -#define DST_ET(g) (LOCAL( g, ET )) -#define DST_EB(g) (LOCAL( g, EB )) -#define DST_WT(g) (LOCAL( g, WT )) -#define DST_WB(g) (LOCAL( g, WB )) - -#endif /* GATHER */ - -#define MAGIC_CAST(v) ((unsigned int*) ((void*) (&(v)))) -#define FLAG_VAR(v) unsigned int* _aux_ = MAGIC_CAST(v) - -#define TEST_FLAG_SWEEP(g,f) ((*MAGIC_CAST(LOCAL(g, FLAGS))) & (f)) -#define SET_FLAG_SWEEP(g,f) {FLAG_VAR(LOCAL(g, FLAGS)); (*_aux_) |= (f);} -#define CLEAR_FLAG_SWEEP(g,f) {FLAG_VAR(LOCAL(g, FLAGS)); (*_aux_) &= ~(f);} -#define CLEAR_ALL_FLAGS_SWEEP(g) {FLAG_VAR(LOCAL(g, FLAGS)); (*_aux_) = 0;} - -#define TEST_FLAG(g,x,y,z,f) ((*MAGIC_CAST(GRID_ENTRY(g, x, y, z, FLAGS))) & (f)) -#define SET_FLAG(g,x,y,z,f) {FLAG_VAR(GRID_ENTRY(g, x, y, z, FLAGS)); (*_aux_) |= (f);} -#define CLEAR_FLAG(g,x,y,z,f) {FLAG_VAR(GRID_ENTRY(g, x, y, z, FLAGS)); (*_aux_) &= ~(f);} -#define CLEAR_ALL_FLAGS(g,x,y,z) {FLAG_VAR(GRID_ENTRY(g, x, y, z, FLAGS)); (*_aux_) = 0;} - -/*############################################################################*/ - -#endif /* _CONFIG_H_ */ - - -/******************************************************************************/ - -__kernel void performStreamCollide_kernel( __global float* srcGrid, __global float* dstGrid ) -{ - srcGrid += MARGIN; - dstGrid += MARGIN; - - - //Using some predefined macros here. Consider this the declaration - // and initialization of the variables SWEEP_X, SWEEP_Y and SWEEP_Z - - SWEEP_VAR - SWEEP_X = get_local_id(0); - SWEEP_Y = get_group_id(0); - SWEEP_Z = get_group_id(1); - - float temp_swp, tempC, tempN, tempS, tempE, tempW, tempT, tempB; - float tempNE, tempNW, tempSE, tempSW, tempNT, tempNB, tempST ; - float tempSB, tempET, tempEB, tempWT, tempWB ; - - //Load all of the input fields - //This is a gather operation of the SCATTER preprocessor variable - // is undefined in layout_config.h, or a "local" read otherwise - tempC = SRC_C(srcGrid); - - tempN = SRC_N(srcGrid); - tempS = SRC_S(srcGrid); - tempE = SRC_E(srcGrid); - tempW = SRC_W(srcGrid); - tempT = SRC_T(srcGrid); - tempB = SRC_B(srcGrid); - - tempNE = SRC_NE(srcGrid); - tempNW = SRC_NW(srcGrid); - tempSE = SRC_SE(srcGrid); - tempSW = SRC_SW(srcGrid); - tempNT = SRC_NT(srcGrid); - tempNB = SRC_NB(srcGrid); - tempST = SRC_ST(srcGrid); - tempSB = SRC_SB(srcGrid); - tempET = SRC_ET(srcGrid); - tempEB = SRC_EB(srcGrid); - tempWT = SRC_WT(srcGrid); - tempWB = SRC_WB(srcGrid); - - //Test whether the cell is fluid or obstacle - if(as_uint(LOCAL(srcGrid,FLAGS)) & (OBSTACLE)) { - - //Swizzle the inputs: reflect any fluid coming into this cell - // back to where it came from - temp_swp = tempN ; tempN = tempS ; tempS = temp_swp ; - temp_swp = tempE ; tempE = tempW ; tempW = temp_swp; - temp_swp = tempT ; tempT = tempB ; tempB = temp_swp; - temp_swp = tempNE; tempNE = tempSW ; tempSW = temp_swp; - temp_swp = tempNW; tempNW = tempSE ; tempSE = temp_swp; - temp_swp = tempNT ; tempNT = tempSB ; tempSB = temp_swp; - temp_swp = tempNB ; tempNB = tempST ; tempST = temp_swp; - temp_swp = tempET ; tempET= tempWB ; tempWB = temp_swp; - temp_swp = tempEB ; tempEB = tempWT ; tempWT = temp_swp; - } - else { - - //The math meat of LBM: ignore for optimization - float ux, uy, uz, rho, u2; - float temp1, temp2, temp_base; - rho = tempC + tempN - + tempS + tempE - + tempW + tempT - + tempB + tempNE - + tempNW + tempSE - + tempSW + tempNT - + tempNB + tempST - + tempSB + tempET - + tempEB + tempWT - + tempWB; - - ux = + tempE - tempW - + tempNE - tempNW - + tempSE - tempSW - + tempET + tempEB - - tempWT - tempWB; - - uy = + tempN - tempS - + tempNE + tempNW - - tempSE - tempSW - + tempNT + tempNB - - tempST - tempSB; - - uz = + tempT - tempB - + tempNT - tempNB - + tempST - tempSB - + tempET - tempEB - + tempWT - tempWB; - - ux /= rho; - uy /= rho; - uz /= rho; - - if(as_uint(LOCAL(srcGrid,FLAGS)) & (ACCEL)) { - - ux = 0.005f; - uy = 0.002f; - uz = 0.000f; - } - - u2 = 1.5f * (ux*ux + uy*uy + uz*uz) - 1.0f; - temp_base = OMEGA*rho; - temp1 = DFL1*temp_base; - - //Put the output values for this cell in the shared memory - temp_base = OMEGA*rho; - temp1 = DFL1*temp_base; - temp2 = 1.0f-OMEGA; - tempC = temp2*tempC + temp1*( - u2); - temp1 = DFL2*temp_base; - tempN = temp2*tempN + temp1*( uy*(4.5f*uy + 3.0f) - u2); - tempS = temp2*tempS + temp1*( uy*(4.5f*uy - 3.0f) - u2); - tempT = temp2*tempT + temp1*( uz*(4.5f*uz + 3.0f) - u2); - tempB = temp2*tempB + temp1*( uz*(4.5f*uz - 3.0f) - u2); - tempE = temp2*tempE + temp1*( ux*(4.5f*ux + 3.0f) - u2); - tempW = temp2*tempW + temp1*( ux*(4.5f*ux - 3.0f) - u2); - temp1 = DFL3*temp_base; - tempNT= temp2*tempNT + temp1 *( (+uy+uz)*(4.5f*(+uy+uz) + 3.0f) - u2); - tempNB= temp2*tempNB + temp1 *( (+uy-uz)*(4.5f*(+uy-uz) + 3.0f) - u2); - tempST= temp2*tempST + temp1 *( (-uy+uz)*(4.5f*(-uy+uz) + 3.0f) - u2); - tempSB= temp2*tempSB + temp1 *( (-uy-uz)*(4.5f*(-uy-uz) + 3.0f) - u2); - tempNE = temp2*tempNE + temp1 *( (+ux+uy)*(4.5f*(+ux+uy) + 3.0f) - u2); - tempSE = temp2*tempSE + temp1 *((+ux-uy)*(4.5f*(+ux-uy) + 3.0f) - u2); - tempET = temp2*tempET + temp1 *( (+ux+uz)*(4.5f*(+ux+uz) + 3.0f) - u2); - tempEB = temp2*tempEB + temp1 *( (+ux-uz)*(4.5f*(+ux-uz) + 3.0f) - u2); - tempNW = temp2*tempNW + temp1 *( (-ux+uy)*(4.5f*(-ux+uy) + 3.0f) - u2); - tempSW = temp2*tempSW + temp1 *( (-ux-uy)*(4.5f*(-ux-uy) + 3.0f) - u2); - tempWT = temp2*tempWT + temp1 *( (-ux+uz)*(4.5f*(-ux+uz) + 3.0f) - u2); - tempWB = temp2*tempWB + temp1 *( (-ux-uz)*(4.5f*(-ux-uz) + 3.0f) - u2); - } - - //Write the results computed above - //This is a scatter operation of the SCATTER preprocessor variable - // is defined in layout_config.h, or a "local" write otherwise - DST_C ( dstGrid ) = tempC; - - DST_N ( dstGrid ) = tempN; - DST_S ( dstGrid ) = tempS; - DST_E ( dstGrid ) = tempE; - DST_W ( dstGrid ) = tempW; - DST_T ( dstGrid ) = tempT; - DST_B ( dstGrid ) = tempB; - - DST_NE( dstGrid ) = tempNE; - DST_NW( dstGrid ) = tempNW; - DST_SE( dstGrid ) = tempSE; - DST_SW( dstGrid ) = tempSW; - DST_NT( dstGrid ) = tempNT; - DST_NB( dstGrid ) = tempNB; - DST_ST( dstGrid ) = tempST; - DST_SB( dstGrid ) = tempSB; - DST_ET( dstGrid ) = tempET; - DST_EB( dstGrid ) = tempEB; - DST_WT( dstGrid ) = tempWT; - DST_WB( dstGrid ) = tempWB; -} - -#endif // LBM_KERNEL_CL diff --git a/tests/opencl/lbm/layout_config.h b/tests/opencl/lbm/layout_config.h deleted file mode 100644 index 9ce9a52e..00000000 --- a/tests/opencl/lbm/layout_config.h +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -/*############################################################################*/ - -#ifndef _LAYOUT_CONFIG_H_ -#define _LAYOUT_CONFIG_H_ - -/*############################################################################*/ - -//Unchangeable settings: volume simulation size for the given example -#define SIZE_X (32) -#define SIZE_Y (16) -#define SIZE_Z (8) - -//Changeable settings -//Padding in each dimension -#define PADDING_X (8) -#define PADDING_Y (0) -#define PADDING_Z (4) - -//Pitch in each dimension -#define PADDED_X (SIZE_X+PADDING_X) -#define PADDED_Y (SIZE_Y+PADDING_Y) -#define PADDED_Z (SIZE_Z+PADDING_Z) - -#define TOTAL_CELLS (SIZE_X*SIZE_Y*SIZE_Z) -#define TOTAL_PADDED_CELLS (PADDED_X*PADDED_Y*PADDED_Z) - -//Flattening function -// This macro will be used to map a 3-D index and element to a value -// The macro below implements the equivalent of a 3-D array of -// 20-element structures in C standard layout. -#define CALC_INDEX(x,y,z,e) ( e + N_CELL_ENTRIES*\ - ((x)+(y)*PADDED_X+(z)*PADDED_X*PADDED_Y) ) - -#define MARGIN (CALC_INDEX(0, 0, 2, 0) - CALC_INDEX(0,0,0,0)) - -// Set this value to 1 for GATHER, or 0 for SCATTER -#if 1 -#define GATHER -#else -#define SCATTER -#endif - -//OpenCL block size (not trivially changeable here) -#define BLOCK_SIZE SIZE_X - -/*############################################################################*/ - -typedef enum {C = 0, - N, S, E, W, T, B, - NE, NW, SE, SW, - NT, NB, ST, SB, - ET, EB, WT, WB, - FLAGS, N_CELL_ENTRIES} CELL_ENTRIES; - -#define N_DISTR_FUNCS FLAGS - -typedef enum {OBSTACLE = 1 << 0, - ACCEL = 1 << 1, - IN_OUT_FLOW = 1 << 2} CELL_FLAGS; - -#endif /* _CONFIG_H_ */ diff --git a/tests/opencl/lbm/lbm.c b/tests/opencl/lbm/lbm.c deleted file mode 100644 index 0ea55d9e..00000000 --- a/tests/opencl/lbm/lbm.c +++ /dev/null @@ -1,356 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -/*############################################################################*/ - -// includes, system -#include -#include -#include -#include -#include -#include - -// includes, project -#include "layout_config.h" -#include "lbm_macros.h" -#include "ocl.h" -#include "lbm.h" - -#include "parboil.h" - -/******************************************************************************/ - -void OpenCL_LBM_performStreamCollide( const OpenCL_Param* prm, cl_mem srcGrid, cl_mem dstGrid ) { - - cl_int clStatus; - - clStatus = clSetKernelArg(prm->clKernel,0,sizeof(cl_mem),(void*)&srcGrid); - CHECK_ERROR("clSetKernelArg") - - clStatus = clSetKernelArg(prm->clKernel,1,sizeof(cl_mem),(void*)&dstGrid); - CHECK_ERROR("clSetKernelArg") - - size_t dimBlock[3] = {SIZE_X,1,1}; - size_t dimGrid[3] = {SIZE_X*SIZE_Y,SIZE_Z,1}; - clStatus = clEnqueueNDRangeKernel(prm->clCommandQueue,prm->clKernel,3,NULL,dimGrid,dimBlock,0,NULL,NULL); - CHECK_ERROR("clEnqueueNDRangeKernel") - - clStatus = clFinish(prm->clCommandQueue); - CHECK_ERROR("clFinish") -} -/*############################################################################*/ - -void LBM_allocateGrid( float** ptr ) { - const size_t size = TOTAL_PADDED_CELLS * N_CELL_ENTRIES * sizeof(float); - *ptr = (float*)malloc( size ); - if( !ptr ) { - printf( "LBM_allocateGrid: could not allocate %.1f MByte\n", - size / (1024.0*1024.0) ); - exit( 1 ); - } - - memset( *ptr, 0, size ); - - printf( "LBM_allocateGrid: allocated %.1f MByte\n", - size / (1024.0*1024.0) ); - - *ptr += MARGIN; -} - -/******************************************************************************/ - -void OpenCL_LBM_allocateGrid( const OpenCL_Param* prm, cl_mem* ptr ) { - const size_t size = TOTAL_PADDED_CELLS*N_CELL_ENTRIES*sizeof( float ); - cl_int clStatus; -/*size_t max_alloc_size = 0; - clGetDeviceInfo(prm->clDevice, CL_DEVICE_MAX_MEM_ALLOC_SIZE, - sizeof(max_alloc_size), &max_alloc_size, NULL); - if (max_alloc_size < size) { - fprintf(stderr, "Can't allocate buffer: max alloc size is %dMB\n", - (int) (max_alloc_size >> 20)); - exit(-1); - }*/ - *ptr = clCreateBuffer(prm->clContext,CL_MEM_READ_WRITE,size,NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") -} - -/*############################################################################*/ - -void LBM_freeGrid( float** ptr ) { - free( *ptr-MARGIN ); - *ptr = NULL; -} - -/******************************************************************************/ - -void OpenCL_LBM_freeGrid(cl_mem ptr) { - clReleaseMemObject(ptr); -} - -/*############################################################################*/ - -void LBM_initializeGrid( LBM_Grid grid ) { - SWEEP_VAR - - SWEEP_START( 0, 0, 0, 0, 0, SIZE_Z ) - SRC_C( grid ) = DFL1; - SRC_N( grid ) = DFL2; - SRC_S( grid ) = DFL2; - SRC_E( grid ) = DFL2; - SRC_W( grid ) = DFL2; - SRC_T( grid ) = DFL2; - SRC_B( grid ) = DFL2; - SRC_NE( grid ) = DFL3; - SRC_NW( grid ) = DFL3; - SRC_SE( grid ) = DFL3; - SRC_SW( grid ) = DFL3; - SRC_NT( grid ) = DFL3; - SRC_NB( grid ) = DFL3; - SRC_ST( grid ) = DFL3; - SRC_SB( grid ) = DFL3; - SRC_ET( grid ) = DFL3; - SRC_EB( grid ) = DFL3; - SRC_WT( grid ) = DFL3; - SRC_WB( grid ) = DFL3; - - CLEAR_ALL_FLAGS_SWEEP( grid ); - SWEEP_END -} - -/******************************************************************************/ - -void OpenCL_LBM_initializeGrid( const OpenCL_Param* prm, cl_mem d_grid, LBM_Grid h_grid ) { - const size_t size = TOTAL_PADDED_CELLS*N_CELL_ENTRIES*sizeof( float ); - cl_int clStatus; - clStatus = clEnqueueWriteBuffer(prm->clCommandQueue,d_grid,CL_TRUE,0,size,h_grid-MARGIN,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") -} - -void OpenCL_LBM_getDeviceGrid( const OpenCL_Param* prm, cl_mem d_grid, LBM_Grid h_grid ) { - const size_t size = TOTAL_PADDED_CELLS*N_CELL_ENTRIES*sizeof( float ); - cl_int clStatus; - clStatus = clEnqueueReadBuffer(prm->clCommandQueue,d_grid,CL_TRUE,0,size,h_grid-MARGIN,0,NULL,NULL); - CHECK_ERROR("clEnqueueReadBuffer") -} - -/*############################################################################*/ - -void LBM_swapGrids( cl_mem* grid1, cl_mem* grid2 ) { - cl_mem aux = *grid1; - *grid1 = *grid2; - *grid2 = aux; -} - -/*############################################################################*/ - -void LBM_loadObstacleFile( LBM_Grid grid, const char* filename ) { - int x, y, z; - - FILE* file = fopen( filename, "rb" ); - - for( z = 0; z < SIZE_Z; z++ ) { - for( y = 0; y < SIZE_Y; y++ ) { - for( x = 0; x < SIZE_X; x++ ) { - if( fgetc( file ) != '.' ) SET_FLAG( grid, x, y, z, OBSTACLE ); - } - fgetc( file ); - } - fgetc( file ); - } - - fclose( file ); -} - -/*############################################################################*/ - -void LBM_initializeSpecialCellsForLDC( LBM_Grid grid ) { - int x, y, z; - - for( z = -2; z < SIZE_Z+2; z++ ) { - for( y = 0; y < SIZE_Y; y++ ) { - for( x = 0; x < SIZE_X; x++ ) { - if( x == 0 || x == SIZE_X-1 || - y == 0 || y == SIZE_Y-1 || - z == 0 || z == SIZE_Z-1 ) { - SET_FLAG( grid, x, y, z, OBSTACLE ); - } - else { - if( (z == 1 || z == SIZE_Z-2) && - x > 1 && x < SIZE_X-2 && - y > 1 && y < SIZE_Y-2 ) { - SET_FLAG( grid, x, y, z, ACCEL ); - } - } - } - } - } -} - -/*############################################################################*/ - -void LBM_showGridStatistics( LBM_Grid grid ) { - int nObstacleCells = 0, - nAccelCells = 0, - nFluidCells = 0; - float ux, uy, uz; - float minU2 = 1e+30, maxU2 = -1e+30, u2; - float minRho = 1e+30, maxRho = -1e+30, rho; - float mass = 0; - - SWEEP_VAR - - SWEEP_START( 0, 0, 0, 0, 0, SIZE_Z ) - rho = LOCAL( grid, C ) + LOCAL( grid, N ) - + LOCAL( grid, S ) + LOCAL( grid, E ) - + LOCAL( grid, W ) + LOCAL( grid, T ) - + LOCAL( grid, B ) + LOCAL( grid, NE ) - + LOCAL( grid, NW ) + LOCAL( grid, SE ) - + LOCAL( grid, SW ) + LOCAL( grid, NT ) - + LOCAL( grid, NB ) + LOCAL( grid, ST ) - + LOCAL( grid, SB ) + LOCAL( grid, ET ) - + LOCAL( grid, EB ) + LOCAL( grid, WT ) - + LOCAL( grid, WB ); - - if( rho < minRho ) minRho = rho; - if( rho > maxRho ) maxRho = rho; - mass += rho; - - if( TEST_FLAG_SWEEP( grid, OBSTACLE )) { - nObstacleCells++; - } - else { - if( TEST_FLAG_SWEEP( grid, ACCEL )) - nAccelCells++; - else - nFluidCells++; - - ux = + LOCAL( grid, E ) - LOCAL( grid, W ) - + LOCAL( grid, NE ) - LOCAL( grid, NW ) - + LOCAL( grid, SE ) - LOCAL( grid, SW ) - + LOCAL( grid, ET ) + LOCAL( grid, EB ) - - LOCAL( grid, WT ) - LOCAL( grid, WB ); - uy = + LOCAL( grid, N ) - LOCAL( grid, S ) - + LOCAL( grid, NE ) + LOCAL( grid, NW ) - - LOCAL( grid, SE ) - LOCAL( grid, SW ) - + LOCAL( grid, NT ) + LOCAL( grid, NB ) - - LOCAL( grid, ST ) - LOCAL( grid, SB ); - uz = + LOCAL( grid, T ) - LOCAL( grid, B ) - + LOCAL( grid, NT ) - LOCAL( grid, NB ) - + LOCAL( grid, ST ) - LOCAL( grid, SB ) - + LOCAL( grid, ET ) - LOCAL( grid, EB ) - + LOCAL( grid, WT ) - LOCAL( grid, WB ); - u2 = (ux*ux + uy*uy + uz*uz) / (rho*rho); - if( u2 < minU2 ) minU2 = u2; - if( u2 > maxU2 ) maxU2 = u2; - } - SWEEP_END - - printf( "LBM_showGridStatistics:\n" - "\tnObstacleCells: %7i nAccelCells: %7i nFluidCells: %7i\n" - "\tminRho: %8.4f maxRho: %8.4f mass: %e\n" - "\tminU: %e maxU: %e\n\n", - nObstacleCells, nAccelCells, nFluidCells, - minRho, maxRho, mass, - sqrt( minU2 ), sqrt( maxU2 ) ); - -} - -/*############################################################################*/ - -static void storeValue( FILE* file, OUTPUT_PRECISION* v ) { - const int litteBigEndianTest = 1; - if( (*((unsigned char*) &litteBigEndianTest)) == 0 ) { /* big endian */ - const char* vPtr = (char*) v; - char buffer[sizeof( OUTPUT_PRECISION )]; - int i; - - for (i = 0; i < sizeof( OUTPUT_PRECISION ); i++) - buffer[i] = vPtr[sizeof( OUTPUT_PRECISION ) - i - 1]; - - fwrite( buffer, sizeof( OUTPUT_PRECISION ), 1, file ); - } - else { /* little endian */ - fwrite( v, sizeof( OUTPUT_PRECISION ), 1, file ); - } -} - -/*############################################################################*/ - -static void loadValue( FILE* file, OUTPUT_PRECISION* v ) { - const int litteBigEndianTest = 1; - if( (*((unsigned char*) &litteBigEndianTest)) == 0 ) { /* big endian */ - char* vPtr = (char*) v; - char buffer[sizeof( OUTPUT_PRECISION )]; - int i; - - fread( buffer, sizeof( OUTPUT_PRECISION ), 1, file ); - - for (i = 0; i < sizeof( OUTPUT_PRECISION ); i++) - vPtr[i] = buffer[sizeof( OUTPUT_PRECISION ) - i - 1]; - } - else { /* little endian */ - fread( v, sizeof( OUTPUT_PRECISION ), 1, file ); - } -} - -/*############################################################################*/ - -void LBM_storeVelocityField( LBM_Grid grid, const char* filename, - const int binary ) { - OUTPUT_PRECISION rho, ux, uy, uz; - - FILE* file = fopen( filename, (binary ? "wb" : "w") ); - - SWEEP_VAR - SWEEP_START(0,0,0,SIZE_X,SIZE_Y,SIZE_Z) - rho = + SRC_C( grid ) + SRC_N( grid ) - + SRC_S( grid ) + SRC_E( grid ) - + SRC_W( grid ) + SRC_T( grid ) - + SRC_B( grid ) + SRC_NE( grid ) - + SRC_NW( grid ) + SRC_SE( grid ) - + SRC_SW( grid ) + SRC_NT( grid ) - + SRC_NB( grid ) + SRC_ST( grid ) - + SRC_SB( grid ) + SRC_ET( grid ) - + SRC_EB( grid ) + SRC_WT( grid ) - + SRC_WB( grid ); - ux = + SRC_E( grid ) - SRC_W( grid ) - + SRC_NE( grid ) - SRC_NW( grid ) - + SRC_SE( grid ) - SRC_SW( grid ) - + SRC_ET( grid ) + SRC_EB( grid ) - - SRC_WT( grid ) - SRC_WB( grid ); - uy = + SRC_N( grid ) - SRC_S( grid ) - + SRC_NE( grid ) + SRC_NW( grid ) - - SRC_SE( grid ) - SRC_SW( grid ) - + SRC_NT( grid ) + SRC_NB( grid ) - - SRC_ST( grid ) - SRC_SB( grid ); - uz = + SRC_T( grid ) - SRC_B( grid ) - + SRC_NT( grid ) - SRC_NB( grid ) - + SRC_ST( grid ) - SRC_SB( grid ) - + SRC_ET( grid ) - SRC_EB( grid ) - + SRC_WT( grid ) - SRC_WB( grid ); - ux /= rho; - uy /= rho; - uz /= rho; - - if( binary ) { - /* - fwrite( &ux, sizeof( ux ), 1, file ); - fwrite( &uy, sizeof( uy ), 1, file ); - fwrite( &uz, sizeof( uz ), 1, file ); - */ - storeValue( file, &ux ); - storeValue( file, &uy ); - storeValue( file, &uz ); - } else - fprintf( file, "%e %e %e\n", ux, uy, uz ); - - SWEEP_END; - - fclose( file ); -} diff --git a/tests/opencl/lbm/lbm.h b/tests/opencl/lbm/lbm.h deleted file mode 100644 index 1764b5c8..00000000 --- a/tests/opencl/lbm/lbm.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef _LBM_H_ -#define _LBM_H_ - -#include "ocl.h" -#include "lbm_macros.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void LBM_allocateGrid( float** ptr ); -void LBM_freeGrid( float** ptr ); -void LBM_initializeGrid( LBM_Grid grid ); -void LBM_initializeSpecialCellsForLDC( LBM_Grid grid ); -void LBM_loadObstacleFile( LBM_Grid grid, const char* filename ); -void LBM_swapGrids( cl_mem* grid1, cl_mem* grid2 ); -void LBM_showGridStatistics( LBM_Grid Grid ); -void LBM_storeVelocityField( LBM_Grid grid, const char* filename, - const BOOL binary ); - -/* OpenCL *********************************************************************/ - -void OpenCL_LBM_allocateGrid( const OpenCL_Param* prm, cl_mem* ptr ); -void OpenCL_LBM_freeGrid( cl_mem ptr ); -void OpenCL_LBM_initializeGrid( const OpenCL_Param* prm, cl_mem d_grid, LBM_Grid h_grid ); -void OpenCL_LBM_getDeviceGrid( const OpenCL_Param* prm, cl_mem d_grid, LBM_Grid h_grid ); -void OpenCL_LBM_performStreamCollide( const OpenCL_Param* prm, cl_mem srcGrid, cl_mem dstGrid ); - -#ifdef __cplusplus -} -#endif - -#endif /* _LBM_H_ */ diff --git a/tests/opencl/lbm/lbm_macros.h b/tests/opencl/lbm/lbm_macros.h deleted file mode 100644 index 24fad432..00000000 --- a/tests/opencl/lbm/lbm_macros.h +++ /dev/null @@ -1,177 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef _LBM_MARCOS_H -#define _LBM_MACROS_H_ - -#define OMEGA (1.95f) - -#define OUTPUT_PRECISION float - -#define BOOL int -#define TRUE (-1) -#define FALSE (0) - -#define DFL1 (1.0f/ 3.0f) -#define DFL2 (1.0f/18.0f) -#define DFL3 (1.0f/36.0f) - -/*############################################################################*/ - -typedef float* LBM_Grid;//float LBM_Grid[PADDED_Z*PADDED_Y*PADDED_X*N_CELL_ENTRIES]; -typedef LBM_Grid* LBM_GridPtr; - -/*############################################################################*/ - - -#define SWEEP_X __temp_x__ -#define SWEEP_Y __temp_y__ -#define SWEEP_Z __temp_z__ -#define SWEEP_VAR int __temp_x__, __temp_y__, __temp_z__; - -#define SWEEP_START(x1,y1,z1,x2,y2,z2) \ - for( __temp_z__ = z1; \ - __temp_z__ < z2; \ - __temp_z__++) { \ - for( __temp_y__ = 0; \ - __temp_y__ < SIZE_Y; \ - __temp_y__++) { \ - for(__temp_x__ = 0; \ - __temp_x__ < SIZE_X; \ - __temp_x__++) { \ - -#define SWEEP_END }}} - - -#define GRID_ENTRY(g,x,y,z,e) ((g)[CALC_INDEX( x, y, z, e)]) -#define GRID_ENTRY_SWEEP(g,dx,dy,dz,e) ((g)[CALC_INDEX((dx)+SWEEP_X, (dy)+SWEEP_Y, (dz)+SWEEP_Z, e)]) - -#define LOCAL(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, 0, e )) -#define NEIGHBOR_C(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, 0, e )) -#define NEIGHBOR_N(g,e) (GRID_ENTRY_SWEEP( g, 0, +1, 0, e )) -#define NEIGHBOR_S(g,e) (GRID_ENTRY_SWEEP( g, 0, -1, 0, e )) -#define NEIGHBOR_E(g,e) (GRID_ENTRY_SWEEP( g, +1, 0, 0, e )) -#define NEIGHBOR_W(g,e) (GRID_ENTRY_SWEEP( g, -1, 0, 0, e )) -#define NEIGHBOR_T(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, +1, e )) -#define NEIGHBOR_B(g,e) (GRID_ENTRY_SWEEP( g, 0, 0, -1, e )) -#define NEIGHBOR_NE(g,e) (GRID_ENTRY_SWEEP( g, +1, +1, 0, e )) -#define NEIGHBOR_NW(g,e) (GRID_ENTRY_SWEEP( g, -1, +1, 0, e )) -#define NEIGHBOR_SE(g,e) (GRID_ENTRY_SWEEP( g, +1, -1, 0, e )) -#define NEIGHBOR_SW(g,e) (GRID_ENTRY_SWEEP( g, -1, -1, 0, e )) -#define NEIGHBOR_NT(g,e) (GRID_ENTRY_SWEEP( g, 0, +1, +1, e )) -#define NEIGHBOR_NB(g,e) (GRID_ENTRY_SWEEP( g, 0, +1, -1, e )) -#define NEIGHBOR_ST(g,e) (GRID_ENTRY_SWEEP( g, 0, -1, +1, e )) -#define NEIGHBOR_SB(g,e) (GRID_ENTRY_SWEEP( g, 0, -1, -1, e )) -#define NEIGHBOR_ET(g,e) (GRID_ENTRY_SWEEP( g, +1, 0, +1, e )) -#define NEIGHBOR_EB(g,e) (GRID_ENTRY_SWEEP( g, +1, 0, -1, e )) -#define NEIGHBOR_WT(g,e) (GRID_ENTRY_SWEEP( g, -1, 0, +1, e )) -#define NEIGHBOR_WB(g,e) (GRID_ENTRY_SWEEP( g, -1, 0, -1, e )) - - -#ifdef SCATTER - -#define SRC_C(g) (LOCAL( g, C )) -#define SRC_N(g) (LOCAL( g, N )) -#define SRC_S(g) (LOCAL( g, S )) -#define SRC_E(g) (LOCAL( g, E )) -#define SRC_W(g) (LOCAL( g, W )) -#define SRC_T(g) (LOCAL( g, T )) -#define SRC_B(g) (LOCAL( g, B )) -#define SRC_NE(g) (LOCAL( g, NE )) -#define SRC_NW(g) (LOCAL( g, NW )) -#define SRC_SE(g) (LOCAL( g, SE )) -#define SRC_SW(g) (LOCAL( g, SW )) -#define SRC_NT(g) (LOCAL( g, NT )) -#define SRC_NB(g) (LOCAL( g, NB )) -#define SRC_ST(g) (LOCAL( g, ST )) -#define SRC_SB(g) (LOCAL( g, SB )) -#define SRC_ET(g) (LOCAL( g, ET )) -#define SRC_EB(g) (LOCAL( g, EB )) -#define SRC_WT(g) (LOCAL( g, WT )) -#define SRC_WB(g) (LOCAL( g, WB )) - -#define DST_C(g) (NEIGHBOR_C ( g, C )) -#define DST_N(g) (NEIGHBOR_N ( g, N )) -#define DST_S(g) (NEIGHBOR_S ( g, S )) -#define DST_E(g) (NEIGHBOR_E ( g, E )) -#define DST_W(g) (NEIGHBOR_W ( g, W )) -#define DST_T(g) (NEIGHBOR_T ( g, T )) -#define DST_B(g) (NEIGHBOR_B ( g, B )) -#define DST_NE(g) (NEIGHBOR_NE( g, NE )) -#define DST_NW(g) (NEIGHBOR_NW( g, NW )) -#define DST_SE(g) (NEIGHBOR_SE( g, SE )) -#define DST_SW(g) (NEIGHBOR_SW( g, SW )) -#define DST_NT(g) (NEIGHBOR_NT( g, NT )) -#define DST_NB(g) (NEIGHBOR_NB( g, NB )) -#define DST_ST(g) (NEIGHBOR_ST( g, ST )) -#define DST_SB(g) (NEIGHBOR_SB( g, SB )) -#define DST_ET(g) (NEIGHBOR_ET( g, ET )) -#define DST_EB(g) (NEIGHBOR_EB( g, EB )) -#define DST_WT(g) (NEIGHBOR_WT( g, WT )) -#define DST_WB(g) (NEIGHBOR_WB( g, WB )) - -#else /* GATHER */ - -#define SRC_C(g) (NEIGHBOR_C ( g, C )) -#define SRC_N(g) (NEIGHBOR_S ( g, N )) -#define SRC_S(g) (NEIGHBOR_N ( g, S )) -#define SRC_E(g) (NEIGHBOR_W ( g, E )) -#define SRC_W(g) (NEIGHBOR_E ( g, W )) -#define SRC_T(g) (NEIGHBOR_B ( g, T )) -#define SRC_B(g) (NEIGHBOR_T ( g, B )) -#define SRC_NE(g) (NEIGHBOR_SW( g, NE )) -#define SRC_NW(g) (NEIGHBOR_SE( g, NW )) -#define SRC_SE(g) (NEIGHBOR_NW( g, SE )) -#define SRC_SW(g) (NEIGHBOR_NE( g, SW )) -#define SRC_NT(g) (NEIGHBOR_SB( g, NT )) -#define SRC_NB(g) (NEIGHBOR_ST( g, NB )) -#define SRC_ST(g) (NEIGHBOR_NB( g, ST )) -#define SRC_SB(g) (NEIGHBOR_NT( g, SB )) -#define SRC_ET(g) (NEIGHBOR_WB( g, ET )) -#define SRC_EB(g) (NEIGHBOR_WT( g, EB )) -#define SRC_WT(g) (NEIGHBOR_EB( g, WT )) -#define SRC_WB(g) (NEIGHBOR_ET( g, WB )) - -#define DST_C(g) (LOCAL( g, C )) -#define DST_N(g) (LOCAL( g, N )) -#define DST_S(g) (LOCAL( g, S )) -#define DST_E(g) (LOCAL( g, E )) -#define DST_W(g) (LOCAL( g, W )) -#define DST_T(g) (LOCAL( g, T )) -#define DST_B(g) (LOCAL( g, B )) -#define DST_NE(g) (LOCAL( g, NE )) -#define DST_NW(g) (LOCAL( g, NW )) -#define DST_SE(g) (LOCAL( g, SE )) -#define DST_SW(g) (LOCAL( g, SW )) -#define DST_NT(g) (LOCAL( g, NT )) -#define DST_NB(g) (LOCAL( g, NB )) -#define DST_ST(g) (LOCAL( g, ST )) -#define DST_SB(g) (LOCAL( g, SB )) -#define DST_ET(g) (LOCAL( g, ET )) -#define DST_EB(g) (LOCAL( g, EB )) -#define DST_WT(g) (LOCAL( g, WT )) -#define DST_WB(g) (LOCAL( g, WB )) - -#endif /* GATHER */ - -#define MAGIC_CAST(v) ((unsigned int*) ((void*) (&(v)))) -#define FLAG_VAR(v) unsigned int* _aux_ = MAGIC_CAST(v) - -#define TEST_FLAG_SWEEP(g,f) ((*MAGIC_CAST(LOCAL(g, FLAGS))) & (f)) -#define SET_FLAG_SWEEP(g,f) {FLAG_VAR(LOCAL(g, FLAGS)); (*_aux_) |= (f);} -#define CLEAR_FLAG_SWEEP(g,f) {FLAG_VAR(LOCAL(g, FLAGS)); (*_aux_) &= ~(f);} -#define CLEAR_ALL_FLAGS_SWEEP(g) {FLAG_VAR(LOCAL(g, FLAGS)); (*_aux_) = 0;} - -#define TEST_FLAG(g,x,y,z,f) ((*MAGIC_CAST(GRID_ENTRY(g, x, y, z, FLAGS))) & (f)) -#define SET_FLAG(g,x,y,z,f) {FLAG_VAR(GRID_ENTRY(g, x, y, z, FLAGS)); (*_aux_) |= (f);} -#define CLEAR_FLAG(g,x,y,z,f) {FLAG_VAR(GRID_ENTRY(g, x, y, z, FLAGS)); (*_aux_) &= ~(f);} -#define CLEAR_ALL_FLAGS(g,x,y,z) {FLAG_VAR(GRID_ENTRY(g, x, y, z, FLAGS)); (*_aux_) = 0;} - -/*############################################################################*/ - -#endif /* _CONFIG_H_ */ diff --git a/tests/opencl/lbm/main.cc b/tests/opencl/lbm/main.cc deleted file mode 100644 index 58a930e9..00000000 --- a/tests/opencl/lbm/main.cc +++ /dev/null @@ -1,260 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -/*############################################################################*/ - -#include -#include -#include -#include -#include - - -#include "layout_config.h" -#include "lbm.h" -#include "lbm_macros.h" -#include "main.h" -#include "ocl.h" - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return CL_INVALID_VALUE; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return CL_INVALID_VALUE; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return CL_SUCCESS; -} - -/*############################################################################*/ - -static cl_mem OpenCL_srcGrid, OpenCL_dstGrid; - -/*############################################################################*/ - -struct pb_TimerSet timers; -int main(int nArgs, char *arg[]) { - MAIN_Param param; - int t; - - OpenCL_Param prm; - - pb_InitializeTimerSet(&timers); - struct pb_Parameters *params; - params = pb_ReadParameters(&nArgs, arg); - - params->inpFiles = (char **)malloc(sizeof(char *) * 2); - params->inpFiles[0] = (char *)malloc(100); - params->inpFiles[1] = NULL; - strncpy(params->inpFiles[0], "120_120_150_ldc.of", 100); - - static LBM_GridPtr TEMP_srcGrid; - // Setup TEMP datastructures - LBM_allocateGrid((float **)&TEMP_srcGrid); - MAIN_parseCommandLine(nArgs, arg, ¶m, params); - MAIN_printInfo(¶m); - - OpenCL_initialize(params, &prm); - MAIN_initialize(¶m, &prm); - - for (t = 1; t <= param.nTimeSteps; t++) { - pb_SwitchToTimer(&timers, pb_TimerID_KERNEL); - OpenCL_LBM_performStreamCollide(&prm, OpenCL_srcGrid, OpenCL_dstGrid); - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - LBM_swapGrids(&OpenCL_srcGrid, &OpenCL_dstGrid); - - if ((t & 63) == 0) { - printf("timestep: %i\n", t); -#if 0 - CUDA_LBM_getDeviceGrid((float**)&CUDA_srcGrid, (float**)&TEMP_srcGrid); - LBM_showGridStatistics( *TEMP_srcGrid ); -#endif - } - } - - MAIN_finalize(¶m, &prm); - - LBM_freeGrid((float **)&TEMP_srcGrid); - - pb_SwitchToTimer(&timers, pb_TimerID_NONE); - pb_PrintTimerSet(&timers); - pb_FreeParameters(params); - return 0; -} - -/*############################################################################*/ - -void MAIN_parseCommandLine(int nArgs, char *arg[], MAIN_Param *param, - struct pb_Parameters *params) { - struct stat fileStat; - - /*if (nArgs < 2) { - printf("syntax: lbm

>5=QsK}X}CDd&+f@k{+-!Zk*K2w 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�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