Skip to content

Commit 14b4120

Browse files
committed
More aggressively deduplicate global warnings based on contents.
I've been getting complaints from users being spammed by -gmodules missing file warnings going out of control because each object file depends on an entire DAG of PCM files that usually are all missing at once. To reduce this problem, this patch does two things: 1. Module now maintains a DenseMap<hash, once> that is used to display each warning only once, based on its actual text. 2. The PCM warning itself is reworded to include less details, such as the DIE offset, which is only useful to LLDB developers, who can get this from the dwarf log if they need it. Because the detail is omitted the hashing from (1) deduplicates the warnings. rdar://138144624
1 parent 90767bc commit 14b4120

File tree

4 files changed

+65
-25
lines changed

4 files changed

+65
-25
lines changed

lldb/include/lldb/Core/Module.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include "llvm/ADT/DenseSet.h"
3232
#include "llvm/ADT/STLFunctionalExtras.h"
33+
#include "llvm/ADT/StableHashing.h"
3334
#include "llvm/ADT/StringRef.h"
3435
#include "llvm/Support/Chrono.h"
3536

@@ -1057,9 +1058,10 @@ class Module : public std::enable_shared_from_this<Module>,
10571058
/// time for the symbol tables can be aggregated here.
10581059
StatsDuration m_symtab_index_time;
10591060

1060-
std::once_flag m_optimization_warning;
1061-
std::once_flag m_language_warning;
1062-
1061+
/// A set of hashes of all warnings and errors, to avoid reporting them
1062+
/// multiple times to the same Debugger.
1063+
llvm::DenseMap<llvm::stable_hash, std::unique_ptr<std::once_flag>>
1064+
m_shown_diagnostics;
10631065
void SymbolIndicesToSymbolContextList(Symtab *symtab,
10641066
std::vector<uint32_t> &symbol_indexes,
10651067
SymbolContextList &sc_list);
@@ -1086,6 +1088,7 @@ class Module : public std::enable_shared_from_this<Module>,
10861088
void ReportWarning(const llvm::formatv_object_base &payload);
10871089
void ReportError(const llvm::formatv_object_base &payload);
10881090
void ReportErrorIfModifyDetected(const llvm::formatv_object_base &payload);
1091+
std::once_flag *GetDiagnosticOnceFlag(llvm::StringRef msg);
10891092
};
10901093

10911094
} // namespace lldb_private

lldb/source/Core/Module.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,8 +1093,8 @@ void Module::ReportWarningOptimization(
10931093
ss << file_name
10941094
<< " was compiled with optimization - stepping may behave "
10951095
"oddly; variables may not be available.";
1096-
Debugger::ReportWarning(std::string(ss.GetString()), debugger_id,
1097-
&m_optimization_warning);
1096+
llvm::StringRef msg = ss.GetString();
1097+
Debugger::ReportWarning(msg.str(), debugger_id, GetDiagnosticOnceFlag(msg));
10981098
}
10991099

11001100
void Module::ReportWarningUnsupportedLanguage(
@@ -1104,8 +1104,8 @@ void Module::ReportWarningUnsupportedLanguage(
11041104
<< Language::GetNameForLanguageType(language)
11051105
<< "\". "
11061106
"Inspection of frame variables will be limited.";
1107-
Debugger::ReportWarning(std::string(ss.GetString()), debugger_id,
1108-
&m_language_warning);
1107+
llvm::StringRef msg = ss.GetString();
1108+
Debugger::ReportWarning(msg.str(), debugger_id, GetDiagnosticOnceFlag(msg));
11091109
}
11101110

11111111
void Module::ReportErrorIfModifyDetected(
@@ -1125,20 +1125,34 @@ void Module::ReportErrorIfModifyDetected(
11251125
}
11261126
}
11271127

1128+
std::once_flag *Module::GetDiagnosticOnceFlag(llvm::StringRef msg) {
1129+
// The manual DWARF index holds the module mutex on one thread, then
1130+
// spawns multiple worker threads which all can emit diagnostics. If
1131+
// this happens we give up on deduplicating them.
1132+
if (!m_mutex.try_lock())
1133+
return nullptr;
1134+
auto &once_ptr = m_shown_diagnostics[llvm::stable_hash_name(msg)];
1135+
if (!once_ptr)
1136+
once_ptr = std::make_unique<std::once_flag>();
1137+
m_mutex.unlock();
1138+
return once_ptr.get();
1139+
}
1140+
11281141
void Module::ReportError(const llvm::formatv_object_base &payload) {
11291142
StreamString strm;
11301143
GetDescription(strm.AsRawOstream(), lldb::eDescriptionLevelBrief);
1131-
strm.PutChar(' ');
1132-
strm.PutCString(payload.str());
1133-
Debugger::ReportError(strm.GetString().str());
1144+
std::string msg = payload.str();
1145+
strm << ' ' << msg;
1146+
Debugger::ReportError(strm.GetString().str(), {}, GetDiagnosticOnceFlag(msg));
11341147
}
11351148

11361149
void Module::ReportWarning(const llvm::formatv_object_base &payload) {
11371150
StreamString strm;
11381151
GetDescription(strm.AsRawOstream(), lldb::eDescriptionLevelFull);
1139-
strm.PutChar(' ');
1140-
strm.PutCString(payload.str());
1141-
Debugger::ReportWarning(std::string(strm.GetString()));
1152+
std::string msg = payload.str();
1153+
strm << ' ' << msg;
1154+
Debugger::ReportWarning(strm.GetString().str(), {},
1155+
GetDiagnosticOnceFlag(msg));
11421156
}
11431157

11441158
void Module::LogMessage(Log *log, const llvm::formatv_object_base &payload) {

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,13 +2069,15 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
20692069
Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp,
20702070
nullptr, nullptr, nullptr);
20712071
if (!module_sp) {
2072+
// ReportWarning also rate-limits based on the warning string,
2073+
// but in a -gmodules build, each object file has a similar DAG
2074+
// of module dependencies that would all be listed here.
20722075
GetObjectFile()->GetModule()->ReportWarning(
2073-
"{0:x16}: unable to locate module needed for external types: "
2074-
"{1}\nerror: {2}\nDebugging will be degraded due to missing "
2075-
"types. Rebuilding the project will regenerate the needed "
2076-
"module files.",
2077-
die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str(),
2078-
error.AsCString("unknown error"));
2076+
"{0}", error.AsCString("unknown error"));
2077+
GetObjectFile()->GetModule()->ReportWarning(
2078+
"Unable to locate module needed for external types.\n"
2079+
"Debugging will be degraded due to missing types. Rebuilding the "
2080+
"project will regenerate the needed module files.");
20792081
continue;
20802082
}
20812083

@@ -2095,12 +2097,11 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
20952097

20962098
if (dwo_id != dwo_dwo_id) {
20972099
GetObjectFile()->GetModule()->ReportWarning(
2098-
"{0:x16}: Module {1} is out-of-date (hash mismatch). Type "
2099-
"information "
2100-
"from this module may be incomplete or inconsistent with the rest of "
2101-
"the program. Rebuilding the project will regenerate the needed "
2102-
"module files.",
2103-
die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str());
2100+
"Module {0} is out-of-date (hash mismatch).\n"
2101+
"Type information from this module may be incomplete or inconsistent "
2102+
"with the rest of the program. Rebuilding the project will "
2103+
"regenerate the needed module files.",
2104+
dwo_module_spec.GetFileSpec().GetPath());
21042105
}
21052106
}
21062107
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# REQUIRES: system-darwin
2+
# Test the rate-limiting of module not found warnings.
3+
# RUN: rm -rf %t
4+
# RUN: mkdir -p %t
5+
6+
# RUN: echo 'module "C" { header "c.h" }' >%t/module.modulemap
7+
# RUN: echo 'struct c {};' >>%t/c.h
8+
# RUN: echo '@import C;' >%t/a.m
9+
# RUN: echo 'struct a { struct c c; } a;' >>%t/a.m
10+
# RUN: echo '@import C;' >%t/b.m
11+
# RUN: echo 'struct b { struct c c; } b;' >>%t/b.m
12+
# RUN: echo 'int main() {}' >>%t/b.m
13+
14+
# RUN: %clang_host -fmodules -Xclang -fmodules-cache-path=%t/cache -I%t -g -gmodules %t/a.m -o %t/a.o -c
15+
# RUN: %clang_host -fmodules -Xclang -fmodules-cache-path=%t/cache -I%t -g -gmodules %t/b.m -o %t/b.o -c
16+
# RUN: %clang_host %t/a.o %t/b.o -o %t/a.out
17+
# RUN: rm -rf %t/cache
18+
# RUN: %lldb %t/a.out -o "b main" -o run -o "p a" -o "p b" -o q 2>&1 | FileCheck %s
19+
# CHECK: {{[ab]}}.o{{.*}}/cache/{{.*}}/C-{{.*}}.pcm' does not exist
20+
# CHECK-NOT: /cache/{{.*}}/C-{.*}.pcm' does not exist
21+
# CHECK: {{[ab]}}.o{{.*}}/cache/{{.*}}/C-{{.*}}.pcm' does not exist
22+
# CHECK-NOT: /cache/{{.*}}/C-{.*}.pcm' does not exist

0 commit comments

Comments
 (0)