Skip to content

Commit 0b0b7c4

Browse files
committed
[LiveDebugValues] Add cutoffs to avoid pathological behavior
Summary: We received a report of LiveDebugValues consuming 25GB+ of RAM when compiling code generated by Unity's IL2CPP scripting backend. There's an initial 5GB spike due to repeatedly copying cached lists of MachineBasicBlocks within the UserValueScopes members of VarLocs. But the larger scaling issue arises due to the fact that prior to range extension, there are 81K basic blocks and 156K DBG_VALUEs: given enough memory, LiveDebugValues would insert 101 million MIs (I counted this by incrementing a counter inside of VarLoc::BuildDbgValue). It seems like LiveDebugValues would have to be rearchitected to support this kind of input (we'd need some new represntation for DBG_VALUEs that get inserted into ~every block via flushPendingLocs). OTOH, large globs of auto-generated code are typically not debugged interactively. So: add cutoffs to disable range extension when the input is too big. I chose the cutoffs experimentally, erring on the conservative side. When compiling a large collection of Apple software, range extension never got disabled. rdar://63418929 Reviewers: aprantl, friss, jmorse, Orlando Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D80662 (cherry picked from commit d11155d)
1 parent 04853a8 commit 0b0b7c4

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

llvm/lib/CodeGen/LiveDebugValues.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ using namespace llvm;
8080
STATISTIC(NumInserted, "Number of DBG_VALUE instructions inserted");
8181
STATISTIC(NumRemoved, "Number of DBG_VALUE instructions removed");
8282

83+
// Options to prevent pathological compile-time behavior. If InputBBLimit and
84+
// InputDbgValueLimit are both exceeded, range extension is disabled.
85+
static cl::opt<unsigned> InputBBLimit(
86+
"livedebugvalues-input-bb-limit",
87+
cl::desc("Maximum input basic blocks before DBG_VALUE limit applies"),
88+
cl::init(10000), cl::Hidden);
89+
static cl::opt<unsigned> InputDbgValueLimit(
90+
"livedebugvalues-input-dbg-value-limit",
91+
cl::desc(
92+
"Maximum input DBG_VALUE insts supported by debug range extension"),
93+
cl::init(50000), cl::Hidden);
94+
8395
// If @MI is a DBG_VALUE with debug value described by a defined
8496
// register, returns the number of this register. In the other case, returns 0.
8597
static Register isDbgValueDescribedByReg(const MachineInstr &MI) {
@@ -1752,6 +1764,22 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
17521764
Worklist.push(RPONumber);
17531765
++RPONumber;
17541766
}
1767+
1768+
if (RPONumber > InputBBLimit) {
1769+
unsigned NumInputDbgValues = 0;
1770+
for (auto &MBB : MF)
1771+
for (auto &MI : MBB)
1772+
if (MI.isDebugValue())
1773+
++NumInputDbgValues;
1774+
if (NumInputDbgValues > InputDbgValueLimit) {
1775+
LLVM_DEBUG(dbgs() << "Disabling LiveDebugValues: " << MF.getName()
1776+
<< " has " << RPONumber << " basic blocks and "
1777+
<< NumInputDbgValues
1778+
<< " input DBG_VALUEs, exceeding limits.\n");
1779+
return false;
1780+
}
1781+
}
1782+
17551783
// This is a standard "union of predecessor outs" dataflow problem.
17561784
// To solve it, we perform join() and process() using the two worklist method
17571785
// until the ranges converge.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Test cutoffs for livedebugvalues debug range extension.
2+
# Disable LDV if the input-bb-limit AND the input-dbg-value-limit are both exceeded.
3+
4+
# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown \
5+
# RUN: -livedebugvalues-input-bb-limit=1 \
6+
# RUN: -livedebugvalues-input-dbg-value-limit=1 \
7+
# RUN: | FileCheck %s -check-prefix=LDV-DISABLED
8+
9+
# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown \
10+
# RUN: -livedebugvalues-input-bb-limit=1 \
11+
# RUN: -livedebugvalues-input-dbg-value-limit=10 \
12+
# RUN: | FileCheck %s -check-prefix=LDV-ENABLED
13+
14+
# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown \
15+
# RUN: -livedebugvalues-input-bb-limit=10 \
16+
# RUN: -livedebugvalues-input-dbg-value-limit=1 \
17+
# RUN: | FileCheck %s -check-prefix=LDV-ENABLED
18+
19+
# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown \
20+
# RUN: -livedebugvalues-input-bb-limit=10 \
21+
# RUN: -livedebugvalues-input-dbg-value-limit=10 \
22+
# RUN: | FileCheck %s -check-prefix=LDV-ENABLED
23+
24+
# LDV-DISABLED-LABEL: bb.1.exit
25+
# LDV-DISABLED-NEXT: $edi = MOV32rm
26+
27+
# LDV-ENABLED-LABEL: bb.1.exit
28+
# LDV-ENABLED-NEXT: DBG_VALUE $rsp, 0, {{.*}}, !DIExpression(DW_OP_plus_uconst, 4)
29+
# LDV-ENABLED-NEXT: $edi = MOV32rm
30+
31+
--- |
32+
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
33+
34+
declare i32 @use(i32)
35+
36+
define i32 @foo(i32 %x) !dbg !6 {
37+
entry:
38+
%y = add i32 %x, %x, !dbg !12
39+
call void @llvm.dbg.value(metadata i32 %y, metadata !9, metadata !DIExpression()), !dbg !12
40+
br label %exit, !dbg !13
41+
42+
exit: ; preds = %entry
43+
%z = call i32 @use(i32 %y), !dbg !14
44+
call void @llvm.dbg.value(metadata i32 %z, metadata !11, metadata !DIExpression()), !dbg !14
45+
ret i32 %z, !dbg !15
46+
}
47+
48+
declare void @llvm.dbg.value(metadata, metadata, metadata)
49+
50+
!llvm.dbg.cu = !{!0}
51+
!llvm.debugify = !{!3, !4}
52+
!llvm.module.flags = !{!5}
53+
54+
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
55+
!1 = !DIFile(filename: "/tmp/t.ll", directory: "/")
56+
!2 = !{}
57+
!3 = !{i32 4}
58+
!4 = !{i32 2}
59+
!5 = !{i32 2, !"Debug Info Version", i32 3}
60+
!6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
61+
!7 = !DISubroutineType(types: !2)
62+
!8 = !{!9, !11}
63+
!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
64+
!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
65+
!11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 3, type: !10)
66+
!12 = !DILocation(line: 1, column: 1, scope: !6)
67+
!13 = !DILocation(line: 2, column: 1, scope: !6)
68+
!14 = !DILocation(line: 3, column: 1, scope: !6)
69+
!15 = !DILocation(line: 4, column: 1, scope: !6)
70+
71+
...
72+
---
73+
name: foo
74+
liveins:
75+
- { reg: '$edi', virtual-reg: '' }
76+
stack:
77+
- { id: 0, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
78+
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
79+
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
80+
body: |
81+
bb.0.entry:
82+
successors: %bb.1(0x80000000)
83+
liveins: $edi
84+
85+
frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
86+
CFI_INSTRUCTION def_cfa_offset 16
87+
renamable $edi = ADD32rr renamable $edi, killed renamable $edi, implicit-def $eflags, debug-location !12
88+
DBG_VALUE renamable $edi, $noreg, !9, !DIExpression(), debug-location !12
89+
MOV32mr $rsp, 1, $noreg, 4, $noreg, killed $edi :: (store 4 into %stack.0)
90+
DBG_VALUE $rsp, 0, !9, !DIExpression(DW_OP_plus_uconst, 4), debug-location !12
91+
92+
bb.1.exit:
93+
$edi = MOV32rm $rsp, 1, $noreg, 4, $noreg :: (load 4 from %stack.0)
94+
CALL64pcrel32 @use, csr_64, implicit $rsp, implicit $ssp, implicit killed $edi, implicit-def $eax, debug-location !14
95+
DBG_VALUE renamable $eax, $noreg, !11, !DIExpression(), debug-location !14
96+
$rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !15
97+
RETQ implicit killed $eax, debug-location !15
98+
99+
...

0 commit comments

Comments
 (0)