Uncached os.listdir() in _get_family() causes much slower resolves on Windows - #2195
Uncached os.listdir() in _get_family() causes much slower resolves on Windows#2195mandeep wants to merge 3 commits into
Conversation
On Windows, get_family was calling os.listdir on every invocation of a package directory search. This caused a massive slowdown on resolve performance. Changing this search to use the cached directories instead improves performance by orders of magnitude. Signed-off-by: mandeep <10521687+mandeep@users.noreply.github.com>
|
|
|
Hi @mandeep , thanks for opening this PR. Do you have more details on the performance slow down you were getting and what you get now with these changes? Extreme and massive are two big adjectives. Not saying that it wasn't the case, but I'd like to see some numbers to back this up and help us a bit. When talking about performance, it's important to provide some numbers and more context to get an idea of the scale of the problem and changes. Things like what kind of performance you were getting before, and what you get now, how many directories are in your repos, how many repos, how many packages, type of filesystem, etc. It will also help us determine if the problem is this or if it's related to something (like the cache for example). Thanks! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2195 +/- ##
==========================================
+ Coverage 61.30% 61.33% +0.03%
==========================================
Files 164 164
Lines 20572 20575 +3
Branches 3575 3578 +3
==========================================
+ Hits 12611 12620 +9
+ Misses 7089 7085 -4
+ Partials 872 870 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
On Windows 11 with a network drive formatted to NTFS, resolves were taking 45-60 seconds for any given project. There are 10 or so repos with 250-350 packages in each. This setup uses memcached with a hit rate of 99%. With this change, resolves are now 1-3 seconds. Calling If there's any command output or anything else you would like to see, please let me know! |
Signed-off-by: mandeep <10521687+mandeep@users.noreply.github.com>
eefdf93 to
f9bb7cb
Compare
JeanChristopheMorinPerso
left a comment
There was a problem hiding this comment.
I've only looked for 10 minutes, but so far, I'm not convinced that this will bring a performance improvement. In fact, I think this might actually create a performance regression. I think.
| name not in os.listdir(self.location): | ||
| return None | ||
| if not platform_.has_case_sensitive_filesystem: | ||
| dirs = set(dir_name for (dir_name, ext) in self._get_family_dirs() if ext is None) |
There was a problem hiding this comment.
I've not yet spent enough time on this, but from a first look, self._get_family_dirs() calls os.isdir adn then os.listdir, and then for each dir returned by os.listdir, call os.isdir. This will result in a performance regression in theory... And _get_family_dirs is not cached, so I don't see how it can actually improve the performance.
There was a problem hiding this comment.
Spent a little bit more time on this. The performance regression will only be when caching is disabled, which is the default.
There was a problem hiding this comment.
I am new to the codebase, but I think this line uses memcached for directory lookup.
You're correct that this would be a regression when caching is disabled. Ideally, os.listdir would not be called per package.
There was a problem hiding this comment.
@JeanChristopheMorinPerso, I was thinking that since the extra os.isdir call will slow down the default case even more that we could just add a check to see if the cache is enabled. If it is enabled then it runs the new cached branch, and if it is disabled then we can just run the old os.listdir check as is.
This can be achieved with a simple if statement or a more involved solution of a new decorator wrapped around listdir.
|
I'm 99% certain that this specific "fix" has come up before, and I do recall that it's fundamentally required for some mechanic reason in rez, but I'll need to hunt to come up with the reason why. That doesn't mean that opportunities for optimizing it, or perhaps finding creative ways to work around or configure-away the problem are without merit, but it does need scrutiny. |
|
Thanks @maxnbk. I agree that scrutiny is needed and hopefully we can work through a solution. The fix here doesn't really alter much for those not using a cache. In #689 it appears that the author added the |
Signed-off-by: mandeep <10521687+mandeep@users.noreply.github.com>
141903e to
4f06e77
Compare
Hi all,
I was seeing extremely slow resolve times on Windows, even with memcached showing a 99% hit rate. I caught that
os.listdir()was being called for every package check. I changed this to use the decorated_get_familydirs()and noticed that resolve times were now instant. I'm new to Rez so I don't know if this is the correct way to handle this, but it seems to be working now as intended.Thanks!
Mandeep