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

Add spin wait to the desktop compilation service client #11709

Merged
merged 4 commits into from
Jun 3, 2016

Conversation

agocke
Copy link
Member

@agocke agocke commented Jun 2, 2016

On .NET 4.5 the implementation for NamedPipeClientStream busy waits
during the timeout period, blocking the running CPU. Fixes #10413.

/cc @jaredpar @stephentoub @dotnet/roslyn-compiler

On .NET 4.5 the implementation for NamedPipeClientStream busy waits
during the timeout period, blocking the running CPU. Fixes dotnet#10413.
if (timeoutMs != Timeout.Infinite && waitTime <= 0)
{
Log($"Connecting to server timed out after {timeoutMs} ms");
break;
Copy link
Member

Choose a reason for hiding this comment

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

When we break out of here, we won't be connected, but then we subsequently log "Named pipe '{0}' connected", and it looks like the code proceeds under the assumption that it is connected. Does that matter? If you're ok with that, you could also change the beginning of the loop from while (true) { cancellationToken.ThrowIfCancellationRequested(); ... } to while (!cancellationToken.IsCancellationRequested), as the code after the loop also does the check-and-throw.

Copy link
Member

Choose a reason for hiding this comment

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

You might consider separating all of this new code out into its own ConnectWithSpinWait method, or something like that, which provides the same logical behavior as Connect (including the throw for timeout / cancellation / etc.) except with the added spin wait... then none of the rest of the logic needs to change, and the method could easily be swapped out if/when Connect is fixed on all supported platforms.

Copy link
Member Author

Choose a reason for hiding this comment

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

@stephentoub No that should be a return null; instead of a break -- nice catch. I will add a test for this.

@agocke agocke force-pushed the spin-in-compiler-server-wait branch from 4c0615c to 0c04ad4 Compare June 2, 2016 19:46
@agocke
Copy link
Member Author

agocke commented Jun 2, 2016

@stephentoub I believe I've addressed your comments.

break;
}
catch (Exception e) when (e is IOException || e is TimeoutException)
{
Copy link
Member

Choose a reason for hiding this comment

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

Connect can throw two exceptions on a time out?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah... TimeoutException is when it doesn't find an available pipe server. IOException happens when a server exists but it's serving another client and the current client times out.

@jcouv
Copy link
Member

jcouv commented Jun 2, 2016

LGTM

}
catch (Exception e) when (e is IOException || e is TimeoutException)
{
// Ignore timeout
Copy link
Contributor

Choose a reason for hiding this comment

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

It is not clear why are we ignoring IOException. Perhaps explain in the comment?
Also, would it be better to have two strongly typed catch clauses instead of using a filter?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I should add an explanation for that. IOException can sometimes indicate timeout.

Copy link
Member Author

Choose a reason for hiding this comment

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

Regarding two catch clauses: this clause addresses the single semantic case of a timeout, which the framework has unfortunately provided two types for, which I describe in the comment. I think it is clearer to collect this code in a single catch, as opposed to splitting it into two cases.

@agocke agocke force-pushed the spin-in-compiler-server-wait branch from 7e75ee6 to a1eaab2 Compare June 2, 2016 21:40
@agocke
Copy link
Member Author

agocke commented Jun 2, 2016

Issues should be fixed and test cases added.

@agocke
Copy link
Member Author

agocke commented Jun 2, 2016

/cc @MattGertz for ask-mode approval

waitTime = Math.Min(timeoutMs - elapsedMs, maxWaitIntervalMs);
if (waitTime <= 0)
{
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

What should happen with negative input that is not Timeout.Infinite? Should we try at least once? Or is such input not possible?

Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a unit-test for this scenario.


In reply to: 65632978 [](ancestors = 65632978)

Copy link
Member Author

@agocke agocke Jun 2, 2016

Choose a reason for hiding this comment

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

This timeout is even more constrained than I thought: it isn't set anywhere except in test code. In public endpoints it is always set to a constant positive value. I will add an assert that it is in the expected range.

@AlekseyTs
Copy link
Contributor

LGTM

1 similar comment
@VSadov
Copy link
Member

VSadov commented Jun 3, 2016

LGTM

@agocke agocke merged commit 98de71e into dotnet:stabilization Jun 3, 2016
@agocke agocke deleted the spin-in-compiler-server-wait branch June 3, 2016 03:58
@agocke
Copy link
Member Author

agocke commented Jun 3, 2016

@jaredpar @stephentoub Sorry, I saw the approvals and merged this before you had finished reviewing. If you find anything more I should add let me know and I'll address it in another PR.

@robertmclaws
Copy link

Is there any way we can get this tested with the DotNetCompiler project in an Azure environment to make sure the implementation actually solves the problem I and several others were experiencing in Production? There were some assumptions in the conversations that make me nervous, and I'd hate to see this get into whatever release is next and have it still not solve the problem.

I'm an MVP, if there are any ways I can help test this before it ships, please let me know. Thanks!

@agocke
Copy link
Member Author

agocke commented Jun 6, 2016

@advancedrei If you have a production environment that you can test this on, the 1.1.0-beta1-60606-02 build of package Microsoft.Net.Compilers from https://dotnet.myget.org/F/roslyn-stabilization-nightly/ should contain this change. Thanks for your offer!

@agocke
Copy link
Member Author

agocke commented Jun 6, 2016

You'll probably also need to set <UseSharedCompilation>true</UseSharedCompilation> in order to actually use the compiler server path.

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.

None yet

10 participants