Skip to content

Conversation

@joeldushouyu
Copy link

Support GELU operation for ggml-hexagon.

@github-actions github-actions bot added the ggml changes relating to the ggml tensor library for machine learning label Dec 11, 2025
@joeldushouyu
Copy link
Author

While both commit 2a787a6 and 83412e0 is a fully functional gelu implementation that passed the official ggml test by running, but there is a significant performance difference between the two and maybe worth an discussion?

HB=0  ./scripts/snapdragon/adb/run-tool.sh test-backend-ops -b HTP0 -o GELU

The GELU code from commit 2a787a6 is simply a sigmoid GELU implementation but commit 83412e0 is a 7th polynomial approximation of GELU generated from the qhcg tool from Hexagon SDK with some modification.

When running on input of size [4096x4304] ( non-linear input data size for gemma3 vision model), I got some significant performance between this two implementation.

data-size gelu-sigmoid gelu-polynomial approximation
4096x4304( unaligned address) 11772 usec 6531usec
4096x4096 (aligned address) 4988 usec 4799 usec

The data above are tested on Samsung galaxy s25 ultra using the test repo I wrote : current on refactor-dev branch.

For the usec second above, I recorded the longest usec among the 6 threads that is printed out to FARF log

In addition, when plotting out the polynomial approximation using my plot script I wrote in my test repo, I did not much if any error between the polynimal approximation version vs the CPU reference.

image image

@joeldushouyu
Copy link
Author

joeldushouyu commented Dec 11, 2025

After revisiting the polynomial-approximation implementation, I noticed there was a block-prefetch operation in the code which I have commented out in commit 7233999 for a fair comparison. With that in mind, here are the updated results:

data-size GELU-sigmoid GELU polynomial approximation
4096×4304 (unaligned) 11833 µs 8680 µs
4096×4096 (aligned) 5006 µs 7990 µs

From the new testbench runs, a few things stand out:

  1. The 7th-order polynomial path is actually slower computationally than the sigmoid-based GELU.
  2. The current L2-prefetch logic used in the regular SiLU, GELU, and SwiGLU kernels appears to be either underutilized or triggered too late. This likely explains why the polynomial approximation—with its more aggressive L2 prefetching—outperforms the sigmoid-GELU in the unaligned case.
  3. The unaligned version of the sigmoid-GELU could potentially benefit from adopting the same unaligned-load strategy used in the polynomial-approximation path.

For the remainder of this PR, I plan to:

  • refine the L2-prefetching strategy in sigmoild-gelu, and
  • apply the polynomial-approximation’s unaligned-load approach to the sigmoid-GELU path

to see whether we can push sigmoid-GELU performance ahead of the polynomial method.

May I kindly ask for your thoughts and suggestions @max-krasnyansky ?

@joeldushouyu
Copy link
Author

For commit fc2289d, I noticed a significant performance gap between the two sigmoid implementations that handle unaligned input vectors.

The first version treats x as an aligned HVX_Vector pointer and uses Q6_V_valign_VVR to handle any address misalignment, while the second version treats the input as an unaligned HVX_UVector pointer.

On my local device, when used inside the GELU kernel, the first implementation runs in about 6400–6500 µs, whereas the unaligned version takes around 7300–7400 µs for an input of size 4096 × 4304. This seems consistent with my point (3) above? It would be good to have someone else verify these numbers, but if they hold, it might be worth applying the same approach to other functions such as hvx_mul_f32 and hvx_add_f32?

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

Labels

ggml changes relating to the ggml tensor library for machine learning

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant