diff --git a/clang-tools-extra/clangd/index/remote/Client.cpp b/clang-tools-extra/clangd/index/remote/Client.cpp --- a/clang-tools-extra/clangd/index/remote/Client.cpp +++ b/clang-tools-extra/clangd/index/remote/Client.cpp @@ -37,12 +37,15 @@ bool FinalResult = false; trace::Span Tracer(RequestT::descriptor()->name()); const auto RPCRequest = ProtobufMarshaller->toProtobuf(Request); + SPAN_ATTACH(Tracer, "Request", RPCRequest.DebugString()); grpc::ClientContext Context; std::chrono::system_clock::time_point Deadline = std::chrono::system_clock::now() + DeadlineWaitingTime; Context.set_deadline(Deadline); auto Reader = (Stub.get()->*RPCCall)(&Context, RPCRequest); ReplyT Reply; + unsigned Successful = 0; + unsigned FailedToParse = 0; while (Reader->Read(&Reply)) { if (!Reply.has_stream_result()) { FinalResult = Reply.final_result(); @@ -51,11 +54,15 @@ auto Response = ProtobufMarshaller->fromProtobuf(Reply.stream_result()); if (!Response) { elog("Received invalid {0}", ReplyT::descriptor()->name()); + ++FailedToParse; continue; } Callback(*Response); + ++Successful; } - SPAN_ATTACH(Tracer, "status", Reader->Finish().ok()); + SPAN_ATTACH(Tracer, "Status", Reader->Finish().ok()); + SPAN_ATTACH(Tracer, "Successful", Successful); + SPAN_ATTACH(Tracer, "Failed to parse", FailedToParse); return FinalResult; } diff --git a/clang-tools-extra/clangd/index/remote/server/Server.cpp b/clang-tools-extra/clangd/index/remote/server/Server.cpp --- a/clang-tools-extra/clangd/index/remote/server/Server.cpp +++ b/clang-tools-extra/clangd/index/remote/server/Server.cpp @@ -8,7 +8,10 @@ #include "index/Index.h" #include "index/Serialization.h" +#include "index/Symbol.h" #include "index/remote/marshalling/Marshalling.h" +#include "support/Logger.h" +#include "support/Trace.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Path.h" @@ -16,6 +19,7 @@ #include #include +#include #include "Index.grpc.pb.h" @@ -35,6 +39,16 @@ llvm::cl::opt IndexRoot(llvm::cl::desc(""), llvm::cl::Positional, llvm::cl::Required); +llvm::cl::opt TracerFile( + "tracer-file", + llvm::cl::desc("Path to the file where tracer logs will be stored")); + +llvm::cl::opt PrettyPrint{ + "pretty", + llvm::cl::desc("Pretty-print JSON output in the trace"), + llvm::cl::init(false), +}; + llvm::cl::opt ServerAddress( "server-address", llvm::cl::init("0.0.0.0:50051"), llvm::cl::desc("Address of the invoked server. Defaults to 0.0.0.0:50051")); @@ -56,24 +70,63 @@ } private: + template + typename std::result_of::type + streamRPC(const RequestT *Request, grpc::ServerWriter *Reply, + ClangdRequestT ClangdRequest, IndexCall &&Call) { + // Adding Sent and FailedToSend messages to the tracer has to happen after + // Callback but the temporary value can not be stored. Use a dummy struct + // to hold data for tracer and then add data to the trace on destruction + // happening after the callback. + struct TracerCounter { + trace::Span Tracer; + unsigned Sent = 0; + unsigned FailedToSend = 0; + TracerCounter(llvm::StringRef RequestInfo) + : Tracer(RequestT::descriptor()->name()) { + SPAN_ATTACH(Tracer, "Request", RequestInfo); + } + ~TracerCounter() { + SPAN_ATTACH(Tracer, "Sent", Sent); + SPAN_ATTACH(Tracer, "Failed to send", FailedToSend); + } + } Counter(Request->DebugString()); + return std::forward(Call)( + *Index, ClangdRequest, [&](const StreamType &Item) { + auto SerializedItem = ProtobufMarshaller->toProtobuf(Item); + if (!SerializedItem) { + ++Counter.FailedToSend; + return; + } + ReplyT NextMessage; + *NextMessage.mutable_stream_result() = *SerializedItem; + Reply->Write(NextMessage); + ++Counter.Sent; + }); + } + grpc::Status Lookup(grpc::ServerContext *Context, const LookupRequest *Request, grpc::ServerWriter *Reply) override { clangd::LookupRequest Req; for (const auto &ID : Request->ids()) { auto SID = SymbolID::fromStr(StringRef(ID)); - if (!SID) + if (!SID) { + elog("Lookup request cancelled: invalid SymbolID {1}", SID.takeError()); return grpc::Status::CANCELLED; + } Req.IDs.insert(*SID); } - Index->lookup(Req, [&](const clangd::Symbol &Sym) { - auto SerializedSymbol = ProtobufMarshaller->toProtobuf(Sym); - if (!SerializedSymbol) - return; - LookupReply NextMessage; - *NextMessage.mutable_stream_result() = *SerializedSymbol; - Reply->Write(NextMessage); - }); + std::function)> + IndexCall = &clangd::SymbolIndex::lookup; + streamRPC>( + Request, Reply, Req, std::move(IndexCall)); LookupReply LastMessage; LastMessage.set_final_result(true); Reply->Write(LastMessage); @@ -84,14 +137,15 @@ const FuzzyFindRequest *Request, grpc::ServerWriter *Reply) override { const auto Req = ProtobufMarshaller->fromProtobuf(Request); - bool HasMore = Index->fuzzyFind(Req, [&](const clangd::Symbol &Sym) { - auto SerializedSymbol = ProtobufMarshaller->toProtobuf(Sym); - if (!SerializedSymbol) - return; - FuzzyFindReply NextMessage; - *NextMessage.mutable_stream_result() = *SerializedSymbol; - Reply->Write(NextMessage); - }); + std::function)> + IndexCall = &clangd::SymbolIndex::fuzzyFind; + bool HasMore = + streamRPC>( + Request, Reply, Req, std::move(IndexCall)); FuzzyFindReply LastMessage; LastMessage.set_final_result(HasMore); Reply->Write(LastMessage); @@ -103,18 +157,20 @@ clangd::RefsRequest Req; for (const auto &ID : Request->ids()) { auto SID = SymbolID::fromStr(StringRef(ID)); - if (!SID) + if (!SID) { + elog("Refs request cancelled: invalid SymbolID {1}", SID.takeError()); return grpc::Status::CANCELLED; + } Req.IDs.insert(*SID); } - bool HasMore = Index->refs(Req, [&](const clangd::Ref &Reference) { - auto SerializedRef = ProtobufMarshaller->toProtobuf(Reference); - if (!SerializedRef) - return; - RefsReply NextMessage; - *NextMessage.mutable_stream_result() = *SerializedRef; - Reply->Write(NextMessage); - }); + std::function)> + IndexCall = &clangd::SymbolIndex::refs; + bool HasMore = streamRPC>( + Request, Reply, Req, std::move(IndexCall)); RefsReply LastMessage; LastMessage.set_final_result(HasMore); Reply->Write(LastMessage); @@ -154,6 +210,29 @@ return -1; } + llvm::Optional TracerStream; + std::unique_ptr Tracer; + if (!TracerFile.empty()) { + std::error_code EC; + TracerStream.emplace(TracerFile, EC, + llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write); + if (EC) { + TracerStream.reset(); + llvm::errs() << "Error while opening trace file " << TracerFile << ": " + << EC.message(); + } else { + // FIXME(kirillbobyrev): Also create metrics tracer to track latency and + // accumulate other request statistics. + Tracer = + clang::clangd::trace::createJSONTracer(*TracerStream, PrettyPrint); + llvm::outs() << "Successfully created a tracer.\n"; + } + } + + llvm::Optional TracingSession; + if (Tracer) + TracingSession.emplace(*Tracer); + std::unique_ptr Index = openIndex(IndexPath); if (!Index) {