-
Notifications
You must be signed in to change notification settings - Fork 1.5k
introduced a cache for followAllReferences()
calls
#7192
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -252,11 +252,7 @@ struct ReferenceToken { | |
ErrorPath errors; | ||
}; | ||
|
||
SmallVector<ReferenceToken> followAllReferences(const Token* tok, | ||
bool temporary = true, | ||
bool inconclusive = true, | ||
ErrorPath errors = ErrorPath{}, | ||
int depth = 20); | ||
SmallVector<ReferenceToken> followAllReferences(const Token* tok, bool temporary = true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we are removing the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The removed flags were not used outside of |
||
const Token* followReferences(const Token* tok, ErrorPath* errors = nullptr); | ||
|
||
CPPCHECKLIB bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors=nullptr); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2648,6 +2648,8 @@ TokenImpl::~TokenImpl() | |
delete mOriginalName; | ||
delete mValueType; | ||
delete mValues; | ||
delete mRefs; | ||
delete mRefsTemp; | ||
|
||
if (mTemplateSimplifierPointers) { | ||
for (auto *templateSimplifierPointer : *mTemplateSimplifierPointers) { | ||
|
@@ -2739,3 +2741,16 @@ void Token::templateArgFrom(const Token* fromToken) { | |
mImpl->mTemplateArgLineNumber = fromToken ? fromToken->mImpl->mLineNumber : -1; | ||
mImpl->mTemplateArgColumn = fromToken ? fromToken->mImpl->mColumn : -1; | ||
} | ||
|
||
const SmallVector<ReferenceToken>& Token::refs(bool temporary) const | ||
{ | ||
if (temporary) { | ||
if (!mImpl->mRefsTemp) | ||
mImpl->mRefsTemp = new SmallVector<ReferenceToken>(followAllReferences(this, true)); | ||
return *mImpl->mRefsTemp; | ||
} | ||
|
||
if (!mImpl->mRefs) | ||
mImpl->mRefs = new SmallVector<ReferenceToken>(followAllReferences(this, false)); | ||
return *mImpl->mRefs; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not the right way to do this. This is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I was about to add a comment about this. This violates the technical I am not sure how easy it would be to implement an earlier pass since it is not done for all tokens but there are lots of checks which are performed before we actually end up following references. That would need to be replicated I reckon - and that also has a certain visible overhead and we would need to run through that twice then. Actually I would also have the ValueFlow behave this way so we might avoid running it for code which is not relevant. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That should be totally fine (by precedent). We modify
Please disregard this. This is wishful thinking as this would not be possible the way the ValueFlow is working. I totally forgot I already looked into this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The const_cast should be fixed, but we shouldn't add more code that needs to be fixed. Also this is called in ValueFlowForward and ValueFlowReverse so its already called on almost every token in functionScopes, so it really won't help performance being a cache. Furthermore, in copcheck we update the tokens through passes rather than using a cache, this makes it easier to debug and we can provide this information to addons later on. So doing a pass in SymbolDatabase would be consistent with the rest of the code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Will give it a try and check how it impacts performance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we know if it causes a perf impact or how much? It seems we are making it worse for premature optimizations. There are other advantages to doing it the correct way too such as better debugging and addons can take advantage of this information (this seems like a useful analysis for addons). So if we enable it for addons then we will beed to run a pass regardless. Also you could consider skipping this for functions we are skipping analysis for, if the performance is too bad, but it would be good to see some actual numbers to make this decision.
This comment was marked as duplicate.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I meant to say "It seems like the currently best approach".
Various performance numbers are in the PR. It is a massive improvement. It would also help with the runtime of the CI.
That was an idea regarding the ValueFlow (see https://trac.cppcheck.net/ticket/12528) but that won't work since not all passes are based on function scopes. But that is currently out-of-scope and is something I am looking at within another context hopefully soon. It might actually not an issue after all because with the duplicated calls eliminated it basically no longer has any footprint. The only issue could be that we perform it for more tokens than we actually need so that would introduce new overhead but it might not be much. Will test that. Although I would prefer not to have that at all since all the overhead adds up - a lot. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized this is called when setting exprids, so it always called on every token regardless of ValueFlow analysis. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just gave it a small spin and it does not increase the Ir so that looks feasible. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
#include "config.h" | ||
#include "errortypes.h" | ||
#include "mathlib.h" | ||
#include "smallvector.h" | ||
#include "templatesimplifier.h" | ||
#include "utils.h" | ||
#include "vfvalue.h" | ||
|
@@ -53,6 +54,7 @@ class ConstTokenRange; | |
class Token; | ||
struct TokensFrontBack; | ||
class TokenList; | ||
struct ReferenceToken; | ||
|
||
struct ScopeInfo2 { | ||
ScopeInfo2(std::string name_, const Token *bodyEnd_, std::set<std::string> usingNamespaces_ = std::set<std::string>()) : name(std::move(name_)), bodyEnd(bodyEnd_), usingNamespaces(std::move(usingNamespaces_)) {} | ||
|
@@ -149,6 +151,9 @@ struct TokenImpl { | |
void setCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint value); | ||
bool getCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint &value) const; | ||
|
||
SmallVector<ReferenceToken>* mRefs{}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is going to be a pointer, you should use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I modeled it after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should model it after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That requires There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can just move the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, but It is unfortunate enough that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The spillage could be addressed by moving There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Onward into the next rabbithole: #7831. |
||
SmallVector<ReferenceToken>* mRefsTemp{}; | ||
|
||
TokenImpl() : mFunction(nullptr) {} | ||
|
||
~TokenImpl(); | ||
|
@@ -1349,6 +1354,9 @@ class CPPCHECKLIB Token { | |
return mImpl->mValues ? *mImpl->mValues : TokenImpl::mEmptyValueList; | ||
} | ||
|
||
// provides and caches result of a followAllReferences() call | ||
const SmallVector<ReferenceToken>& refs(bool temporary = true) const; | ||
|
||
/** | ||
* Sets the original name. | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -647,7 +647,8 @@ struct ValueFlowAnalyzer : Analyzer { | |
if (invalid()) | ||
return Action::Invalid; | ||
// Follow references | ||
auto refs = followAllReferences(tok); | ||
// TODO: avoid copy | ||
auto refs = tok->refs(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This copy is necessary since an additional entry is being added. But I think this is not necessary and I will try to refactor the code to avoid it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I adjusted this by unfortunately there is some redundant code introduced. |
||
const bool inconclusiveRefs = refs.size() != 1; | ||
if (std::none_of(refs.cbegin(), refs.cend(), [&](const ReferenceToken& ref) { | ||
return tok == ref.token; | ||
|
Uh oh!
There was an error while loading. Please reload this page.