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

[WIP] idea to speed up Xamarin.Android.Build.Tests #1008

Closed

Conversation

jonathanpeppers
Copy link
Member

I wanted to send this in to discuss next week.

The current situation

Currently the Xamarin.Android.Build.Tests are doing the following:

  • Running msbuild w/ verbose logging to file and /noconsolelogger
  • Combining stdout and stderror into a large string named LastBuildOutput
  • Many tests are asserting against the text in LastBuildOutput
  • There is also some code that opens the log file on disk to find the MSBuild build duration

So a couple issues from this:

  • We use a lot of memory here, with potentially enormous strings, some of it is duplicated strings
  • Asserting against LastBuildOutput is doing a string.Contains on potentially massive strings
  • The test BuildAMassiveApp always fails on Windows with OutOfMemoryException
  • On Windows, our Process.Start/WaitForExit implementation can hang. If the stdout or stderror buffer gets full, when WaitForExit hangs with the 10 minute timeout. I see this happening mostly if a test fails (because the output is bigger). Link about this here.

I'm sure this code evolved over time--it probably wasn't planned to be implemented this way.

An idea

The "idea" is we could instead:

  • Run msbuild with verbose logging to the console (not to file at all)
  • Use the OutputDataReceived and ErrorDataReceived events to assert against MSBuild output as it streams through
  • Append this output to a file for failures later if needed

The problem with doing this, is you would have to setup assertions before running the build. Then checking if they all passed after the build. This is a bit confusing, and a juxtaposition of the Arrange, Act, Assert pattern people think about when writing tests.

The initial results

I did a quick implementation of this idea, and compared the results of the following test class with 44 tests (on Mac):

make run-nunit-tests TEST=Xamarin.Android.Build.Tests.AndroidUpdateResourcesTest

The results on master:

Test Run Summary
  Overall result: Warning
  Test Count: 44, Passed: 35, Failed: 0, Warnings: 0, Inconclusive: 0, Skipped: 9
    Skipped Tests - Ignored: 9, Explicit: 0, Other: 0
  Start time: 2017-11-03 16:46:54Z
    End time: 2017-11-03 16:54:49Z
    Duration: 474.909 seconds

The results with this PR:

Test Run Summary
  Overall result: Failed
  Test Count: 44, Passed: 30, Failed: 5, Warnings: 0, Inconclusive: 0, Skipped: 9
    Failed Tests - Failures: 5, Errors: 0, Invalid: 0
    Skipped Tests - Ignored: 9, Explicit: 0, Other: 0
  Start time: 2017-11-03 20:04:41Z
    End time: 2017-11-03 20:11:00Z
    Duration: 379.545 seconds

There are still some failures I'll look into fixing here. These failures seemed to be running the full test (they aren't failing and taking less than <10ms that would influence the shorter time).

This boils down to maybe a 20% speed increase of these tests. These tests are currently taking about 1 hour on Jenkins PRs.

Drawbacks

This seems like a decent amount of work--and the not very fun kind. It also seems scary that we could mistakenly change a test to make it always pass.

Investing in this, while it would improve quality & build times, doesn't bring new features to Xamarin.Android.

Thinking we can run assertions as the stdout events are coming through, and also append to file at the same time.

Hoping this will speed up the tests overall and fix the deadlocking issue on Windows when the stdout buffer is full.

See https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
Goal is to get AndroidUpdateResourcesTests refactored/passing

There are 44 of these and this seems like a good trial run
Temporary hack. It would be better to figure out what is causing this and remove thsi commit.
@jonathanpeppers jonathanpeppers added the do-not-merge PR should not be merged. label Nov 3, 2017
@dnfclas
Copy link

dnfclas commented Nov 3, 2017

@jonathanpeppers,
Thanks for having already signed the Contribution License Agreement. Your agreement was validated by .NET Foundation. We will now review your pull request.
Thanks,
.NET Foundation Pull Request Bot

@@ -215,8 +235,17 @@ protected virtual void CleanupTest ()
return;
if (TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed ||
TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Skipped) {
FileSystemUtils.SetDirectoryWriteable (output);
Copy link
Member Author

Choose a reason for hiding this comment

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

Ignore this, this is something else to figure out about these tests on Windows.

public TimeSpan LastBuildTime { get; protected set; }
public string BuildLogFile { get; set; }
public bool ThrowOnBuildFailure { get; set; }

//TODO: remove
public string LastBuildOutput {
get { throw new NotImplementedException (); }
Copy link
Member Author

@jonathanpeppers jonathanpeppers Nov 3, 2017

Choose a reason for hiding this comment

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

This PR leaves a couple methods that would be removed if we moved forward with this.

I left them here with NotImplementedException so it would compile.

@jonathanpeppers
Copy link
Member Author

I think we need to switch to the OutputDataReceived and ErrorDataReceived events to fix Windows hanging on WaitForExit. Dean should have a PR for this from our team meeting last week.

The other stuff in here related to changing assertions seems like it is too much work to port across all the tests.

jonpryor pushed a commit that referenced this pull request Jul 19, 2022
Fixes: dotnet/java-interop#969
Fixes: dotnet/java-interop#982
Fixes: dotnet/java-interop#984

Changes: dotnet/java-interop@fadbb82...032f1e7

  * dotnet/java-interop@032f1e71: [Xamarin.Android.Tools.Bytecode-Tests] Fix BuildClasses (#1013)
  * dotnet/java-interop@0eaa47e1: [Java.Interop.Tools.JavaCallableWrappers] NRT Support (#1012)
  * dotnet/java-interop@45fe3928: [generator] BG8403 when type name matches enclosing namespace name (#1010)
  * dotnet/java-interop@fe60483b: [generator] Mark abstract methods as [Obsolete] if needed (#1011)
  * dotnet/java-interop@275fa755: [generator] Kotlin metadata can apply to multiple Java method (#1009)
  * dotnet/java-interop@3ff6f8fb: [Java.Base] Fix CS0108 Warnings (#1008)

Of note is dotnet/java-interop@fe60483b, which can cause public
members to become marked as `[Obsolete]`.  These members *always*
should have been `[Obsolete]`, but weren't.  (Oops.)  This also
required changes to the `Mono.Android` API-compat checks.

Also of note is dotnet/java-interop@45fe3928, which introduces a new
BG8403 binding warning when a bound type has the same name as its
enclosing namespace name-part, e.g. `Example.View.View`.
@jonathanpeppers jonathanpeppers deleted the wip-test-performance branch April 26, 2023 15:31
@github-actions github-actions bot locked and limited conversation to collaborators Feb 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
do-not-merge PR should not be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants