387 lines · plain
1;; Test callsite context graph generation for call graph with with MIBs2;; that have pruned contexts that partially match multiple inlined3;; callsite contexts, requiring duplication of context ids and nodes4;; while matching callsite nodes onto the graph. This test requires more5;; complex duplication due to multiple contexts for different allocations6;; that share some of the same callsite nodes.7;;8;; Original code looks like:9;;10;; char *D(bool Call1) {11;; if (Call1)12;; return new char[10];13;; else14;; return new char[10];15;; }16;;17;; char *C(bool Call1) {18;; return D(Call1);19;; }20;;21;; char *B(bool Call1) {22;; if (Call1)23;; return C(true);24;; else25;; return C(false);26;; }27;;28;; char *A(bool Call1) {29;; return B(Call1);30;; }31;;32;; char *A1() {33;; return A(true);34;; }35;;36;; char *A2() {37;; return A(true);38;; }39;;40;; char *A3() {41;; return A(false);42;; }43;;44;; char *A4() {45;; return A(false);46;; }47;;48;; char *E() {49;; return B(true);50;; }51;;52;; char *F() {53;; return B(false);54;; }55;;56;; int main(int argc, char **argv) {57;; char *a1 = A1(); // cold58;; char *a2 = A2(); // cold59;; char *e = E(); // default60;; char *a3 = A3(); // default61;; char *a4 = A4(); // default62;; char *f = F(); // cold63;; memset(a1, 0, 10);64;; memset(a2, 0, 10);65;; memset(e, 0, 10);66;; memset(a3, 0, 10);67;; memset(a4, 0, 10);68;; memset(f, 0, 10);69;; delete[] a3;70;; delete[] a4;71;; delete[] e;72;; sleep(10);73;; delete[] a1;74;; delete[] a2;75;; delete[] f;76;; return 0;77;; }78;;79;; Code compiled with -mllvm -memprof-ave-lifetime-cold-threshold=5 so that the80;; memory freed after sleep(10) results in cold lifetimes.81;;82;; The code below was created by forcing inlining of A into its callers,83;; without any other inlining or optimizations. Since both allocation contexts84;; via A for each allocation in D have the same allocation type (cold via85;; A1 and A2 for the first new in D, and non-cold via A3 and A4 for the second86;; new in D, the contexts for those respective allocations are pruned above A.87;; The allocations via E and F are to ensure we don't prune above B.88;;89;; The matching onto the inlined A[1234]->A sequences will require duplication90;; of the context id assigned to the context from A for each allocation in D.91;; This test ensures that we do this correctly in the presence of callsites92;; shared by the different duplicated context ids (i.e. callsite in C).93;;94;; The IR was then reduced using llvm-reduce with the expected FileCheck input.95 96; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \97; RUN: -memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \98; RUN: -memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \99; RUN: %s -S 2>&1 | FileCheck %s --check-prefix=DUMP100 101 102target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"103target triple = "x86_64-unknown-linux-gnu"104 105; Function Attrs: mustprogress noinline uwtable106define ptr @_Z1Db(i1 %Call1) #0 {107entry:108 %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7, !memprof !0, !callsite !5109 br label %return110 111if.else: ; No predecessors!112 %call1 = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7, !memprof !6, !callsite !11113 br label %return114 115return: ; preds = %if.else, %entry116 ret ptr null117}118 119; Function Attrs: nobuiltin120declare ptr @_Znam(i64) #1121 122define ptr @_Z1Cb(i1 %Call1) {123entry:124 %tobool = trunc i8 0 to i1125 %call = call noundef ptr @_Z1Db(i1 noundef zeroext %tobool), !callsite !12126 ret ptr null127}128 129; Function Attrs: mustprogress noinline uwtable130define ptr @_Z1Bb(i1 %Call1) #0 {131entry:132 %call = call noundef ptr @_Z1Cb(i1 noundef zeroext true), !callsite !13133 br label %return134 135if.else: ; No predecessors!136 %call1 = call noundef ptr @_Z1Cb(i1 noundef zeroext false), !callsite !14137 br label %return138 139return: ; preds = %if.else, %entry140 ret ptr null141}142 143define ptr @_Z1Ab(i1 %tobool) #2 {144entry:145 %call = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool), !callsite !15146 ret ptr null147}148 149; Function Attrs: mustprogress noinline uwtable150define ptr @_Z2A1v(i1 %tobool.i) #0 {151entry:152 %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i), !callsite !16153 ret ptr null154}155 156; Function Attrs: mustprogress noinline uwtable157define ptr @_Z2A2v(i1 %tobool.i) #0 {158entry:159 %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i), !callsite !17160 ret ptr null161}162 163; Function Attrs: mustprogress noinline uwtable164define ptr @_Z2A3v(i1 %tobool.i) #0 {165entry:166 %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i), !callsite !18167 ret ptr null168}169 170; Function Attrs: mustprogress noinline uwtable171define ptr @_Z2A4v(i1 %tobool.i) #0 {172entry:173 %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i), !callsite !19174 ret ptr null175}176 177; Function Attrs: mustprogress noinline uwtable178define ptr @_Z1Ev() #0 {179entry:180 %call = call noundef ptr @_Z1Bb(i1 noundef zeroext true), !callsite !20181 ret ptr null182}183 184; Function Attrs: mustprogress noinline uwtable185define ptr @_Z1Fv() #0 {186entry:187 %call = call noundef ptr @_Z1Bb(i1 noundef zeroext false), !callsite !21188 ret ptr null189}190 191; Function Attrs: noinline192declare i32 @main() #3193 194; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)195declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #4196 197declare void @_ZdaPv() #5198 199declare i32 @sleep() #6200 201; uselistorder directives202uselistorder ptr @_Znam, { 1, 0 }203 204attributes #0 = { mustprogress noinline uwtable "disable-tail-calls"="true" "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }205attributes #1 = { nobuiltin }206attributes #2 = { "tune-cpu"="generic" }207attributes #3 = { noinline }208attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: write) }209attributes #5 = { "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }210attributes #6 = { "disable-tail-calls"="true" }211attributes #7 = { builtin allocsize(0) }212 213!0 = !{!1, !3}214!1 = !{!2, !"notcold"}215!2 = !{i64 4854880825882961848, i64 -904694911315397047, i64 6532298921261778285, i64 1905834578520680781}216!3 = !{!4, !"cold"}217!4 = !{i64 4854880825882961848, i64 -904694911315397047, i64 6532298921261778285, i64 -6528110295079665978}218!5 = !{i64 4854880825882961848}219!6 = !{!7, !9}220!7 = !{!8, !"notcold"}221!8 = !{i64 -8775068539491628272, i64 -904694911315397047, i64 7859682663773658275, i64 -6528110295079665978}222!9 = !{!10, !"cold"}223!10 = !{i64 -8775068539491628272, i64 -904694911315397047, i64 7859682663773658275, i64 -4903163940066524832}224!11 = !{i64 -8775068539491628272}225!12 = !{i64 -904694911315397047}226!13 = !{i64 6532298921261778285}227!14 = !{i64 7859682663773658275}228!15 = !{i64 -6528110295079665978}229!16 = !{i64 -6528110295079665978, i64 5747919905719679568}230!17 = !{i64 -6528110295079665978, i64 -5753238080028016843}231!18 = !{i64 -6528110295079665978, i64 1794685869326395337}232!19 = !{i64 -6528110295079665978, i64 5462047985461644151}233!20 = !{i64 1905834578520680781}234!21 = !{i64 -4903163940066524832}235 236 237;; After adding only the alloc node memprof metadata, we only have 4 contexts (we only238;; match the interesting parts of the pre-update graph here).239 240; DUMP: CCG before updating call stack chains:241; DUMP: Callsite Context Graph:242 243; DUMP: Node [[D1:0x[a-z0-9]+]]244; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7 (clone 0)245; DUMP: AllocTypes: NotColdCold246; DUMP: ContextIds: 1 2247 248; DUMP: Node [[C:0x[a-z0-9]+]]249; DUMP: null Call250; DUMP: AllocTypes: NotColdCold251; DUMP: ContextIds: 1 2 3 4252; DUMP: CalleeEdges:253; DUMP: Edge from Callee [[D1]] to Caller: [[C]] AllocTypes: NotColdCold ContextIds: 1 2254; DUMP: Edge from Callee [[D2:0x[a-z0-9]+]] to Caller: [[C]] AllocTypes: NotColdCold ContextIds: 3 4255 256; DUMP: Node [[D2]]257; DUMP: %call1 = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7 (clone 0)258; DUMP: AllocTypes: NotColdCold259; DUMP: ContextIds: 3 4260 261 262;; After updating for callsite metadata, we should have duplicated the context263;; ids coming from node A (2 and 3) 4 times, for the 4 different callers of A,264;; and used those on new nodes for those callers. Note that while in reality265;; we only have cold edges coming from A1 and A2 and noncold from A3 and A4,266;; due to the pruning we have lost this information and thus end up duplicating267;; both of A's contexts to all of the new nodes (which could result in some268;; unnecessary cloning.269 270; DUMP: CCG before cloning:271; DUMP: Callsite Context Graph:272; DUMP: Node [[D1]]273; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7 (clone 0)274; DUMP: AllocTypes: NotColdCold275; DUMP: ContextIds: 1 2 5 7 9 11276; DUMP: CalleeEdges:277; DUMP: CallerEdges:278; DUMP: Edge from Callee [[D1]] to Caller: [[C]] AllocTypes: NotColdCold ContextIds: 1 2 5 7 9 11279 280; DUMP: Node [[C]]281; DUMP: %call = call noundef ptr @_Z1Db(i1 noundef zeroext %tobool) (clone 0)282; DUMP: AllocTypes: NotColdCold283; DUMP: ContextIds: 1 2 3 4 5 6 7 8 9 10 11 12284; DUMP: CalleeEdges:285; DUMP: Edge from Callee [[D1]] to Caller: [[C]] AllocTypes: NotColdCold ContextIds: 1 2 5 7 9 11286; DUMP: Edge from Callee [[D2]] to Caller: [[C]] AllocTypes: NotColdCold ContextIds: 3 4 6 8 10 12287; DUMP: CallerEdges:288; DUMP: Edge from Callee [[C]] to Caller: [[B1:0x[a-z0-9]+]] AllocTypes: NotColdCold ContextIds: 1 2 5 7 9 11289; DUMP: Edge from Callee [[C]] to Caller: [[B2:0x[a-z0-9]+]] AllocTypes: NotColdCold ContextIds: 3 4 6 8 10 12290 291; DUMP: Node [[B1]]292; DUMP: %call = call noundef ptr @_Z1Cb(i1 noundef zeroext true) (clone 0)293; DUMP: AllocTypes: NotColdCold294; DUMP: ContextIds: 1 2 5 7 9 11295; DUMP: CalleeEdges:296; DUMP: Edge from Callee [[C]] to Caller: [[B1]] AllocTypes: NotColdCold ContextIds: 1 2 5 7 9 11297; DUMP: CallerEdges:298; DUMP: Edge from Callee [[B1]] to Caller: [[E:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1299; DUMP: Edge from Callee [[B1]] to Caller: [[A2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 5300; DUMP: Edge from Callee [[B1]] to Caller: [[A3:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 7301; DUMP: Edge from Callee [[B1]] to Caller: [[A1:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 9302; DUMP: Edge from Callee [[B1]] to Caller: [[A4:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 11303; DUMP: Edge from Callee [[B1]] to Caller: [[A:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 2304 305; DUMP: Node [[E]]306; DUMP: %call = call noundef ptr @_Z1Bb(i1 noundef zeroext true) (clone 0)307; DUMP: AllocTypes: NotCold308; DUMP: ContextIds: 1309; DUMP: CalleeEdges:310; DUMP: Edge from Callee [[B1]] to Caller: [[E]] AllocTypes: NotCold ContextIds: 1311; DUMP: CallerEdges:312 313; DUMP: Node [[D2]]314; DUMP: %call1 = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #7 (clone 0)315; DUMP: AllocTypes: NotColdCold316; DUMP: ContextIds: 3 4 6 8 10 12317; DUMP: CalleeEdges:318; DUMP: CallerEdges:319; DUMP: Edge from Callee [[D2]] to Caller: [[C]] AllocTypes: NotColdCold ContextIds: 3 4 6 8 10 12320 321; DUMP: Node [[B2]]322; DUMP: %call1 = call noundef ptr @_Z1Cb(i1 noundef zeroext false) (clone 0)323; DUMP: AllocTypes: NotColdCold324; DUMP: ContextIds: 3 4 6 8 10 12325; DUMP: CalleeEdges:326; DUMP: Edge from Callee [[C]] to Caller: [[B2]] AllocTypes: NotColdCold ContextIds: 3 4 6 8 10 12327; DUMP: CallerEdges:328; DUMP: Edge from Callee [[B2]] to Caller: [[F:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 4329; DUMP: Edge from Callee [[B2]] to Caller: [[A2]] AllocTypes: NotCold ContextIds: 6330; DUMP: Edge from Callee [[B2]] to Caller: [[A3]] AllocTypes: NotCold ContextIds: 8331; DUMP: Edge from Callee [[B2]] to Caller: [[A1]] AllocTypes: NotCold ContextIds: 10332; DUMP: Edge from Callee [[B2]] to Caller: [[A4]] AllocTypes: NotCold ContextIds: 12333; DUMP: Edge from Callee [[B2]] to Caller: [[A]] AllocTypes: NotCold ContextIds: 3334 335; DUMP: Node [[F]]336; DUMP: %call = call noundef ptr @_Z1Bb(i1 noundef zeroext false) (clone 0)337; DUMP: AllocTypes: Cold338; DUMP: ContextIds: 4339; DUMP: CalleeEdges:340; DUMP: Edge from Callee [[B2]] to Caller: [[F]] AllocTypes: Cold ContextIds: 4341; DUMP: CallerEdges:342 343; DUMP: Node [[A2]]344; DUMP: %call = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool) (clone 0)345; DUMP: AllocTypes: NotColdCold346; DUMP: ContextIds: 5 6347; DUMP: CalleeEdges:348; DUMP: Edge from Callee [[B1]] to Caller: [[A2]] AllocTypes: Cold ContextIds: 5349; DUMP: Edge from Callee [[B2]] to Caller: [[A2]] AllocTypes: NotCold ContextIds: 6350; DUMP: CallerEdges:351 352; DUMP: Node [[A3]]353; DUMP: %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i) (clone 0)354; DUMP: AllocTypes: NotColdCold355; DUMP: ContextIds: 7 8356; DUMP: CalleeEdges:357; DUMP: Edge from Callee [[B1]] to Caller: [[A3]] AllocTypes: Cold ContextIds: 7358; DUMP: Edge from Callee [[B2]] to Caller: [[A3]] AllocTypes: NotCold ContextIds: 8359; DUMP: CallerEdges:360 361; DUMP: Node [[A1]]362; DUMP: %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i) (clone 0)363; DUMP: AllocTypes: NotColdCold364; DUMP: ContextIds: 9 10365; DUMP: CalleeEdges:366; DUMP: Edge from Callee [[B1]] to Caller: [[A1]] AllocTypes: Cold ContextIds: 9367; DUMP: Edge from Callee [[B2]] to Caller: [[A1]] AllocTypes: NotCold ContextIds: 10368; DUMP: CallerEdges:369 370; DUMP: Node [[A4]]371; DUMP: %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i) (clone 0)372; DUMP: AllocTypes: NotColdCold373; DUMP: ContextIds: 11 12374; DUMP: CalleeEdges:375; DUMP: Edge from Callee [[B1]] to Caller: [[A4]] AllocTypes: Cold ContextIds: 11376; DUMP: Edge from Callee [[B2]] to Caller: [[A4]] AllocTypes: NotCold ContextIds: 12377; DUMP: CallerEdges:378 379; DUMP: Node [[A]]380; DUMP: %call.i = call noundef ptr @_Z1Bb(i1 noundef zeroext %tobool.i) (clone 0)381; DUMP: AllocTypes: NotColdCold382; DUMP: ContextIds: 2 3383; DUMP: CalleeEdges:384; DUMP: Edge from Callee [[B1]] to Caller: [[A]] AllocTypes: Cold ContextIds: 2385; DUMP: Edge from Callee [[B2]] to Caller: [[A]] AllocTypes: NotCold ContextIds: 3386; DUMP: CallerEdges:387