Move using below #include to make preamble happy
textDocument/references: if no references, first line or last line => list where this file is included
malloc_trim() only if files have been indexed in last cycle
Intern: use CachedHashStringRef
This commit is contained in:
Fangrui Song 2018-09-23 12:10:40 -07:00
parent 32f7d148ca
commit 854225bd30
22 changed files with 87 additions and 71 deletions

View File

@ -175,7 +175,9 @@ std::unique_ptr<CompilerInstance> BuildCompilerInstance(
CompletionSession &session, std::unique_ptr<CompilerInvocation> CI, CompletionSession &session, std::unique_ptr<CompilerInvocation> CI,
DiagnosticConsumer &DC, const WorkingFiles::Snapshot &snapshot, DiagnosticConsumer &DC, const WorkingFiles::Snapshot &snapshot,
std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Bufs) { std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Bufs) {
std::string main = ResolveIfRelative(session.file.directory, CI->getFrontendOpts().Inputs[0].getFile()); std::string main = ResolveIfRelative(
session.file.directory,
sys::path::convert_to_slash(CI->getFrontendOpts().Inputs[0].getFile()));
for (auto &file : snapshot.files) { for (auto &file : snapshot.files) {
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(file.content)); Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(file.content));
if (file.filename == main) if (file.filename == main)

View File

@ -22,7 +22,6 @@ limitations under the License.
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.h" #include "platform.h"
#include "serializer.h" #include "serializer.h"
using namespace ccls;
#include <clang/AST/AST.h> #include <clang/AST/AST.h>
#include <clang/Frontend/FrontendAction.h> #include <clang/Frontend/FrontendAction.h>
@ -33,16 +32,15 @@ using namespace ccls;
#include <llvm/ADT/DenseSet.h> #include <llvm/ADT/DenseSet.h>
#include <llvm/Support/CrashRecoveryContext.h> #include <llvm/Support/CrashRecoveryContext.h>
#include <llvm/Support/Path.h> #include <llvm/Support/Path.h>
#include <llvm/Support/Timer.h>
using namespace clang;
using llvm::Timer;
#include <algorithm> #include <algorithm>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <map> #include <map>
#include <unordered_set> #include <unordered_set>
using namespace ccls;
using namespace clang;
namespace { namespace {
constexpr int kInitializerMaxLines = 3; constexpr int kInitializerMaxLines = 3;
@ -509,7 +507,7 @@ public:
def.short_name_offset = Str.size() + qualified.size() - short_name.size(); def.short_name_offset = Str.size() + qualified.size() - short_name.size();
def.short_name_size = short_name.size(); def.short_name_size = short_name.size();
Str += StringRef(qualified.data(), qualified.size()); Str += StringRef(qualified.data(), qualified.size());
def.detailed_name = Intern(Str.str()); def.detailed_name = Intern(Str);
} else { } else {
SetName(D, short_name, qualified, def); SetName(D, short_name, qualified, def);
} }

View File

@ -30,7 +30,6 @@ limitations under the License.
#include <llvm/ADT/DenseMap.h> #include <llvm/ADT/DenseMap.h>
#include <algorithm> #include <algorithm>
#include <optional>
#include <stdint.h> #include <stdint.h>
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>

View File

@ -20,15 +20,12 @@ limitations under the License.
#include "serializers/json.h" #include "serializers/json.h"
#include "test.h" #include "test.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <llvm/Support/CommandLine.h> #include <llvm/Support/CommandLine.h>
#include <llvm/Support/CrashRecoveryContext.h> #include <llvm/Support/CrashRecoveryContext.h>
#include <llvm/Support/Process.h> #include <llvm/Support/Process.h>
#include <llvm/Support/Program.h> #include <llvm/Support/Program.h>
#include <llvm/Support/Signals.h> #include <llvm/Support/Signals.h>
using namespace llvm;
using namespace llvm::cl;
#include <rapidjson/error/en.h> #include <rapidjson/error/en.h>
@ -38,6 +35,10 @@ using namespace llvm::cl;
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
using namespace ccls;
using namespace llvm;
using namespace llvm::cl;
std::string g_init_options; std::string g_init_options;
namespace { namespace {

View File

@ -87,7 +87,6 @@ MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, jsonrpc, method,
struct MessageHandler { struct MessageHandler {
DB *db = nullptr; DB *db = nullptr;
MultiQueueWaiter *waiter = nullptr;
Project *project = nullptr; Project *project = nullptr;
VFS *vfs = nullptr; VFS *vfs = nullptr;
SemanticHighlight *highlight = nullptr; SemanticHighlight *highlight = nullptr;

View File

@ -17,10 +17,11 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
using namespace ccls;
#include <unordered_set> #include <unordered_set>
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/call"; MethodType kMethodType = "$ccls/call";

View File

@ -17,14 +17,15 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
using namespace ccls;
#include <clang/AST/Type.h> #include <clang/AST/Type.h>
#include <llvm/ADT/DenseSet.h> #include <llvm/ADT/DenseSet.h>
using namespace clang;
#include <unordered_set> #include <unordered_set>
using namespace ccls;
using namespace clang;
namespace { namespace {
MethodType kMethodType = "$ccls/member"; MethodType kMethodType = "$ccls/member";

View File

@ -17,14 +17,14 @@ limitations under the License.
#include "match.h" #include "match.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.h"
#include "project.h" #include "project.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <queue> #include <queue>
#include <unordered_set> #include <unordered_set>
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/reload"; MethodType kMethodType = "$ccls/reload";
@ -34,8 +34,7 @@ struct In_CclsReload : public NotificationInMessage {
bool dependencies = true; bool dependencies = true;
std::vector<std::string> whitelist; std::vector<std::string> whitelist;
std::vector<std::string> blacklist; std::vector<std::string> blacklist;
}; } params;
Params params;
}; };
MAKE_REFLECT_STRUCT(In_CclsReload::Params, dependencies, whitelist, MAKE_REFLECT_STRUCT(In_CclsReload::Params, dependencies, whitelist,
blacklist); blacklist);

View File

@ -23,16 +23,16 @@ limitations under the License.
#include "project.h" #include "project.h"
#include "serializers/json.h" #include "serializers/json.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <llvm/ADT/Twine.h> #include <llvm/ADT/Twine.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
using namespace llvm;
#include <iostream>
#include <stdexcept> #include <stdexcept>
#include <thread> #include <thread>
using namespace ccls;
using namespace llvm;
// TODO Cleanup global variables // TODO Cleanup global variables
extern std::string g_init_options; extern std::string g_init_options;

View File

@ -20,16 +20,16 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <clang/Sema/CodeCompleteConsumer.h> #include <clang/Sema/CodeCompleteConsumer.h>
#include <clang/Sema/Sema.h> #include <clang/Sema/Sema.h>
#include <llvm/Support/Timer.h>
using namespace clang;
using namespace llvm;
#include <regex> #include <regex>
using namespace ccls;
using namespace clang;
using namespace llvm;
namespace { namespace {
MethodType kMethodType = "textDocument/completion"; MethodType kMethodType = "textDocument/completion";
@ -179,10 +179,6 @@ void FilterAndSortCompletionResponse(
const std::string &complete_text, bool has_open_paren) { const std::string &complete_text, bool has_open_paren) {
if (!g_config->completion.filterAndSort) if (!g_config->completion.filterAndSort)
return; return;
static Timer timer("FilterAndSortCompletionResponse", "");
TimeRegion region(timer);
auto &items = complete_response->result.items; auto &items = complete_response->result.items;
auto finalize = [&]() { auto finalize = [&]() {

View File

@ -16,11 +16,12 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
using namespace ccls;
#include <cstdlib>
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/definition"; MethodType kMethodType = "textDocument/definition";

View File

@ -26,8 +26,7 @@ struct In_TextDocumentDidClose : public NotificationInMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
}; } params;
Params params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentDidClose::Params, textDocument); MAKE_REFLECT_STRUCT(In_TextDocumentDidClose::Params, textDocument);
MAKE_REFLECT_STRUCT(In_TextDocumentDidClose, params); MAKE_REFLECT_STRUCT(In_TextDocumentDidClose, params);

View File

@ -24,7 +24,6 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/didOpen"; MethodType kMethodType = "textDocument/didOpen";
// Open, view, change, close file
struct In_TextDocumentDidOpen : public NotificationInMessage { struct In_TextDocumentDidOpen : public NotificationInMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
@ -49,7 +48,7 @@ struct Handler_TextDocumentDidOpen
// NOTE: This function blocks code lens. If it starts taking a long time // NOTE: This function blocks code lens. If it starts taking a long time
// we will need to find a way to unblock the code lens request. // we will need to find a way to unblock the code lens request.
const auto &params = request->params; const auto &params = request->params;
std::string path = params.textDocument.uri.GetPath(); const std::string &path = params.textDocument.uri.GetPath();
WorkingFile *working_file = working_files->OnOpen(params.textDocument); WorkingFile *working_file = working_files->OnOpen(params.textDocument);
if (std::optional<std::string> cached_file_contents = if (std::optional<std::string> cached_file_contents =

View File

@ -16,7 +16,6 @@ limitations under the License.
#include "clang_complete.hh" #include "clang_complete.hh"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.h"
using namespace ccls; using namespace ccls;
namespace { namespace {
@ -44,7 +43,7 @@ struct Handler_TextDocumentDidSave
void Run(In_TextDocumentDidSave *request) override { void Run(In_TextDocumentDidSave *request) override {
const auto &params = request->params; const auto &params = request->params;
std::string path = params.textDocument.uri.GetPath(); const std::string &path = params.textDocument.uri.GetPath();
pipeline::Index(path, {}, IndexMode::Normal); pipeline::Index(path, {}, IndexMode::Normal);
clang_complete->NotifySave(path); clang_complete->NotifySave(path);
} }

View File

@ -16,10 +16,11 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
using namespace ccls;
#include <unordered_set> #include <unordered_set>
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/references"; MethodType kMethodType = "textDocument/references";
@ -66,13 +67,17 @@ struct Handler_TextDocumentReferences
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
Out_TextDocumentReferences out; Out_TextDocumentReferences out;
out.id = request->id; out.id = request->id;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
if (!file) {
pipeline::WriteStdout(kMethodType, out);
return;
}
bool container = g_config->xref.container; bool container = g_config->xref.container;
std::unordered_set<Use> seen_uses; std::unordered_set<Use> seen_uses;
int line = params.position.line;
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) { for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) {
// Found symbol. Return references. // Found symbol. Return references.
@ -127,7 +132,7 @@ struct Handler_TextDocumentReferences
// = 0, // = 0,
// use the current filename. // use the current filename.
std::string path; std::string path;
if (params.position.line == 0) if (line == 0 || line >= (int)wfile->buffer_lines.size() - 1)
path = file->def->path; path = file->def->path;
for (const IndexInclude &include : file->def->includes) for (const IndexInclude &include : file->def->includes)
if (include.line == params.position.line) { if (include.line == params.position.line) {

View File

@ -16,12 +16,11 @@ limitations under the License.
#include "clang_complete.hh" #include "clang_complete.hh"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
using namespace ccls;
#include <clang/Sema/Sema.h> #include <clang/Sema/Sema.h>
using namespace clang;
#include <stdint.h> using namespace ccls;
using namespace clang;
namespace { namespace {
MethodType kMethodType = "textDocument/signatureHelp"; MethodType kMethodType = "textDocument/signatureHelp";

View File

@ -17,13 +17,14 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
using namespace ccls;
#include <algorithm> #include <algorithm>
#include <ctype.h> #include <ctype.h>
#include <functional> #include <functional>
#include <limits.h> #include <limits.h>
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "workspace/symbol"; MethodType kMethodType = "workspace/symbol";

View File

@ -490,7 +490,6 @@ void MainLoop() {
// Setup shared references. // Setup shared references.
for (MessageHandler *handler : *MessageHandler::message_handlers) { for (MessageHandler *handler : *MessageHandler::message_handlers) {
handler->db = &db; handler->db = &db;
handler->waiter = indexer_waiter;
handler->project = &project; handler->project = &project;
handler->vfs = &vfs; handler->vfs = &vfs;
handler->highlight = &highlight; handler->highlight = &highlight;
@ -499,6 +498,7 @@ void MainLoop() {
handler->include_complete = &include_complete; handler->include_complete = &include_complete;
} }
bool last_indexed = false;
while (true) { while (true) {
std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll(); std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll();
bool did_work = messages.size(); bool did_work = messages.size();
@ -515,18 +515,22 @@ void MainLoop() {
LOG_S(ERROR) << "No handler for " << message->GetMethodType(); LOG_S(ERROR) << "No handler for " << message->GetMethodType();
} }
for (int i = 80; i--;) { bool indexed = false;
for (int i = 20; i--;) {
std::optional<IndexUpdate> update = on_indexed->TryPopFront(); std::optional<IndexUpdate> update = on_indexed->TryPopFront();
if (!update) if (!update)
break; break;
did_work = true; did_work = true;
indexed = true;
Main_OnIndexed(&db, &highlight, &working_files, &*update); Main_OnIndexed(&db, &highlight, &working_files, &*update);
} }
if (!did_work) { if (!did_work) {
FreeUnusedMemory(); if (last_indexed)
FreeUnusedMemory();
main_waiter->Wait(on_indexed, on_request); main_waiter->Wait(on_indexed, on_request);
} }
last_indexed = indexed;
} }
} }

View File

@ -113,7 +113,7 @@ std::string NormalizePath(const std::string &path) {
void FreeUnusedMemory() { void FreeUnusedMemory() {
#ifdef __GLIBC__ #ifdef __GLIBC__
malloc_trim(0); malloc_trim(4 * 1024 * 1024);
#endif #endif
} }

View File

@ -25,18 +25,14 @@ limitations under the License.
#include "serializers/json.h" #include "serializers/json.h"
#include "utils.h" #include "utils.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <clang/Driver/Compilation.h> #include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h> #include <clang/Driver/Driver.h>
#include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CompilationDatabase.h> #include <clang/Tooling/CompilationDatabase.h>
#include <llvm/ADT/ArrayRef.h>
#include <llvm/ADT/STLExtras.h> #include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringSet.h> #include <llvm/ADT/StringSet.h>
#include <llvm/Support/LineIterator.h> #include <llvm/Support/LineIterator.h>
using namespace clang;
using namespace llvm;
#include <rapidjson/writer.h> #include <rapidjson/writer.h>
@ -44,10 +40,14 @@ using namespace llvm;
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <limits> #include <limits.h>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
using namespace ccls;
using namespace clang;
using namespace llvm;
namespace { namespace {
enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand }; enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand };
@ -399,7 +399,7 @@ Project::FindCompilationEntryForFile(const std::string &filename) {
// We couldn't find the file. Try to infer it. // We couldn't find the file. Try to infer it.
// TODO: Cache inferred file in a separate array (using a lock or similar) // TODO: Cache inferred file in a separate array (using a lock or similar)
Entry *best_entry = nullptr; Entry *best_entry = nullptr;
int best_score = std::numeric_limits<int>::min(); int best_score = INT_MIN;
for (Entry &entry : entries) { for (Entry &entry : entries) {
int score = ComputeGuessScore(filename, entry.filename); int score = ComputeGuessScore(filename, entry.filename);
if (score > best_score) { if (score > best_score) {

View File

@ -166,12 +166,11 @@ void Reflect(Reader &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
if (vis.Format() == SerializeFormat::Json) { if (vis.Format() == SerializeFormat::Json) {
auto &vis1 = static_cast<JsonReader&>(vis); auto &vis1 = static_cast<JsonReader&>(vis);
for (auto it = vis1.m().MemberBegin(); it != vis1.m().MemberEnd(); ++it) for (auto it = vis1.m().MemberBegin(); it != vis1.m().MemberEnd(); ++it)
v[CachedHashStringRef(Intern(it->name.GetString()))] = v[InternH(it->name.GetString())] = it->value.GetInt64();
it->value.GetInt64();
} else { } else {
vis.IterArray([&](Reader &entry) { vis.IterArray([&](Reader &entry) {
Reflect(entry, name); Reflect(entry, name);
Reflect(entry, v[CachedHashStringRef(Intern(name))]); Reflect(entry, v[InternH(name)]);
}); });
} }
} }
@ -356,18 +355,26 @@ void Reflect(Writer &visitor, SerializeFormat &value) {
namespace ccls { namespace ccls {
static BumpPtrAllocator Alloc; static BumpPtrAllocator Alloc;
static DenseSet<StringRef> Strings; static DenseSet<CachedHashStringRef> Strings;
static std::mutex AllocMutex; static std::mutex AllocMutex;
const char *Intern(const std::string &str) { CachedHashStringRef InternH(StringRef S) {
if (str.empty()) if (S.empty())
return ""; S = "";
StringRef Str(str.data(), str.size() + 1); CachedHashString HS(S);
std::lock_guard lock(AllocMutex); std::lock_guard lock(AllocMutex);
auto R = Strings.insert(Str); auto R = Strings.insert(HS);
if (R.second) if (R.second) {
*R.first = Str.copy(Alloc); char *P = Alloc.Allocate<char>(S.size() + 1);
return R.first->data(); memcpy(P, S.data(), S.size());
P[S.size()] = '\0';
*R.first = CachedHashStringRef(StringRef(P, S.size()), HS.hash());
}
return *R.first;
}
const char *Intern(StringRef S) {
return InternH(S).val().data();
} }
std::string Serialize(SerializeFormat format, IndexFile &file) { std::string Serialize(SerializeFormat format, IndexFile &file) {
@ -482,7 +489,7 @@ Deserialize(SerializeFormat format, const std::string &path,
for (auto &it : file->dependencies) { for (auto &it : file->dependencies) {
std::string path = it.first.val().str(); std::string path = it.first.val().str();
DoPathMapping(path); DoPathMapping(path);
dependencies[CachedHashStringRef(Intern(path))] = it.second; dependencies[InternH(path)] = it.second;
} }
file->dependencies = std::move(dependencies); file->dependencies = std::move(dependencies);
} }

View File

@ -30,6 +30,11 @@ limitations under the License.
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
namespace llvm {
class CachedHashStringRef;
class StringRef;
}
enum class SerializeFormat { Binary, Json }; enum class SerializeFormat { Binary, Json };
struct JsonNull {}; struct JsonNull {};
@ -320,7 +325,8 @@ template <typename T> void ReflectMember(Writer &vis, const char *name, T &v) {
// API // API
namespace ccls { namespace ccls {
const char *Intern(const std::string &str); const char *Intern(llvm::StringRef str);
llvm::CachedHashStringRef InternH(llvm::StringRef str);
std::string Serialize(SerializeFormat format, IndexFile &file); std::string Serialize(SerializeFormat format, IndexFile &file);
std::unique_ptr<IndexFile> std::unique_ptr<IndexFile>
Deserialize(SerializeFormat format, const std::string &path, Deserialize(SerializeFormat format, const std::string &path,