Performance tracing facility for clangd.

Summary:
This lets you visualize clangd's activity on different threads over time,
and understand critical paths of requests and object lifetimes.
The data produced can be visualized in Chrome (at chrome://tracing), or
in a standalone copy of catapult (http://github.com/catapult-project/catapult)

This patch consists of:
 - a command line flag "-trace" that causes clangd to emit JSON trace data
 - an API (in Trace.h) allowing clangd code to easily add events to the stream
 - several initial uses of this API to capture JSON-RPC requests, builds, logs

Example result: https://photos.app.goo.gl/12L9swaz5REGQ1rm1

Caveats:
 - JSON serialization is ad-hoc (isn't it everywhere?) so the API is
   limited to naming events rather than attaching arbitrary metadata.
   I'd like to fix this (I think we could use a JSON-object abstraction).
 - The recording is very naive: events are written immediately by
   locking a mutex. Contention on the mutex might disturb performance.
 - For now it just traces instants or spans on the current thread.
   There are other things that make sense to show (cross-thread flows,
   non-thread resources such as ASTs). But we have to start somewhere.

Reviewers: ioeric, ilya-biryukov

Subscribers: cfe-commits, mgorny

Differential Revision: https://reviews.llvm.org/D39086

llvm-svn: 317193
diff --git a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
index 0aa1f39..121ddb9 100644
--- a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
+++ b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
@@ -9,6 +9,7 @@
 
 #include "JSONRPCDispatcher.h"
 #include "ProtocolHandlers.h"
+#include "Trace.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/YAMLParser.h"
@@ -32,6 +33,7 @@
 }
 
 void JSONOutput::log(const Twine &Message) {
+  trace::log(Message);
   std::lock_guard<std::mutex> Guard(StreamMutex);
   Logs << Message;
   Logs.flush();
@@ -75,8 +77,10 @@
             llvm::yaml::MappingNode *Params,
             const JSONRPCDispatcher::Handler &UnknownHandler, JSONOutput &Out) {
   llvm::SmallString<64> MethodStorage;
-  auto I = Handlers.find(Method->getValue(MethodStorage));
+  llvm::StringRef MethodStr = Method->getValue(MethodStorage);
+  auto I = Handlers.find(MethodStr);
   auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
+  trace::Span Tracer(MethodStr);
   Handler(RequestContext(Out, Id ? Id->getRawValue() : ""), Params);
 }
 
@@ -206,21 +210,27 @@
     }
 
     if (ContentLength > 0) {
-      // Now read the JSON. Insert a trailing null byte as required by the YAML
-      // parser.
       std::vector<char> JSON(ContentLength + 1, '\0');
-      In.read(JSON.data(), ContentLength);
-      Out.mirrorInput(StringRef(JSON.data(), In.gcount()));
+      llvm::StringRef JSONRef;
+      {
+        trace::Span Tracer("Reading request");
+        // Now read the JSON. Insert a trailing null byte as required by the
+        // YAML parser.
+        In.read(JSON.data(), ContentLength);
+        Out.mirrorInput(StringRef(JSON.data(), In.gcount()));
 
-      // If the stream is aborted before we read ContentLength bytes, In
-      // will have eofbit and failbit set.
-      if (!In) {
-        Out.log("Input was aborted. Read only " + std::to_string(In.gcount()) +
-                " bytes of expected " + std::to_string(ContentLength) + ".\n");
-        break;
+        // If the stream is aborted before we read ContentLength bytes, In
+        // will have eofbit and failbit set.
+        if (!In) {
+          Out.log("Input was aborted. Read only " +
+                  std::to_string(In.gcount()) + " bytes of expected " +
+                  std::to_string(ContentLength) + ".\n");
+          break;
+        }
+
+        JSONRef = StringRef(JSON.data(), ContentLength);
       }
 
-      llvm::StringRef JSONRef(JSON.data(), ContentLength);
       // Log the message.
       Out.log("<-- " + JSONRef + "\n");