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

configure to run tests in parallel and eliminate global state #73

Merged
merged 2 commits into from
Mar 1, 2023

Conversation

christophsturm
Copy link
Contributor

@christophsturm christophsturm commented Oct 4, 2022

this speeds up a ./gradlew cleanTest test run from 14 seconds to 5 seconds on my m1 macbook pro.
If you like I can also create a PR that converts the test suite to https://github.com/failgood/failgood, which will probably make it even faster, simpler and nicer to read </commercial>

Copy link
Contributor

@TWiStErRob TWiStErRob left a comment

Choose a reason for hiding this comment

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

Few thoughts from a watcher (not maintainer).

if (this is RuntimeException && message != null && message!!.startsWith("result:"))
return message!!.substringAfter("result:")
Copy link
Contributor

@TWiStErRob TWiStErRob Oct 4, 2022

Choose a reason for hiding this comment

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

could this be a typed custom exception instead?

class DebugFunctionFailure(result: String) : RuntimeException(result)

+

if (ex.cause is DebugFunctionFailure) return ex.cause.message

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i wanted to keep it simple because the exception would need to be declared in the main method and in the method catching it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, that sounds like there may be a fun classloader issue there. Curious what @bnorm thinks.

Comment on lines 134 to 135
val cnt = AtomicLong()
fun nextMain() = "${cnt.addAndGet(1)}"
Copy link
Contributor

Choose a reason for hiding this comment

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

To remove global state fully, "main${UUID.randomUUID()}.kt" might be a more decoupled way. or even using the temp functionality of JUnit which has an added benefit of deleting the file which makes sure that the file handles are closed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thats an interesting thought, using a counter is also some kind of shared state, I never thought about it that way. I usually always use UUIDs but this time i wanted to avoid too long indentifiers.

Copy link
Contributor

@TWiStErRob TWiStErRob Oct 5, 2022

Choose a reason for hiding this comment

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

Note that Gradle has parallelization too for tests and if that's enabled there'll be multiple JVMs launched for each test task, so in memory synchronized state is not enough.

Check out Test.maxParallelForks property (example usage)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure but multiple vms is slow so thats not what I'm targetting here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Depends on the setup, I would spawn multiple VMs because the compilation is the bottleneck in these tests. Although that might be parallelized anyway with the current setup you did.

About targeting this or not: fair, I just wanted to highlight that "global" state is not fully removed, because the disk is still shared (same folder). And you got that.


I'll try a measurement on the weekend, I'm curious how this change or using forks changes the count to validate if JVMs are really as expensive. (I have 28 cores and 96GB) Don't need to wait for me on anything, just FYI.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

btw if you have so many cores, can you do me a favor and run the test suite of my orm library https://github.com/christophsturm/the.orm and tell me how fast it runs?

@christophsturm
Copy link
Contributor Author

@TWiStErRob thanks for your feedback, I have found out that the whole "making file name unique" effort was not needed and that the only problem was System.out. so now this PR turned out really simple.

@TWiStErRob
Copy link
Contributor

TWiStErRob commented Oct 5, 2022

Niiice! (You can resolve most comments then)

@christophsturm
Copy link
Contributor Author

about the formatting, maybe we could also add the kotlinter gradle plugin to run formatting locally and not only check it on CI

Copy link
Owner

@bnorm bnorm left a comment

Choose a reason for hiding this comment

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

First off, I apologize for not being very active in this repository recently. Life has kept me busy elsewhere but I'm hoping to dedicate some more time to this repo again soon.

Secondly, I appreciate the contribution and am excited about the reduction in test times! Thank you!

However, I'm not sure I like the conversion to exceptions for these tests. Use of println was sort of a hack to emulate a proper logging framework. I wonder if we can add a top-level StringBuilder to the dbg code which can be accessed after main is executed or if we can integrate with JUL somehow.

Regardless, I don't think this change reduces the test coverage at all so I'm going to merge it as-is and consider alternatives at a later time.

@bnorm bnorm merged commit be90be5 into bnorm:master Mar 1, 2023
@christophsturm
Copy link
Contributor Author

However, I'm not sure I like the conversion to exceptions for these tests. Use of println was sort of a hack to emulate a proper logging framework. I wonder if we can add a top-level StringBuilder to the dbg code which can be accessed after main is executed or if we can integrate with JUL somehow.

yes, I just fixed it in the simplest way that I could think of, the idea of the PR was mainly to show what problems we have when running test in parallel.

also I'm excited to see activity again in this repo!

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

Successfully merging this pull request may close these issues.

None yet

3 participants