Skip to content

feat(bench): add vectorized + unrolled optimal version#63

Open
dssgabriel wants to merge 2 commits into
mainfrom
feature/unrolled-vectorized-gemm
Open

feat(bench): add vectorized + unrolled optimal version#63
dssgabriel wants to merge 2 commits into
mainfrom
feature/unrolled-vectorized-gemm

Conversation

@dssgabriel

Copy link
Copy Markdown
Collaborator

Description

As discussed with @hmt23, add a "more optimal" version of the GEMM benchmark where we unroll and vectorize our most efficient implementation (mbtsv w/ $B$ in LTL layout).

Related issue(s):

Scope: benchmarks

Type of change: feature

Checklist

  • New or existing tests cover these changes.

@dssgabriel dssgabriel self-assigned this Sep 5, 2025
@dssgabriel dssgabriel added C-enhancement Category: an enhancement or bug fix T-performance Topic: something related to performance A-benches Area: layout-tiled benchmarks labels Sep 5, 2025
@github-actions

github-actions Bot commented Sep 5, 2025

Copy link
Copy Markdown

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-format (v20.1.2) reports: 1 file(s) not formatted
  • benchmarks/gemm.cpp
clang-tidy (v20.1.2) reports: 1 concern(s)
  • benchmarks/gemm.cpp:293:30: warning: [portability-simd-intrinsics]

    '_mm_add_pd' is a non-portable x86_64 intrinsic function

      293 |               __m128d hsum = _mm_add_pd(_mm256_castpd256_pd128(vacc), _mm256_extractf128_pd(vacc, 1));
          |                              ^
    /home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:627:10: warning: do not declare C-style arrays, use 'std::array' instead [cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays]
      627 |   static struct option long_options[] = {
          |          ^
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1683:5: error: 5 uninitialized fields at the end of the constructor call [clang-analyzer-optin.cplusplus.UninitializedObject,-warnings-as-errors]
     1683 |     ignore_unused(arg_index, named_arg_index);
          |     ^
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:520:15: note: uninitialized pointer 'this->context_.parse_context::fmt_.data_'
      520 |   const Char* data_;
          |               ^~~~~
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:521:10: note: uninitialized field 'this->context_.parse_context::fmt_.size_'
      521 |   size_t size_;
          |          ^~~~~
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:870:7: note: uninitialized field 'this->context_.parse_context::next_arg_id_'
      870 |   int next_arg_id_;
          |       ^~~~~~~~~~~~
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1213:7: note: uninitialized field 'this->context_.num_args_'
     1213 |   int num_args_;
          |       ^~~~~~~~~
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1214:15: note: uninitialized pointer 'this->context_.types_'
     1214 |   const type* types_;
          |               ^~~~~~
    /home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:637:10: note: Assuming the condition is true
      637 |   while ((opt = getopt_long(argc, argv, "n:t:o:h", static_cast<const struct option*>(long_options), nullptr)) != -1) {
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:637:3: note: Loop condition is true.  Entering loop body
      637 |   while ((opt = getopt_long(argc, argv, "n:t:o:h", static_cast<const struct option*>(long_options), nullptr)) != -1) {
          |   ^
    /home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:638:5: note: Control jumps to the 'default' case at line 659
      638 |     switch (opt) {
          |     ^
    /home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:660:18: note: Calling constructor for 'fstring<std::basic_string<char> &>'
      660 |       fmt::print("{}", HELP_MSG);
          |                  ^~~~
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:2709:5: note: Taking true branch
     2709 |     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
          |     ^
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:2709:57: note: Calling constructor for 'format_string_checker<char, 1, 0, false>'
     2709 |     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
          |                                                         ^~~~~~~~~~~~~~~~~~~~~~
    /home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1683:5: note: 5 uninitialized fields at the end of the constructor call
     1683 |     ignore_unused(arg_index, named_arg_index);
          |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Have any feedback or feature suggestions? Share it here.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cpp-linter Review

Used clang-tidy v20.1.2

Have any feedback or feature suggestions? Share it here.

Comment thread benchmarks/gemm.cpp
vacc = _mm256_fmadd_pd(va7, vb7, vacc);
}

__m128d hsum = _mm_add_pd(_mm256_castpd256_pd128(vacc), _mm256_extractf128_pd(vacc, 1));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy diagnostic

benchmarks/gemm.cpp:294:30: warning: [portability-simd-intrinsics]

'_mm_add_pd' is a non-portable x86_64 intrinsic function

  294 |               __m128d hsum = _mm_add_pd(_mm256_castpd256_pd128(vacc), _mm256_extractf128_pd(vacc, 1));
      |                              ^
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:539:10: warning: do not declare C-style arrays, use 'std::array' instead [cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays]
  539 |   static struct option long_options[] = {
      |          ^
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1683:5: error: 5 uninitialized fields at the end of the constructor call [clang-analyzer-optin.cplusplus.UninitializedObject,-warnings-as-errors]
 1683 |     ignore_unused(arg_index, named_arg_index);
      |     ^
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1213:7: note: uninitialized field 'this->context_.num_args_'
 1213 |   int num_args_;
      |       ^~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1214:15: note: uninitialized pointer 'this->context_.types_'
 1214 |   const type* types_;
      |               ^~~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:520:15: note: uninitialized pointer 'this->context_.parse_context::fmt_.data_'
  520 |   const Char* data_;
      |               ^~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:521:10: note: uninitialized field 'this->context_.parse_context::fmt_.size_'
  521 |   size_t size_;
      |          ^~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:870:7: note: uninitialized field 'this->context_.parse_context::next_arg_id_'
  870 |   int next_arg_id_;
      |       ^~~~~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:549:10: note: Assuming the condition is true
  549 |   while ((opt = getopt_long(argc, argv, "n:t:o:h", static_cast<const struct option*>(long_options), nullptr)) != -1) {
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:549:3: note: Loop condition is true.  Entering loop body
  549 |   while ((opt = getopt_long(argc, argv, "n:t:o:h", static_cast<const struct option*>(long_options), nullptr)) != -1) {
      |   ^
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:550:5: note: Control jumps to the 'default' case at line 571
  550 |     switch (opt) {
      |     ^
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:572:18: note: Calling constructor for 'fstring<std::basic_string<char> &>'
  572 |       fmt::print("{}", HELP_MSG);
      |                  ^~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:2709:5: note: Taking true branch
 2709 |     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
      |     ^
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:2709:57: note: Calling constructor for 'format_string_checker<char, 1, 0, false>'
 2709 |     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
      |                                                         ^~~~~~~~~~~~~~~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1683:5: note: 5 uninitialized fields at the end of the constructor call
 1683 |     ignore_unused(arg_index, named_arg_index);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Broadcast 4 elems of A and multiply against cols of B, accumulating into
8 vals of C. This beats the simple vectorization strategy used in
`*_vec_unroll_k`.

Signed-off-by: Gabriel Dos Santos <gabriel.dossantos@cea.fr>
@github-actions github-actions Bot dismissed their stale review September 9, 2025 13:59

outdated suggestion

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cpp-linter Review

Used clang-tidy v20.1.2

Have any feedback or feature suggestions? Share it here.

Comment thread benchmarks/gemm.cpp
__m256d vb7 = _mm256_loadu_pd(&tB[k + 28, j]);
vacc = _mm256_fmadd_pd(va7, vb7, vacc);
}
__m128d hsum = _mm_add_pd(_mm256_castpd256_pd128(vacc), _mm256_extractf128_pd(vacc, 1));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy diagnostic

benchmarks/gemm.cpp:293:30: warning: [portability-simd-intrinsics]

'_mm_add_pd' is a non-portable x86_64 intrinsic function

  293 |               __m128d hsum = _mm_add_pd(_mm256_castpd256_pd128(vacc), _mm256_extractf128_pd(vacc, 1));
      |                              ^
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:627:10: warning: do not declare C-style arrays, use 'std::array' instead [cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays]
  627 |   static struct option long_options[] = {
      |          ^
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1683:5: error: 5 uninitialized fields at the end of the constructor call [clang-analyzer-optin.cplusplus.UninitializedObject,-warnings-as-errors]
 1683 |     ignore_unused(arg_index, named_arg_index);
      |     ^
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:520:15: note: uninitialized pointer 'this->context_.parse_context::fmt_.data_'
  520 |   const Char* data_;
      |               ^~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:521:10: note: uninitialized field 'this->context_.parse_context::fmt_.size_'
  521 |   size_t size_;
      |          ^~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:870:7: note: uninitialized field 'this->context_.parse_context::next_arg_id_'
  870 |   int next_arg_id_;
      |       ^~~~~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1213:7: note: uninitialized field 'this->context_.num_args_'
 1213 |   int num_args_;
      |       ^~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1214:15: note: uninitialized pointer 'this->context_.types_'
 1214 |   const type* types_;
      |               ^~~~~~
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:637:10: note: Assuming the condition is true
  637 |   while ((opt = getopt_long(argc, argv, "n:t:o:h", static_cast<const struct option*>(long_options), nullptr)) != -1) {
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:637:3: note: Loop condition is true.  Entering loop body
  637 |   while ((opt = getopt_long(argc, argv, "n:t:o:h", static_cast<const struct option*>(long_options), nullptr)) != -1) {
      |   ^
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:638:5: note: Control jumps to the 'default' case at line 659
  638 |     switch (opt) {
      |     ^
/home/runner/work/layout-tiled/layout-tiled/benchmarks/gemm.cpp:660:18: note: Calling constructor for 'fstring<std::basic_string<char> &>'
  660 |       fmt::print("{}", HELP_MSG);
      |                  ^~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:2709:5: note: Taking true branch
 2709 |     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
      |     ^
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:2709:57: note: Calling constructor for 'format_string_checker<char, 1, 0, false>'
 2709 |     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
      |                                                         ^~~~~~~~~~~~~~~~~~~~~~
/home/runner/work/layout-tiled/layout-tiled/build/_deps/fmt-src/include/fmt/base.h:1683:5: note: 5 uninitialized fields at the end of the constructor call
 1683 |     ignore_unused(arg_index, named_arg_index);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-benches Area: layout-tiled benchmarks C-enhancement Category: an enhancement or bug fix T-performance Topic: something related to performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant