Skip to content

[Optimization] Zen 4 / EPYC Macro-Blocking (P, Q, R) tuning utilizing COOPERLAKE kernels #5837

Closed

Description

@Vasudeva-bit

Hi OpenBLAS team,

I have been profiling SGEMM performance on an AMD Zen 4 (EPYC 9334) server and noticed that the build system accurately falls back to the COOPERLAKE target to leverage the AVX-512/BF16 instructions. While the micro-kernels run flawlessly, the default COOPERLAKE macro-blocking parameters (P, Q, R) seem to bottleneck on AMD's 32MB L3 CCX boundaries.

I recently ran Bayesian Optimisation parameter tuning specifically targeting the macro-blocking dimensions for this hardware. Without altering any assembly, adjusting the blocking limits yielded a performance jump from ~2.8 TFLOPs to ~3.0 TFLOPs for square matrices around N=8192. I also observed similar improvements on smaller square matrices, though performance on heavily skewed shapes (skinny/wide matrices) remained largely unchanged.

It appears the default COOPERLAKE blocking parameters—which assume a monolithic L3—might be causing some cache contention on this 32 MB L3 Zen 4 CCX boundary. The tuned parameters seem to eliminate that L3 thrashing.

Before I open a PR or formalise these values into param.h, I want to confirm this is the right direction or am I missing something.

Thanks for your time and guidance!
Kilaru Vasu Deva.

Activity

  1. martin-frbg commented on Jun 15, 2026

    @martin-frbg
    Collaborator

    Sounds right, but would probably require cloning the COOPERLAKE target to create a dedicated ZEN4. I guess you could try if
    adding a conditional inside the COOPERLAKE section of param.h would be sufficient, something like

    if L3_SIZE == 33554432
    #define SGEMM_DEFAULT_P = <your p for zen4>
    ...
    else
    #define SGEMM_DEFAULT_P = 640
    ...
    endif
    ```
    and similarly set `TABLE_NAME.sgemm_p` etc. depending on the value of `l3` in the COOPERLAKE section of `kernel/setparam-ref.c` for the DYNAMIC_ARCH case. (I do wonder how many different L3 cache configurations we'd have to cater for across the "ZEN4" processor family ?)
    
  2. Vasudeva-bit commented on Jun 15, 2026

    @Vasudeva-bit
    ContributorAuthor

    I shall try the conditional workaround to see if it's sufficient. Based on my search and Zen4 Wikipedia table, the majority seem to use the standard 32 MB per CCD, with two other variants: 96MB (per CCD with 3D V-Cache) and 16/8 MB (APUs).

    Also, I think I could scale the new values of P, Q, R accordingly for DGEMM, BFGEMM, etc.

  3. Vasudeva-bit commented on Jun 19, 2026

    @Vasudeva-bit
    ContributorAuthor

    @martin-frbg I tried a few things. I see that the L3_SIZE macro in param.h and the get_l3_size function in setparam-ref.c track L3 cache size as a total over all the chiplets. The following conditioning works for cases with more or fewer than 4 chiplets (9334 has 4). I believe this covers a majority of the Zen4 family.

    // param.h
    #if L3 > 0 and L3_SIZE % 33554432 == 0
    #define SGEMM_DEFAULT_P 320
    #define SGEMM_DEFAULT_Q 512
    #else
    #define SGEMM_DEFAULT_P 640
    #define SGEMM_DEFAULT_Q 320
    #endif
    
    #define SGEMM_DEFAULT_R sgemm_r
    

    &

    // setparam-ref.c
    int l3_kb = get_l3_size();
    unsigned int eax, ebx, ecx, edx;
    cpuid(0, &eax, &ebx, &ecx, &edx);
    
    // 0x68747541 = "Auth" (AuthenticAMD)
    if ((ebx == 0x68747541) && (l3_kb > 0) && (l3_kb % 32768 == 0)) {
        TABLE_NAME.sgemm_p = 320;
        TABLE_NAME.sgemm_q = 512;
        // R is dynamically calculated
    }
    

    I shall make a PR based on this. Kindly let me know your comments, if any.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions