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

Don't rerun mockgen if it's already up-to-date #5620

Merged
merged 28 commits into from
Mar 29, 2024

Conversation

MichaelSnowden
Copy link
Contributor

@MichaelSnowden MichaelSnowden commented Mar 28, 2024

What changed?

I added time-based caching to our mockgen invocations in go:generate directives. The tool gets bypassed in the CI.

Why?

I run make ci-build-misc a lot during development, and I noticed that make go-generate is a huge bottleneck there, taking about 45s-1min for me. I tested our other generate directives like the rpcwrapper, but that one seems fast, it looks like mockgen is the real culprit. I tried upgrading our dep to the latest version in the Uber fork to see if there was a quick win there, but it seems even slower now somehow. I considered batching our commands as well, but there isn't a way to batch mockgen commands in source mode (multiple -source and -destination flags). So, I figured I would borrow what Make does and just only run mockgen if the generated code is stale when compared to the source code.

How did you test it?

Running make go-generate locally now takes about 7.7s, down from 44.0s, so it's about 6x as fast:

temporal  snowden/cached-mockgen [$] ➜ time make go-generate
Process go:generate directives...
make go-generate  6.74s user 5.61s system 159% cpu 7.743 total
temporal  snowden/cached-mockgen [$] took 7.7s ➜ git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
temporal  main [$?] ➜ time make go-generate
Process go:generate directives...
make go-generate  68.13s user 123.43s system 435% cpu 43.955 total
temporal  main [$?] took 44.0s ➜ 

I also added unit tests which check cases like the destination file not being present, and it tested that manually as well.

Finally, I also deleted all _mock.go files and reran the command to verify that it works ok even when everything is out-of-date. In that case, there is a slight regression in time, up to 1 minute. I don't know why that's the case, but it should still be faster when there's no mocks.

Potential risks

Documentation

Is hotfix candidate?

@MichaelSnowden MichaelSnowden requested a review from a team as a code owner March 28, 2024 00:00
@MichaelSnowden MichaelSnowden force-pushed the snowden/cached-mockgen branch from 01b19de to d53dd74 Compare March 28, 2024 00:48
@MichaelSnowden MichaelSnowden requested a review from dnr March 28, 2024 00:55
@dnr
Copy link
Member

dnr commented Mar 28, 2024

In that case, there is a slight regression in time, up to 1 minute. I don't know why that's the case, but it should still be faster when there's no mocks.

I would guess that's the overhead of go run.. it has to check all the sources against its build cache.

General comment:

I'm fine with this for interactive use, but I would prefer if there was a way to make sure CI always did the full generation ignoring mod times. Mostly because I don't trust git to set mod times correctly in all cases. Could we do that with an environment variable or something that's set in CI but not interactive use?

@MichaelSnowden
Copy link
Contributor Author

In that case, there is a slight regression in time, up to 1 minute. I don't know why that's the case, but it should still be faster when there's no mocks.

I would guess that's the overhead of go run.. it has to check all the sources against its build cache.

Great insight. I just made it use the prebuilt binary, and it now only takes 7 seconds instead of 22!

General comment:

I'm fine with this for interactive use, but I would prefer if there was a way to make sure CI always did the full generation ignoring mod times. Mostly because I don't trust git to set mod times correctly in all cases. Could we do that with an environment variable or something that's set in CI but not interactive use?

That should definitely be possible, and I agree that it's a good idea. I'll look into it.

@MichaelSnowden
Copy link
Contributor Author

I'm fine with this for interactive use, but I would prefer if there was a way to make sure CI always did the full generation ignoring mod times. Mostly because I don't trust git to set mod times correctly in all cases. Could we do that with an environment variable or something that's set in CI but not interactive use?

I set a new BUILD_ENV environment variable in our CI, and I now check it in the tool. I confirmed that, with this set to true, the time for a full cached mockgen run (which just passes through to mockgen), is no slower than it was before (thanks to your idea about improving go run).

@MichaelSnowden MichaelSnowden requested a review from dnr March 28, 2024 15:42
@MichaelSnowden MichaelSnowden requested a review from dnr March 29, 2024 00:35
@MichaelSnowden MichaelSnowden merged commit c0b705f into main Mar 29, 2024
42 checks passed
@MichaelSnowden MichaelSnowden deleted the snowden/cached-mockgen branch March 29, 2024 20:24
bergundy added a commit that referenced this pull request Apr 3, 2024
## What changed and why?

Revert most of the changes from #5620 since this doesn't properly detect
stale files and we don't want to take the time to fix it at the moment.
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.

3 participants