Skip to content

Commit e0064ba

Browse files
feat: Add progress bar for indexing & merging (#402)
1 parent 6b6f539 commit e0064ba

File tree

9 files changed

+145
-37
lines changed

9 files changed

+145
-37
lines changed

indexer/CliOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct CliOptions {
3232
std::string statsFilePath;
3333
std::string packageMapPath;
3434
bool showCompilerDiagnostics;
35+
bool showProgress;
3536

3637
size_t ipcSizeHintBytes;
3738
std::chrono::seconds receiveTimeout;

indexer/Driver.cc

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "indexer/LlvmAdapter.h"
5252
#include "indexer/Logging.h"
5353
#include "indexer/Path.h"
54+
#include "indexer/ProgressReporter.h"
5455
#include "indexer/RAII.h"
5556
#include "indexer/ScipExtras.h"
5657
#include "indexer/Statistics.h"
@@ -210,6 +211,7 @@ struct DriverOptions {
210211
AbsolutePath statsFilePath;
211212
AbsolutePath packageMapPath;
212213
bool showCompilerDiagnostics;
214+
bool showProgress;
213215
DriverIpcOptions ipcOptions;
214216
size_t numWorkers;
215217
bool deterministic;
@@ -229,7 +231,8 @@ struct DriverOptions {
229231
projectRootPath(AbsolutePath("/"), RootKind::Project), compdbPath(),
230232
indexOutputPath(), statsFilePath(), packageMapPath(),
231233
showCompilerDiagnostics(cliOpts.showCompilerDiagnostics),
232-
ipcOptions{cliOpts.ipcSizeHintBytes, cliOpts.receiveTimeout},
234+
showProgress(cliOpts.showProgress), ipcOptions{cliOpts.ipcSizeHintBytes,
235+
cliOpts.receiveTimeout},
233236
numWorkers(cliOpts.numWorkers), deterministic(cliOpts.deterministic),
234237
preprocessorRecordHistoryFilterRegex(
235238
cliOpts.preprocessorRecordHistoryFilterRegex),
@@ -336,6 +339,9 @@ struct DriverOptions {
336339
if (this->showCompilerDiagnostics) {
337340
args.push_back("--show-compiler-diagnostics");
338341
}
342+
if (!this->showProgress) {
343+
args.push_back("--no-progress-report");
344+
}
339345
if (!this->preprocessorRecordHistoryFilterRegex.empty()) {
340346
args.push_back(fmt::format("--preprocessor-record-history-filter={}",
341347
this->preprocessorRecordHistoryFilterRegex));
@@ -812,6 +818,13 @@ class Scheduler final {
812818
return this->maybeErroredJobs.size();
813819
}
814820

821+
std::string_view getTuPath(JobId jobId) const {
822+
auto it = this->allJobList.find(jobId);
823+
ENFORCE(it != this->allJobList.end());
824+
ENFORCE(it->second.job.kind == IndexJob::Kind::SemanticAnalysis);
825+
return std::string_view(it->second.job.semanticAnalysis.command.filePath);
826+
}
827+
815828
private:
816829
ToBeScheduledWorkerId claimIdleWorker() {
817830
ENFORCE(!this->idleWorkers.empty());
@@ -883,6 +896,7 @@ class Driver {
883896

884897
/// Total number of commands in the compilation database.
885898
size_t compdbCommandCount = 0;
899+
TusIndexedCount indexedSoFar;
886900
compdb::ResumableParser compdbParser;
887901

888902
public:
@@ -1079,23 +1093,37 @@ class Driver {
10791093
llvm::UniqueStringSaver stringSaver{allocator};
10801094
scip::SymbolNameInterner interner{stringSaver};
10811095
scip::IndexBuilder builder{interner};
1082-
// TODO: Measure how much time this is taking and parallelize if too slow.
1083-
for (auto &paths : this->shardPaths) {
1084-
scip::Index indexShard;
1085-
if (!readIndexShard(paths.docsAndExternals, indexShard)) {
1086-
continue;
1087-
}
1088-
for (auto &doc : *indexShard.mutable_documents()) {
1089-
bool isMultiplyIndexed = this->isMultiplyIndexedApproximate(
1090-
doc.relative_path(), paths.docsAndExternals.asRef(), badJobIds);
1091-
builder.addDocument(std::move(doc), isMultiplyIndexed);
1092-
}
1093-
// See NOTE(ref: precondition-deterministic-ext-symbol-docs); in
1094-
// deterministic mode, indexes should be the same, and iterated over in
1095-
// sorted order. So if external symbol emission in each part is
1096-
// deterministic, addExternalSymbol will be called in deterministic order.
1097-
for (auto &extSym : *indexShard.mutable_external_symbols()) {
1098-
builder.addExternalSymbol(std::move(extSym));
1096+
{
1097+
ProgressReporter progressReporter(this->options.showProgress,
1098+
"Merged partial index for",
1099+
this->shardPaths.size());
1100+
size_t count = 1;
1101+
for (auto &paths : this->shardPaths) {
1102+
scip::Index indexShard;
1103+
if (!readIndexShard(paths.docsAndExternals, indexShard)) {
1104+
continue;
1105+
}
1106+
for (auto &doc : *indexShard.mutable_documents()) {
1107+
bool isMultiplyIndexed = this->isMultiplyIndexedApproximate(
1108+
doc.relative_path(), paths.docsAndExternals.asRef(), badJobIds);
1109+
builder.addDocument(std::move(doc), isMultiplyIndexed);
1110+
}
1111+
// See NOTE(ref: precondition-deterministic-ext-symbol-docs); in
1112+
// deterministic mode, indexes should be the same, and iterated over in
1113+
// sorted order. So if external symbol emission in each part is
1114+
// deterministic, addExternalSymbol will be called in deterministic
1115+
// order.
1116+
for (auto &extSym : *indexShard.mutable_external_symbols()) {
1117+
builder.addExternalSymbol(std::move(extSym));
1118+
}
1119+
if (auto optFileName = paths.docsAndExternals.asRef().fileName()) {
1120+
if (auto optJobId = ShardPaths::tryParseJobId(optFileName.value())) {
1121+
progressReporter.report(
1122+
count,
1123+
this->scheduler.getTuPath(JobId::newTask(optJobId.value())));
1124+
}
1125+
}
1126+
count++;
10991127
}
11001128
}
11011129

@@ -1178,19 +1206,20 @@ class Driver {
11781206

11791207
/// Returns the number of TUs processed
11801208
std::pair<TusIndexedCount, size_t> runJobsTillCompletionAndShutdownWorkers() {
1181-
TusIndexedCount tusIndexedCount{};
1209+
ProgressReporter progressReporter(this->options.showProgress, "Indexed",
1210+
this->compdbCommandCount);
11821211
this->scheduler.runJobsTillCompletionAndShutdownWorkers(
11831212
Scheduler::RunCallbacks{
1184-
[this, &tusIndexedCount]() -> void {
1185-
tusIndexedCount += this->processOneOrMoreJobResults();
1213+
[this, &progressReporter]() -> void {
1214+
this->processOneOrMoreJobResults(progressReporter);
11861215
},
11871216
[this]() -> size_t { return this->refillJobs(); },
11881217
[this](ToBeScheduledWorkerId &&workerId, JobId jobId) -> bool {
11891218
return this->tryAssignJobToWorker(std::move(workerId), jobId);
11901219
},
11911220
[this](WorkerId workerId) { this->shutdownWorker(workerId); }});
11921221
this->scheduler.waitForAllWorkers();
1193-
return {tusIndexedCount, this->scheduler.numErroredJobs()};
1222+
return {this->indexedSoFar, this->scheduler.numErroredJobs()};
11941223
}
11951224

11961225
FileGuard openCompilationDatabase() {
@@ -1241,17 +1270,17 @@ class Driver {
12411270
});
12421271
}
12431272

1244-
TusIndexedCount processWorkerResponse(IndexJobResponse &&response) {
1273+
void processWorkerResponse(IndexJobResponse &&response,
1274+
const ProgressReporter &progressReporter) {
12451275
TRACE_EVENT(tracing::indexing, "Driver::processWorkerResponse",
12461276
perfetto::TerminatingFlow::Global(response.jobId.traceId()));
1247-
TusIndexedCount tusIndexedCount{};
12481277
auto optLatestIdleWorkerId = this->scheduler.markCompleted(
12491278
response.workerId, response.jobId, response.result.kind);
12501279
if (!optLatestIdleWorkerId.has_value()) {
12511280
spdlog::debug("worker {} was terminated before job {}'s result "
12521281
"was processed, so can't send an emit index job",
12531282
response.workerId, response.jobId);
1254-
return tusIndexedCount;
1283+
return;
12551284
}
12561285
auto latestIdleWorkerId = *optLatestIdleWorkerId;
12571286
switch (response.result.kind) {
@@ -1299,7 +1328,7 @@ class Driver {
12991328
oldHandle.terminate();
13001329
return this->spawnWorker(workerId);
13011330
});
1302-
return tusIndexedCount;
1331+
return;
13031332
}
13041333
break;
13051334
}
@@ -1310,17 +1339,21 @@ class Driver {
13101339
std::move(result.statistics));
13111340
}
13121341
this->shardPaths.emplace_back(std::move(result.shardPaths));
1313-
tusIndexedCount.value += 1;
1342+
this->indexedSoFar.value += 1;
1343+
if (this->options.showProgress) {
1344+
auto semaJobId = JobId::newTask(response.jobId.taskId());
1345+
progressReporter.report(this->indexedSoFar.value,
1346+
this->scheduler.getTuPath(semaJobId));
1347+
}
13141348
break;
13151349
}
13161350
}
1317-
return tusIndexedCount;
1351+
return;
13181352
}
13191353

1320-
TusIndexedCount processOneOrMoreJobResults() {
1354+
void processOneOrMoreJobResults(const ProgressReporter &progressReporter) {
13211355
using namespace std::chrono_literals;
13221356
auto workerTimeout = this->receiveTimeout();
1323-
TusIndexedCount tusIndexedCount{};
13241357
IndexJobResponse response;
13251358
TRACE_EVENT_BEGIN(tracing::ipc, "driver.waitForResponse");
13261359
auto recvError =
@@ -1337,9 +1370,9 @@ class Driver {
13371370
} else {
13381371
spdlog::debug("received response for {} from worker {}", response.jobId,
13391372
response.workerId);
1340-
tusIndexedCount = this->processWorkerResponse(std::move(response));
1373+
this->processWorkerResponse(std::move(response), progressReporter);
13411374
while (this->queues.workerToDriver.tryReceiveInstant(response)) {
1342-
tusIndexedCount += this->processWorkerResponse(std::move(response));
1375+
this->processWorkerResponse(std::move(response), progressReporter);
13431376
}
13441377
}
13451378
// NOTE(def: mail-from-the-dead)
@@ -1360,7 +1393,7 @@ class Driver {
13601393
// was actually submitted by a worker which was terminated.
13611394
auto now = std::chrono::steady_clock::now();
13621395
this->terminateLongRunningWorkersAndRespawn(now - workerTimeout);
1363-
return tusIndexedCount;
1396+
return;
13641397
}
13651398

13661399
// Assign a job to a specific worker. When this method is called,

indexer/IpcMessages.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ std::optional<uint32_t> ShardPaths::tryParseJobId(std::string_view fileName) {
184184
return taskId;
185185
}
186186
return {};
187-
// return fmt::format("job-{}-worker-{}", taskId, workerId);
188187
}
189188

190189
} // namespace scip_clang

indexer/ProgressReporter.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <cmath>
2+
#include <cstdint>
3+
#include <iostream>
4+
#include <ostream>
5+
#include <string_view>
6+
7+
#include "spdlog/fmt/fmt.h"
8+
9+
#include "indexer/ProgressReporter.h"
10+
11+
namespace scip_clang {
12+
13+
ProgressReporter::ProgressReporter(bool active, std::string_view msg,
14+
size_t totalCount)
15+
: message(msg), totalCount(totalCount), countWidth(), active(active) {
16+
if (this->totalCount == 0) {
17+
countWidth = 1;
18+
} else {
19+
countWidth = std::log10(double(this->totalCount)) + 1;
20+
}
21+
}
22+
23+
void ProgressReporter::report(size_t count, std::string_view extraData) const {
24+
if (!this->active) {
25+
return;
26+
}
27+
int maxExtraWidth = 256;
28+
auto backspaceCount = std::max(maxExtraWidth - int(extraData.size()), 0);
29+
fmt::print("\r[{1:>{0}}/{2:>{0}}] {3} {4:<{5}}{6:\b<{7}}", countWidth, count,
30+
this->totalCount, this->message, extraData, maxExtraWidth, "",
31+
backspaceCount);
32+
std::flush(std::cout);
33+
}
34+
35+
ProgressReporter::~ProgressReporter() {
36+
if (this->active) {
37+
fmt::print("\n");
38+
}
39+
}
40+
41+
} // namespace scip_clang

indexer/ProgressReporter.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef SCIP_CLANG_PROGRESS_REPORTER_H
2+
#define SCIP_CLANG_PROGRESS_REPORTER_H
3+
4+
#include <cstdint>
5+
#include <string_view>
6+
7+
namespace scip_clang {
8+
9+
class ProgressReporter {
10+
std::string_view message;
11+
size_t totalCount;
12+
size_t countWidth;
13+
bool active;
14+
15+
public:
16+
ProgressReporter(bool active, std::string_view msg, size_t totalCount);
17+
18+
void report(size_t count, std::string_view extraData) const;
19+
20+
~ProgressReporter();
21+
};
22+
23+
} // namespace scip_clang
24+
25+
#endif // SCIP_CLANG_PROGRESS_REPORTER_H

indexer/Worker.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ WorkerOptions WorkerOptions::fromCliOptions(const CliOptions &cliOptions) {
119119
statsFilePath,
120120
cliOptions.packageMapPath,
121121
cliOptions.showCompilerDiagnostics,
122+
cliOptions.showProgress,
122123
cliOptions.logLevel,
123124
cliOptions.deterministic,
124125
cliOptions.measureStatistics,

indexer/Worker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct WorkerOptions {
5858

5959
StdPath packageMapPath;
6060
bool showCompilerDiagnostics;
61+
bool showProgress;
6162

6263
spdlog::level::level_enum logLevel;
6364
bool deterministic;

indexer/main.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ static scip_clang::CliOptions parseArguments(int argc, char *argv[]) {
3939
"index-output-path",
4040
"Path to write the SCIP index to",
4141
cxxopts::value<std::string>(cliOptions.indexOutputPath)->default_value("index.scip"));
42+
parser.add_options(defaultGroup)(
43+
"package-map-path",
44+
"Path to use for path->package mappings in JSON format.",
45+
cxxopts::value<std::string>(cliOptions.packageMapPath));
4246
parser.add_options(defaultGroup)(
4347
"j,jobs",
4448
fmt::format(
@@ -50,9 +54,9 @@ static scip_clang::CliOptions parseArguments(int argc, char *argv[]) {
5054
"One of 'debug', 'info', 'warning' or 'error'",
5155
cxxopts::value<std::string>()->default_value("info"));
5256
parser.add_options(defaultGroup)(
53-
"package-map-path",
54-
"Path to use for path->package mappings in JSON format.",
55-
cxxopts::value<std::string>(cliOptions.packageMapPath));
57+
"no-progress-report",
58+
"Suppress progress information reported after a TU is indexed",
59+
cxxopts::value<bool>());
5660
parser.add_options(defaultGroup)(
5761
"show-compiler-diagnostics",
5862
"Show Clang diagnostics triggered when running semantic analysis."
@@ -172,6 +176,8 @@ static scip_clang::CliOptions parseArguments(int argc, char *argv[]) {
172176
std::exit(EXIT_FAILURE);
173177
}
174178

179+
cliOptions.showProgress = result.count("no-progress-report") == 0;
180+
175181
auto level = result["log-level"].as<std::string>();
176182
if (level == "debug") {
177183
cliOptions.logLevel = spdlog::level::level_enum::debug;

test/test_main.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ TEST_CASE("INDEX") {
454454
args.push_back(fmt::format("--driver-id=index-{}",
455455
test::globalCliOptions.testName));
456456
args.push_back("--deterministic");
457+
args.push_back("--no-progress-report");
457458
auto packageMapPath =
458459
StdPath(rootInSourceDir.asStringRef()) / "package-map.json";
459460
if (std::filesystem::exists(packageMapPath)) {

0 commit comments

Comments
 (0)