Skip to content

AArch64: Improve DCT performance #901

Merged
kirithika7 merged 4 commits into
Multicorewareinc:masterfrom
georges-arm:georges-arm/arm-dct-improvements
Jul 2, 2026
Merged

AArch64: Improve DCT performance #901
kirithika7 merged 4 commits into
Multicorewareinc:masterfrom
georges-arm:georges-arm/arm-dct-improvements

Conversation

@georges-arm

@georges-arm georges-arm commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Improve the existing AArch64 Neon and SVE DCT 16x16 and 32x32 implementations:

  • For Neon: merge the first and second pass functions to avoid duplication.

  • For Neon and SVE: merge the outer loops to avoid the need to maintain O/EO/EEE/EEO arrays on the stack and consistently process four rows at a time.

  • Fix the rev16 and rev32 helper functions to use TBL instead of TBX instructions (TBL has slightly better performance on some CPUs).

Benchmarking on a range of Neoverse server platforms with LLVM 21, this change shows (depending on exact CPU micro-architecture):

  • 7-12% improvement in Neon DCT16.
  • 0-9% improvement in Neon DCT32.
  • 10-15% improvement in SVE DCT16.
  • 0-15% improvement in SVE DCT32.

With this change the Neon intrinsics implementation is now faster than the assembly implementation, so update setupDCTPrimitives_neon to use the intrinsics version instead.

The aarch64/dct.S file contains assembly implementations of DCT16 and IDCT16, however these are now unused since the existing intrinsics-based versions are faster and therefore preferred. Since this code is unused, delete it from the library.

@kirithika7 kirithika7 requested a review from mcw-Lavanya June 18, 2026 10:02
@jwright-arm

Copy link
Copy Markdown

Could we get a review here please, @chenm001?

@mcw-Lavanya

Copy link
Copy Markdown
Collaborator

Hi @georges-arm ,
Can we get benchmarking results which you performed to validate this patch to verify at out end. And the machine configuration which is used.

thank you.

@chenm001 chenm001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

looks good to me, need smoke-test before merge

@chenm001 chenm001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

looks good to me, need smoke-test before merge

@chenm001 chenm001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

looks good to me, need smoke-test before merge

@georges-arm

Copy link
Copy Markdown
Contributor Author

Hi @georges-arm , Can we get benchmarking results which you performed to validate this patch to verify at out end. And the machine configuration which is used.

thank you.

Hi @mcw-Lavanya ,

Benchmarks run on Neoverse V2, compiled with LLVM 22. Benchmark results from ./test/TestBench:

Before:

dct16x16 | 1.44x
dct32x32 | 5.48x

After:

dct16x16 | 1.51x
dct32x32 | 5.70x

@mcw-Lavanya

Copy link
Copy Markdown
Collaborator

Hi @georges-arm,
Thank you for the results,
the patch looks good

@mcw-Lavanya mcw-Lavanya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi @georges-arm ,

According to this PR, with LLVM 21 and LLVM 20 the expected performance improvement is 7–12% for DCT16x16 and 0–9% for DCT32x32. Our LLVM 21 results are consistent with these expectations.

However, when testing with GCC, we observed significantly different behaviour:

GCC 14 shows much larger improvements than expected for both DCT16x16 and DCT32x32.
GCC 13 shows only about 2% improvement for DCT16x16, but DCT32x32 regresses by nearly 86%.

We wanted to understand whether the new intrinsic or code restructuring are expected to expose any performance weakness or compiler code-generation issue with older compilers (specifically GCC versions prior to 14), particularly for the DCT32x32 kernel. Has this behaviour been observed before, or would you expect GCC 13 to perform similarly to newer compilers?

Merge the outer loops to avoid the need to maintain O/EO/EEE/EEO arrays
on the stack and consistently process four rows at a time. Also fix the
`rev16` and `rev32` helper functions to use TBL instead of TBX (TBL has
slightly better performance on some CPUs).

Benchmarking on a range of Neoverse server platforms with LLVM 21, this
change shows a reduction in observed time spent in DCT16 by 10-15%.
Merge the outer loops to avoid the need to maintain O/EO/EEE/EEO arrays
on the stack and consistently process four rows at a time.

Benchmarking on a range of Neoverse server platforms with LLVM 21, this
change shows a reduction in observed time spent in DCT32 by 0-15%.
Merge the first and second pass functions to avoid duplication.

Merge the outer loops to avoid the need to maintain O/EO/EEE/EEO arrays
on the stack and consistently process four rows at a time.

Benchmarking on a range of Neoverse server platforms with LLVM 22, this
change shows a 0-9% reduction in observed time spent in Neon DCT16, and
a 2-17% reduction in Neon DCT32.

Since the Neon intrinsics implementation is now faster than the assembly
implementation, update `setupDCTPrimitives_neon` to use the intrinsics
version instead.
The `aarch64/dct.S` file contains assembly implementations of DCT16 and
IDCT16, however neither of these are actually used in practice since the
existing intrinsics-based versions are faster and therefore preferred.

Since this code is unused, delete it from the library.
@georges-arm georges-arm force-pushed the georges-arm/arm-dct-improvements branch from 1c8e9cb to e6bccb5 Compare July 1, 2026 16:23
@georges-arm

Copy link
Copy Markdown
Contributor Author

Hi @georges-arm ,

According to this PR, with LLVM 21 and LLVM 20 the expected performance improvement is 7–12% for DCT16x16 and 0–9% for DCT32x32. Our LLVM 21 results are consistent with these expectations.

However, when testing with GCC, we observed significantly different behaviour:

GCC 14 shows much larger improvements than expected for both DCT16x16 and DCT32x32. GCC 13 shows only about 2% improvement for DCT16x16, but DCT32x32 regresses by nearly 86%.

We wanted to understand whether the new intrinsic or code restructuring are expected to expose any performance weakness or compiler code-generation issue with older compilers (specifically GCC versions prior to 14), particularly for the DCT32x32 kernel. Has this behaviour been observed before, or would you expect GCC 13 to perform similarly to newer compilers?

Hi @mcw-Lavanya ,

Thanks for the report. I have reproduced your performance with GCC 13 and adjusted the Neon implementation in aarch64/dct-prim.cpp to reduce the amount of stack spills that the compiler produces.

Performance on a Neoverse V2 when built with LLVM 22, according to test/TestBench:

gcc13 dct32:
master | 4.47x  (current `master` branch before this PR)
prev   | 2.40x  (the old version of this PR)
new    | 4.85x  (the new version of this PR after the GCC 13 fix)

gcc16 dct32:
master | 4.82x
prev   | 4.82x
new    | 4.83x

llvm22 dct32:
master | 5.50x
prev   | 5.54x
new    | 5.52x

@mcw-Lavanya mcw-Lavanya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The updated patch seems to be fine and we are able to see good results across different llvm versions and gcc versions.

@kirithika7 kirithika7 merged commit 4455762 into Multicorewareinc:master Jul 2, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants