EgorBo / EgorBo/IntrinsicsPlayground
Performance improvements using alignment and pipelining
- Dominant language
- C#
- Stars
- 65
- Forks
- 5
- PR merge metrics
- No merged PRs in 30d
Description
Hi Egor,
I wrote a blog post about [alignment and pipelining](https://mijailovic.net/2018/07/20/alignment-and-pipelining/), which you could use to further boost the performance of most examples in your repository. In essence, you can transform this code:
```csharp
public static int Sum(int[] source)
{
const int VectorSizeInInts = 8;
fixed (int* ptr = &source[0])
{
var pos = 0;
var sum = Avx.SetZeroVector256();
for (; pos <= source.Length - VectorSizeInInts; pos += VectorSizeInInts)
{
var current = Avx.LoadVector256(ptr + pos);
sum = Avx2.Add(current, sum);
}
var temp = stackalloc int[VectorSizeInInts];
Avx.Store(temp, sum);
var final = Sum(temp, VectorSizeInInts);
final += Sum(ptr + pos, source.Length - pos);
return final;
}
}
```
Into this:
```csharp
public static int SumAlignedPipelined(int[] source)
{
const ulong AlignmentMask = 31UL;
const int VectorSizeInInts = 8;
const int BlockSizeInInts = 32;
fixed (int* ptr = &source[0])
{
var aligned = (int*)(((ulong)ptr + AlignmentMask) & ~AlignmentMask);
var pos = (int)(aligned - ptr);
var sum = Avx.SetZeroVector256();
var final = Sum(ptr, pos);
for (; pos <= source.Length - BlockSizeInInts; pos += BlockSizeInInts)
{
var block0 = Avx.LoadAlignedVector256(ptr + pos + 0 * VectorSizeInInts);
var block1 = Avx.LoadAlignedVector256(ptr + pos + 1 * VectorSizeInInts);
var block2 = Avx.LoadAlignedVector256(ptr + pos + 2 * VectorSizeInInts);
var block3 = Avx.LoadAlignedVector256(ptr + pos + 3 * VectorSizeInInts);
sum = Avx2.Add(block0, sum);
sum = Avx2.Add(block1, sum);
sum = Avx2.Add(block2, sum);
sum = Avx2.Add(block3, sum);
}
for (; pos <= source.Length - VectorSizeInInts; pos += VectorSizeInInts)
{
var current = Avx.LoadAlignedVector256(ptr + pos);
sum = Avx2.Add(current, sum);
}
var temp = stackalloc int[VectorSizeInInts];
Avx.Store(temp, sum);
final += Sum(temp, VectorSizeInInts);
final += Sum(ptr + pos, source.Length - pos);
return final;
}
}
```
On my machine this results in 27% boost in performance when working with aligned arrays, and 34% on unaligned arrays (some arrays in your benchmarks are aligned, and some are not, which can results in around 10% difference in performance).
I don't have the time to send you a pull request, but I though you might be interested in this.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reviewing the repository’s existing SSE/AVX examples and benchmarks, then compare them with the alignment and pipelining approach shown in the issue. Determine which examples are in scope and validate changes with the existing performance benchmarks; done means the selected examples preserve their results while achieving the intended performance improvement.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- performance
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100