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