r247018 - Fix performance regression when running clang tools.

Manuel Klimek via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 8 08:14:06 PDT 2015


Author: klimek
Date: Tue Sep  8 10:14:06 2015
New Revision: 247018

URL: http://llvm.org/viewvc/llvm-project?rev=247018&view=rev
Log:
Fix performance regression when running clang tools.

Brings tool start time for a large synthetic test case down from (on my
machine) 4 seconds to 0.5 seconds.

Modified:
    cfe/trunk/include/clang/Tooling/JSONCompilationDatabase.h
    cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp
    cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp

Modified: cfe/trunk/include/clang/Tooling/JSONCompilationDatabase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/JSONCompilationDatabase.h?rev=247018&r1=247017&r2=247018&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/JSONCompilationDatabase.h (original)
+++ cfe/trunk/include/clang/Tooling/JSONCompilationDatabase.h Tue Sep  8 10:14:06 2015
@@ -99,17 +99,21 @@ private:
   /// failed.
   bool parse(std::string &ErrorMessage);
 
-  // Tuple (directory, commandline) where 'commandline' pointing to the
-  // corresponding nodes in the YAML stream.
-  typedef std::pair<llvm::yaml::ScalarNode*,
-                    std::vector<std::string>> CompileCommandRef;
+  // Tuple (directory, commandline) where 'commandline' points to the
+  // corresponding scalar nodes in the YAML stream.
+  // If the command line contains a single argument, it is a shell-escaped
+  // command line.
+  // Otherwise, each entry in the command line vector is a literal
+  // argument to the compiler.
+  typedef std::pair<llvm::yaml::ScalarNode *,
+                    std::vector<llvm::yaml::ScalarNode *>> CompileCommandRef;
 
   /// \brief Converts the given array of CompileCommandRefs to CompileCommands.
   void getCommands(ArrayRef<CompileCommandRef> CommandsRef,
                    std::vector<CompileCommand> &Commands) const;
 
   // Maps file paths to the compile command lines for that file.
-  llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
+  llvm::StringMap<std::vector<CompileCommandRef>> IndexByFile;
 
   FileMatchTrie MatchTrie;
 

Modified: cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp?rev=247018&r1=247017&r2=247018&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp (original)
+++ cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp Tue Sep  8 10:14:06 2015
@@ -214,15 +214,26 @@ JSONCompilationDatabase::getAllCompileCo
   return Commands;
 }
 
+static std::vector<std::string>
+nodeToCommandLine(const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
+  SmallString<1024> Storage;
+  if (Nodes.size() == 1) {
+    return unescapeCommandLine(Nodes[0]->getValue(Storage));
+  }
+  std::vector<std::string> Arguments;
+  for (auto *Node : Nodes) {
+    Arguments.push_back(Node->getValue(Storage));
+  }
+  return Arguments;
+}
+
 void JSONCompilationDatabase::getCommands(
-                                  ArrayRef<CompileCommandRef> CommandsRef,
-                                  std::vector<CompileCommand> &Commands) const {
+    ArrayRef<CompileCommandRef> CommandsRef,
+    std::vector<CompileCommand> &Commands) const {
   for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
     SmallString<8> DirectoryStorage;
-    SmallString<1024> CommandStorage;
-    Commands.emplace_back(
-      CommandsRef[I].first->getValue(DirectoryStorage),
-      CommandsRef[I].second);
+    Commands.emplace_back(CommandsRef[I].first->getValue(DirectoryStorage),
+                          nodeToCommandLine(CommandsRef[I].second));
   }
 }
 
@@ -249,11 +260,8 @@ bool JSONCompilationDatabase::parse(std:
       return false;
     }
     llvm::yaml::ScalarNode *Directory = nullptr;
-    std::vector<std::string> Arguments;
-    std::vector<std::string> Command;
+    llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
     llvm::yaml::ScalarNode *File = nullptr;
-    bool ArgumentsFound = false;
-    bool CommandFound = false;
     for (auto& NextKeyValue : *Object) {
       llvm::yaml::ScalarNode *KeyString =
           dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -282,18 +290,18 @@ bool JSONCompilationDatabase::parse(std:
       if (KeyValue == "directory") {
         Directory = ValueString;
       } else if (KeyValue == "arguments") {
-        for (auto& NextArgument : *SequenceString) {
-          SmallString<128> CommandStorage;
-          auto ValueString = dyn_cast<llvm::yaml::ScalarNode>(&NextArgument);
-
-          Arguments.push_back(ValueString->getValue(CommandStorage));
+        Command = std::vector<llvm::yaml::ScalarNode *>();
+        for (auto &Argument : *SequenceString) {
+          auto Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
+          if (!Scalar) {
+            ErrorMessage = "Only strings are allowed in 'arguments'.";
+            return false;
+          }
+          Command->push_back(Scalar);
         }
-        ArgumentsFound = true;
       } else if (KeyValue == "command") {
-        SmallString<1024> CommandStorage;
-        // FIXME: Escape correctly:
-        Command = unescapeCommandLine(ValueString->getValue(CommandStorage));
-        CommandFound = true;
+        if (!Command)
+          Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
       } else if (KeyValue == "file") {
         File = ValueString;
       } else {
@@ -306,7 +314,7 @@ bool JSONCompilationDatabase::parse(std:
       ErrorMessage = "Missing key: \"file\".";
       return false;
     }
-    if (!ArgumentsFound && !CommandFound) {
+    if (!Command) {
       ErrorMessage = "Missing key: \"command\" or \"arguments\".";
       return false;
     }
@@ -327,7 +335,7 @@ bool JSONCompilationDatabase::parse(std:
       llvm::sys::path::native(FileName, NativeFilePath);
     }
     IndexByFile[NativeFilePath].push_back(
-        CompileCommandRef(Directory, ArgumentsFound ? Arguments : Command));
+        CompileCommandRef(Directory, *Command));
     MatchTrie.insert(NativeFilePath);
   }
   return true;

Modified: cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp?rev=247018&r1=247017&r2=247018&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp Tue Sep  8 10:14:06 2015
@@ -42,6 +42,8 @@ TEST(JSONCompilationDatabase, ErrsOnInva
   expectFailure("[{\"arguments\":\"\",\"file\":\"\"}]", "Missing directory");
   expectFailure("[{\"directory\":\"\",\"arguments\":\"\",\"file\":\"\"}]", "Arguments not array");
   expectFailure("[{\"directory\":\"\",\"command\":[],\"file\":\"\"}]", "Command not string");
+  expectFailure("[{\"directory\":\"\",\"arguments\":[[]],\"file\":\"\"}]",
+                "Arguments contain non-string");
 }
 
 static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
@@ -140,8 +142,8 @@ TEST(JSONCompilationDatabase, ArgumentsP
    CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
       FileName,
       ("[{\"directory\":\"" + Directory + "\","
-         "\"command\":\"" + Command + "\","
          "\"arguments\":[\"" + Arguments + "\"],"
+         "\"command\":\"" + Command + "\","
          "\"file\":\"" + FileName + "\"}]").str(),
       ErrorMessage);
    EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;




More information about the cfe-commits mailing list