Marat Dukhan | 1718dae | 2017-02-17 22:41:54 -0500 | [diff] [blame] | 1 | #include <benchmark/benchmark.h> |
| 2 | |
| 3 | #include <fp16.h> |
| 4 | #ifndef EMSCRIPTEN |
| 5 | #include <fp16/psimd.h> |
| 6 | #endif |
| 7 | |
| 8 | #include <vector> |
| 9 | #include <random> |
| 10 | #include <chrono> |
| 11 | #include <functional> |
| 12 | #include <algorithm> |
| 13 | |
| 14 | #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__) |
| 15 | #include <immintrin.h> |
| 16 | #endif |
| 17 | |
Marat Dukhan | 5d73573 | 2017-03-23 14:33:37 +0000 | [diff] [blame] | 18 | #if defined(__ARM_NEON__) || defined(__aarch64__) |
| 19 | #include <arm_neon.h> |
| 20 | #endif |
| 21 | |
Marat Dukhan | 1718dae | 2017-02-17 22:41:54 -0500 | [diff] [blame] | 22 | |
| 23 | static void fp16_alt_from_fp32_value(benchmark::State& state) { |
| 24 | const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count(); |
| 25 | auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed)); |
| 26 | |
| 27 | std::vector<float> fp32(state.range(0)); |
| 28 | std::vector<uint16_t> fp16(state.range(0)); |
| 29 | std::generate(fp32.begin(), fp32.end(), std::ref(rng)); |
| 30 | |
| 31 | while (state.KeepRunning()) { |
| 32 | float* input = fp32.data(); |
| 33 | benchmark::DoNotOptimize(input); |
| 34 | |
| 35 | uint16_t* output = fp16.data(); |
| 36 | const size_t n = state.range(0); |
| 37 | for (size_t i = 0; i < n; i++) { |
| 38 | output[i] = fp16_alt_from_fp32_value(input[i]); |
| 39 | } |
| 40 | |
| 41 | benchmark::DoNotOptimize(output); |
| 42 | } |
| 43 | state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0))); |
| 44 | } |
| 45 | BENCHMARK(fp16_alt_from_fp32_value)->RangeMultiplier(2)->Range(1<<10, 64<<20); |
| 46 | |
Marat Dukhan | 5d73573 | 2017-03-23 14:33:37 +0000 | [diff] [blame] | 47 | #if defined(__ARM_NEON_FP) && (__ARM_NEON_FP & 0x2) || defined(__aarch64__) |
| 48 | static void hardware_vcvt_f16_f32(benchmark::State& state) { |
| 49 | const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count(); |
| 50 | auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed)); |
| 51 | |
| 52 | std::vector<float> fp32(state.range(0)); |
| 53 | std::vector<uint16_t> fp16(state.range(0)); |
| 54 | std::generate(fp32.begin(), fp32.end(), std::ref(rng)); |
| 55 | |
| 56 | while (state.KeepRunning()) { |
| 57 | float* input = fp32.data(); |
| 58 | benchmark::DoNotOptimize(input); |
| 59 | |
| 60 | uint16_t* output = fp16.data(); |
| 61 | const size_t n = state.range(0); |
| 62 | #if defined(__aarch64__) |
| 63 | const unsigned int fpcr = __builtin_aarch64_get_fpcr(); |
| 64 | /* Disable flush-to-zero (bit 24) and enable Alternative FP16 format (bit 26) */ |
| 65 | __builtin_aarch64_set_fpcr((fpcr & 0xFEFFFFFFu) | 0x08000000u); |
| 66 | #else |
| 67 | unsigned int fpscr; |
| 68 | __asm__ __volatile__ ("VMRS %[fpscr], fpscr" : [fpscr] "=r" (fpscr)); |
| 69 | /* Disable flush-to-zero (bit 24) and enable Alternative FP16 format (bit 26) */ |
| 70 | __asm__ __volatile__ ("VMSR fpscr, %[fpscr]" : |
| 71 | : [fpscr] "r" ((fpscr & 0xFEFFFFFFu) | 0x08000000u)); |
| 72 | #endif |
| 73 | for (size_t i = 0; i < n; i += 4) { |
| 74 | vst1_u16(&output[i], |
| 75 | (uint16x4_t) vcvt_f16_f32( |
| 76 | vld1q_f32(&input[i]))); |
| 77 | } |
| 78 | #if defined(__aarch64__) |
| 79 | __builtin_aarch64_set_fpcr(fpcr); |
| 80 | #else |
| 81 | __asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :: [fpscr] "r" (fpscr)); |
| 82 | #endif |
| 83 | |
| 84 | benchmark::DoNotOptimize(output); |
| 85 | } |
| 86 | state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0))); |
| 87 | } |
| 88 | BENCHMARK(hardware_vcvt_f16_f32)->RangeMultiplier(2)->Range(1<<10, 64<<20); |
| 89 | #endif |
| 90 | |
Marat Dukhan | 1718dae | 2017-02-17 22:41:54 -0500 | [diff] [blame] | 91 | BENCHMARK_MAIN(); |