Experiment with caching CXIndex across multiple sessions

This commit is contained in:
Jacob Dufault 2017-05-24 19:04:19 -07:00
parent d47869ad0f
commit 32940e2c88
9 changed files with 110 additions and 90 deletions

View File

@ -10,6 +10,7 @@
namespace { namespace {
unsigned Flags() { unsigned Flags() {
// TODO: use clang_defaultEditingTranslationUnitOptions()?
return return
CXTranslationUnit_Incomplete | CXTranslationUnit_Incomplete |
CXTranslationUnit_KeepGoing | CXTranslationUnit_KeepGoing |
@ -249,7 +250,7 @@ void EnsureDocumentParsed(CompletionSession* session,
std::cerr << "[complete] Creating completion session with arguments " << StringJoin(args) << std::endl; std::cerr << "[complete] Creating completion session with arguments " << StringJoin(args) << std::endl;
*index = MakeUnique<clang::Index>(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/); *index = MakeUnique<clang::Index>(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/);
*tu = MakeUnique<clang::TranslationUnit>(*index->get(), session->file.filename, args, unsaved, Flags()); *tu = MakeUnique<clang::TranslationUnit>(index->get(), session->file.filename, args, unsaved, Flags());
std::cerr << "[complete] Done creating active; did_fail=" << (*tu)->did_fail << std::endl; std::cerr << "[complete] Done creating active; did_fail=" << (*tu)->did_fail << std::endl;
} }

View File

@ -1142,6 +1142,7 @@ bool ImportCachedIndex(Config* config,
void ParseFile(Config* config, void ParseFile(Config* config,
WorkingFiles* working_files, WorkingFiles* working_files,
FileConsumer::SharedState* file_consumer_shared, FileConsumer::SharedState* file_consumer_shared,
clang::Index* index,
Index_DoIdMapQueue* queue_do_id_map, Index_DoIdMapQueue* queue_do_id_map,
const Project::Entry& entry, const Project::Entry& entry,
const optional<std::string>& indexed_content, const optional<std::string>& indexed_content,
@ -1158,7 +1159,7 @@ void ParseFile(Config* config,
config, file_consumer_shared, config, file_consumer_shared,
tu_path, tu_args, tu_path, tu_args,
entry.filename, indexed_content, entry.filename, indexed_content,
&perf); &perf, index);
for (std::unique_ptr<IndexFile>& new_index : indexes) { for (std::unique_ptr<IndexFile>& new_index : indexes) {
Timer time; Timer time;
@ -1271,6 +1272,7 @@ bool IndexMain_DoIndex(Config* config,
FileConsumer::SharedState* file_consumer_shared, FileConsumer::SharedState* file_consumer_shared,
Project* project, Project* project,
WorkingFiles* working_files, WorkingFiles* working_files,
clang::Index* index,
Index_DoIndexQueue* queue_do_index, Index_DoIndexQueue* queue_do_index,
Index_DoIdMapQueue* queue_do_id_map) { Index_DoIdMapQueue* queue_do_id_map) {
optional<Index_DoIndex> index_request = queue_do_index->TryDequeue(); optional<Index_DoIndex> index_request = queue_do_index->TryDequeue();
@ -1301,7 +1303,7 @@ bool IndexMain_DoIndex(Config* config,
case Index_DoIndex::Type::Parse: { case Index_DoIndex::Type::Parse: {
// index_request->path can be a cc/tu or a dependency path. // index_request->path can be a cc/tu or a dependency path.
file_consumer_shared->Reset(index_request->entry.filename); file_consumer_shared->Reset(index_request->entry.filename);
ParseFile(config, working_files, file_consumer_shared, queue_do_id_map, index_request->entry, index_request->content, index_request->is_interactive); ParseFile(config, working_files, file_consumer_shared, index, queue_do_id_map, index_request->entry, index_request->content, index_request->is_interactive);
break; break;
} }
@ -1311,7 +1313,7 @@ bool IndexMain_DoIndex(Config* config,
bool needs_reparse = ResetStaleFiles(config, file_consumer_shared, index_request->entry.filename); bool needs_reparse = ResetStaleFiles(config, file_consumer_shared, index_request->entry.filename);
if (needs_reparse) if (needs_reparse)
ParseFile(config, working_files, file_consumer_shared, queue_do_id_map, index_request->entry, index_request->content, index_request->is_interactive); ParseFile(config, working_files, file_consumer_shared, index, queue_do_id_map, index_request->entry, index_request->content, index_request->is_interactive);
break; break;
} }
} }
@ -1327,6 +1329,7 @@ bool IndexMain_DoCreateIndexUpdate(
return false; return false;
Timer time; Timer time;
// TODO/FIXME: Running call tree on IndexUpdate::CreateDelta crashes cquery.
IndexUpdate update = IndexUpdate::CreateDelta(response->previous_id_map.get(), response->current_id_map.get(), IndexUpdate update = IndexUpdate::CreateDelta(response->previous_id_map.get(), response->current_id_map.get(),
response->previous_index.get(), response->current_index.get()); response->previous_index.get(), response->current_index.get());
response->perf.index_make_delta = time.ElapsedMicrosecondsAndReset(); response->perf.index_make_delta = time.ElapsedMicrosecondsAndReset();
@ -1398,6 +1401,9 @@ void IndexMain(
Index_OnIndexedQueue* queue_on_indexed) { Index_OnIndexedQueue* queue_on_indexed) {
SetCurrentThreadName("indexer"); SetCurrentThreadName("indexer");
// TODO: dispose of index after it is not used for a while.
clang::Index index(1, 0);
while (true) { while (true) {
// TODO: process all off IndexMain_DoIndex before calling IndexMain_DoCreateIndexUpdate for // TODO: process all off IndexMain_DoIndex before calling IndexMain_DoCreateIndexUpdate for
// better icache behavior. We need to have some threads spinning on both though // better icache behavior. We need to have some threads spinning on both though
@ -1407,7 +1413,7 @@ void IndexMain(
// IndexMain_DoCreateIndexUpdate so we don't starve querydb from doing any // IndexMain_DoCreateIndexUpdate so we don't starve querydb from doing any
// work. Running both also lets the user query the partially constructed // work. Running both also lets the user query the partially constructed
// index. // index.
bool did_index = IndexMain_DoIndex(config, file_consumer_shared, project, working_files, queue_do_index, queue_do_id_map); bool did_index = IndexMain_DoIndex(config, file_consumer_shared, project, working_files, &index, queue_do_index, queue_do_id_map);
bool did_create_update = IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed); bool did_create_update = IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed);
bool did_merge = false; bool did_merge = false;
@ -2949,7 +2955,16 @@ int main(int argc, char** argv) {
if (context.shouldExit()) if (context.shouldExit())
return res; return res;
for (int i = 0; i < 50; ++i)
RunTests(); RunTests();
for (int i = 0; i < 20; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cerr << "[POST] " << GetProcessMemoryUsedInMb() << std::endl;
}
std::cerr << std::endl << "[Enter] to exit" << std::endl;
std::cin.get();
return 0; return 0;
} }
else if (HasOption(options, "--language-server")) { else if (HasOption(options, "--language-server")) {

View File

@ -1536,6 +1536,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
const std::string& file_contents_path, const std::string& file_contents_path,
const optional<std::string>& file_contents, const optional<std::string>& file_contents,
PerformanceImportFile* perf, PerformanceImportFile* perf,
clang::Index* index,
bool dump_ast) { bool dump_ast) {
if (!config->enableIndexing) if (!config->enableIndexing)
@ -1545,8 +1546,9 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
Timer timer; Timer timer;
clang::Index index(0 /*excludeDeclarationsFromPCH*/, //clang::Index index(0 /*excludeDeclarationsFromPCH*/,
0 /*displayDiagnostics*/); // 0 /*displayDiagnostics*/);
std::vector<CXUnsavedFile> unsaved_files; std::vector<CXUnsavedFile> unsaved_files;
if (file_contents) { if (file_contents) {
CXUnsavedFile unsaved; CXUnsavedFile unsaved;
@ -1555,7 +1557,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
unsaved.Length = (unsigned long)file_contents->size(); unsaved.Length = (unsigned long)file_contents->size();
unsaved_files.push_back(unsaved); unsaved_files.push_back(unsaved);
} }
clang::TranslationUnit tu(index, file, args, unsaved_files, CXTranslationUnit_KeepGoing | CXTranslationUnit_DetailedPreprocessingRecord); clang::TranslationUnit tu(index, file, args, unsaved_files, CXTranslationUnit_KeepGoing | CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_Incomplete);
perf->index_parse = timer.ElapsedMicrosecondsAndReset(); perf->index_parse = timer.ElapsedMicrosecondsAndReset();
@ -1576,7 +1578,7 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
param.primary_file = ConsumeFile(&param, cx_file); param.primary_file = ConsumeFile(&param, cx_file);
//std::cerr << "!! [START] Indexing " << file << std::endl; //std::cerr << "!! [START] Indexing " << file << std::endl;
CXIndexAction index_action = clang_IndexAction_create(index.cx_index); CXIndexAction index_action = clang_IndexAction_create(index->cx_index);
clang_indexTranslationUnit(index_action, &param, callbacks, sizeof(callbacks), clang_indexTranslationUnit(index_action, &param, callbacks, sizeof(callbacks),
CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession | CXIndexOpt_IndexImplicitTemplateInstantiations, CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession | CXIndexOpt_IndexImplicitTemplateInstantiations,
tu.cx_tu); tu.cx_tu);

View File

@ -5,6 +5,7 @@
#include "serializer.h" #include "serializer.h"
#include "utils.h" #include "utils.h"
#include "language_server_api.h" #include "language_server_api.h"
#include "libclangmm/Index.h"
#include "libclangmm/Utility.h" #include "libclangmm/Utility.h"
#include "performance.h" #include "performance.h"
@ -554,5 +555,6 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
const std::string& file_contents_path, const std::string& file_contents_path,
const optional<std::string>& file_contents, const optional<std::string>& file_contents,
PerformanceImportFile* perf, PerformanceImportFile* perf,
clang::Index* index,
bool dump_ast = false); bool dump_ast = false);
void IndexInit(); void IndexInit();

View File

@ -10,7 +10,7 @@
namespace clang { namespace clang {
TranslationUnit::TranslationUnit(Index& index, TranslationUnit::TranslationUnit(Index* index,
const std::string& filepath, const std::string& filepath,
const std::vector<std::string>& arguments, const std::vector<std::string>& arguments,
std::vector<CXUnsavedFile> unsaved_files, std::vector<CXUnsavedFile> unsaved_files,
@ -27,7 +27,7 @@ TranslationUnit::TranslationUnit(Index& index,
//CXErrorCode error_code = clang_parseTranslationUnit2FullArgv( //CXErrorCode error_code = clang_parseTranslationUnit2FullArgv(
CXErrorCode error_code = clang_parseTranslationUnit2( CXErrorCode error_code = clang_parseTranslationUnit2(
index.cx_index, filepath.c_str(), args.data(), (int)args.size(), index->cx_index, filepath.c_str(), args.data(), (int)args.size(),
unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu); unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
switch (error_code) { switch (error_code) {

View File

@ -12,7 +12,7 @@
namespace clang { namespace clang {
class TranslationUnit { class TranslationUnit {
public: public:
TranslationUnit(Index& index, TranslationUnit(Index* index,
const std::string& filepath, const std::string& filepath,
const std::vector<std::string>& arguments, const std::vector<std::string>& arguments,
std::vector<CXUnsavedFile> unsaved_files, std::vector<CXUnsavedFile> unsaved_files,

View File

@ -98,27 +98,29 @@ void RunTests() {
// TODO: Assert that we need to be on clang >= 3.9.1 // TODO: Assert that we need to be on clang >= 3.9.1
bool update_all = false; bool update_all = false;
clang::Index index(1, 0);
for (std::string path : GetFilesInFolder("tests", true /*recursive*/, true /*add_folder_to_path*/)) { for (std::string path : GetFilesInFolder("tests", true /*recursive*/, true /*add_folder_to_path*/)) {
float memory_before = GetProcessMemoryUsedInMb();
float memory_after = -1.;
{
//if (path != "tests/templates/specialized_func_definition.cc") continue; //if (path != "tests/templates/specialized_func_definition.cc") continue;
//if (path != "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc") continue; //if (path != "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc") continue;
//if (path != "tests/multi_file/funky_enum.cc") continue; //if (path != "tests/multi_file/funky_enum.cc") continue;
//if (path != "tests/multi_file/simple_impl.cc") continue; //if (path != "tests/multi_file/simple_impl.cc") continue;
//if (path != "tests/usage/func_called_implicit_ctor.cc") continue; //if (path != "tests/usage/func_called_implicit_ctor.cc") continue;
//if (path != "tests/templates/implicit_variable_instantiation.cc") continue; //if (path != "tests/templates/implicit_variable_instantiation.cc") continue;
//if (path != "tests/_empty_test.cc") continue; //if (path != "tests/multi_file/bad_type_remove.cc") continue;
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue; //if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;
//path = "C:/Users/jacob/Desktop/superindex/indexer/" + path; //path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
// Parse expected output from the test, parse it into JSON document.
std::unordered_map<std::string, std::string> all_expected_output = ParseTestExpectation(path);
Config config; Config config;
FileConsumer::SharedState file_consumer_shared; FileConsumer::SharedState file_consumer_shared;
// Run test. // Run test.
std::cout << "[START] " << path << std::endl; //std::cout << "[START] " << path << std::endl;
PerformanceImportFile perf; PerformanceImportFile perf;
std::vector<std::unique_ptr<IndexFile>> dbs = Parse( std::vector<std::unique_ptr<IndexFile>> dbs = Parse(
&config, &file_consumer_shared, &config, &file_consumer_shared,
@ -133,37 +135,12 @@ void RunTests() {
}, },
"", nullopt, "", nullopt,
&perf, &perf,
&index,
false /*dump_ast*/); false /*dump_ast*/);
#if false #if false
for (auto& db : dbs) { // Parse expected output from the test, parse it into JSON document.
assert(db); std::unordered_map<std::string, std::string> all_expected_output = ParseTestExpectation(path);
if (!db) {
std::cerr << "no db!!!" << std::endl;
continue;
}
for (auto& func : db->funcs) {
if (!func.HasInterestingState())
continue;
if (func.uses.size() !=
(func.callers.size() + func.declarations.size() + (func.def.definition_spelling.has_value() ? 1 : 0))) {
std::cout << "func.def.usr = " << func.def.usr << std::endl;
std::cout << "func.uses.size() = " << func.uses.size() << std::endl;
std::cout << "func.callers.size() = " << func.callers.size() << std::endl;
std::cout << "func.declarations.size() = " << func.declarations.size() << std::endl;
std::cout << "func.definition_spelling.has_value() = " << func.def.definition_spelling.has_value() << std::endl;
std::cerr << "err" << std::endl;
}
}
}
#endif
for (auto& entry : all_expected_output) { for (auto& entry : all_expected_output) {
const std::string& expected_path = entry.first; const std::string& expected_path = entry.first;
const std::string& expected_output = entry.second; const std::string& expected_output = entry.second;
@ -206,9 +183,23 @@ void RunTests() {
} }
} }
#endif
memory_after = GetProcessMemoryUsedInMb();
} }
std::cin.get(); float memory_cleanup = GetProcessMemoryUsedInMb();
std::cerr << "[memory] before=" << memory_before << "mb, after=" << memory_after << "mb, cleanup=" << memory_cleanup << "mb" << std::endl;
}
std::cerr << "[final presleep] " << GetProcessMemoryUsedInMb() << "mb" << std::endl;
//std::this_thread::sleep_for(std::chrono::seconds(10));
//std::cerr << "[final postsleep] " << GetProcessMemoryUsedInMb() << "mb" << std::endl;
std::cerr << std::endl;
std::cerr << std::endl;
std::cerr << std::endl;
std::cerr << std::endl;
std::cerr << std::endl;
} }
// TODO: ctor/dtor, copy ctor // TODO: ctor/dtor, copy ctor

View File

@ -2,6 +2,7 @@
#include "platform.h" #include "platform.h"
#include <sparsepp/spp_memory.h>
#include <tinydir.h> #include <tinydir.h>
#include <algorithm> #include <algorithm>
@ -315,3 +316,9 @@ void WriteToFile(const std::string& filename, const std::string& content) {
std::ofstream file(filename); std::ofstream file(filename);
file << content; file << content;
} }
float GetProcessMemoryUsedInMb() {
const float kBytesToMb = 1000000;
uint64_t memory_after = spp::GetProcessMemoryUsed();
return memory_after / kBytesToMb;
}

View File

@ -122,3 +122,5 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
}\ }\
};\ };\
} }
float GetProcessMemoryUsedInMb();