@@ -346,6 +346,128 @@ void unpack_uint4_values(
346346 }
347347}
348348
349+ // Benchmark utility to compare variants of uint5 packing
350+ void pack_uint5_values (
351+ uint8_t * packed,
352+ uint8_t * unpacked,
353+ int packed_size,
354+ int unpacked_size,
355+ int variant) {
356+ constexpr int nbit = 5 ;
357+ constexpr int bitsPerByte = 8 ;
358+ assert (unpacked_size * nbit / bitsPerByte == packed_size);
359+ assert (packed_size % variant == 0 );
360+
361+ uint8x16_t unpacked0;
362+ uint8x16_t unpacked1;
363+ uint8x16_t unpacked2;
364+ uint8x16_t unpacked3;
365+ uint8x16_t unpacked4;
366+ uint8x16_t unpacked5;
367+ uint8x16_t unpacked6;
368+ uint8x16_t unpacked7;
369+
370+ switch (variant) {
371+ case 8 :
372+ for (int i = 0 ; i < unpacked_size; i += 8 ) {
373+ torchao::bitpacking::internal::pack_8_uint5_values (
374+ packed + ((i * nbit) / bitsPerByte), unpacked + i);
375+ }
376+ break ;
377+ case 64 :
378+ for (int i = 0 ; i < unpacked_size; i += 64 ) {
379+ torchao::bitpacking::internal::vec_load_64_uint8_values (
380+ unpacked0, unpacked1, unpacked2, unpacked3, unpacked + i);
381+ torchao::bitpacking::internal::vec_pack_64_uint5_values (
382+ packed + ((i * nbit) / bitsPerByte),
383+ unpacked0,
384+ unpacked1,
385+ unpacked2,
386+ unpacked3);
387+ }
388+ break ;
389+ case 128 :
390+ for (int i = 0 ; i < unpacked_size; i += 128 ) {
391+ torchao::bitpacking::internal::vec_load_64_uint8_values (
392+ unpacked0, unpacked1, unpacked2, unpacked3, unpacked + i);
393+ torchao::bitpacking::internal::vec_load_64_uint8_values (
394+ unpacked4, unpacked5, unpacked6, unpacked7, unpacked + i + 64 );
395+ torchao::bitpacking::internal::vec_pack_128_uint5_values (
396+ packed + ((i * nbit) / bitsPerByte),
397+ unpacked0,
398+ unpacked1,
399+ unpacked2,
400+ unpacked3,
401+ unpacked4,
402+ unpacked5,
403+ unpacked6,
404+ unpacked7);
405+ }
406+ break ;
407+ }
408+ }
409+
410+ // Benchmark utility to compare variants of uint5 unpacking
411+ void unpack_uint5_values (
412+ uint8_t * unpacked,
413+ uint8_t * packed,
414+ int unpacked_size,
415+ int packed_size,
416+ int variant) {
417+ constexpr int nbit = 5 ;
418+ constexpr int bitsPerByte = 8 ;
419+ assert (unpacked_size * nbit / bitsPerByte == packed_size);
420+ assert (packed_size % variant == 0 );
421+
422+ uint8x16_t unpacked0;
423+ uint8x16_t unpacked1;
424+ uint8x16_t unpacked2;
425+ uint8x16_t unpacked3;
426+ uint8x16_t unpacked4;
427+ uint8x16_t unpacked5;
428+ uint8x16_t unpacked6;
429+ uint8x16_t unpacked7;
430+
431+ switch (variant) {
432+ case 8 :
433+ for (int i = 0 ; i < unpacked_size; i += 8 ) {
434+ torchao::bitpacking::internal::unpack_8_uint5_values (
435+ unpacked + i, packed + ((i * nbit) / bitsPerByte));
436+ }
437+ break ;
438+ case 64 :
439+ for (int i = 0 ; i < unpacked_size; i += 64 ) {
440+ torchao::bitpacking::internal::vec_unpack_64_uint5_values (
441+ unpacked0,
442+ unpacked1,
443+ unpacked2,
444+ unpacked3,
445+ packed + ((i * nbit) / bitsPerByte));
446+ torchao::bitpacking::internal::vec_store_64_uint8_values (
447+ unpacked + i, unpacked0, unpacked1, unpacked2, unpacked3);
448+ }
449+ break ;
450+ case 128 :
451+ for (int i = 0 ; i < unpacked_size; i += 128 ) {
452+ torchao::bitpacking::internal::vec_unpack_128_uint5_values (
453+ unpacked0,
454+ unpacked1,
455+ unpacked2,
456+ unpacked3,
457+ unpacked4,
458+ unpacked5,
459+ unpacked6,
460+ unpacked7,
461+ packed + ((i * nbit) / bitsPerByte));
462+ torchao::bitpacking::internal::vec_store_64_uint8_values (
463+ unpacked + i, unpacked0, unpacked1, unpacked2, unpacked3);
464+ torchao::bitpacking::internal::vec_store_64_uint8_values (
465+ unpacked + i + 64 , unpacked4, unpacked5, unpacked6, unpacked7);
466+ }
467+ break ;
468+ }
469+ }
470+
349471} // namespace
350472
351473static void benchmark_pack_uint2_values (benchmark::State& state) {
@@ -462,12 +584,52 @@ static void benchmark_unpack_uint4_values(benchmark::State& state) {
462584 }
463585}
464586
587+ static void benchmark_pack_uint5_values (benchmark::State& state) {
588+ int unpacked_size = state.range (0 );
589+ int variant = state.range (1 );
590+ int nbit = 5 ;
591+
592+ assert (unpacked_size % 8 == 0 );
593+ int packed_size = (unpacked_size / 8 ) * nbit;
594+
595+ auto packed = std::vector<uint8_t >(unpacked_size, 0 );
596+ auto unpacked = torchao::get_random_lowbit_vector (packed_size, 8 );
597+
598+ for (auto _ : state) {
599+ pack_uint5_values (
600+ packed.data (), unpacked.data (), packed_size, unpacked_size, variant);
601+ }
602+ }
603+
604+ static void benchmark_unpack_uint5_values (benchmark::State& state) {
605+ int unpacked_size = state.range (0 );
606+ int variant = state.range (1 );
607+ int nbit = 5 ;
608+
609+ assert (unpacked_size % 8 == 0 );
610+ int packed_size = (unpacked_size / 8 ) * nbit;
611+
612+ auto packed = torchao::get_random_lowbit_vector (packed_size, 8 );
613+ auto unpacked = std::vector<uint8_t >(unpacked_size, 0 );
614+
615+ for (auto _ : state) {
616+ unpack_uint5_values (
617+ unpacked.data (),
618+ packed.data (),
619+ unpacked.size (),
620+ packed.size (),
621+ variant);
622+ }
623+ }
624+
465625BENCHMARK (benchmark_pack_uint2_values)->ArgsProduct ({{128 }, {4 , 32 , 64 }});
466626BENCHMARK (benchmark_unpack_uint2_values)->ArgsProduct ({{128 }, {4 , 32 , 64 }});
467627BENCHMARK (benchmark_pack_uint3_values)->ArgsProduct ({{128 }, {8 , 64 , 128 }});
468628BENCHMARK (benchmark_unpack_uint3_values)->ArgsProduct ({{128 }, {8 , 64 , 128 }});
469629BENCHMARK (benchmark_pack_uint4_values)->ArgsProduct ({{128 }, {2 , 16 , 32 }});
470630BENCHMARK (benchmark_unpack_uint4_values)->ArgsProduct ({{128 }, {2 , 16 , 32 }});
631+ BENCHMARK (benchmark_pack_uint5_values)->ArgsProduct ({{128 }, {8 , 64 , 128 }});
632+ BENCHMARK (benchmark_unpack_uint5_values)->ArgsProduct ({{128 }, {8 , 64 , 128 }});
471633
472634// Run the benchmark
473635BENCHMARK_MAIN ();
0 commit comments