Skip to content

More Efficient algorithm for List.groupBy - #1378

Merged
KevinRansom merged 4 commits into
dotnet:masterfrom
liboz:working
Aug 23, 2016
Merged

More Efficient algorithm for List.groupBy #1378
KevinRansom merged 4 commits into
dotnet:masterfrom
liboz:working

Conversation

@liboz

@libozliboz commented Jul 25, 2016

Copy link
Copy Markdown
Contributor

Also fixes a related unit test.

Here's a gist showing the difference: https://gist.github.com/liboz/d1f2ef35c9c46a5019127bd3b4f99d17
Note that I just made a clone of the original List.groupBy called List.groupBy2 for the purposes of the test

There seems to be inconsistent inlining in the List module, but I inlined the stuff I did here because the original was inlined.

Will edit in a benchmark with BenchmarkDotNet in a couple hours.

EDIT:

Here's the source code for the BenchmarkDotNet: https://gist.github.com/liboz/d1d513c378aefbc78889f2db27f2800f
and I pasted the results:. It's mostly the same test suite as the fsi gist I have above.

CLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1080.0

Type=groupBy Mode=Throughput GarbageCollection=Concurrent Workstation

MethodcountMedianStdDevGen 0Gen 1Gen 2Bytes Allocated/Op
groupByModulus10705.8428 ns42.6993 ns0.03--469.55
groupByOriginalModulus101,839.0410 ns93.7306 ns0.04--763.10
groupBy101,255.7102 ns61.1925 ns0.07--1,232.88
groupByOriginal103,987.1858 ns160.5903 ns0.09--1,610.93
groupByMixed10582,407.5966 ns30,728.3895 ns6.924.30-337,104.46
groupByOriginalMixed10736,841.4709 ns37,799.7629 ns8.595.55-379,064.74
groupByModulus1004,406.7663 ns169.0106 ns0.15--2,729.34
groupByOriginalModulus1007,344.0738 ns255.2806 ns0.20--3,557.86
groupBy10010,367.8809 ns381.3533 ns0.62--11,856.14
groupByOriginal10032,412.6751 ns1,597.1644 ns0.85--16,286.61
groupByMixed100572,375.6532 ns22,456.2116 ns6.594.49-332,997.24
groupByOriginalMixed100741,901.9452 ns35,264.1825 ns5.694.86-288,494.12
groupByModulus10000525,283.8138 ns28,838.6492 ns5.293.39-254,351.92
groupByOriginalModulus10000664,096.0494 ns26,908.3865 ns7.444.89-328,690.80
groupBy100002,761,663.8746 ns64,557.9006 ns17.59-17.501,213,041.70
groupByOriginal100005,317,136.8731 ns254,277.2331 ns20.544.8816.691,516,082.90
groupByMixed100001,300,531.4866 ns61,808.7686 ns11.7411.40-794,595.49
groupByOriginalMixed100001,630,609.7672 ns73,949.6140 ns16.0511.84-896,730.53
groupByModulus1000000231,907,137.1163 ns4,046,452.1418 ns301.91225.42108.9819,284,699.38
groupByOriginalModulus1000000231,722,288.2738 ns2,443,656.7017 ns274.10188.98119.0219,670,409.44
groupBy1000000804,278,639.9725 ns22,017,307.4191 ns656.45578.39118.5264,999,778.71
groupByOriginal10000001,191,626,049.8725 ns13,775,845.9996 ns1,125.25736.46136.3387,812,227.41
groupByMixed1000000688,763,766.6713 ns21,067,158.4101 ns781.33661.33146.0052,232,920.00
groupByOriginalMixed1000000635,669,734.7538 ns22,632,039.2767 ns964.44775.56209.7869,421,290.06
groupByModulus100000002,536,577,746.9513 ns62,383,748.7772 ns1,919.753,452.31148.25192,795,744.98
groupByOriginalModulus100000002,696,990,104.5825 ns58,256,910.0715 ns3,744.003,749.00358.00326,685,879.41
groupBy100000007,250,552,647.7425 ns245,053,956.2612 ns7,797.718,358.86212.00808,063,523.82
groupByOriginal1000000011,373,338,310.5325 ns255,350,492.3006 ns11,926.008,566.67192.00931,257,868.36
groupByMixed100000006,623,608,707.1300 ns212,181,053.7540 ns6,827.457,176.06180.74503,127,305.38
groupByOriginalMixed100000006,849,243,043.4850 ns134,781,808.1311 ns7,022.137,195.38198.00588,532,280.50

@msftclas

Copy link
Copy Markdown

Hi @liboz, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!
You've already signed the contribution license agreement. Thanks!

The agreement was validated by Microsoft and real humans are currently evaluating your PR.

TTYL, MSBOT;

@forki

Copy link
Copy Markdown
Contributor

ok the appveyor fail is probably unrelated, but still interesting. It seems property-based testing revealed an issue with Async.Choice.

 1) Error : FSharp.Core.Unittests.FSharp_Core.Microsoft_FSharp_Control.AsyncModule.Async.Choice specification test
System.Exception : Falsifiable, after 45 tests (0 shrinks) (StdGen (1588791491,296183942)):
Original:
ChoiceWorkflow
([NoneResultAfter 0; NoneResultAfter 7; SomeResultAfter -8; SomeResultAfter -1;
ExceptionAfter 9; ExceptionAfter 7; NoneResultAfter -11; NoneResultAfter -1;
SomeResultAfter 6; SomeResultAfter -9; ExceptionAfter -2; ExceptionAfter 8;
NoneResultAfter -10; NoneResultAfter 0],Some 10)
with exception:
NUnit.Framework.AssertionException: Expected: less than or equal to 4
But was: 5

@eiriktsarpalis any ideas what this might be?

forki added a commit to forki/visualfsharp that referenced this pull request Jul 25, 2016
@forki

Copy link
Copy Markdown
Contributor

@eiriktsarpalis I tried to reproduce the test in #1379 - all green. meh.

@eiriktsarpalis

Copy link
Copy Markdown
Member

@forki I'm pretty certain that those values should not be negative. They represent timeouts.

@forki

Copy link
Copy Markdown
Contributor

then the pbt should be narrowed?

@forki

Copy link
Copy Markdown
Contributor

mhm the normalize function is already using abs to make that positive

@eiriktsarpalis

Copy link
Copy Markdown
Member

yeah, just remembered that now. No problem then.

@forki

Copy link
Copy Markdown
Contributor

but it still crashed!? do we ignore that?

@smoothdeveloper

Copy link
Copy Markdown
Contributor

Haven't look at the test but if we are chasing a race condition, we should run the code many many times for more chances to reproduce it isn't it?

@eiriktsarpalis

Copy link
Copy Markdown
Member

@forki sorry, I meant no problem w.r.t. the tested inputs obviously.

@eiriktsarpalis

Copy link
Copy Markdown
Member

It is possible for the test to fail, provided that the thread pool behaves pathologically enough. I have made the durations be multiples of 2 seconds, assuming that it's way larger than any possible delay introduced by the thread pool. Might be related to this issue http://stackoverflow.com/questions/17429246/preventing-thread-pool-starvation-with-a-timer-running-at-same-time-as-parallel

@forki

Copy link
Copy Markdown
Contributor

let's continue discussion on #1379 - it's unrelated to this PR

@liboz

Copy link
Copy Markdown
ContributorAuthor

Well that's unexpected to reveal a random other bug as well with this.

dsyme added a commit that referenced this pull request Aug 1, 2016
try to reproduce async choice error revealed in #1378
Comment threadsrc/fsharp/FSharp.Core/local.fs Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You evaluate ie.Current three times on each iteration - please evaluate it only once.

Comment threadsrc/fsharp/FSharp.Core/local.fs Outdated
cons


let inline groupBy (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (list: 'T list) =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a huge method to inline is it really advantageous to inline it?

@libozlibozAug 14, 2016

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KevinRansom So, the original function was inlined, which is why I have this one inlined. If this function isn't inlined, then the inlining on the function in list.fs doesn't do anything and there is probably an over 15% performance hit in a simple benchmark I tried.

@libozlibozAug 16, 2016

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I reran some tests and inline seems to not make any difference. I've removed it.

@liboz

Copy link
Copy Markdown
ContributorAuthor

It appears Async.Choice failed on AppVeyor.

@KevinRansom

Copy link
Copy Markdown
Contributor

@dotnet-bot test this please

@KevinRansom

Copy link
Copy Markdown
Contributor

This looks good to me.

@KevinRansom
KevinRansom merged commit b80d8fc into dotnet:masterAug 23, 2016
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@liboz@msftclas@forki@eiriktsarpalis@smoothdeveloper@KevinRansom@dsyme