Repository navigation
Conversation
| // Resolving a templated name below declares a new variable in the | ||
| // interpreter (see AppendTypesSlow), so remember the result to not declare | ||
| // one, and grow the memory, on every lookup of the same name. | ||
| static std::map<std::pair<void*, std::string>, TCppScope_t> template_scopes; |
There was a problem hiding this comment.
std::unordered_map probably not worth it if there aren't ton of templates
There was a problem hiding this comment.
We can't make an assumption on the size of loaded libraries/TU's which can grow exponentially e.g boost, eigen. So that would probably need to be an unordered_map
There was a problem hiding this comment.
But the cache doesn't grow with the size of the loaded libraries. It only holds templated names that someone actually looked up by string, failed both direct lookups and then resolved through AppendTypesSlow. The thing is that there is no hash function for std::pair, so I either have to implement one or use a nested std::unordered_map.
There was a problem hiding this comment.
Right, I meant the number of templates that can come from loaded libraries. Some TU's have lots of templates that can come back for a name. But I missed the fact that this is only the ones that are resolved with AppendTypesSlow. For that the current map is fine.
|
#155's cache is inside AppendTypesSlow, but the autoload happens earlier, when |
Binding an object to a templated class by name, for example
cppjit.bind_object(addr, "std::vector<double>"), grows the memory on every call: by about 7 kB per call here, and about 11 kB per call in ROOT, whereTDirectoryFile.Getdoes this for every object it returns. ROOT 6.40, before cppjit, doesn't have this growth. In a ROOT master build:interop::GetScopedoesn't remember what a templated name resolved to, so every lookup of the same name repeats this:Cpp::GetScopeandCpp::GetScopeFromCompleteNamefail on the name. In ROOT, the failed lookup makesTClingCallbacks::LookupObjecttry to autoload it, andTCling::GetClassSharedLibsparses the name again withcling::LookupHelper::findScope. Forstd::vector<double>this adds new AST nodes, about 350 B per call (found with heaptrack).AppendTypesSlowdeclares a new__cppjit_interop_sNvariable in the interpreter to resolve the name. This is most of the growth.This PR caches successful lookups of templated names at the start of
interop::GetScope, so both are skipped. Failed lookups aren't cached because they may succeed once more declarations are available. With the change, the growth after 20000 calls in ROOT is 0 kB for bothvector<double>andstd::vector<double>.#155 is related, but it doesn't fully fix this issue. It memoizes the result inside
AppendTypesSlow, which removes the new variable on every call, including for the other callers ofAppendTypesSlowsuch as overload ranking. However, the failing lookups, and in ROOT the autoload, happen beforeAppendTypesSlowis called. Caching at that later point, which I tried first in ROOT, still leavesstd::vector<double>growing by a few hundred bytes per call. The two changes are complementary.The new test
test58_repeated_template_scope_lookupfails without the change (the memory grows by 13 MB over 2000 calls, with a threshold of 4 MB) and passes with it.Tested on AlmaLinux 9 with LLVM 22.1.5 and gcc 16, and in a ROOT master build, where the cppjit tests also pass with this change applied to the
ROOTbranch's copy ofinterop::GetScope.