Skip to content

TST: Cache .hypothesis - #11161

Closed
pllim wants to merge 2 commits into
astropy:mainfrom
pllim:actions-cache-hypothesis
Closed

pllim wants to merge 2 commits into
astropy:mainfrom
pllim:actions-cache-hypothesis

Conversation

@pllim

@pllim pllim commented Dec 10, 2020 •

Copy link
Copy Markdown
Member

Description

This pull request is to address the caching .hypothesis portion of #11038 using actions/cache according to advise at #11038 (comment) . I guess it makes the most sense to insert this step right after setting up Python but before installing dependencies.

Open questions

  • Will all the jobs accessing the same cache create a race condition if two jobs try to populate the same cache at the same time?
  • Do we need to cache by OS etc.?
  • Do we need cache for "32-bit and parallel" job?
  • Do we need cache for cron jobs too?
  • Or perhaps we do not need this cache at all? Is there any noticeable performance improvements using it? (From comments, the performance is not in speed but rather robustness.)

Comment thread .github/workflows/ci_workflows.yml Outdated
python-version: ${{ matrix.python }}
- uses: actions/cache@v2
with:
path: .hypothesis

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Is this path specification enough? I have no idea where that directory is supposed to be. Is it in some special tox dir, home, root, or ...? How do I find out?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I need someone very familiar with tox + hypothesis to chime in here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tox runs tests in .tmp/{envname}, so the .hypothesis directory should be created there, but I don't know how to run hypothesis tests locally to check. I guess in actions {envname} should always be ${{ matrix.toxenv }}, so it should work with something like path: .tmp/${{ matrix.toxenv }}/.hypothesis, but I think that would mean that each env would have its own cache...
If we want to share the cache across envs, we could modify tox's config to run in .tmp/ instead of .tmp/{envname}. Nothing is generated in this directory except .hypothesis, so I don't think we need a per-env tmp directory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Does it matter if the path is different as long as key is the same? 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I asked myself the same question ;). I think yes, because actions will store and restore this specific path.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@saimn AFAICT you're correct here. Caching per-env would be fine, or you can configure Hypothesis to use a particular path (e.g. the repo root) - see https://github.com/numpy/numpy/blob/91d9bbebc159ada6cccd0e1fcec1926e26b19c6f/numpy/conftest.py#L17-L21.

I kinda like this approach because it means that updating the tox env won't discard the cache, which is going to be nice for local development too.

@pllim
pllim requested review from astrofrog, embray and saimn December 10, 2020 23:12
@saimn

saimn commented Dec 11, 2020

Copy link
Copy Markdown
Contributor

I have no idea what's in this directory and if it's really useful to cache it. Maybe cc @Zac-HD if you can provide some insights ?

@Zac-HD

Zac-HD commented Dec 11, 2020

Copy link
Copy Markdown
Contributor

Here's the Hypothesis docs about the database. In short:

I can't answer questions about how GitHub Actions caching works, but that's the Hypothesis side. Always happy to help with follow-up questions etc. too 🙂

@saimn

saimn commented Dec 11, 2020

Copy link
Copy Markdown
Contributor

Thanks @Zac-HD , really useful !

@pllim
pllim force-pushed the actions-cache-hypothesis branch from 11aaed0 to b46b884 Compare December 15, 2020 18:48
@pllim

pllim commented Dec 15, 2020

Copy link
Copy Markdown
Member Author

I modified the code to make the .hypothesis cache to be toxenv specific. Do you happen to know how big each cache is expected to be? Actions has a hard limit of 5 GB. When we expand things that we cache and each run generates 5 GB of cache or more, that means caching is meaningless. Something to keep in mind.

@pllim

pllim commented Dec 15, 2020

Copy link
Copy Markdown
Member Author

CI failure is unrelated. This is what the log looks like on first run:

2020-12-15T18:49:15.1092310Z ##[group]Run actions/cache@v2
2020-12-15T18:49:15.1092751Z with:
2020-12-15T18:49:15.1093205Z   path: .tmp/py39-test/.hypothesis
2020-12-15T18:49:15.1093808Z   key: hypothesis-py39-test
2020-12-15T18:49:15.1094406Z   restore-keys: hypothesis-
...
2020-12-15T18:49:15.1097820Z ##[endgroup]
2020-12-15T18:49:15.3307896Z Cache not found for input keys: hypothesis-py39-test, hypothesis-

I guess we'll see what it looks like on subsequent pushes after a successful CI run. I expect something like "cache hit, restoring cache" or something. 🤞

@pllim
pllim force-pushed the actions-cache-hypothesis branch from b46b884 to 7be76dd Compare December 15, 2020 20:14
@pllim

pllim commented Dec 15, 2020

Copy link
Copy Markdown
Member Author

At the end of a successful run, you will see this:

2020-12-15T20:24:37.8040280Z Cache saved successfully

But if I understand https://docs.github.com/en/free-pro-team@latest/actions/guides/caching-dependencies-to-speed-up-workflows#example-of-search-priority correctly, when a new PR is opened and master branch already has a cache from the last run (say, from a merge commit of unrelated PR), the new PR will grab the cache for that toxenv from master. Is this desirable?

@pllim

pllim commented Dec 15, 2020

Copy link
Copy Markdown
Member Author

At the next run, you will see something like this:

2020-12-15T20:47:12.5792988Z Received 22 of 22 (100.0%), 0.0 MBs/sec
2020-12-15T20:47:12.5794005Z Cache Size: ~0 MB (22 B)
...
2020-12-15T20:47:12.5928181Z Cache restored from key: hypothesis-py39-test
...
2020-12-15T20:56:03.9312308Z Cache hit occurred on the primary key hypothesis-py39-test, not saving cache.

So, I guess it is not going to be a problem as far as cache size limit is concerned...

@saimn

saimn commented Dec 15, 2020

Copy link
Copy Markdown
Contributor

Is this desirable?

Yes! That's what we want ;)

@pllim
pllim marked this pull request as ready for review December 15, 2020 22:27
@Zac-HD

Zac-HD commented Dec 16, 2020

Copy link
Copy Markdown
Contributor

Cache hit occurred on the primary key hypothesis-py39-test, not saving cache.

🚨🚨🚨 That's not desirable though - if the cached database is loaded and then updated, we'd want GitHub Actions to update the cache.

That could probably be forced by adding e.g. build number as a final key suffix? So there would always be a cache miss, and then load the most recent alternative... not exactly the intended use, but it would work.


[cache size questions]

TLDR: it's designed not to be too large, I'd be surprised if the cache ever got to 1GB.
If it did, you're safe to just delete the whole thing and start over at any time.

Details: the maximum possible size of each value is 8 KiB, but typical sizes are more like tens of bytes with a right-tail up to ~hundreds or ~1K at the largest realistic end. Each key (=test) can have in principle unlimited keys; but in practice it shouldn't go above tens unless you have failing examples - and latter passing runs discard now-passing entries. Running fuzzing mode can grow it further, but it's still reasonably bounded and you're not doing that in CI anyway.

@pllim

pllim commented Dec 16, 2020

Copy link
Copy Markdown
Member Author

(Unrelated: I think both CircleCI and astropy-bot hate me now. One runs when I said to skip, the other one just never runs when I open a PR.)

@pllim
pllim force-pushed the actions-cache-hypothesis branch from 14335ca to ee510df Compare December 16, 2020 16:12
@pllim

pllim commented Dec 16, 2020

Copy link
Copy Markdown
Member Author

Here is what the logs look like now:

Successful run

Cache restored from key: hypothesis-py39-test-{{ github.run_id }}
...
Cache saved successfully

The -{{ github.run_id }} is from a commit earlier where I forgot the $, which has since been fixed. But that run was cached, so now it reminds me of my shame until the cache is automatically invalidated in the future, as there is no way to manually delete the cache. This message means that it must have it the hypothesis-${{ matrix.toxenv }}- restore key.

This also means that if someone rerun this workflow with the same Run ID, it will restore but not write the cache, is that okay, @Zac-HD ?

Failed run

Cache not found for input keys: hypothesis-py37-test-devdeps-426074051, hypothesis-py37-test-devdeps-, hypothesis-

This job has been failing for a while, so a cache was never created. You can see that the run ID is properly populated here, hiding my shame a little. Since it is still failing, a cache is also not written out.

@Zac-HD

Zac-HD commented Dec 16, 2020

Copy link
Copy Markdown
Contributor

This also means that if someone rerun this workflow with the same Run ID, it will restore but not write the cache, is that okay?

I think it's unlikely enough to ever be a problem that we should just ignore the possibility - we'd only care if the repeat run found a bug that the first run didn't. You could use eg unix timestamps instead of run ID, but I'd just leave it as is.

@pllim

pllim commented Dec 16, 2020

Copy link
Copy Markdown
Member Author

Okay, I'll leave it as-is then, because I am not sure how to do the timestamp thing in an OS-agnostic way and I don't feel like dabbling in Powershell for the Windows job. 😬 Thanks for the review and advice! 😸

@pllim

pllim commented Apr 19, 2021

Copy link
Copy Markdown
Member Author

It's been a while and we haven't seen any problems that indicates that we actually need this. Should we close without merge?

@pllim pllim added the Close? Tell stale bot that this issue/PR is stale label Apr 19, 2021
@pllim

pllim commented Apr 19, 2021

Copy link
Copy Markdown
Member Author

@saimn voted to close. Can always revisit if the need arises.

@pllim pllim closed this Apr 19, 2021
@pllim
pllim deleted the actions-cache-hypothesis branch April 19, 2021 16:37
@Zac-HD

Zac-HD commented Apr 20, 2021

Copy link
Copy Markdown
Contributor

We haven't seen any problems that indicate we actually need this.

The 'problem' that caching .hypothesis/ prevents is that one CI run might find a rare bug, which is then not rediscovered by a subsequent run. If this kind of flakiness is concerning, that's exactly what the database is designed to prevent.

On the other hand, derandomize=True (which you set in conftest.py) also prevents this problem, by making runs deterministic - so you either always find or never find that hypothetical rare bug - and the print_blob=True setting means that you can always reproduce failures in CI anyway.

TLDR; closing this is fine 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Close? Tell stale bot that this issue/PR is stale Enhancement no-changelog-entry-needed testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants