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

speed up multiple invocations of counterfeiter #123

Merged
merged 10 commits into from
Jun 3, 2019
Merged

Conversation

joefitzgerald
Copy link
Collaborator

@joefitzgerald joefitzgerald commented Jun 3, 2019

In v6, we switched to use go/packages to load interfaces and packages, which gave us compatibility with go modules. It also included a significant degradation in speed that was mostly tolerable for single invocations of counterfeiter, but unacceptable when multiple invocations were required (see #120).

This PR implements two things:

  1. a very simple cache that takes the work done by packages.Load and caches the results
  2. logic that will identify all //go:generate directives in a given package; for a package with 100 directives
    • go generate will invoke counterfeiter 100 times
    • on the first invocation, counterfeiter will generate fakes for all 100 directives (leveraging the cache)
    • on invocations 2..100, counterfeiter will be a no-op and exit without doing work

This yields impressive performance gains, but is still a regression relative to v5 performance (an approach which will not work for go modules), using go generate in https://github.com/cloudfoundry/cli/tree/7dc650d65b462a1df674b5697121b08362003cd0/cf/api as a benchmark:

  • counterfeiter v6 (with caching) (3.92 seconds) runs about 20.5 times faster than v6 (without caching) (80.45 seconds)
  • counterfeiter v6 (with caching) (3.92 seconds) runs about 5 times slower than v5 (0.78 seconds)

counterfeiter v5

$ time go generate
Wrote `FakeAppSummaryRepository` to `apifakes/fake_app_summary_repository.go`
Wrote `FakeBuildpackBitsRepository` to `apifakes/fake_buildpack_bits_repository.go`
Wrote `FakeBuildpackRepository` to `apifakes/fake_buildpack_repository.go`
Wrote `FakeClientRepository` to `apifakes/fake_client_repository.go`
Wrote `FakeCurlRepository` to `apifakes/fake_curl_repository.go`
Wrote `FakeDomainRepository` to `apifakes/fake_domain_repository.go`
Wrote `FakeRouteServiceBindingRepository` to `apifakes/fake_route_service_binding_repository.go`
Wrote `FakeRouteRepository` to `apifakes/fake_route_repository.go`
Wrote `FakeRoutingAPIRepository` to `apifakes/fake_routing_apirepository.go`
Wrote `FakeServiceAuthTokenRepository` to `apifakes/fake_service_auth_token_repository.go`
Wrote `FakeServiceBindingRepository` to `apifakes/fake_service_binding_repository.go`
Wrote `FakeServiceBrokerRepository` to `apifakes/fake_service_broker_repository.go`
Wrote `FakeServiceKeyRepository` to `apifakes/fake_service_key_repository.go`
Wrote `FakeServicePlanRepository` to `apifakes/fake_service_plan_repository.go`
Wrote `FakeServicePlanVisibilityRepository` to `apifakes/fake_service_plan_visibility_repository.go`
Wrote `FakeServiceSummaryRepository` to `apifakes/fake_service_summary_repository.go`
Wrote `FakeServiceRepository` to `apifakes/fake_service_repository.go`
Wrote `FakeUserProvidedServiceInstanceRepository` to `apifakes/fake_user_provided_service_instance_repository.go`
Wrote `FakeUserRepository` to `apifakes/fake_user_repository.go`
go generate  0.78s user 0.29s system 126% cpu 0.844 total

counterfeiter v6 (caching disabled)

$ export COUNTERFEITER_DISABLECACHE=true
$ time go generate
Writing `FakeAppSummaryRepository` to `apifakes/fake_app_summary_repository.go`... Done
Writing `FakeBuildpackBitsRepository` to `apifakes/fake_buildpack_bits_repository.go`... Done
Writing `FakeBuildpackRepository` to `apifakes/fake_buildpack_repository.go`... Done
Writing `FakeClientRepository` to `apifakes/fake_client_repository.go`... Done
Writing `FakeCurlRepository` to `apifakes/fake_curl_repository.go`... Done
Writing `FakeDomainRepository` to `apifakes/fake_domain_repository.go`... Done
Writing `FakeRouteServiceBindingRepository` to `apifakes/fake_route_service_binding_repository.go`... Done
Writing `FakeRouteRepository` to `apifakes/fake_route_repository.go`... Done
Writing `FakeRoutingAPIRepository` to `apifakes/fake_routing_apirepository.go`... Done
Writing `FakeServiceAuthTokenRepository` to `apifakes/fake_service_auth_token_repository.go`... Done
Writing `FakeServiceBindingRepository` to `apifakes/fake_service_binding_repository.go`... Done
Writing `FakeServiceBrokerRepository` to `apifakes/fake_service_broker_repository.go`... Done
Writing `FakeServiceKeyRepository` to `apifakes/fake_service_key_repository.go`... Done
Writing `FakeServicePlanRepository` to `apifakes/fake_service_plan_repository.go`... Done
Writing `FakeServicePlanVisibilityRepository` to `apifakes/fake_service_plan_visibility_repository.go`... Done
Writing `FakeServiceSummaryRepository` to `apifakes/fake_service_summary_repository.go`... Done
Writing `FakeServiceRepository` to `apifakes/fake_service_repository.go`... Done
Writing `FakeUserProvidedServiceInstanceRepository` to `apifakes/fake_user_provided_service_instance_repository.go`... Done
Writing `FakeUserRepository` to `apifakes/fake_user_repository.go`... Done
go generate  80.45s user 33.72s system 380% cpu 29.985 total

counterfeiter v6

$ time go generate
Writing `FakeAppSummaryRepository` to `apifakes/fake_app_summary_repository.go`... Done
Writing `FakeBuildpackBitsRepository` to `apifakes/fake_buildpack_bits_repository.go`... Done
Writing `FakeBuildpackRepository` to `apifakes/fake_buildpack_repository.go`... Done
Writing `FakeClientRepository` to `apifakes/fake_client_repository.go`... Done
Writing `FakeCurlRepository` to `apifakes/fake_curl_repository.go`... Done
Writing `FakeDomainRepository` to `apifakes/fake_domain_repository.go`... Done
Writing `FakeRouteServiceBindingRepository` to `apifakes/fake_route_service_binding_repository.go`... Done
Writing `FakeRouteRepository` to `apifakes/fake_route_repository.go`... Done
Writing `FakeRoutingAPIRepository` to `apifakes/fake_routing_apirepository.go`... Done
Writing `FakeServiceAuthTokenRepository` to `apifakes/fake_service_auth_token_repository.go`... Done
Writing `FakeServiceBindingRepository` to `apifakes/fake_service_binding_repository.go`... Done
Writing `FakeServiceBrokerRepository` to `apifakes/fake_service_broker_repository.go`... Done
Writing `FakeServiceKeyRepository` to `apifakes/fake_service_key_repository.go`... Done
Writing `FakeServicePlanRepository` to `apifakes/fake_service_plan_repository.go`... Done
Writing `FakeServicePlanVisibilityRepository` to `apifakes/fake_service_plan_visibility_repository.go`... Done
Writing `FakeServiceSummaryRepository` to `apifakes/fake_service_summary_repository.go`... Done
Writing `FakeServiceRepository` to `apifakes/fake_service_repository.go`... Done
Writing `FakeUserProvidedServiceInstanceRepository` to `apifakes/fake_user_provided_service_instance_repository.go`... Done
Writing `FakeUserRepository` to `apifakes/fake_user_repository.go`... Done
go generate  3.92s user 1.66s system 322% cpu 1.731 total

/cc @Samze @jamesjoshuahill @williammartin

@joefitzgerald joefitzgerald merged commit 1b61d54 into master Jun 3, 2019
@joefitzgerald joefitzgerald deleted the jf-moar-speed branch June 3, 2019 02:49
crsimmons added a commit to EngineerBetter/control-tower that referenced this pull request Jun 11, 2019
it seems counterfeiter was rewritten recently which broke our unit tests. I followed maxbrunsfeld/counterfeiter#123 to implement this

Signed-off-by: Colin Simmons <[email protected]>
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.

1 participant