Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Span_FirstF and List_FirstF are slower than just calling foreach -> Why? #22

Open
Smurf-IV opened this issue Aug 2, 2019 · 15 comments

Comments

@Smurf-IV
Copy link

Smurf-IV commented Aug 2, 2019

image
image

    [Benchmark]
    public double IntSpanFirstForEach()
    {
        Span<int> asSpan = intArray.AsSpan();
        foreach (int i in asSpan)
        {
            if (firstInts(i))
            {
                return i;
            }
        }

        return 0;
    }

    [Benchmark]
    public double IntSpanFirstFast()
    {
        return intArray.AsSpan().FirstF(firstInts);
    }

    [Benchmark]
    public double IntListFirstLinq()
    {
        return intList.First(firstInts);
    }

    [Benchmark]
    public double IntListFirstFast()
    {
        return intList.FirstF(firstInts);
    }

    [Benchmark]
    public double IntListFirstFast1()
    {
        Predicate<int> predicate = new Predicate<int>(firstInts);
        int sourceCount = intList.Count;
        for (int i = 0; i < sourceCount; i++)
        {
            if (predicate(intList[i]))
            {
                return intList[i];
            }
        }

        return 0;
    }
Smurf-IV pushed a commit to Smurf-IV/LinqFaster that referenced this issue Aug 2, 2019
@Smurf-IV Smurf-IV changed the title [Question] Span_FirstF and List_First are slower than just calling foreach -> Why? [Question] Span_FirstF and List_FirstF are slower than just calling foreach -> Why? Aug 2, 2019
@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

Just in case the VM is causing problems, this is the host, and it still shows a difference
Ideally it should be in the same region as the ArrayFirstF result.

image

@jackmott
Copy link
Owner

jackmott commented Aug 2, 2019

try making a local copy of the array inside the function calling FirstF

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

try making a local copy of the array inside the function calling FirstF

I do not understand, In the Benchmark, or in the Implementation of FirstF for Span<T>?

[Benchmark]
public double IntSpanFirstForEach()
{
    Span<int> asSpan = intArray.AsSpan();
    foreach (int i in asSpan)
    {
        if (firstInts(i))
        {
            return i;
        }
    }

    return 0;
}

[Benchmark]
public double IntSpanFirstFast()
{
    return intArray.AsSpan().FirstF(firstInts);
}

@jackmott
Copy link
Owner

jackmott commented Aug 2, 2019

in the benchmark

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

in the benchmark

I've shown the code, isn't is generating a local for each of the benchmarks ?

@jackmott
Copy link
Owner

jackmott commented Aug 2, 2019

public double IntSpanFirstFast()
{
    var localArray = intArray;
    return localArray.AsSpan().FirstF(firstInts);
}

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

No difference ...
image

    [Benchmark]
    public double IntSpanFirstForEach()
    {
        int[] localArray = intArray;
        Span<int> asSpan = localArray.AsSpan();
        foreach (int i in asSpan)
        {
            if (firstInts(i))
            {
                return i;
            }
        }

        return 0;
    }

    [Benchmark]
    public double IntSpanFirstFast()
    {
        int[] localArray = intArray;
        Span<int> asSpan = localArray.AsSpan();
        return asSpan.FirstF(firstInts);
    }

@jackmott
Copy link
Owner

jackmott commented Aug 2, 2019

These are such small differences (nanoseconds) it might just be the function call overhead of calling into FirstF. Like the difference is pretty close to the latency of a single memory location lookup

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

Because the function is not the same for each run (private static readonly Func<int, bool> firstInts = (x) => x > 0;) then any difference seen should be taken into account.
Converting to a Span is quick and does not have a great impact (As seen by the other benchmarks), then these differences should be raising a red flag, especially as the Array.FirstF is so much quicker.

Span is quick, see the difference for Sum, i.e. Span.SumFor is slower than the Span.SumFastF

IntArraySumLinq 1000000 5,610,364.063 ns 110,617.3880 ns 178,626.4625 ns 5,569,376.563 ns - - - -
IntArraySumFast 1000000 632,074.231 ns 11,899.6764 ns 11,687.0733 ns 632,253.467 ns - - - -
IntSpanSumFor 1000000 959,628.695 ns 18,512.4370 ns 24,071.3973 ns 957,722.656 ns - - - -
IntSpanSumFast 1000000 944,971.122 ns 18,046.1893 ns 15,997.4767 ns 941,054.688 ns - - - -

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

Checking back through the Benchmarks...
It appears that the Span functions are slower apart from the Sum...

IntArrayAggregateLinq 1000000 6,644,730.651 ns 72,946.5557 ns 68,234.2534 ns 6,645,266.016 ns - - - -
IntArrayAggregateFast 1000000 2,155,960.964 ns 35,396.5436 ns 33,109.9488 ns 2,143,233.203 ns - - - -
IntReadOnlyArrayAggregateLinq 1000000 7,335,447.578 ns 74,533.0185 ns 69,718.2318 ns 7,309,037.891 ns - - - 128 B
IntReadOnlyArrayAggregateFast 1000000 6,347,838.229 ns 64,908.7109 ns 60,715.6484 ns 6,331,896.875 ns - - - -
IntSpanAggregateForEach 1000000 2,757,356.406 ns 39,808.8742 ns 37,237.2456 ns 2,745,133.203 ns - - - -
IntSpanAggregateFast 1000000 3,085,561.250 ns 38,936.5386 ns 36,421.2624 ns 3,079,746.094 ns - - - -
 

 

@jackmott
Copy link
Owner

jackmott commented Aug 2, 2019

are you testing with .net core? span is slow when not on .net core

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 2, 2019

Picture states .Net 4.7.2, so nope.

Smurf-IV pushed a commit to Smurf-IV/LinqFaster that referenced this issue Aug 2, 2019
@jackmott
Copy link
Owner

jackmott commented Aug 2, 2019

yeah so span being slow is to be expected, nothing to be done about it.

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 3, 2019

yeah so span being slow is to be expected, nothing to be done about it.

So would it be prudent to move the Linq for Span<T> into an extensions dll, with a caveat that "Some" API's are not faster ?

@Smurf-IV
Copy link
Author

Smurf-IV commented Aug 8, 2019

#21

Smurf-IV pushed a commit to Smurf-IV/LinqFaster that referenced this issue Aug 8, 2019
…er a span

Create jackmott#22: [Question] Span_FirstF and List_FirstF are slower than just calling foreach -> Why?
Span this jackmott#24: [Enhancement] DefaultIfEmptyF should be implemented
Add Span jackmott#25: [Enhancement] Please also target .net4.8 and Benchmark
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants