Skip to content

Commit e5c3b3f

Browse files
Merge pull request #65423 from cachemeifyoucan/eng/PR-cached-diagnostics-processor
[CAS] Add caching diagnostic processor
2 parents 89b9e48 + d3891a8 commit e5c3b3f

12 files changed

+1099
-18
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,9 @@ ERROR(error_create_cas, none, "failed to create CAS '%0' (%1)", (StringRef, Stri
494494
ERROR(error_invalid_cas_id, none, "invalid CASID '%0' (%1)", (StringRef, StringRef))
495495
ERROR(error_cas, none, "CAS error encountered: %0", (StringRef))
496496

497+
ERROR(error_failed_cached_diag, none, "failed to serialize cached diagnostics: %0", (StringRef))
498+
ERROR(error_replay_cached_diag, none, "failed to replay cached diagnostics: %0", (StringRef))
499+
497500
// Dependency Verifier Diagnostics
498501
ERROR(missing_member_dependency,none,
499502
"expected "
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- CachedDiagnostics.h - Cached Diagnostics ---------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the CachedDiagnosticConsumer class, which
14+
// caches the diagnostics which can be replayed with other DiagnosticConumers.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_CACHEDDIAGNOSTICS_H
19+
#define SWIFT_CACHEDDIAGNOSTICS_H
20+
21+
#include "llvm/Support/Error.h"
22+
23+
namespace swift {
24+
25+
class CompilerInstance;
26+
class DiagnosticEngine;
27+
class SourceManager;
28+
class FrontendInputsAndOutputs;
29+
30+
class CachingDiagnosticsProcessor {
31+
public:
32+
CachingDiagnosticsProcessor(CompilerInstance &Instance);
33+
~CachingDiagnosticsProcessor();
34+
35+
/// Start capturing all the diagnostics from DiagnosticsEngine.
36+
void startDiagnosticCapture();
37+
/// End capturing all the diagnostics from DiagnosticsEngine.
38+
void endDiagnosticCapture();
39+
40+
/// Emit serialized diagnostics into output stream.
41+
llvm::Error serializeEmittedDiagnostics(llvm::raw_ostream &os);
42+
43+
/// Used to replay the previously cached diagnostics, after a cache hit.
44+
llvm::Error replayCachedDiagnostics(llvm::StringRef Buffer);
45+
46+
private:
47+
class Implementation;
48+
Implementation& Impl;
49+
};
50+
51+
}
52+
53+
#endif

include/swift/Frontend/Frontend.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/Basic/LangOptions.h"
3131
#include "swift/Basic/SourceManager.h"
3232
#include "swift/ClangImporter/ClangImporter.h"
33+
#include "swift/Frontend/CachedDiagnostics.h"
3334
#include "swift/Frontend/DiagnosticVerifier.h"
3435
#include "swift/Frontend/FrontendOptions.h"
3536
#include "swift/Frontend/ModuleInterfaceSupport.h"
@@ -462,6 +463,7 @@ class CompilerInstance {
462463
std::unique_ptr<ASTContext> Context;
463464
std::unique_ptr<Lowering::TypeConverter> TheSILTypes;
464465
std::unique_ptr<DiagnosticVerifier> DiagVerifier;
466+
std::unique_ptr<CachingDiagnosticsProcessor> CDP;
465467

466468
/// A cache describing the set of inter-module dependencies that have been queried.
467469
/// Null if not present.
@@ -548,6 +550,9 @@ class CompilerInstance {
548550
Optional<llvm::cas::ObjectRef> getCompilerBaseKey() const {
549551
return CompileJobBaseKey;
550552
}
553+
CachingDiagnosticsProcessor *getCachingDiagnosticsProcessor() const {
554+
return CDP.get();
555+
}
551556

552557
ASTContext &getASTContext() { return *Context; }
553558
const ASTContext &getASTContext() const { return *Context; }
@@ -678,6 +683,7 @@ class CompilerInstance {
678683
void setupDependencyTrackerIfNeeded();
679684
bool setupCASIfNeeded(ArrayRef<const char *> Args);
680685
void setupOutputBackend();
686+
void setupCachingDiagnosticsProcessorIfNeeded();
681687

682688
/// \return false if successful, true on error.
683689
bool setupDiagnosticVerifierIfNeeded();

lib/DriverTool/swift_cache_tool_main.cpp

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ enum class SwiftCacheToolAction {
4242
Invalid,
4343
PrintBaseKey,
4444
PrintOutputKeys,
45-
ValidateOutputs
45+
ValidateOutputs,
46+
RenderDiags
4647
};
4748

4849
struct OutputEntry {
@@ -134,11 +135,13 @@ class SwiftCacheToolInvocation {
134135
.Case("print-base-key", SwiftCacheToolAction::PrintBaseKey)
135136
.Case("print-output-keys", SwiftCacheToolAction::PrintOutputKeys)
136137
.Case("validate-outputs", SwiftCacheToolAction::ValidateOutputs)
138+
.Case("render-diags", SwiftCacheToolAction::RenderDiags)
137139
.Default(SwiftCacheToolAction::Invalid);
138140

139141
if (ActionKind == SwiftCacheToolAction::Invalid) {
140-
llvm::errs() << "Invalid option specified for -cache-tool-action: "
141-
<< "use print-base-key|print-output-keys|validate-outputs\n";
142+
llvm::errs()
143+
<< "Invalid option specified for -cache-tool-action: "
144+
<< "print-base-key|print-output-keys|validate-outputs|render-diags\n";
142145
return 1;
143146
}
144147

@@ -153,6 +156,8 @@ class SwiftCacheToolInvocation {
153156
return printOutputKeys();
154157
case SwiftCacheToolAction::ValidateOutputs:
155158
return validateOutputs();
159+
case SwiftCacheToolAction::RenderDiags:
160+
return renderDiags();
156161
case SwiftCacheToolAction::Invalid:
157162
return 0; // No action. Probably just print help. Return.
158163
}
@@ -202,6 +207,10 @@ class SwiftCacheToolInvocation {
202207
return true;
203208
}
204209

210+
// Disable diagnostic caching from this fake instance.
211+
if (auto *CDP = Instance.getCachingDiagnosticsProcessor())
212+
CDP->endDiagnosticCapture();
213+
205214
return false;
206215
}
207216

@@ -233,6 +242,7 @@ class SwiftCacheToolInvocation {
233242

234243
int printOutputKeys();
235244
int validateOutputs();
245+
int renderDiags();
236246
};
237247

238248
} // end anonymous namespace
@@ -283,6 +293,10 @@ int SwiftCacheToolInvocation::printOutputKeys() {
283293
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs(),
284294
addFromInputFile);
285295

296+
// Add diagnostics file.
297+
addOutputKey("<cached-diagnostics>", file_types::ID::TY_CachedDiagnostics,
298+
"<cached-diagnostics>");
299+
286300
if (hasError)
287301
return 1;
288302

@@ -301,6 +315,26 @@ int SwiftCacheToolInvocation::printOutputKeys() {
301315
return 0;
302316
}
303317

318+
static llvm::Expected<llvm::json::Array>
319+
readOutputEntriesFromFile(StringRef Path) {
320+
auto JSONContent = llvm::MemoryBuffer::getFile(Path);
321+
if (!JSONContent)
322+
return llvm::createStringError(JSONContent.getError(),
323+
"failed to read input file");
324+
325+
auto JSONValue = llvm::json::parse((*JSONContent)->getBuffer());
326+
if (!JSONValue)
327+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
328+
"failed to parse input file as JSON");
329+
330+
auto Keys = JSONValue->getAsArray();
331+
if (!Keys)
332+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
333+
"invalid JSON format for input file");
334+
335+
return *Keys;
336+
}
337+
304338
int SwiftCacheToolInvocation::validateOutputs() {
305339
auto DB = llvm::cas::createOnDiskUnifiedCASDatabases(CASPath);
306340
if (!DB)
@@ -310,22 +344,10 @@ int SwiftCacheToolInvocation::validateOutputs() {
310344
Instance.getDiags().addConsumer(PDC);
311345

312346
auto validateCacheKeysFromFile = [&](const std::string &Path) {
313-
auto JSONContent = llvm::MemoryBuffer::getFile(Path);
314-
if (!JSONContent) {
315-
llvm::errs() << "failed to read " << Path << ": "
316-
<< JSONContent.getError().message() << "\n";
317-
return true;
318-
}
319-
auto JSONValue = llvm::json::parse((*JSONContent)->getBuffer());
320-
if (!JSONValue) {
321-
llvm::errs() << "failed to parse " << Path << ": "
322-
<< toString(JSONValue.takeError()) << "\n";
323-
return true;
324-
}
325-
326-
auto Keys = JSONValue->getAsArray();
347+
auto Keys = readOutputEntriesFromFile(Path);
327348
if (!Keys) {
328-
llvm::errs() << "invalid keys format in " << Path << "\n";
349+
llvm::errs() << "cannot read file " << Path << ": "
350+
<< toString(Keys.takeError()) << "\n";
329351
return true;
330352
}
331353

@@ -350,6 +372,51 @@ int SwiftCacheToolInvocation::validateOutputs() {
350372
return llvm::any_of(Inputs, validateCacheKeysFromFile);
351373
}
352374

375+
int SwiftCacheToolInvocation::renderDiags() {
376+
if (setupCompiler())
377+
return 1;
378+
379+
auto *CDP = Instance.getCachingDiagnosticsProcessor();
380+
if (!CDP) {
381+
llvm::errs() << "provided commandline doesn't support cached diagnostics\n";
382+
return 1;
383+
}
384+
385+
auto renderDiagsFromFile = [&](const std::string &Path) {
386+
auto Keys = readOutputEntriesFromFile(Path);
387+
if (!Keys) {
388+
llvm::errs() << "cannot read file " << Path << ": "
389+
<< toString(Keys.takeError()) << "\n";
390+
return true;
391+
}
392+
393+
for (const auto& Entry : *Keys) {
394+
if (auto *Obj = Entry.getAsObject()) {
395+
if (auto Kind = Obj->getString("OutputKind")) {
396+
if (*Kind != "cached-diagnostics")
397+
continue;
398+
}
399+
if (auto Key = Obj->getString("CacheKey")) {
400+
if (auto Buffer = loadCachedCompileResultFromCacheKey(
401+
Instance.getObjectStore(), Instance.getActionCache(),
402+
Instance.getDiags(), *Key)) {
403+
if (auto E = CDP->replayCachedDiagnostics(Buffer->getBuffer())) {
404+
llvm::errs() << "failed to replay cache: "
405+
<< toString(std::move(E)) << "\n";
406+
return true;
407+
}
408+
return false;
409+
}
410+
}
411+
}
412+
}
413+
llvm::errs() << "cannot locate cached diagnostics in file\n";
414+
return true;
415+
};
416+
417+
return llvm::any_of(Inputs, renderDiagsFromFile);
418+
}
419+
353420
int swift_cache_tool_main(ArrayRef<const char *> Args, const char *Argv0,
354421
void *MainAddr) {
355422
INITIALIZE_LLVM();

lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_swift_host_library(swiftFrontend STATIC
33
ArgsToFrontendInputsConverter.cpp
44
ArgsToFrontendOptionsConverter.cpp
55
ArgsToFrontendOutputsConverter.cpp
6+
CachedDiagnostics.cpp
67
CachingUtils.cpp
78
CompileJobCacheKey.cpp
89
CompilerInvocation.cpp

0 commit comments

Comments
 (0)