xref: /aosp_15_r20/external/FP16/bench/from-ieee-array.cc (revision 5f32b7105932ea8520a0e8811c640f936367d707)
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 #ifdef FP16_COMPARATIVE_BENCHMARKS
23*5f32b710SXin Li 	#include <third-party/THHalf.h>
24*5f32b710SXin Li 	#include <third-party/npy-halffloat.h>
25*5f32b710SXin Li 	#include <third-party/eigen-half.h>
26*5f32b710SXin Li 	#include <third-party/float16-compressor.h>
27*5f32b710SXin Li 	#include <third-party/half.hpp>
28*5f32b710SXin Li #endif
29*5f32b710SXin Li 
30*5f32b710SXin Li 
fp16_ieee_to_fp32_bits(benchmark::State & state)31*5f32b710SXin Li static void fp16_ieee_to_fp32_bits(benchmark::State& state) {
32*5f32b710SXin Li 	const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
33*5f32b710SXin Li 	auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
34*5f32b710SXin Li 
35*5f32b710SXin Li 	std::vector<uint16_t> fp16(state.range(0));
36*5f32b710SXin Li 	std::vector<uint32_t> fp32(state.range(0));
37*5f32b710SXin Li 	std::generate(fp16.begin(), fp16.end(),
38*5f32b710SXin Li 		[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
39*5f32b710SXin Li 
40*5f32b710SXin Li 	while (state.KeepRunning()) {
41*5f32b710SXin Li 		uint16_t* input = fp16.data();
42*5f32b710SXin Li 		benchmark::DoNotOptimize(input);
43*5f32b710SXin Li 
44*5f32b710SXin Li 		uint32_t* output = fp32.data();
45*5f32b710SXin Li 		const size_t n = state.range(0);
46*5f32b710SXin Li 		for (size_t i = 0; i < n; i++) {
47*5f32b710SXin Li 			output[i] = fp16_ieee_to_fp32_bits(input[i]);
48*5f32b710SXin Li 		}
49*5f32b710SXin Li 
50*5f32b710SXin Li 		benchmark::DoNotOptimize(output);
51*5f32b710SXin Li 	}
52*5f32b710SXin Li 	state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
53*5f32b710SXin Li }
54*5f32b710SXin Li BENCHMARK(fp16_ieee_to_fp32_bits)->RangeMultiplier(2)->Range(1<<10, 64<<20);
55*5f32b710SXin Li 
fp16_ieee_to_fp32_value(benchmark::State & state)56*5f32b710SXin Li static void fp16_ieee_to_fp32_value(benchmark::State& state) {
57*5f32b710SXin Li 	const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
58*5f32b710SXin Li 	auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
59*5f32b710SXin Li 
60*5f32b710SXin Li 	std::vector<uint16_t> fp16(state.range(0));
61*5f32b710SXin Li 	std::vector<float> fp32(state.range(0));
62*5f32b710SXin Li 	std::generate(fp16.begin(), fp16.end(),
63*5f32b710SXin Li 		[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
64*5f32b710SXin Li 
65*5f32b710SXin Li 	while (state.KeepRunning()) {
66*5f32b710SXin Li 		uint16_t* input = fp16.data();
67*5f32b710SXin Li 		benchmark::DoNotOptimize(input);
68*5f32b710SXin Li 
69*5f32b710SXin Li 		float* output = fp32.data();
70*5f32b710SXin Li 		const size_t n = state.range(0);
71*5f32b710SXin Li 		for (size_t i = 0; i < n; i++) {
72*5f32b710SXin Li 			output[i] = fp16_ieee_to_fp32_value(input[i]);
73*5f32b710SXin Li 		}
74*5f32b710SXin Li 
75*5f32b710SXin Li 		benchmark::DoNotOptimize(output);
76*5f32b710SXin Li 	}
77*5f32b710SXin Li 	state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
78*5f32b710SXin Li }
79*5f32b710SXin Li BENCHMARK(fp16_ieee_to_fp32_value)->RangeMultiplier(2)->Range(1<<10, 64<<20);
80*5f32b710SXin Li 
81*5f32b710SXin Li #ifndef EMSCRIPTEN
fp16_ieee_to_fp32_psimd(benchmark::State & state)82*5f32b710SXin Li 	static void fp16_ieee_to_fp32_psimd(benchmark::State& state) {
83*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
84*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
85*5f32b710SXin Li 
86*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
87*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
88*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
89*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
90*5f32b710SXin Li 
91*5f32b710SXin Li 		while (state.KeepRunning()) {
92*5f32b710SXin Li 			uint16_t* input = fp16.data();
93*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
94*5f32b710SXin Li 
95*5f32b710SXin Li 			float* output = fp32.data();
96*5f32b710SXin Li 			const size_t n = state.range(0);
97*5f32b710SXin Li 			for (size_t i = 0; i < n - 4; i += 4) {
98*5f32b710SXin Li 				psimd_store_f32(&output[i],
99*5f32b710SXin Li 					fp16_ieee_to_fp32_psimd(
100*5f32b710SXin Li 						psimd_load_u16(&input[i])));
101*5f32b710SXin Li 			}
102*5f32b710SXin Li 			const psimd_u16 last_vector = { input[n - 4], input[n - 3], input[n - 2], input[n - 1] };
103*5f32b710SXin Li 			psimd_store_f32(&output[n - 4],
104*5f32b710SXin Li 				fp16_ieee_to_fp32_psimd(last_vector));
105*5f32b710SXin Li 
106*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
107*5f32b710SXin Li 		}
108*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
109*5f32b710SXin Li 	}
110*5f32b710SXin Li 	BENCHMARK(fp16_ieee_to_fp32_psimd)->RangeMultiplier(2)->Range(1<<10, 64<<20);
111*5f32b710SXin Li 
fp16_ieee_to_fp32x2_psimd(benchmark::State & state)112*5f32b710SXin Li 	static void fp16_ieee_to_fp32x2_psimd(benchmark::State& state) {
113*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
114*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
115*5f32b710SXin Li 
116*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
117*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
118*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
119*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
120*5f32b710SXin Li 
121*5f32b710SXin Li 		while (state.KeepRunning()) {
122*5f32b710SXin Li 			uint16_t* input = fp16.data();
123*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
124*5f32b710SXin Li 
125*5f32b710SXin Li 			float* output = fp32.data();
126*5f32b710SXin Li 			const size_t n = state.range(0);
127*5f32b710SXin Li 			for (size_t i = 0; i < n; i += 8) {
128*5f32b710SXin Li 				const psimd_f32x2 data =
129*5f32b710SXin Li 					fp16_ieee_to_fp32x2_psimd(
130*5f32b710SXin Li 						psimd_load_u16(&input[i]));
131*5f32b710SXin Li 				psimd_store_f32(&output[i], data.lo);
132*5f32b710SXin Li 				psimd_store_f32(&output[i + 4], data.hi);
133*5f32b710SXin Li 			}
134*5f32b710SXin Li 
135*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
136*5f32b710SXin Li 		}
137*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
138*5f32b710SXin Li 	}
139*5f32b710SXin Li 	BENCHMARK(fp16_ieee_to_fp32x2_psimd)->RangeMultiplier(2)->Range(1<<10, 64<<20);
140*5f32b710SXin Li #endif
141*5f32b710SXin Li 
142*5f32b710SXin Li #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
hardware_mm_cvtph_ps(benchmark::State & state)143*5f32b710SXin Li 	static void hardware_mm_cvtph_ps(benchmark::State& state) {
144*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
145*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
146*5f32b710SXin Li 
147*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
148*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
149*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
150*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
151*5f32b710SXin Li 
152*5f32b710SXin Li 		while (state.KeepRunning()) {
153*5f32b710SXin Li 			uint16_t* input = fp16.data();
154*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
155*5f32b710SXin Li 
156*5f32b710SXin Li 			float* output = fp32.data();
157*5f32b710SXin Li 			const size_t n = state.range(0);
158*5f32b710SXin Li 			for (size_t i = 0; i < n; i += 4) {
159*5f32b710SXin Li 				_mm_storeu_ps(&output[i],
160*5f32b710SXin Li 					_mm_cvtph_ps(
161*5f32b710SXin Li 						_mm_loadl_epi64(static_cast<const __m128i*>(static_cast<const void*>(&input[i])))));
162*5f32b710SXin Li 			}
163*5f32b710SXin Li 
164*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
165*5f32b710SXin Li 		}
166*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
167*5f32b710SXin Li 	}
168*5f32b710SXin Li 	BENCHMARK(hardware_mm_cvtph_ps)->RangeMultiplier(2)->Range(1<<10, 64<<20);
169*5f32b710SXin Li 
hardware_mm256_cvtph_ps(benchmark::State & state)170*5f32b710SXin Li 	static void hardware_mm256_cvtph_ps(benchmark::State& state) {
171*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
172*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
173*5f32b710SXin Li 
174*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
175*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
176*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
177*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
178*5f32b710SXin Li 
179*5f32b710SXin Li 		while (state.KeepRunning()) {
180*5f32b710SXin Li 			uint16_t* input = fp16.data();
181*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
182*5f32b710SXin Li 
183*5f32b710SXin Li 			float* output = fp32.data();
184*5f32b710SXin Li 			const size_t n = state.range(0);
185*5f32b710SXin Li 			for (size_t i = 0; i < n; i += 8) {
186*5f32b710SXin Li 				_mm256_storeu_ps(&output[i],
187*5f32b710SXin Li 					_mm256_cvtph_ps(
188*5f32b710SXin Li 						_mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(&input[i])))));
189*5f32b710SXin Li 			}
190*5f32b710SXin Li 
191*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
192*5f32b710SXin Li 		}
193*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
194*5f32b710SXin Li 	}
195*5f32b710SXin Li 	BENCHMARK(hardware_mm256_cvtph_ps)->RangeMultiplier(2)->Range(1<<10, 64<<20);
196*5f32b710SXin Li #endif
197*5f32b710SXin Li 
198*5f32b710SXin Li #if defined(__ARM_NEON_FP) && (__ARM_NEON_FP & 0x2) || defined(__aarch64__)
hardware_vcvt_f32_f16(benchmark::State & state)199*5f32b710SXin Li 	static void hardware_vcvt_f32_f16(benchmark::State& state) {
200*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
201*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
202*5f32b710SXin Li 
203*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
204*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
205*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
206*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
207*5f32b710SXin Li 
208*5f32b710SXin Li 		while (state.KeepRunning()) {
209*5f32b710SXin Li 			uint16_t* input = fp16.data();
210*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
211*5f32b710SXin Li 
212*5f32b710SXin Li 			float* output = fp32.data();
213*5f32b710SXin Li 			const size_t n = state.range(0);
214*5f32b710SXin Li 			#if defined(__aarch64__)
215*5f32b710SXin Li 				const unsigned int fpcr = __builtin_aarch64_get_fpcr();
216*5f32b710SXin Li 				/* Disable flush-to-zero (bit 24) and Alternative FP16 format (bit 26) */
217*5f32b710SXin Li 				__builtin_aarch64_set_fpcr(fpcr & 0xF6FFFFFFu);
218*5f32b710SXin Li 			#else
219*5f32b710SXin Li 				unsigned int fpscr;
220*5f32b710SXin Li 				__asm__ __volatile__ ("VMRS %[fpscr], fpscr" : [fpscr] "=r" (fpscr));
221*5f32b710SXin Li 				/* Disable flush-to-zero (bit 24) and Alternative FP16 format (bit 26) */
222*5f32b710SXin Li 				__asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :
223*5f32b710SXin Li 					: [fpscr] "r" (fpscr & 0xF6FFFFFFu));
224*5f32b710SXin Li 			#endif
225*5f32b710SXin Li 			for (size_t i = 0; i < n; i += 4) {
226*5f32b710SXin Li 				vst1q_f32(&output[i],
227*5f32b710SXin Li 					vcvt_f32_f16(
228*5f32b710SXin Li 						(float16x4_t) vld1_u16(&input[i])));
229*5f32b710SXin Li 			}
230*5f32b710SXin Li 			#if defined(__aarch64__)
231*5f32b710SXin Li 				__builtin_aarch64_set_fpcr(fpcr);
232*5f32b710SXin Li 			#else
233*5f32b710SXin Li 				__asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :: [fpscr] "r" (fpscr));
234*5f32b710SXin Li 			#endif
235*5f32b710SXin Li 
236*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
237*5f32b710SXin Li 		}
238*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
239*5f32b710SXin Li 	}
240*5f32b710SXin Li 	BENCHMARK(hardware_vcvt_f32_f16)->RangeMultiplier(2)->Range(1<<10, 64<<20);
241*5f32b710SXin Li #endif
242*5f32b710SXin Li 
243*5f32b710SXin Li #ifdef FP16_COMPARATIVE_BENCHMARKS
TH_halfbits2float(benchmark::State & state)244*5f32b710SXin Li 	static void TH_halfbits2float(benchmark::State& state) {
245*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
246*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
247*5f32b710SXin Li 
248*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
249*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
250*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
251*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
252*5f32b710SXin Li 
253*5f32b710SXin Li 		while (state.KeepRunning()) {
254*5f32b710SXin Li 			uint16_t* input = fp16.data();
255*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
256*5f32b710SXin Li 
257*5f32b710SXin Li 			float* output = fp32.data();
258*5f32b710SXin Li 			const size_t n = state.range(0);
259*5f32b710SXin Li 			for (size_t i = 0; i < n; i++) {
260*5f32b710SXin Li 				TH_halfbits2float(&input[i], &output[i]);
261*5f32b710SXin Li 			}
262*5f32b710SXin Li 
263*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
264*5f32b710SXin Li 		}
265*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
266*5f32b710SXin Li 	}
267*5f32b710SXin Li 	BENCHMARK(TH_halfbits2float)->RangeMultiplier(2)->Range(1<<10, 64<<20);
268*5f32b710SXin Li 
npy_halfbits_to_floatbits(benchmark::State & state)269*5f32b710SXin Li 	static void npy_halfbits_to_floatbits(benchmark::State& state) {
270*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
271*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
272*5f32b710SXin Li 
273*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
274*5f32b710SXin Li 		std::vector<uint32_t> fp32(state.range(0));
275*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
276*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
277*5f32b710SXin Li 
278*5f32b710SXin Li 		while (state.KeepRunning()) {
279*5f32b710SXin Li 			uint16_t* input = fp16.data();
280*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
281*5f32b710SXin Li 
282*5f32b710SXin Li 			uint32_t* output = fp32.data();
283*5f32b710SXin Li 			const size_t n = state.range(0);
284*5f32b710SXin Li 			for (size_t i = 0; i < n; i++) {
285*5f32b710SXin Li 				output[i] = npy_halfbits_to_floatbits(input[i]);
286*5f32b710SXin Li 			}
287*5f32b710SXin Li 
288*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
289*5f32b710SXin Li 		}
290*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
291*5f32b710SXin Li 	}
292*5f32b710SXin Li 	BENCHMARK(npy_halfbits_to_floatbits)->RangeMultiplier(2)->Range(1<<10, 64<<20);
293*5f32b710SXin Li 
Eigen_half_to_float(benchmark::State & state)294*5f32b710SXin Li 	static void Eigen_half_to_float(benchmark::State& state) {
295*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
296*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
297*5f32b710SXin Li 
298*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
299*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
300*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
301*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
302*5f32b710SXin Li 
303*5f32b710SXin Li 		while (state.KeepRunning()) {
304*5f32b710SXin Li 			uint16_t* input = fp16.data();
305*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
306*5f32b710SXin Li 
307*5f32b710SXin Li 			float* output = fp32.data();
308*5f32b710SXin Li 			const size_t n = state.range(0);
309*5f32b710SXin Li 			for (size_t i = 0; i < n; i++) {
310*5f32b710SXin Li 				output[i] =
311*5f32b710SXin Li 					Eigen::half_impl::half_to_float(
312*5f32b710SXin Li 						Eigen::half_impl::raw_uint16_to_half(input[i]));
313*5f32b710SXin Li 			}
314*5f32b710SXin Li 
315*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
316*5f32b710SXin Li 		}
317*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
318*5f32b710SXin Li 	}
319*5f32b710SXin Li 	BENCHMARK(Eigen_half_to_float)->RangeMultiplier(2)->Range(1<<10, 64<<20);
320*5f32b710SXin Li 
Float16Compressor_decompress(benchmark::State & state)321*5f32b710SXin Li 	static void Float16Compressor_decompress(benchmark::State& state) {
322*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
323*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
324*5f32b710SXin Li 
325*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
326*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
327*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
328*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
329*5f32b710SXin Li 
330*5f32b710SXin Li 		while (state.KeepRunning()) {
331*5f32b710SXin Li 			uint16_t* input = fp16.data();
332*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
333*5f32b710SXin Li 
334*5f32b710SXin Li 			float* output = fp32.data();
335*5f32b710SXin Li 			const size_t n = state.range(0);
336*5f32b710SXin Li 			for (size_t i = 0; i < n; i++) {
337*5f32b710SXin Li 				output[i] = Float16Compressor::decompress(input[i]);
338*5f32b710SXin Li 			}
339*5f32b710SXin Li 
340*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
341*5f32b710SXin Li 		}
342*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
343*5f32b710SXin Li 	}
344*5f32b710SXin Li 	BENCHMARK(Float16Compressor_decompress)->RangeMultiplier(2)->Range(1<<10, 64<<20);
345*5f32b710SXin Li 
half_float_detail_half2float_table(benchmark::State & state)346*5f32b710SXin Li 	static void half_float_detail_half2float_table(benchmark::State& state) {
347*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
348*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
349*5f32b710SXin Li 
350*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
351*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
352*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
353*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
354*5f32b710SXin Li 
355*5f32b710SXin Li 		while (state.KeepRunning()) {
356*5f32b710SXin Li 			uint16_t* input = fp16.data();
357*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
358*5f32b710SXin Li 
359*5f32b710SXin Li 			float* output = fp32.data();
360*5f32b710SXin Li 			const size_t n = state.range(0);
361*5f32b710SXin Li 			for (size_t i = 0; i < n; i++) {
362*5f32b710SXin Li 				output[i] = half_float::detail::half2float_impl(input[i],
363*5f32b710SXin Li 					half_float::detail::true_type());
364*5f32b710SXin Li 			}
365*5f32b710SXin Li 
366*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
367*5f32b710SXin Li 		}
368*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
369*5f32b710SXin Li 	}
370*5f32b710SXin Li 	BENCHMARK(half_float_detail_half2float_table)->RangeMultiplier(2)->Range(1<<10, 64<<20);
371*5f32b710SXin Li 
half_float_detail_half2float_branch(benchmark::State & state)372*5f32b710SXin Li 	static void half_float_detail_half2float_branch(benchmark::State& state) {
373*5f32b710SXin Li 		const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
374*5f32b710SXin Li 		auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
375*5f32b710SXin Li 
376*5f32b710SXin Li 		std::vector<uint16_t> fp16(state.range(0));
377*5f32b710SXin Li 		std::vector<float> fp32(state.range(0));
378*5f32b710SXin Li 		std::generate(fp16.begin(), fp16.end(),
379*5f32b710SXin Li 			[&rng]{ return fp16_ieee_from_fp32_value(rng()); });
380*5f32b710SXin Li 
381*5f32b710SXin Li 		while (state.KeepRunning()) {
382*5f32b710SXin Li 			uint16_t* input = fp16.data();
383*5f32b710SXin Li 			benchmark::DoNotOptimize(input);
384*5f32b710SXin Li 
385*5f32b710SXin Li 			float* output = fp32.data();
386*5f32b710SXin Li 			const size_t n = state.range(0);
387*5f32b710SXin Li 			for (size_t i = 0; i < n; i++) {
388*5f32b710SXin Li 				output[i] = half_float::detail::half2float_impl(input[i],
389*5f32b710SXin Li 					half_float::detail::false_type());
390*5f32b710SXin Li 			}
391*5f32b710SXin Li 
392*5f32b710SXin Li 			benchmark::DoNotOptimize(output);
393*5f32b710SXin Li 		}
394*5f32b710SXin Li 		state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
395*5f32b710SXin Li 	}
396*5f32b710SXin Li 	BENCHMARK(half_float_detail_half2float_branch)->RangeMultiplier(2)->Range(1<<10, 64<<20);
397*5f32b710SXin Li #endif
398*5f32b710SXin Li 
399*5f32b710SXin Li BENCHMARK_MAIN();
400