Library / SDK
gnuradio/volk avatar
gnuradio/volk

VOLK and the argument for hand written SIMD kernels over compiler flags

The Vector Optimized Library of Kernels

678 stars229 forksC++LGPL-3.0

At a glance

What is it?
VOLK is the Vector-Optimized Library of Kernels, a GNU Radio sub-project that ships hand written SIMD implementations of common signal processing operations and picks the right one at runtime. It is a performance layer you insert beneath your own code, and its cost is a profiling step and a set of platform constraints.
Who is it for?
VOLK fits engineers writing hot loops over sample buffers who need the same operation to run well on both x86 with SSE or AVX and ARM with NEON, and who are willing to run volk_profile on the target hardware. It is the wrong choice if your workload is dominated by overhead outside the inner loop, or if you need MIPS or RISC-V support that is still experimental, since some kernels are known not to work there.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 40 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A library of hand written kernels, one call site for every architecture

VOLK is the Vector-Optimized Library of Kernels, a sub-project of GNU Radio. The problem it addresses is stated directly in the project documentation: each SIMD architecture can be very different, and no compiler has come along to handle vectorization properly or highly efficiently, so VOLK approaches the problem differently.

The approach is a table of implementations rather than a compiler flag. For each architecture or platform a developer wants to vectorize for, a proto-kernel is added to VOLK. At runtime VOLK selects the correct proto-kernel, which means the calling code is platform and architecture agnostic while the work underneath is not.

That design has a consequence for how you read the code. A kernel is not a function you call directly with your data. It is a name that resolves, at load time, to whichever concrete implementation the current machine supports. The user-facing benefit is portable SIMD code: one call site, and the library handles the difference between an AVX-512 machine and a Raspberry Pi.

The audience is therefore not general software developers. It is the layer underneath an application that processes sample streams, where the same multiply, add or filter runs millions of times and the difference between a scalar loop and a vectorised one is measurable in whether the pipeline keeps up in real time.

The build is CMake, and the test suite runs before you install

Building on most x86 platforms, both 32-bit and 64-bit, follows a plain CMake sequence. The documentation shows the whole thing in one block, from the build directory to the profiling step:

bash
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make test
$ sudo make install

The order matters. make test comes before make install, so the test suite runs against what you just compiled rather than against a system copy. The documentation also suggests exploring the make -j options for a multicore CPU, which is a real saving on a project with a lot of kernels to compile.

After installation there is a platform specific step. On Linux the shared library has to be linked and cached:

bash
# Linux OS: Link and cache shared library
$ sudo ldconfig

On macOS and Windows the note is to update the PATH environment variable to point to the library install location, since there is no equivalent cache mechanism to refresh. The last command in the sequence is the one that matters at runtime:

bash
# volk_profile will profile your system so that the best kernel is used
$ volk_profile

The project also ships continuous integration through Travis and AppVeyor, plus GitHub workflow badges for checking pull request formatting and running the VOLK tests, so the matrix of platforms is exercised somewhere other than on your own machine.

Dynamic dispatch leans on cpu_features, with a FetchContent fallback

How VOLK decides which CPU features are available is worth understanding, because it affects what you build and what you ship. The project uses Google's cpu_features library to detect CPU features such as AVX, which is what makes dynamic dispatch possible.

The build logic prefers a system-installed copy. If CMake can find a system-installed cpu_features version, it uses that, which keeps the build from compiling a vendored dependency and keeps the installed footprint smaller. If no system-installed version is found, the build falls back to CMake FetchContent, which downloads the dependency at configure time.

That fallback has a practical consequence for packaging. A build machine without network access and without the dependency already installed will fail at the configure step rather than at the compile step, and a distribution packager who wants reproducible builds needs to vendor the dependency or provide it in the base system. The exception is static builds with static dispatch, where the feature detection is compiled in and the system copy is not consulted.

The documentation keeps the details of how to use the library in the doxygen pages at libvolk.org, and points bug tracking, documentation and source code at the same site rather than at the repository, which is a sign that the repository is the code and the site is the manual.

ARM boards need a toolchain file, and the model of the board decides which

Building for a Raspberry Pi or another 32-bit ARM board is not the same procedure, because the board's own core determines which instructions the compiler can emit. The documentation says you need to specify the correct cmake toolchain file for best performance, and lists one per board:

* Raspberry Pi 5 `arm_cortex_a76_hardfp_native.cmake` * Raspberry Pi 4 `arm_cortex_a72_hardfp_native.cmake` * Raspberry Pi 3 `arm_cortex_a53_hardfp_native.cmake`

The build itself then differs only in that one cmake invocation:

bash
$ mkdir build && cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/arm_cortex_a76_hardfp_native.cmake ..
# make -j4 might be faster
$ make
$ make test
$ sudo make install

Note the use of the native toolchain file, which means the build is tuned for the core it is compiled on rather than for a generic ARM target. The documentation also adds a note that there is no need for extra compiler options for 64-bit, so the toolchain file dance is specific to the 32-bit boards.

The practical reading of all this is that a native toolchain file ties a build to a board model. If you deploy the same binary to a Pi 3 and a Pi 5, one of them is running a kernel tuned for the other, and the profiling step becomes the way to find out what actually got selected at runtime.

Supported architectures are narrower than portable, and the project says so

VOLK aims to be portable to as many platforms as possible, but the documentation is careful to add that tests can only be run on some platforms. The current stated hardware position is optimized kernels on x86 with SSE or AVX and on ARM with NEON. Support for MIPS and RISC-V is described as experimental, with the warning that some kernels are known not to work on those architectures.

That sentence is the one to hold on to. An experimental architecture label with known broken kernels is not a deployment target, it is a development area. If your hardware is RISC-V, the library's own documentation tells you not to count on it.

Operating system support follows the same shape of ambition with a reality check. Tests run on a variety of Ubuntu versions and the goal is to support as many current distributions as possible, with the same goal for other operating systems. The documentation admits that VOLK may not work on obsolete distributions, giving Ubuntu 12.04 as an example, though that case does not arise often.

The compiler policy is the most practically useful part of the section. The project wants VOLK to work with standard compliant C and C++ compilers, focuses on open source compilers, most notably GCC and Clang, and targets AppleClang and MSVC as well. There is one specific caveat recorded there: MSVC lacks aligned_alloc support for aligned arrays, so the code uses MSVC specific instructions in that case, and those cannot be freed with free. If you maintain a C++ codebase with manual memory management, that is the kind of detail that shows up as a leak or a crash in a debug allocator rather than in a build error.

Dependency versions are a policy, not an accident

The dependency version policy is spelled out at length and is a good example of a project deciding its own boundaries. The project wants to ensure that all widely used and openly maintained distributions are supported, and treats the default dependency versions in those distributions as the baseline, or oldest supported versions.

The reason stated is practical. While older dependencies might work, the project does not want to maintain workarounds for them, and it wants to signal to contributors that certain minimum versions can be relied on.

The consequence for a user on an old distribution is stated without hedging: if you use VOLK on an obsolete distribution, you are assumed to know what you are doing and to be able to make the necessary changes to compile VOLK there, for example by decreasing the minimum version checks and fixing the resulting errors. The project frames this as a balance between using VOLK on every possible platform and being able to use the latest features.

For a team deciding whether to depend on VOLK, this is the part to read. You are inheriting a defined baseline of supported toolchains, not an anything-goes compatibility promise, and on a platform below that baseline you are expected to patch the build yourself.

The licence changed at version 3.0, and the reasoning is documented

VOLK 3.0 and later are licensed under the GNU Lesser General Public License v3.0 or later. Earlier versions of VOLK, before 3.0, were licensed under the GNU General Public License v3.0 or later, and the project migrated to the LGPL afterwards.

The reasoning is unusual enough to be worth reading, because it is not the usual blanket assertion. The project counts its historical commits, and reports that three people out of 74, accounting for four commits out of 1092, thirteen additions out of 282822 and seven deletions out of 170421, could not be reached at all. It states that those commits were reviewed and are simple, trivial changes, in one case a single line, and that most are no longer relevant because the file they touched no longer exists. On the basis of the small number of changes per committer and the triviality of each, the maintainers proceeded with relicensing without those approvals, while saying they will keep trying to reach them.

Whether that reasoning satisfies you is a judgement for your own legal review. What matters practically is the shape of the change: for a project linked into another program, the LGPL sets different obligations from the GPL, and it applies from version 3.0 onward. The repository is licensed under LGPL-3.0, with a COPYING file at the root, and the project also carries a Zenodo DOI for citation.

On maintenance, the last push was on 2026-09-13, the repository is not archived, and the tagged releases run v3.1.2, v3.2.0 and v3.3.0, with v3.3.0 released on 2026-02-08. A CHANGELOG is kept for every release and the project follows semantic versioning as set out in its versioning guide, so the upgrade path for a user is a versioned changelog rather than a moving master branch.

Editorial conclusion

VOLK fits engineers writing hot loops over sample buffers who need the same operation to run well on both x86 with SSE or AVX and ARM with NEON, and who are willing to run volk_profile on the target hardware. It is the wrong choice if your workload is dominated by overhead outside the inner loop, or if you need MIPS or RISC-V support that is still experimental, since some kernels are known not to work there. Before adopting it, build with make test on your target machine, run volk_profile to see which kernels the runtime will actually select, and read the LGPL-3.0-or-later terms, which replaced the GPL-3.0-or-later licence of versions before 3.0.

Frequently asked questions

How do I build and install VOLK?

Create a build directory, run cmake .., then make, make test and sudo make install. On Linux run sudo ldconfig afterwards to cache the shared library, and on macOS or Windows update PATH to the library install location.

What does volk_profile do?

The documentation describes volk_profile as profiling your system so that the best kernel is used. It is the last step in both the x86 and the ARM build instructions, because runtime selection depends on the CPU features of the machine the profile runs on.

Which CPU architectures does VOLK support?

VOLK aims to run with optimized kernels on x86 with SSE or AVX and on ARM with NEON. Support for MIPS and RISC-V is described as experimental, and some kernels are known not to work on those architectures.

How do I build VOLK for a Raspberry Pi?

Pass the toolchain file for the specific board to cmake, for example -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/arm_cortex_a76_hardfp_native.cmake for a Raspberry Pi 5, then make, make test and sudo make install. Separate toolchain files are listed for the Pi 4 and the Pi 3.

What licence applies to VOLK?

VOLK 3.0 and later are licensed under the GNU Lesser General Public License v3.0 or later. Versions before 3.0 were licensed under the GNU General Public License v3.0 or later, and the project documents its reasoning for relicensing.

Official sources

  1. gnuradio/volk on GitHub
  2. License: LGPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gnuradio-volk.svg)](https://hysenlabs.com/projects/gnuradio-volk)

Was this useful?