https://github.com/abetlen/simdinfo
Small C library for SIMD feature detection at runtime
Science Score: 13.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
○CITATION.cff file
-
✓codemeta.json file
Found codemeta.json file -
○.zenodo.json file
-
○DOI references
-
○Academic publication links
-
○Academic email domains
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (7.9%) to scientific vocabulary
Repository
Small C library for SIMD feature detection at runtime
Basic Info
Statistics
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 1
- Releases: 0
Metadata Files
README.md
simdinfo
simdinfo is a simple, header-only library for detecting SIMD support at runtime.
If you have a function that already checks for SIMD support at compile time via preprocessor directives
```c float sum(float *a, size_t size) {
if defined(AVX)
return sum_avx(a, size);
else
return sum_scalar(a, size);
endif
} ```
You can use simdinfo to replace the compile-time check with a runtime check using the same directive names
```c
include "simdinfo.h"
float sum(float *a, sizet size) { simdinfot info = simdinfo(); if (SIMDINFOSUPPORTS(info, _AVX_)) { return sumavx(a, size); } else { return sum_scalar(a, size); } } ```
Basic Example (Sum of Floats)
Let's start with a little example of a c function that sums up an array of floats.
c
float sum_serial(float *data, size_t n) {
float sum = 0;
for (size_t i = 0; i < n; i++) {
sum += data[i];
}
return sum;
}
This function iterates over a data array one element at a time and adds it to a running sum.
If we want to make this function faster one thing we can do is make use of specialised SIMD instructions to add up multiple elements at the same time.
The following uses x86_64 AVX simd intrinsics to load 8 floats a time into a vector and add them to a sum vector holding 8 partial sums.
```c
if defined(AVX)
include
float sumavx(float *data, sizet n) { _m256 sum = _mm256setzerops(); for (sizet i = 0; i < n; i += 8) { _m256 v = _mm256loadups(data + i); sum = _mm256addps(sum, v); } float result[8]; _mm256storeups(result, sum); float x = result[0] + result[1] + result[2] + result[3] + result[4] + result[5] + result[6] + result[7]; // handle remaining elements since n is not always divisible by 8 for (sizet i = n - n % 8; i < n; i++) { x += data[i]; } return x; }
endif
```
The above code will be compiled only if the compiler supports AVX instructions. Usually this is done by setting -march=native if you're compiling the code for the machine you're running it on.
What do you do if don't know if the machine you're running the code on supports AVX instructions? You can manually tell the compiler to include the AVX code path by setting -mavx flag and use SIMDINFO_SUPPORTS to check if the machine supports AVX instructions at runtime.
Below is a full example
```c // sum.c
include
include
include "simdinfo.h"
float sumserial(float *data, sizet n) { float sum = 0; for (size_t i = 0; i < n; i++) { sum += data[i]; } return sum; }
if defined(AVX)
include
float sumavx(float *data, sizet n) { _m256 sum = _mm256setzerops(); for (sizet i = 0; i < n; i += 8) { _m256 v = _mm256loadups(data + i); sum = _mm256addps(sum, v); } float result[8]; _mm256storeups(result, sum); float x = result[0] + result[1] + result[2] + result[3] + result[4] + result[5] + result[6] + result[7]; for (sizet i = n - n % 8; i < n; i++) { x += data[i]; } return x; }
endif
float sum(float *data, sizet n) { simdinfot info = simdinfo();
if defined(AVX)
if (SIMDINFO_SUPPORTS(info, __AVX__)) {
return sum_avx(data, n);
}
endif
return sum_serial(data, n);
}
int main() { sizet n = 1000000; float *data = malloc(n * sizeof(float)); for (sizet i = 0; i < n; i++) { data[i] = 1.0; } float s = sum(data, n); printf("sum = %f\n", s); free(data); return 0; } ```
Then we can compile the code for a generic x86_64 machine with -mavx flags.
bash
wget https://raw.githubusercontent.com/abetlen/simdinfo/main/simdinfo.h
gcc \
-march=x86_64 \
-mavx \
-O2 \
-mtune=generic \
-o sum \
sum.c \
-I.
./sum
If you only want to enable dynamic dispatch on some builds you can implement a pattern like the following
```c float sum(float *data, size_t n) {
if defined(DYNAMIC_DISPATCH)
simdinfo_t info = simdinfo();
else
undef SIMDINFO_SUPPORTS
define SIMDINFO_SUPPORTS(info, feature) 1
endif
if defined(AVX)
if (SIMDINFO_SUPPORTS(info, __AVX__)) {
return sum_avx(data, n);
}
endif
return sum_serial(data, n);
} ```
In the above code, if DYNAMIC_DISPATCH is defined, the code will use simdinfo to check if the machine supports AVX instructions. If DYNAMIC_DISPATCH is not defined, the code will always use the AVX code path if the compiler supports AVX instructions.
Related Projects
- https://github.com/ashvardanian/SimSIMD
- https://github.com/Mozilla-Ocho/llamafile
- https://github.com/google/cpu_features
- https://github.com/google/highway
Owner
- Name: Andrei
- Login: abetlen
- Kind: user
- Location: San Francisco, California
- Twitter: abetlen
- Repositories: 49
- Profile: https://github.com/abetlen
GitHub Events
Total
- Issues event: 1
- Watch event: 3
Last Year
- Issues event: 1
- Watch event: 3
Issues and Pull Requests
Last synced: 10 months ago
All Time
- Total issues: 1
- Total pull requests: 0
- Average time to close issues: N/A
- Average time to close pull requests: N/A
- Total issue authors: 1
- Total pull request authors: 0
- Average comments per issue: 0.0
- Average comments per pull request: 0
- Merged pull requests: 0
- Bot issues: 0
- Bot pull requests: 0
Past Year
- Issues: 1
- Pull requests: 0
- Average time to close issues: N/A
- Average time to close pull requests: N/A
- Issue authors: 1
- Pull request authors: 0
- Average comments per issue: 0.0
- Average comments per pull request: 0
- Merged pull requests: 0
- Bot issues: 0
- Bot pull requests: 0
Top Authors
Issue Authors
- byroot (1)