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

[clang-tidy] Improve performance of google-runtime-int #86596

Conversation

PiotrZSL
Copy link
Member

Main problem with performance of this check is caused by hasAncestor matcher, and to be more precise by an llvm::DenseSet and std::deque in matchesAnyAncestorOf.

To reduce impact of this matcher, multiple conditions that were checked in check method were copied into AST matcher that is now checked before hasAncestor.

Using custom getCheckTraversalKind to exclude template instances that shouldn't be checked anyway is an additional improvement, but gain from that one is low.

Tested on ffl_tests.cc, visible reduction from ~442 seconds to ~15 seconds (~96% reduction).

Closes #86553

Main problem with performance of this check is caused by hasAncestor matcher,
and to be more precise by an llvm::DenseSet and std::deque in matchesAnyAncestorOf.

To reduce impact of this matcher, multiple conditions that were
checked in check method were copied into ast matcher that is now checked
before hasAncestor.

Using custom getCheckTraversalKind to exclude template instances that
shouldn't be checked anyway is an additional improvment, but gain
from that one is low.

Tested on ffl_tests.cc, visible reduction from ~442 seconds to
~15 seconds (~96% reduction).

Closes llvm#86553
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 25, 2024

@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang-tools-extra

Author: Piotr Zegar (PiotrZSL)

Changes

Main problem with performance of this check is caused by hasAncestor matcher, and to be more precise by an llvm::DenseSet and std::deque in matchesAnyAncestorOf.

To reduce impact of this matcher, multiple conditions that were checked in check method were copied into AST matcher that is now checked before hasAncestor.

Using custom getCheckTraversalKind to exclude template instances that shouldn't be checked anyway is an additional improvement, but gain from that one is low.

Tested on ffl_tests.cc, visible reduction from ~442 seconds to ~15 seconds (~96% reduction).

Closes #86553


Full diff: https://github.com/llvm/llvm-project/pull/86596.diff

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp (+33-8)
  • (modified) clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h (+3)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+3)
diff --git a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp
index ef511e9108f2ee..359d8efd100bad 100644
--- a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp
@@ -40,6 +40,34 @@ namespace {
 AST_MATCHER(FunctionDecl, isUserDefineLiteral) {
   return Node.getLiteralIdentifier() != nullptr;
 }
+
+AST_MATCHER(TypeLoc, isValidAndNotInMacro) {
+  const SourceLocation Loc = Node.getBeginLoc();
+  return Loc.isValid() && !Loc.isMacroID();
+}
+
+AST_MATCHER(TypeLoc, isBuiltinType) {
+  TypeLoc TL = Node;
+  if (auto QualLoc = Node.getAs<QualifiedTypeLoc>())
+    TL = QualLoc.getUnqualifiedLoc();
+
+  const auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>();
+  if (!BuiltinLoc)
+    return false;
+
+  switch (BuiltinLoc.getTypePtr()->getKind()) {
+  case BuiltinType::Short:
+  case BuiltinType::Long:
+  case BuiltinType::LongLong:
+  case BuiltinType::UShort:
+  case BuiltinType::ULong:
+  case BuiltinType::ULongLong:
+    return true;
+  default:
+    return false;
+  }
+}
+
 } // namespace
 
 namespace tidy::google::runtime {
@@ -63,11 +91,11 @@ void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) {
   // "Where possible, avoid passing arguments of types specified by
   // bitwidth typedefs to printf-based APIs."
   Finder->addMatcher(
-      typeLoc(loc(isInteger()),
-              unless(anyOf(hasAncestor(callExpr(
-                               callee(functionDecl(hasAttr(attr::Format))))),
-                           hasParent(parmVarDecl(hasAncestor(
-                               functionDecl(isUserDefineLiteral())))))))
+      typeLoc(loc(isInteger()), isValidAndNotInMacro(), isBuiltinType(),
+              unless(hasAncestor(
+                  callExpr(callee(functionDecl(hasAttr(attr::Format)))))),
+              unless(hasParent(parmVarDecl(
+                  hasAncestor(functionDecl(isUserDefineLiteral()))))))
           .bind("tl"),
       this);
   IdentTable = std::make_unique<IdentifierTable>(getLangOpts());
@@ -77,9 +105,6 @@ void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) {
   auto TL = *Result.Nodes.getNodeAs<TypeLoc>("tl");
   SourceLocation Loc = TL.getBeginLoc();
 
-  if (Loc.isInvalid() || Loc.isMacroID())
-    return;
-
   // Look through qualification.
   if (auto QualLoc = TL.getAs<QualifiedTypeLoc>())
     TL = QualLoc.getUnqualifiedLoc();
diff --git a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h
index 3be7d24021b9ff..c62bda67ae2d98 100644
--- a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h
+++ b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h
@@ -35,6 +35,9 @@ class IntegerTypesCheck : public ClangTidyCheck {
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
 
 private:
   const StringRef UnsignedTypePrefix;
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a604e9276668ae..4d1cd57c2fd478 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -197,6 +197,9 @@ Changes in existing checks
   <clang-tidy/checks/google/global-names-in-headers>` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
 
+- Improved :doc:`google-runtime-int <clang-tidy/checks/google/runtime-int>`
+  check performance through optimizations.
+
 - Improved :doc:`llvm-header-guard
   <clang-tidy/checks/llvm/header-guard>` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.

@PiotrZSL PiotrZSL requested a review from ilovepi March 25, 2024 22:50
Copy link
Contributor

@5chmidti 5chmidti left a comment

Choose a reason for hiding this comment

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

LGTM. That's a very nice speedup :)

Copy link
Contributor

@ilovepi ilovepi left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for the quick fix. I’ll try this out later today and let you know if this completely solves the issue or if there is something else that may still warrant investigating.

@ilovepi
Copy link
Contributor

ilovepi commented Mar 26, 2024

Well, its down to about 15 minutes from 1hr 40 min, which is a pretty great improvement. 15 minutes does still seem to be too long for a file that's only 2KLOC. I know its more complex w/ headers and macros, but it does only take about 1-2 minutes to compile normally, so I feel like it should finish a bit faster than what I'm currently seeing with this patch. But overall, I'm pretty thrilled to see this massive improvement!. Thanks.

@PiotrZSL
Copy link
Member Author

I will go with merging this. There are still few improvements possible, but they require partial check rewrite.
I may to work on some PoC. You could test with additional matcher (at the beginning): unless(isExpansionInSystemHeader()) and see if excluding system headers helps more.

@PiotrZSL PiotrZSL merged commit 5e6e40f into llvm:main Mar 26, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

clang-tidy performance issues in template and consexpr heavy code
4 participants