Skip to content

Commit 67f7914

Browse files
committed
[cxx indexer facebookincubator#2] Add -dump_every N
When indexing a large project using `glean index cpp-cmake -jN` we currently create N clang indexer processees that accumulate facts until all the source files are processed, so they can grow indefinitely. The `-dump_every X` flag causes the indexer to dump the facts to a new file after processing X source files.
1 parent db36dac commit 67f7914

2 files changed

Lines changed: 39 additions & 18 deletions

File tree

glean/lang/clang/glean-clang.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ common fb-haskell
9393
ghc-options: -O2
9494

9595
common fb-cpp
96-
cxx-options: -DOSS=1 -std=c++17
96+
cxx-options: -DOSS=1 -std=c++17 -Wno-nullability-completeness
9797
if arch(x86_64)
9898
cxx-options: -DGLEAN_X86_64 -march=haswell
9999
if flag(opt)

glean/lang/clang/index.cpp

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ DEFINE_string(
5151
dump,
5252
"",
5353
"PATH where generated facts will be dumped instead of sending them to the Glean write server. You MUST specify --dump.");
54+
DEFINE_int32(
55+
dump_every,
56+
0,
57+
"If set, the facts will be dumped to <dump>.i after indexing N files");
5458
DEFINE_string(
5559
ownership_dump,
5660
"",
@@ -262,7 +266,10 @@ struct Config {
262266
if (!FLAGS_dump.empty()) {
263267
// logging is historical, we always dump to a file now
264268
should_log = false;
265-
sender = fileWriter(FLAGS_dump);
269+
sender = fileWriter(
270+
FLAGS_dump_every != 0
271+
? fmt::format("{}.0", FLAGS_dump)
272+
: FLAGS_dump);
266273
} else if (!FLAGS_print_sources_count) {
267274
fail("missing --dump");
268275
}
@@ -386,11 +393,13 @@ class CDB {
386393

387394
struct SourceIndexer {
388395
const Config& config;
389-
Batch<SCHEMA> batch;
396+
std::unique_ptr<Batch<SCHEMA>> batch;
390397
CDB cdb;
391398

392399
explicit SourceIndexer(Config& cfg)
393-
: config(cfg), batch(cfg.schema.get(), FLAGS_fact_cache) {
400+
: config(cfg),
401+
batch(std::make_unique<Batch<SCHEMA>>(
402+
cfg.schema.get(), FLAGS_fact_cache)) {
394403
blank_cell_name = (!FLAGS_blank_cell_name.empty())
395404
? folly::Optional<std::string>(FLAGS_blank_cell_name)
396405
: folly::none;
@@ -400,7 +409,7 @@ struct SourceIndexer {
400409
if (FLAGS_ownership) {
401410
// source file paths will be absolute (see loadCompilationDatabase()) but
402411
// we need the unit path to be relative.
403-
batch.beginUnit(
412+
batch->beginUnit(
404413
std::filesystem::path(source.file)
405414
.lexically_relative(config.root)
406415
.string());
@@ -415,7 +424,7 @@ struct SourceIndexer {
415424
config.root,
416425
config.target_subdir,
417426
config.path_prefix,
418-
batch,
427+
*batch,
419428
},
420429
config.diagnostics.get()};
421430
FrontendActionFactory factory(&cfg);
@@ -465,11 +474,17 @@ struct SourceIndexer {
465474
});
466475
auto ok = tool.run(&factory) == 0;
467476
if (FLAGS_ownership) {
468-
batch.endUnit();
477+
batch->endUnit();
469478
}
470479
return ok;
471480
}
472481

482+
void flush() {
483+
config.sender->flush(batch->base());
484+
batch = std::make_unique<Batch<SCHEMA>>(
485+
config.schema.get(), FLAGS_fact_cache);
486+
}
487+
473488
private:
474489
folly::Optional<std::string> blank_cell_name;
475490

@@ -510,15 +525,15 @@ struct SourceIndexer {
510525

511526
return {
512527
repo_cell,
513-
batch.fact<Buck::Locator>(
528+
batch->fact<Buck::Locator>(
514529
maybe(cell),
515530
source.target.substr(path_start, path_len),
516531
source.target.substr(name_start))};
517532
}
518533

519534
folly::Optional<Fact<Buck::Platform>> platformOf(const SourceFile& file) {
520535
if (file.platform) {
521-
return batch.fact<Buck::Platform>(file.platform.value());
536+
return batch->fact<Buck::Platform>(file.platform.value());
522537
} else {
523538
return folly::none;
524539
}
@@ -690,15 +705,15 @@ int main(int argc, char** argv) {
690705
<< "] " << config.sources[i].file;
691706
if (FLAGS_fact_stats) {
692707
LOG_CFG(INFO, config)
693-
<< "fact buffer: " << showStats(indexer.batch.bufferStats())
694-
<< " cache: " << showStats(indexer.batch.cacheStats().facts)
708+
<< "fact buffer: " << showStats(indexer.batch->bufferStats())
709+
<< " cache: " << showStats(indexer.batch->cacheStats().facts)
695710
<< " lifetime: " << showStats(lifetime_stats);
696711
}
697712
}
698713

699714
const auto& source = config.sources[i];
700-
const auto buf_stats = indexer.batch.bufferStats();
701-
const auto cache_stats = indexer.batch.cacheStats();
715+
const auto buf_stats = indexer.batch->bufferStats();
716+
const auto cache_stats = indexer.batch->cacheStats();
702717
try {
703718
bool ok = config.logger("clang/index")
704719
.log_index(source, buf_stats, cache_stats, [&]() {
@@ -732,7 +747,7 @@ int main(int argc, char** argv) {
732747
<< "fact buffer size " << buf_stats.memory << ", waiting";
733748
}
734749
config.logger(wait ? "clang/wait" : "clang/send").log([&]() {
735-
config.sender->rebaseAndSend(indexer.batch.base(), wait);
750+
config.sender->rebaseAndSend(indexer.batch->base(), wait);
736751
});
737752
if (wait) {
738753
const auto wait_time = std::chrono::steady_clock::now() - start;
@@ -742,7 +757,7 @@ int main(int argc, char** argv) {
742757
.count();
743758
}
744759
}
745-
prev_stats = indexer.batch.bufferStats();
760+
prev_stats = indexer.batch->bufferStats();
746761
++lifetime_files;
747762

748763
memory_exit = FLAGS_max_rss != 0 && (rss = getSelfRSS()) > FLAGS_max_rss;
@@ -758,24 +773,30 @@ int main(int argc, char** argv) {
758773
// because that will skip the next target for no good reason
759774
break;
760775
}
776+
777+
if (FLAGS_dump_every != 0 && lifetime_files % FLAGS_dump_every == 0) {
778+
indexer.flush();
779+
config.sender = fileWriter(
780+
fmt::format("{}.{}", FLAGS_dump, lifetime_files / FLAGS_dump_every));
781+
}
761782
}
762783

763784
if (!FLAGS_dry_run) {
764785
LOG_CFG(INFO, config) << "flushing";
765786
config.logger("clang/flush").log([&]() {
766-
config.sender->flush(indexer.batch.base());
787+
indexer.flush();
767788
});
768789
}
769790

770-
indexer.batch.logEnd();
791+
indexer.batch->logEnd();
771792

772793
// Write ownership data to JSON file if dump path is specified
773794
// This honors the output_ownership_files flag which controls whether
774795
// the --ownership_dump parameter is passed to the indexer
775796
if (!FLAGS_ownership_dump.empty()) {
776797
LOG_CFG(INFO, config) << "Writing ownership data to "
777798
<< FLAGS_ownership_dump;
778-
auto ownership_data = indexer.batch.base().serializeOwnership();
799+
auto ownership_data = indexer.batch->base().serializeOwnership();
779800

780801
folly::dynamic ownership_json = folly::dynamic::object;
781802
for (const auto& [unit_name, fact_id_ranges] : ownership_data) {

0 commit comments

Comments
 (0)