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

Make Atoms() faster via caches #224

Merged
merged 16 commits into from
Jul 23, 2021
Merged

Make Atoms() faster via caches #224

merged 16 commits into from
Jul 23, 2021

Conversation

pmrv
Copy link
Contributor

@pmrv pmrv commented Jun 2, 2021

Fixes #48.

Looking at benchmarks I found that almost all time creating a new Atoms object is spent on either i) reading the periodic table from a csv file and ii) loading mendeleev objects from element strings.

I think it's reasonable to assume that during the lifetime of a pyiron process neither the periodic table changes on disk nor is the mendeleev database updated and therefore cache both on the module level (i.e. even multiple instances of Atoms and PeriodicTable share one cache). In my benchmark that gives a factor 100 speed up.

Caching convert_element has some technical nits with it:

  1. I want one cache for all Atoms objects, since
    • each structure might be small, so a per-instance cache wouldn't help a lot (in fact Atoms has a self-rolled cache like that already; I think we can remove it now, but I want to double check with you)
    • we can expect the results from mendeleev to be the same for all instances anyway
  2. The expensive part is actually only this, so an alternative would be to make Atom some kind of singleton.
  3. At the end of the method it also updates Atoms.species, in the cached case this would not be called. However all call sites of convert_element also call set_species later in the code path, so nothing is lost. It's still messy to rely on this, but I feel this is a separate refactor.

def convert_element(self, el, pse=None):

@pmrv
Copy link
Contributor Author

pmrv commented Jun 2, 2021

Caching the method on Atoms didn't quite work, so I did the much less intrusive change to cache the call to mendeleev directly. This leaves a factor 2 on the table, but all the nits from above are handled by this.

@pmrv pmrv marked this pull request as ready for review June 2, 2021 09:31
@pmrv pmrv added the enhancement New feature or request label Jun 2, 2021
@pmrv pmrv marked this pull request as draft June 2, 2021 15:42
When cached, change in the dataframe is preserved. Therefore, use separate if statements to ensure that the qwargs are stores (Fixes failing test)
Copy link
Member

@sudarsan-surendralal sudarsan-surendralal left a comment

Choose a reason for hiding this comment

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

This looks good! I made a small commit to fix the failing tests for the Atom class.

Can you also add the benchmarking you have locally as part of the unittests for the Atoms class?

Edit: I had to make more than one commit to fix this ;)

@pmrv
Copy link
Contributor Author

pmrv commented Jun 7, 2021

Thanks for the fix! I will look into how to best do a benchmark as a test case in a system-independent way, probably it's sufficient to time two runs and assert the second time is much faster.

I've attached the profile for this problem at the end here.

@stale
Copy link

stale bot commented Jun 21, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jun 21, 2021
@stale stale bot closed this Jul 5, 2021
@pmrv pmrv reopened this Jul 5, 2021
@stale stale bot removed the stale label Jul 5, 2021
@pmrv pmrv marked this pull request as ready for review July 13, 2021 11:38
@pmrv
Copy link
Contributor Author

pmrv commented Jul 13, 2021

@sudarsan-surendralal Can you have another look? I can't reproduce the test failure outside of the CI.

@coveralls
Copy link

coveralls commented Jul 14, 2021

Pull Request Test Coverage Report for Build 1056610704

  • 10 of 10 (100.0%) changed or added relevant lines in 1 file are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage increased (+0.01%) to 68.077%

Files with Coverage Reduction New Missed Lines %
pyiron_atomistics/atomistics/structure/periodic_table.py 1 83.5%
Totals Coverage Status
Change from base Build 1056270290: 0.01%
Covered Lines: 10908
Relevant Lines: 16023

💛 - Coveralls

@sudarsan-surendralal
Copy link
Member

@pmrv The tests should work now. I also took the liberty to extend your benchmarks a bit. We seem to consistently get a 15x speedup which is awesome. But I can't seem to get a 100x speedup you found in your benchmarks.

@pmrv
Copy link
Contributor Author

pmrv commented Jul 14, 2021

@pmrv The tests should work now. I also took the liberty to extend your benchmarks a bit. We seem to consistently get a 15x speedup which is awesome. But I can't seem to get a 100x speedup you found in your benchmarks.

I think my benchmark last time was a more elaborate example creating the atoms via get_structure, so maybe there were extra factors that made it even slower. I'll look for it again to confirm the speed up, but 15x looks already very good.

@@ -349,15 +353,12 @@ def add_element(
self.dataframe = self.dataframe.append(parent_element_data_series)
else:
self.dataframe.loc[new_element] = parent_element_data_series
if len(qwargs) != 0:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is what broke the tests before?

Choose a reason for hiding this comment

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

Yes but not only this. The recent commit b278013 also helped fix the tests

@pmrv
Copy link
Contributor Author

pmrv commented Jul 15, 2021

The tests were failing on mac, so I decreased the expected speedup to 10. Otherwise this looks pretty good! I'll still want to understand what is different now to the original changes, but after that I think we can merge this.

@niklassiemer
Copy link
Member

Is there something wrong in the way the speedup is computed (on mac)? In both last cases the threshold was only slightly missed...

@pmrv
Copy link
Contributor Author

pmrv commented Jul 15, 2021

Is there something wrong in the way the speedup is computed (on mac)? In both last cases the threshold was only slightly missed...

Weird, I changed it to 10, because it ~14 before… :S

@niklassiemer
Copy link
Member

Is there something wrong in the way the speedup is computed (on mac)? In both last cases the threshold was only slightly missed...

Weird, I changed it to 10, because it ~14 before… :S

That is what I meant with both last cases. And in both cases it was only slightly below. Therefore, I asked if there is an error on computing the time difference on Mac 😆

@pmrv
Copy link
Contributor Author

pmrv commented Jul 16, 2021

Is there something wrong in the way the speedup is computed (on mac)? In both last cases the threshold was only slightly missed...

Weird, I changed it to 10, because it ~14 before… :S

That is what I meant with both last cases. And in both cases it was only slightly below. Therefore, I asked if there is an error on computing the time difference on Mac laughing

Yep, I see that now. I'll try to figure it out.

@pmrv
Copy link
Contributor Author

pmrv commented Jul 22, 2021

Suddenly the speed up test worked for a factor x10 on macOS. I still don't know what's going on, but I've made it hopefully more robust by averaging the times and then checking instead of checking in every iteration.

@pmrv
Copy link
Contributor Author

pmrv commented Jul 22, 2021

On my local machine speed ups are in the range x30-40 now, hope that works on CI as well.

Since the timings are sub-seconds, using ints breaks ;)
@pmrv
Copy link
Contributor Author

pmrv commented Jul 22, 2021

The merge commit earlier messed up the tests, so I removed it again via a rebase.

Copy link
Member

@sudarsan-surendralal sudarsan-surendralal left a comment

Choose a reason for hiding this comment

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

Taking the average of the speedup is definitely a better idea. LGTM!

@pmrv pmrv merged commit bdf72b6 into master Jul 23, 2021
@delete-merged-branch delete-merged-branch bot deleted the get_structure branch July 23, 2021 07:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ase_to_pyiron is slow
4 participants