Skip to content

More optimized remainder calculation - #273

Merged
Ben (benmwatson) merged 1 commit into
microsoft:masterfrom
lechu445:divrem
Feb 17, 2023
Merged

Ben (benmwatson) merged 1 commit into
microsoft:masterfrom
lechu445:divrem

Conversation

@lechu445

Copy link
Copy Markdown
Contributor

Instead of division then remainder operation, used Math.DivRem which handles it in a more optimized way. It uses only a single division, multiplication, and subtraction instead of two divisions. Moreover, in the future, it can be even more optimized using intrinsics.

See:
dotnet/runtime#5213 (comment)

Instead of division then remainder operation, used Math.DivRem which handles it in a more optimized way. It uses only a single division, multiplication, and subtraction instead of two divisions. Moreover, in the future, it can be even more optimized using intrinsics.

See:
dotnet/runtime#5213 (comment)
@paulomorgado

Copy link
Copy Markdown
Contributor

It would be nice if this PR was acompanied by benchmarks.

@lechu445

Copy link
Copy Markdown
Contributor Author

before:

|    Method |     Mean |   Error |   StdDev |
|---------- |---------:|--------:|---------:|
| WriteByte | 184.0 ms | 3.64 ms |  5.34 ms |
| WriteSpan | 366.3 ms | 7.07 ms | 12.00 ms |

after:

|    Method |     Mean |   Error |   StdDev |
|---------- |---------:|--------:|---------:|
| WriteByte | 115.5 ms | 2.30 ms |  3.23 ms |
| WriteSpan | 319.7 ms | 6.28 ms | 11.49 ms | 

code:

public class Test
{
    private RecyclableMemoryStream subject;
    private readonly byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6 };

    [IterationSetup]
    public void IterationSetup()
    {
        var manager = new RecyclableMemoryStreamManager();
        this.subject = new RecyclableMemoryStream(manager);
    }

    [Benchmark]
    public void WriteByte()
    {
        for (int i = 0; i < 10_000_000; i++)
        {
            this.subject.WriteByte(1);
        }
    }

    [Benchmark]
    public void WriteSpan()
    {
        for (int i = 0; i < 10_000_000; i++)
        {
            this.subject.Write(bytes.AsSpan());
        }
    }
}

@paulomorgado

Copy link
Copy Markdown
Contributor

I was thinking more in the lines of:

public class Benchmarks
{
	[Benchmark(Baseline = true)]
	public (long quocient, long remainder) DivAndMod() => (4000L / 1024L, 4000L % 1024L);

	[Benchmark]
	public (long quocient, long remainder) MathDivRem() => Math.DivRem(4000L, 1024L);
}
Method Mean Error StdDev Ratio RatioSD
DivAndMod 0.2267 ns 0.0092 ns 0.0077 ns 1.00 0.00
MathDivRem 0.0607 ns 0.0221 ns 0.0271 ns 0.25 0.12

@benmwatson Ben (benmwatson) added this to the 2.0 milestone Feb 16, 2023
@benmwatson
Ben (benmwatson) merged commit a2017d6 into microsoft:master Feb 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants