Skip to content

Commit c5e0ad3

Browse files
Final tweaks
1 parent 24f3939 commit c5e0ad3

4 files changed

Lines changed: 23 additions & 14 deletions

File tree

content/learning-paths/servers-and-cloud-computing/bitmap_scan_sve2/02-bitmap-data-structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,6 @@ size_t bitvector_count_scalar(bitvector_t* bv) {
8383
}
8484
```
8585
86-
## Next up: Implement and benchmark your first scalar bitmap scan
86+
## Next up: implement and benchmark your first scalar bitmap scan
8787
8888
With your bit vector infrastructure in place, you're now ready to scan it for set bits—the core operation that underpins all bitmap-based filters in database systems.

content/learning-paths/servers-and-cloud-computing/bitmap_scan_sve2/03-scalar-implementations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ size_t result_count = 0;
7676
```
7777
Instead of iterating through each bit individually, this implementation processes one byte (8 bits) at a time. The main optimization over the previous scalar implementation is checking if an entire byte is zero and skipping it entirely. For sparse bitmaps, this can dramatically reduce the number of bit checks.
7878

79-
## Next up: Accelerate bitmap scanning with NEON and SVE
79+
## Next up: accelerate bitmap scanning with NEON and SVE
8080

8181
You’ve now implemented two scalar scanning routines:
8282

content/learning-paths/servers-and-cloud-computing/bitmap_scan_sve2/04-vector-implementations.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ layout: "learningpathall"
1010
---
1111
Modern Arm CPUs like Neoverse V2 support SIMD (Single Instruction, Multiple Data) extensions that allow processing multiple bytes in parallel. In this section, you'll explore how NEON and SVE vector instructions can dramatically accelerate bitmap scanning by skipping over large regions of unset data and reducing per-bit processing overhead.
1212

13-
## NEON Implementation
13+
## NEON implementation
14+
15+
This implementation uses NEON SIMD (Single Instruction, Multiple Data) instructions to process 16 bytes (128 bits) at a time, significantly accelerating the scanning process.
16+
17+
Copy the NEON implementation shown below into the same file:
1418

15-
This implementation uses NEON SIMD (Single Instruction, Multiple Data) instructions to process 16 bytes (128 bits) at a time, significantly accelerating the scanning process. Copy the NEON implementation shown below into the same file:
1619
```c
1720
// NEON implementation of bit vector scanning
1821
size_t scan_bitvector_neon(bitvector_t* bv, uint32_t* result_positions) {
@@ -83,9 +86,11 @@ size_t scan_bitvector_neon(bitvector_t* bv, uint32_t* result_positions) {
8386
```
8487
This NEON implementation processes 16 bytes at a time with vector instructions. For sparse bitmaps, entire 16-byte chunks can be skipped at once, providing a significant speedup over byte-level skipping. After vector processing, it falls back to scalar code for any remaining bytes that don't fill a complete 16-byte chunk.
8588
86-
## SVE Implementation
89+
## SVE implementation
90+
91+
This implementation uses SVE instructions which are available in the Arm Neoverse V2 based AWS Graviton 4 processor.
8792
88-
This implementation uses SVE instructions which are available in the Arm Neoverse V2 based AWS Graviton 4 processor. Copy this SVE implementation into the same file:
93+
Copy this SVE implementation into the same file:
8994
9095
```c
9196
// SVE implementation using svcmp_u8, PNEXT, and LASTB
@@ -152,7 +157,7 @@ size_t scan_bitvector_sve2_pnext(bitvector_t* bv, uint32_t* result_positions) {
152157
```
153158
The SVE implementation efficiently scans bitmaps by using `svcmpne_u8` to identify non-zero bytes and `svpnext_b8` to iterate through them sequentially. It extracts byte indices and values with `svlastb_u8`, then processes individual bits using scalar code. This hybrid vector-scalar approach maintains great performance across various bitmap densities. On Graviton4, SVE vectors are 128 bits (16 bytes), allowing processing of 16 bytes at once.
154159

155-
## Next up: Apply vectorized scanning to database workloads
160+
## Next up: apply vectorized scanning to database workloads
156161

157162
With both NEON and SVE implementations in place, you’ve now unlocked the full power of Arm’s vector processing capabilities for bitmap scanning. These SIMD techniques allow you to process large bitvectors more efficiently—especially when filtering sparse datasets or skipping over large blocks of empty rows.
158163

content/learning-paths/servers-and-cloud-computing/bitmap_scan_sve2/05-benchmarking-and-results.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ double benchmark_scan(size_t (*scan_func)(bitvector_t*, uint32_t*),
4040
```
4141
4242
## Main function
43-
The main function of your program is responsible for setting up the test environment, running the benchmarking code for the four different implementations across various bit densities, and reporting the results. In the context of bitmap scanning, bit density refers to the percentage or proportion of bits that are set (have a value of 1) in the bitmap. Copy the main function code below into `bitvector_scan_benchmark.c`:
43+
The main function of your program is responsible for setting up the test environment, running the benchmarking code for the four different implementations across various bit densities, and reporting the results. In the context of bitmap scanning, bit density refers to the percentage or proportion of bits that are set (have a value of 1) in the bitmap.
44+
45+
Copy the main function code below into `bitvector_scan_benchmark.c`:
4446
4547
```C
4648
int main() {
@@ -148,7 +150,7 @@ When running on a Graviton4 c8g.large instance with Ubuntu 24.04, the results sh
148150
| 0.0100 | 99,511 | 7.821 | 1.570 | 2.252 | 1.353 |
149151
| 0.1000 | 951,491 | 12.817 | 8.336 | 9.106 | 6.770 |
150152

151-
### Speed-up vs generic Scalar
153+
### Speed-up vs generic scalar
152154

153155
| Density | Scalar Optimized | NEON | SVE |
154156
|---------|------------------|---------|------------|
@@ -160,23 +162,25 @@ When running on a Graviton4 c8g.large instance with Ubuntu 24.04, the results sh
160162

161163
## Understanding the results
162164

163-
## Generic Scalar vs Optimized Scalar
165+
The benchmarking results reveal how different bitmap scanning implementations perform across a range of bit densities—from completely empty vectors to those with millions of set bits. Understanding these trends is key to selecting the most effective approach for your specific use case.
166+
167+
### Generic scalar vs optimized scalar
164168

165169
The optimized scalar implementation shows significant improvements over the generic scalar implementation due to:
166170

167171
* **Byte-level Skipping**: Avoiding processing empty bytes
168172
* **Reduced Function Calls**: Accessing bits directly rather than through function calls
169173
* **Better Cache Utilization**: More sequential memory access patterns
170174

171-
## Optimized Scalar vs NEON
175+
### Optimized scalar vs NEON
172176

173177
The NEON implementation shows further improvements over the optimized scalar implementation for sparse bit vectors due to:
174178

175179
* **Chunk-level Skipping**: Quickly skipping 16 empty bytes at once
176180
* **Vectorized Comparison**: Checking multiple bytes in parallel
177181
* **Early Termination**: Quickly determining if a chunk contains any set bits
178182

179-
## NEON vs SVE
183+
### NEON vs SVE
180184

181185
The performance comparison between NEON and SVE depends on the bit density:
182186

@@ -190,7 +194,7 @@ The performance comparison between NEON and SVE depends on the bit density:
190194
- SVE consistently outperforms NEON
191195
- SVE achieves up to 1.66x speedup over NEON at 0.01% density
192196

193-
## Key Optimizations in SVE Implementation
197+
### Key optimizations in SVE implementation
194198

195199
The SVE implementation includes several key optimizations:
196200

@@ -204,7 +208,7 @@ The SVE implementation includes several key optimizations:
204208

205209
* **Prefetching**: Using `__builtin_prefetch` to reduce memory latency by prefetching the next chunk of data.
206210

207-
## Next up: Apply what you’ve learned to real-world workloads
211+
## Next up: apply what you’ve learned to real-world workloads
208212

209213
Now that you’ve benchmarked all four bitmap scanning implementations—scalar (generic and optimized), NEON, and SVE—you have a data-driven understanding of how vectorization impacts performance across different bitmap densities.
210214

0 commit comments

Comments
 (0)