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

Alternative System.Lazy implementation #8963

Merged
merged 17 commits into from Mar 4, 2017

Conversation

Projects
None yet
7 participants
@manofstick
Contributor

manofstick commented Jan 17, 2017

2017-21-01: I have modified the implementation a little, so updated the text to reflect the changes
2017-28-01: Updated text to represent current state of implementation

The current version of System.Lazy isn't particularly performant. @mrange had some analysis in an article called On the cost of being lazy.

Ultimately this stemmed back to FSharp's implementations of Seq.init(Infinite)? which wrapped each call to IEnumerator<T>.MoveNext() in a lazy that was only evaluated on Current. (Which is one of the issues that I have address when composing Seqs in my (incomplete) PR Seq Composer - although it still remains in there under some circumstances)

This version:

  • creates less objects for ExecutionAndPublish (2 objects created, vs 3), None (1 vs 2) & PublicationOnly (1 vs 2)
  • Faster access after initialization (just a null check, no casting)
  • Faster creation step - just one virtual call away
  • Arguably a more straight-forward implementation that is easier to follow as logic is partitioned.
  • Much less generics exposure, so as to improve JIT compilation

Still to do:

  • Add and merge your extra tests to for Lazy<T> to corefx repo. (dotnet/corefx#15577)
  • Make sure that all corefx tests for Lazy<T> are passing
  • Incorporate any feedback/bug fixes
  • Merge to CoreCLR repo
  • Port the change to CoreRT repo
  • External (not @manofstick) validation of threading correctness
  • Solution for how to deal with Mode on complete item for Debug object (I suggest Nullable, if that is acceptable)
@dnfclas

This comment has been minimized.

Show comment
Hide comment
@dnfclas

dnfclas Jan 17, 2017

Hi @manofstick, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

dnfclas commented Jan 17, 2017

Hi @manofstick, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

@dnfclas

This comment has been minimized.

Show comment
Hide comment
@dnfclas

dnfclas Jan 17, 2017

@manofstick, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

dnfclas commented Jan 17, 2017

@manofstick, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@dnfclas dnfclas added cla-signed and removed cla-required labels Jan 17, 2017

@mrange

This comment has been minimized.

Show comment
Hide comment
@mrange

mrange Jan 17, 2017

@manofstick - I have updated the charts to include your updated Lazy<'T> class.

https://gist.github.com/mrange/aa82d33e94ad76d0f33ed86e704d7492

mrange commented Jan 17, 2017

@manofstick - I have updated the charts to include your updated Lazy<'T> class.

https://gist.github.com/mrange/aa82d33e94ad76d0f33ed86e704d7492

Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
@mrange

This comment has been minimized.

Show comment
Hide comment
@mrange

mrange Jan 17, 2017

Hi @manofstick, I have checked the code and added a few observations/questions. Overall I see no obvious weakness. You said there was no test-coverage for Lazy<'T> today. Can that be added (damn difficult for these kinds of classes but at least to cover the functionality)?

mrange commented Jan 17, 2017

Hi @manofstick, I have checked the code and added a few observations/questions. Overall I see no obvious weakness. You said there was no test-coverage for Lazy<'T> today. Can that be added (damn difficult for these kinds of classes but at least to cover the functionality)?

@mrange

This comment has been minimized.

Show comment
Hide comment
@mrange

mrange Jan 17, 2017

I think the reason the Lazy<'T> implementation above performs worse for PublicationOnly then Lazzzy<'T> is because of the publication only lock.

mrange commented Jan 17, 2017

I think the reason the Lazy<'T> implementation above performs worse for PublicationOnly then Lazzzy<'T> is because of the publication only lock.

@mrange

This comment has been minimized.

Show comment
Hide comment
@mrange

mrange Jan 17, 2017

From my performance testing the read overhead of a Lazy<'T> object that is initialized is 3x lower with the new implementation. That is pretty good!

mrange commented Jan 17, 2017

From my performance testing the read overhead of a Lazy<'T> object that is initialized is 3x lower with the new implementation. That is pretty good!

@stephentoub

This comment has been minimized.

Show comment
Hide comment
@stephentoub

stephentoub Jan 17, 2017

Member

I've not reviewed these changes yet, but there are functional tests for Lazy; as with most of the types in mscorlib, the full set of tests is in corefx, e.g.
https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/System/LazyTests.cs

Member

stephentoub commented Jan 17, 2017

I've not reviewed these changes yet, but there are functional tests for Lazy; as with most of the types in mscorlib, the full set of tests is in corefx, e.g.
https://github.com/dotnet/corefx/blob/master/src/System.Runtime/tests/System/LazyTests.cs

manofstick added some commits Jan 18, 2017

Remove use of lock for PublicationOnly
This involves a little bit of trickery. In avoiding the lock we need to
go from m_implementation as PublicationOnly to null in a single step. We
can't do this though without another object, so we reuse out Lazy
object, which basically just spins its wheels until the value is ready.
This shouldn't be a very common scenerio (i.e. hitting that code path)
but it is possible.
@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 18, 2017

Contributor

@mrange

OK; with a bit of trickery I restored the CompareExchange in PublicaitonOnly without having to create a new object. In my testing with lots of threads this performed very well. Can you update your numbers to see if you get the previous performance?

Contributor

manofstick commented Jan 18, 2017

@mrange

OK; with a bit of trickery I restored the CompareExchange in PublicaitonOnly without having to create a new object. In my testing with lots of threads this performed very well. Can you update your numbers to see if you get the previous performance?

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 18, 2017

Contributor

Hiya @stephentoub !

Are you happy for me to dump all of my tests into the existing LazyTest file?

Contributor

manofstick commented Jan 18, 2017

Hiya @stephentoub !

Are you happy for me to dump all of my tests into the existing LazyTest file?

@stephentoub

This comment has been minimized.

Show comment
Hide comment
@stephentoub

stephentoub Jan 18, 2017

Member

Are you happy for me to dump all of my tests into the existing LazyTest file?

Extra tests would be excellent, thanks! I'd ask, though, that you de-dup with the existing ones so that we're only adding new tests for behaviors that don't already have them.

Member

stephentoub commented Jan 18, 2017

Are you happy for me to dump all of my tests into the existing LazyTest file?

Extra tests would be excellent, thanks! I'd ask, though, that you de-dup with the existing ones so that we're only adding new tests for behaviors that don't already have them.

manofstick added some commits Jan 19, 2017

Need to check m_implementation before TakeFactory
Threading bug.

TakeFactory() would crash on second call that was banked up behind the
lock.
Minimize additional object creation
Storing factory in Lazy object, and passing Lazy as a parameter to
ILazyItem functions. This means that None & PublicationOnly now need no
creation of secondary object.
@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 21, 2017

Contributor

@mrange sorry dude, I've modified things again, but I think I'm now at absolute minimum. I think None and PublicationOnly should show some improvements, as they no longer create any other objects other than the Lazy object itself (and as per previous comment, PublicationOnly's use of CompareExchange was restored)

@stephentoub hopefully I'll get a bit of chance to review tests tests within the next week (and hopefully no world war will begin within this time... hmmm...) Anyway, I think I'm pretty happy with the whole thing now, I've minimized object creation and all paths seem pretty optimal. I do hope serialization doesn't prove the show stopper...

Contributor

manofstick commented Jan 21, 2017

@mrange sorry dude, I've modified things again, but I think I'm now at absolute minimum. I think None and PublicationOnly should show some improvements, as they no longer create any other objects other than the Lazy object itself (and as per previous comment, PublicationOnly's use of CompareExchange was restored)

@stephentoub hopefully I'll get a bit of chance to review tests tests within the next week (and hopefully no world war will begin within this time... hmmm...) Anyway, I think I'm pretty happy with the whole thing now, I've minimized object creation and all paths seem pretty optimal. I do hope serialization doesn't prove the show stopper...

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Jan 21, 2017

Member

Before this optimization, there are 3 generic types that will be created per T: Lazy<T>, Boxed<T>, LazyInternalExceptionHolder<T>. The last one does not actually have to be generic - it can be moved out to LazyHelpers.

After this throughput optimization, there are 9 generic types that will be created per T: Lazy<T>, ILazyItem, CreateInstance<T>, LazyException, None, ExecutionAndPublication, PublicationOnly, PublicationOnlyWaiter, Boxed. And they are more expensive than the earlier ones because of they tend to implement interfaces.

The generic types take time and memory to create too, and if T is valuetype there is code JITed per T too. It would interesting to look at whether the ~5x+ increase in startup cost and footprint per T pays off in typical programs. For example, if I run https://github.com/aspnet/MusicStore app, how many different Lazy types are there and how many times is each one created?

Member

jkotas commented Jan 21, 2017

Before this optimization, there are 3 generic types that will be created per T: Lazy<T>, Boxed<T>, LazyInternalExceptionHolder<T>. The last one does not actually have to be generic - it can be moved out to LazyHelpers.

After this throughput optimization, there are 9 generic types that will be created per T: Lazy<T>, ILazyItem, CreateInstance<T>, LazyException, None, ExecutionAndPublication, PublicationOnly, PublicationOnlyWaiter, Boxed. And they are more expensive than the earlier ones because of they tend to implement interfaces.

The generic types take time and memory to create too, and if T is valuetype there is code JITed per T too. It would interesting to look at whether the ~5x+ increase in startup cost and footprint per T pays off in typical programs. For example, if I run https://github.com/aspnet/MusicStore app, how many different Lazy types are there and how many times is each one created?

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 21, 2017

Contributor

Hi @jkotas

I must admit I am ignorant in the ways of the JIT. but is it really creating all those types, of are they just potentially created (dare I say it, lazily created)? And if they are created eagerly is that just because they are inner classes, in which case they could be moved out and just the each other with internal scoped members?

I.e. following the happy path of creation would be, 'Lazy', 'ILazyItem', 'ExecutionAndPublication' and that's it. So still just 3. That would be most uses.

You should need 4 for 'PublicationOnly' and 3 for ’None'.

In the case of serialisation of exceptions an extra one each is required, but they are heavy operations anyway.

Anyway, let the knowledgeable people speak, I'll move back to my corner of ignorance!

Contributor

manofstick commented Jan 21, 2017

Hi @jkotas

I must admit I am ignorant in the ways of the JIT. but is it really creating all those types, of are they just potentially created (dare I say it, lazily created)? And if they are created eagerly is that just because they are inner classes, in which case they could be moved out and just the each other with internal scoped members?

I.e. following the happy path of creation would be, 'Lazy', 'ILazyItem', 'ExecutionAndPublication' and that's it. So still just 3. That would be most uses.

You should need 4 for 'PublicationOnly' and 3 for ’None'.

In the case of serialisation of exceptions an extra one each is required, but they are heavy operations anyway.

Anyway, let the knowledgeable people speak, I'll move back to my corner of ignorance!

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Jan 22, 2017

Member

because they are inner classes

Inner class relationship does not matter for performance. What matters is how the implementation is interconnected. For example, execution of private T CreateValue(LazyThreadSafetyMode mode) will load LazyException<T> type too because of it is referenced within the method. It is even worse problem with AOT compilation because of the AOT compilers cannot typically tell which types referenced in the implementation are the useful ones and so they have to compile all of them. You end up paying for it in the AOT binary size and compilation time.

The idea about making the value a direct field and use auxiliary state object is good, ie this is the best part of the change:

     public T Value
     {
            get
            {
                var implementation = m_implementation;
                if (implementation == null)
                    return m_value;

However the number of extra generic plumbing types makes it hard to tell whether it is obvious good trade-off for programs out there. Could you please try to refactor the implementation to avoid the generic types, and use non-generic types instead? The existing implementation is not perfect in this regard either - you should be able to beat it on the startup performance (=number of generic types) as well. Feel free to bring up any issues you may run into.

I have created a small perf test that creates a lot of different Lazy instantiations that you can use to measure: https://gist.github.com/jkotas/9c492e62c59cb5e7220daeed587d254a . On my machines, it gives 3953ms without your changes, 5734ms with your current changes. You can compile it directly against corelib for convenience:

cd \coreclr\bin\Product\Windows_NT.x64.Release
csc /noconfig /nostdlib /r:System.Private.CoreLib.dll /o+ test.cs)

Thank you for your work on this so far!

Member

jkotas commented Jan 22, 2017

because they are inner classes

Inner class relationship does not matter for performance. What matters is how the implementation is interconnected. For example, execution of private T CreateValue(LazyThreadSafetyMode mode) will load LazyException<T> type too because of it is referenced within the method. It is even worse problem with AOT compilation because of the AOT compilers cannot typically tell which types referenced in the implementation are the useful ones and so they have to compile all of them. You end up paying for it in the AOT binary size and compilation time.

The idea about making the value a direct field and use auxiliary state object is good, ie this is the best part of the change:

     public T Value
     {
            get
            {
                var implementation = m_implementation;
                if (implementation == null)
                    return m_value;

However the number of extra generic plumbing types makes it hard to tell whether it is obvious good trade-off for programs out there. Could you please try to refactor the implementation to avoid the generic types, and use non-generic types instead? The existing implementation is not perfect in this regard either - you should be able to beat it on the startup performance (=number of generic types) as well. Feel free to bring up any issues you may run into.

I have created a small perf test that creates a lot of different Lazy instantiations that you can use to measure: https://gist.github.com/jkotas/9c492e62c59cb5e7220daeed587d254a . On my machines, it gives 3953ms without your changes, 5734ms with your current changes. You can compile it directly against corelib for convenience:

cd \coreclr\bin\Product\Windows_NT.x64.Release
csc /noconfig /nostdlib /r:System.Private.CoreLib.dll /o+ test.cs)

Thank you for your work on this so far!

Remove Func<T> for default constructor invoking
Fixing startup performance concerns
@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 22, 2017

Contributor

Howdy @jkotas,

OK, well after a little playing around I have found that the main performance issue that raised its head in regards to your concerns was not so much the creation of generics, but rather that a Func<T> was being created for the default constructor factory.

Anyway, I have made some modification to remove this, and the numbers appear a fair bit better to me. I ran some tests with 32 & 64-bit and class MyG<T, U> and struct MyG<T, U> (where I cut the depth by 1) and the new version wins some and loses some.

Let me know what you think.

Contributor

manofstick commented Jan 22, 2017

Howdy @jkotas,

OK, well after a little playing around I have found that the main performance issue that raised its head in regards to your concerns was not so much the creation of generics, but rather that a Func<T> was being created for the default constructor factory.

Anyway, I have made some modification to remove this, and the numbers appear a fair bit better to me. I ran some tests with 32 & 64-bit and class MyG<T, U> and struct MyG<T, U> (where I cut the depth by 1) and the new version wins some and loses some.

Let me know what you think.

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Jan 22, 2017

Member

CreateInstance<T> and Func<T>

the new version wins some and loses some

Could you please still share some data about where it wins and loses?

I still believe it would be beneficial to make all the plumbing types non-generic. I think you may need to add extra cast from Object to Func<T> to make that work, but that should cost next to nothing.

Member

jkotas commented Jan 22, 2017

CreateInstance<T> and Func<T>

the new version wins some and loses some

Could you please still share some data about where it wins and loses?

I still believe it would be beneficial to make all the plumbing types non-generic. I think you may need to add extra cast from Object to Func<T> to make that work, but that should cost next to nothing.

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 22, 2017

Contributor

@jkotas

I don't think it's as simple as that. Maybe with a completely different implementation, but here I need to be able to call back into the 'Lazy' object from the ILazyItem implementation functions so they therefore need to be generic.

Anyway, I'll have a think. Not sure if I'll get much time to play this week, but I'll try to do a quick run to print timings from your testb at some stage.

Contributor

manofstick commented Jan 22, 2017

@jkotas

I don't think it's as simple as that. Maybe with a completely different implementation, but here I need to be able to call back into the 'Lazy' object from the ILazyItem implementation functions so they therefore need to be generic.

Anyway, I'll have a think. Not sure if I'll get much time to play this week, but I'll try to do a quick run to print timings from your testb at some stage.

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 23, 2017

Contributor

@jkotas

OK; well I found some time to play today, and I think I found the right combination of pieces for pretty much all goals to be achieved (and all without a single cast! hooray!)

So lets start with your test (I'm only running these once, so values may be dubious, but ballpark...

E&P = LazyThreadSafetyMode.ExecutionAndPublication
PO = LazyThreadSafetyMode.PublicationOnly
None = LazyThreadSafetyMode.None

Reference Type - depth = 7
Value Type - depth 6

Construct Args Bittage Type GC Current Implementation New Implementation %
() 64 Reference WorkStation 3719 1625 44%
E&P 64 Reference WorkStation 4532 2140 47%
PO 64 Reference WorkStation 4297 2531 59%
None 64 Reference WorkStation 1843 1656 90%
() 32 Reference WorkStation 5157 2094 41%
E&P 32 Reference WorkStation 5156 2078 40%
PO 32 Reference WorkStation 5125 2468 49%
None 32 Reference WorkStation 2656 2734 103%
() 64 Value WorkStation 9843 9281 94%
E&P 64 Value WorkStation 9860 7531 76%
PO 64 Value WorkStation 13468 9172 68%
None 64 Value WorkStation 11516 8500 74%
() 32 Value WorkStation 9062 5594 62%
E&P 32 Value WorkStation 10015 5610 56%
PO 32 Value WorkStation 9781 5453 58%
None 32 Value WorkStation 7594 5531 73%
() 64 Reference Server 5125 2078 41%

...and then I got bored, as I hadn't automated this...

Anyway, looking pretty good.

The post JITing times are also pretty good. Not quite as good as they were, but from the original @mrange tests, they are about half that.

So I think we're finally, maybe, getting there?

Contributor

manofstick commented Jan 23, 2017

@jkotas

OK; well I found some time to play today, and I think I found the right combination of pieces for pretty much all goals to be achieved (and all without a single cast! hooray!)

So lets start with your test (I'm only running these once, so values may be dubious, but ballpark...

E&P = LazyThreadSafetyMode.ExecutionAndPublication
PO = LazyThreadSafetyMode.PublicationOnly
None = LazyThreadSafetyMode.None

Reference Type - depth = 7
Value Type - depth 6

Construct Args Bittage Type GC Current Implementation New Implementation %
() 64 Reference WorkStation 3719 1625 44%
E&P 64 Reference WorkStation 4532 2140 47%
PO 64 Reference WorkStation 4297 2531 59%
None 64 Reference WorkStation 1843 1656 90%
() 32 Reference WorkStation 5157 2094 41%
E&P 32 Reference WorkStation 5156 2078 40%
PO 32 Reference WorkStation 5125 2468 49%
None 32 Reference WorkStation 2656 2734 103%
() 64 Value WorkStation 9843 9281 94%
E&P 64 Value WorkStation 9860 7531 76%
PO 64 Value WorkStation 13468 9172 68%
None 64 Value WorkStation 11516 8500 74%
() 32 Value WorkStation 9062 5594 62%
E&P 32 Value WorkStation 10015 5610 56%
PO 32 Value WorkStation 9781 5453 58%
None 32 Value WorkStation 7594 5531 73%
() 64 Reference Server 5125 2078 41%

...and then I got bored, as I hadn't automated this...

Anyway, looking pretty good.

The post JITing times are also pretty good. Not quite as good as they were, but from the original @mrange tests, they are about half that.

So I think we're finally, maybe, getting there?

@jkotas

Nice. Yes, we are getting there! The steps to get this change through:

  1. Add and merge your extra tests to for Lazy<T> to corefx repo. Could you please submit PR to corefx with them?
  2. Make sure that all corefx tests for Lazy<T> are passing
  3. Incorporate any feedback/bug fixes
  4. Merge to CoreCLR repo
  5. Port the change to CoreRT repo
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
Show outdated Hide outdated src/mscorlib/src/System/Lazy.cs
@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Jan 24, 2017

Contributor

Yet another round of changes; sorry for the churn, but your test case has led me down a different path of optimizations, but I think this will be it, as I have now removed as much of the generic plumbing as I could (I believe)... And the results are significantly better:

Construct Args Bittage Type GC Current Implementation New Implementation %
() 64 Reference WorkStation 3719 1047 28%
E&P 64 Reference WorkStation 4532 1047 23%
PO 64 Reference WorkStation 4297 1062 25%
None 64 Reference WorkStation 1843 1047 57%
() 32 Reference WorkStation 5157 1532 30%
E&P 32 Reference WorkStation 5156 1578 31%
PO 32 Reference WorkStation 5125 1531 30%
None 32 Reference WorkStation 2656 1531 58%
() 64 Value WorkStation 9843 4202 43%
E&P 64 Value WorkStation 9860 4188 42%
PO 64 Value WorkStation 13468 4218 31%
None 64 Value WorkStation 11516 3828 33%
() 32 Value WorkStation 9062 4047 45%
E&P 32 Value WorkStation 10015 4031 40%
PO 32 Value WorkStation 9781 3937 40%
None 32 Value WorkStation 7594 3750 49%
() 64 Reference Server 5125 1062 21%

I'll hopefully get onto the tests soon; although I have probably already burnt my computer time budget for this week!

Contributor

manofstick commented Jan 24, 2017

Yet another round of changes; sorry for the churn, but your test case has led me down a different path of optimizations, but I think this will be it, as I have now removed as much of the generic plumbing as I could (I believe)... And the results are significantly better:

Construct Args Bittage Type GC Current Implementation New Implementation %
() 64 Reference WorkStation 3719 1047 28%
E&P 64 Reference WorkStation 4532 1047 23%
PO 64 Reference WorkStation 4297 1062 25%
None 64 Reference WorkStation 1843 1047 57%
() 32 Reference WorkStation 5157 1532 30%
E&P 32 Reference WorkStation 5156 1578 31%
PO 32 Reference WorkStation 5125 1531 30%
None 32 Reference WorkStation 2656 1531 58%
() 64 Value WorkStation 9843 4202 43%
E&P 64 Value WorkStation 9860 4188 42%
PO 64 Value WorkStation 13468 4218 31%
None 64 Value WorkStation 11516 3828 33%
() 32 Value WorkStation 9062 4047 45%
E&P 32 Value WorkStation 10015 4031 40%
PO 32 Value WorkStation 9781 3937 40%
None 32 Value WorkStation 7594 3750 49%
() 64 Reference Server 5125 1062 21%

I'll hopefully get onto the tests soon; although I have probably already burnt my computer time budget for this week!

Moved non-generic functionality out of Lazy
...and into a helper class

manofstick added a commit to manofstick/corefx that referenced this pull request Jan 28, 2017

System.Lazy regression tests
This is a prelude to an alternative Lazy implementation in a PR at
dotnet/coreclr#8963
@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Feb 5, 2017

Contributor

Hi @jkotas

So I'm slowly working through the list of items to get this in! One of the items you mentioned was "Merge to CoreCLR repo" - is this something that I should initiate, or are you just saying this is something that will occur as part of your normal dev processes?

Contributor

manofstick commented Feb 5, 2017

Hi @jkotas

So I'm slowly working through the list of items to get this in! One of the items you mentioned was "Merge to CoreCLR repo" - is this something that I should initiate, or are you just saying this is something that will occur as part of your normal dev processes?

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Feb 5, 2017

Member

Merge to CoreCLR repo

It is something that one of the CoreCLR maintainers with the write access to the repo has to do. Just add a comment on this PR when you think it is ready to merge.

Member

jkotas commented Feb 5, 2017

Merge to CoreCLR repo

It is something that one of the CoreCLR maintainers with the write access to the repo has to do. Just add a comment on this PR when you think it is ready to merge.

@danmosemsft

This comment has been minimized.

Show comment
Hide comment
@danmosemsft

danmosemsft Feb 17, 2017

Member

@manofstick how is this one going? Would love to see this improvement committed.

Member

danmosemsft commented Feb 17, 2017

@manofstick how is this one going? Would love to see this improvement committed.

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Feb 22, 2017

Contributor

@jkotas

Were you able to run the corefx tests (both the new ones you have added, and the existing ones) against this? People were reporting troubles running corefx tests against private CoreCLR builds recently.

I've limited time, so I've just got a cut down test project with just the Lazy testing in it that I've been using... Relying on github to do full test suite...

Contributor

manofstick commented Feb 22, 2017

@jkotas

Were you able to run the corefx tests (both the new ones you have added, and the existing ones) against this? People were reporting troubles running corefx tests against private CoreCLR builds recently.

I've limited time, so I've just got a cut down test project with just the Lazy testing in it that I've been using... Relying on github to do full test suite...

@manofstick manofstick referenced this pull request Feb 28, 2017

Closed

[WIP] Seq Composer #1570

71 of 99 tasks complete

manofstick added some commits Mar 1, 2017

Fixed race condition
Race condition was introduced when state wasn't passed to LazyGetValue.

Also just made LazyGetValue into void CreateValue, as it was internally
recursively calling back to Value, so I think this is easier to grok
threading implications (i.e. why it wasn't just returning _value.)
@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Mar 1, 2017

Contributor

@jkotas / @stephentoub

OK, well I think that things are good to progress.

There had been a race condition introduced when I have removed the state from being passed to LazyGetValue, but I believe we're all good again now.

I'm getting "GitHub pull request #8963 of commit 77d3a7f, has merge conflicts." so I think that's why the build is failing? Anyway, all over to you guys.

Contributor

manofstick commented Mar 1, 2017

@jkotas / @stephentoub

OK, well I think that things are good to progress.

There had been a race condition introduced when I have removed the state from being passed to LazyGetValue, but I believe we're all good again now.

I'm getting "GitHub pull request #8963 of commit 77d3a7f, has merge conflicts." so I think that's why the build is failing? Anyway, all over to you guys.

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Mar 1, 2017

Member

@manofstick Could you please merge current CoreCLR master and resolve the conflicts?

Member

jkotas commented Mar 1, 2017

@manofstick Could you please merge current CoreCLR master and resolve the conflicts?

@jkotas jkotas merged commit 2453adf into dotnet:master Mar 4, 2017

13 checks passed

CentOS7.1 x64 Debug Build and Test Build finished.
Details
FreeBSD x64 Checked Build Build finished.
Details
Linux ARM Emulator Cross Debug Build Build finished.
Details
Linux ARM Emulator Cross Release Build Build finished.
Details
OSX x64 Checked Build and Test Build finished.
Details
Ubuntu x64 Checked Build and Test Build finished.
Details
Ubuntu x64 Formatting Build finished.
Details
Windows_NT arm Cross Debug Build Build finished.
Details
Windows_NT arm Cross Release Build Build finished.
Details
Windows_NT x64 Debug Build and Test Build finished.
Details
Windows_NT x64 Formatting Build finished.
Details
Windows_NT x64 Release Priority 1 Build and Test Build finished.
Details
Windows_NT x86 Checked Build and Test Build finished.
Details
@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Mar 4, 2017

Member

Very well done - thanks a lot!

I will take care of porting this to CoreRT repo for you.

Member

jkotas commented Mar 4, 2017

Very well done - thanks a lot!

I will take care of porting this to CoreRT repo for you.

jkotas added a commit to jkotas/corert that referenced this pull request Mar 4, 2017

jkotas added a commit to jkotas/corert that referenced this pull request Mar 4, 2017

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Mar 4, 2017

Contributor

Sorry @jkotas I just noticed that in my shameful use of git merging I splatted over your previous task which removed the ComVisible attribute. Can you just remove it; or do you want me to create a new PR?

Contributor

manofstick commented Mar 4, 2017

Sorry @jkotas I just noticed that in my shameful use of git merging I splatted over your previous task which removed the ComVisible attribute. Can you just remove it; or do you want me to create a new PR?

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Mar 4, 2017

Member

Create a new PR for it please

Member

jkotas commented Mar 4, 2017

Create a new PR for it please

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Mar 4, 2017

Member

I have just moved Lazy.cs to a different directory, so make sure to sync to latest master before creating the PR.

Member

jkotas commented Mar 4, 2017

I have just moved Lazy.cs to a different directory, so make sure to sync to latest master before creating the PR.

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Mar 4, 2017

Contributor

@jkotas do you never sleep/watch a movie/go to pub/etc :-) :-)

Anyway, I'll do it tomorrow. Have a good weekend!

Contributor

manofstick commented Mar 4, 2017

@jkotas do you never sleep/watch a movie/go to pub/etc :-) :-)

Anyway, I'll do it tomorrow. Have a good weekend!

@manofstick manofstick deleted the manofstick:manofstick-lazy branch Mar 5, 2017

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Mar 5, 2017

Member

I went to the pub twice this week, and watched iMax movie today :-)

Thanks for submitting the PR.

Member

jkotas commented Mar 5, 2017

I went to the pub twice this week, and watched iMax movie today :-)

Thanks for submitting the PR.

@manofstick

This comment has been minimized.

Show comment
Hide comment
@manofstick

manofstick Mar 5, 2017

Contributor

@jkotas obviously you're just superhuman then! :-) No worries for PR; anyway, I can pack up my bags and return to the F# playground, I've left it rotting for a couple of months with an alternative linq-to-objects (F#'s Seq module) implementation. I just need to be a superhuman too to find a few weeks of time...

Contributor

manofstick commented Mar 5, 2017

@jkotas obviously you're just superhuman then! :-) No worries for PR; anyway, I can pack up my bags and return to the F# playground, I've left it rotting for a couple of months with an alternative linq-to-objects (F#'s Seq module) implementation. I just need to be a superhuman too to find a few weeks of time...

YongseopKim added a commit to YongseopKim/coreclr that referenced this pull request Mar 10, 2017

Alternative System.Lazy implementation (#8963)
* Remove use of lock for PublicationOnly

This involves a little bit of trickery. In avoiding the lock we need to
go from m_implementation as PublicationOnly to null in a single step. We
can't do this though without another object, so we reuse out Lazy
object, which basically just spins its wheels until the value is ready.
This shouldn't be a very common scenerio (i.e. hitting that code path)
but it is possible.

* Minimize additional object creation

Storing factory in Lazy object, and passing Lazy as a parameter to
ILazyItem functions. This means that None & PublicationOnly now need no
creation of secondary object.

* Remove Func<T> for default constructor invoking

Fixing startup performance concerns

* Moved non-generic functionality out of Lazy

...and into a helper class

* Expression-bodied functions

jorive added a commit to guhuro/coreclr that referenced this pull request May 4, 2017

Alternative System.Lazy implementation (#8963)
* Remove use of lock for PublicationOnly

This involves a little bit of trickery. In avoiding the lock we need to
go from m_implementation as PublicationOnly to null in a single step. We
can't do this though without another object, so we reuse out Lazy
object, which basically just spins its wheels until the value is ready.
This shouldn't be a very common scenerio (i.e. hitting that code path)
but it is possible.

* Minimize additional object creation

Storing factory in Lazy object, and passing Lazy as a parameter to
ILazyItem functions. This means that None & PublicationOnly now need no
creation of secondary object.

* Remove Func<T> for default constructor invoking

Fixing startup performance concerns

* Moved non-generic functionality out of Lazy

...and into a helper class

* Expression-bodied functions

@karelz karelz modified the milestone: 2.0.0 Aug 28, 2017

@manofstick manofstick referenced this pull request May 8, 2018

Closed

[WIP] [CompilerPerf] Seq - the next generation. #2745

9 of 11 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment