in glean/lang/clang/index.cpp [556:708]
int main(int argc, char **argv) {
#if FACEBOOK
facebook::initFacebook(&argc, &argv);
#else
folly::init(&argc, &argv);
#endif
std::signal(SIGTERM, [](int) {
#if FACEBOOK
LOG(CRITICAL)
#else
LOG(ERROR)
#endif
<< "worker " << FLAGS_worker_index << " received SIGTERM, exiting";
_exit(1);
});
Config config(argc, argv);
std::filesystem::current_path(
config.root / std::filesystem::path(config.cwd_subdir.value_or("")));
const auto work_counter = FLAGS_work_file.empty()
? worklist::serialCounter(0, config.sources.size())
: worklist::stealingCounter(
FLAGS_work_file, FLAGS_worker_index, FLAGS_worker_count);
SourceIndexer indexer(config);
llvm::install_fatal_error_handler(&handleLLVMError, nullptr);
const size_t n = FLAGS_stop_after != 0
? std::min(size_t(FLAGS_stop_after), config.sources.size())
: config.sources.size();
FactStats prev_stats = {0,0};
FactStats lifetime_stats = {0,0};
uint32_t lifetime_files = 0;
bool error_exit = false;
bool memory_exit = false;
int rss = 0;
for (auto next = work_counter->next();
next.has_value();
next = work_counter->next()) {
const auto i = next.value().start;
auto errorGuard = folly::makeGuard([&] {
LOG_CFG(ERROR,config) << "error guard at "
<< i+1 << "/" << next.value().end << " [" << n << "] "
<< config.sources[i].file;
});
if (FLAGS_log_every != 0 && (lifetime_files % FLAGS_log_every) == 0) {
LOG_CFG(INFO,config)
<< i+1 << "/" << next.value().end << " [" << n << "] "
<< config.sources[i].file;
if (FLAGS_fact_stats) {
LOG_CFG(INFO,config)
<< "fact buffer: " << showStats(indexer.batch.bufferStats())
<< " cache: " << showStats(indexer.batch.cacheStats().facts)
<< " lifetime: " << showStats(lifetime_stats);
}
}
const auto& source = config.sources[i];
const auto buf_stats = indexer.batch.bufferStats();
const auto cache_stats = indexer.batch.cacheStats();
try {
bool ok = config
.logger("clang/index")
.log_index(source, buf_stats, cache_stats, [&]() {
return indexer.index(source);
});
if (!ok && FLAGS_fail_on_error) {
LOG(ERROR) << "compilation failed for " << source.file;
error_exit = true;
}
} catch(const FatalLLVMError& e) {
// TODO: log this to Scuba if it turns out to happen a lot
LOG(ERROR) << "fatal LLVM error in " << source.file << ": " << e.what();
error_exit = true;
} catch(const std::exception& e) {
LOG(ERROR) << "while indexing " << source.file << ": " << e.what();
error_exit = FLAGS_fail_on_error;
}
lifetime_stats.memory += buf_stats.memory - prev_stats.memory;
lifetime_stats.count += buf_stats.count - prev_stats.count;
config.counters.fact_buffer_size->store(buf_stats.memory);
config.counters.fact_cache_size->store(cache_stats.facts.memory);
config.counters.fact_cache_hits->store(cache_stats.hits);
config.counters.fact_cache_misses->store(cache_stats.misses);
if (!FLAGS_dry_run) {
const bool wait =
FLAGS_fact_buffer != 0 && buf_stats.memory >= FLAGS_fact_buffer;
if (wait) {
LOG_CFG(INFO,config)
<< "fact buffer size " << buf_stats.memory << ", waiting";
}
config.logger(wait ? "clang/wait" : "clang/send").log([&]() {
config.sender->rebaseAndSend(indexer.batch.base(), wait);
});
}
prev_stats = indexer.batch.bufferStats();
++lifetime_files;
memory_exit = FLAGS_max_rss != 0 && (rss = getSelfRSS()) > FLAGS_max_rss;
errorGuard.dismiss();
if ((FLAGS_stop_after != 0 && lifetime_files >= FLAGS_stop_after)
|| memory_exit
|| error_exit) {
LOG_CFG(WARNING,config)
<< "Exiting after "
<< i+1 << "/" << next.value().end << " [" << n << "] "
<< config.sources[i].file;
// we do not want the for loop to call work_counter->next()
// because that will skip the next target for no good reason
break;
}
}
if (!FLAGS_dry_run) {
LOG_CFG(INFO,config) << "flushing";
config.logger("clang/flush").log([&]() {
config.sender->flush(indexer.batch.base());
});
}
config.counters.fact_buffer_size->store(0);
config.counters.fact_cache_size->store(0);
if (memory_exit) {
LOG_CFG(ERROR, config)
<< "Exiting due to memory pressure, RSS was " << rss
<< " kB, RSS after flushing is " << getSelfRSS()
<< " kB, --max-rss is " << FLAGS_max_rss << " kB";
}
LOG_CFG(INFO,config)
<< (error_exit || memory_exit ? "aborting" : "finished")
<< ", lifetime files: " << lifetime_files
<< " facts: " << showStats(lifetime_stats);
if (memory_exit) {
return 147;
}
if (error_exit) {
return 1;
}
return 0;
}