1;; Test callsite context graph generation for simple call graph with 2;; two memprof contexts and no inlining, as well as graph and IR cloning. 3;; 4;; Original code looks like: 5;; 6;; char *bar() { 7;; return new char[10]; 8;; } 9;; 10;; char *baz() { 11;; return bar(); 12;; } 13;; 14;; char *foo() { 15;; return baz(); 16;; } 17;; 18;; int main(int argc, char **argv) { 19;; char *x = foo(); 20;; char *y = foo(); 21;; memset(x, 0, 10); 22;; memset(y, 0, 10); 23;; delete[] x; 24;; sleep(10); 25;; delete[] y; 26;; return 0; 27;; } 28;; 29;; Code compiled with -mllvm -memprof-ave-lifetime-cold-threshold=5 so that the 30;; memory freed after sleep(10) results in cold lifetimes. 31;; 32;; The IR was then reduced using llvm-reduce with the expected FileCheck input. 33 34;; -stats requires asserts 35; REQUIRES: asserts 36 37; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \ 38; RUN: -memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \ 39; RUN: -memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \ 40; RUN: -stats -pass-remarks=memprof-context-disambiguation \ 41; RUN: -memprof-report-hinted-sizes \ 42; RUN: %s -S 2>&1 | FileCheck %s --check-prefix=DUMP --check-prefix=IR \ 43; RUN: --check-prefix=STATS --check-prefix=REMARKS --check-prefix=SIZES 44 45; RUN: cat %t.ccg.postbuild.dot | FileCheck %s --check-prefix=DOT 46;; We should have cloned bar, baz, and foo, for the cold memory allocation. 47; RUN: cat %t.ccg.cloned.dot | FileCheck %s --check-prefix=DOTCLONED 48 49;; Check again without -supports-hot-cold-new and ensure all MIB are cold and 50;; that there is no cloning. 51; RUN: opt -passes=memprof-context-disambiguation \ 52; RUN: -memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \ 53; RUN: -memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \ 54; RUN: -stats -pass-remarks=memprof-context-disambiguation \ 55; RUN: %s -S 2>&1 | FileCheck %s --implicit-check-not="Callsite Context Graph" \ 56; RUN: --implicit-check-not="created clone" 57 58target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 59target triple = "x86_64-unknown-linux-gnu" 60 61define i32 @main() #0 { 62entry: 63 %call = call noundef ptr @_Z3foov(), !callsite !0 64 %call1 = call noundef ptr @_Z3foov(), !callsite !1 65 ret i32 0 66} 67 68; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) 69declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #1 70 71; Function Attrs: nobuiltin 72declare void @_ZdaPv() #2 73 74define internal ptr @_Z3barv() #3 { 75entry: 76 %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !memprof !2, !callsite !7 77 ret ptr null 78} 79 80declare ptr @_Znam(i64) 81 82define internal ptr @_Z3bazv() #4 { 83entry: 84 %call = call noundef ptr @_Z3barv(), !callsite !8 85 ret ptr null 86} 87 88; Function Attrs: noinline 89define internal ptr @_Z3foov() #5 { 90entry: 91 %call = call noundef ptr @_Z3bazv(), !callsite !9 92 ret ptr null 93} 94 95; uselistorder directives 96uselistorder ptr @_Z3foov, { 1, 0 } 97 98attributes #0 = { "tune-cpu"="generic" } 99attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) } 100attributes #2 = { nobuiltin } 101attributes #3 = { "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" } 102attributes #4 = { "stack-protector-buffer-size"="8" } 103attributes #5 = { noinline } 104attributes #6 = { builtin } 105 106!0 = !{i64 8632435727821051414} 107!1 = !{i64 -3421689549917153178} 108!2 = !{!3, !5} 109!3 = !{!4, !"notcold", !10} 110!4 = !{i64 9086428284934609951, i64 -5964873800580613432, i64 2732490490862098848, i64 8632435727821051414} 111!5 = !{!6, !"cold", !11, !12} 112!6 = !{i64 9086428284934609951, i64 -5964873800580613432, i64 2732490490862098848, i64 -3421689549917153178} 113!7 = !{i64 9086428284934609951} 114!8 = !{i64 -5964873800580613432} 115!9 = !{i64 2732490490862098848} 116!10 = !{i64 123, i64 100} 117!11 = !{i64 456, i64 200} 118!12 = !{i64 789, i64 300} 119 120 121; DUMP: CCG before cloning: 122; DUMP: Callsite Context Graph: 123; DUMP: Node [[BAR:0x[a-z0-9]+]] 124; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 125; DUMP: AllocTypes: NotColdCold 126; DUMP: ContextIds: 1 2 127; DUMP: CalleeEdges: 128; DUMP: CallerEdges: 129; DUMP: Edge from Callee [[BAR]] to Caller: [[BAZ:0x[a-z0-9]+]] AllocTypes: NotColdCold ContextIds: 1 2 130 131; DUMP: Node [[BAZ]] 132; DUMP: %call = call noundef ptr @_Z3barv() (clone 0) 133; DUMP: AllocTypes: NotColdCold 134; DUMP: ContextIds: 1 2 135; DUMP: CalleeEdges: 136; DUMP: Edge from Callee [[BAR]] to Caller: [[BAZ]] AllocTypes: NotColdCold ContextIds: 1 2 137; DUMP: CallerEdges: 138; DUMP: Edge from Callee [[BAZ]] to Caller: [[FOO:0x[a-z0-9]+]] AllocTypes: NotColdCold ContextIds: 1 2 139 140; DUMP: Node [[FOO]] 141; DUMP: %call = call noundef ptr @_Z3bazv() (clone 0) 142; DUMP: AllocTypes: NotColdCold 143; DUMP: ContextIds: 1 2 144; DUMP: CalleeEdges: 145; DUMP: Edge from Callee [[BAZ]] to Caller: [[FOO]] AllocTypes: NotColdCold ContextIds: 1 2 146; DUMP: CallerEdges: 147; DUMP: Edge from Callee [[FOO]] to Caller: [[MAIN1:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1 148; DUMP: Edge from Callee [[FOO]] to Caller: [[MAIN2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 2 149 150; DUMP: Node [[MAIN1]] 151; DUMP: %call = call noundef ptr @_Z3foov() (clone 0) 152; DUMP: AllocTypes: NotCold 153; DUMP: ContextIds: 1 154; DUMP: CalleeEdges: 155; DUMP: Edge from Callee [[FOO]] to Caller: [[MAIN1]] AllocTypes: NotCold ContextIds: 1 156; DUMP: CallerEdges: 157 158; DUMP: Node [[MAIN2]] 159; DUMP: %call1 = call noundef ptr @_Z3foov() (clone 0) 160; DUMP: AllocTypes: Cold 161; DUMP: ContextIds: 2 162; DUMP: CalleeEdges: 163; DUMP: Edge from Callee [[FOO]] to Caller: [[MAIN2]] AllocTypes: Cold ContextIds: 2 164; DUMP: CallerEdges: 165 166; DUMP: CCG after cloning: 167; DUMP: Callsite Context Graph: 168; DUMP: Node [[BAR:0x[a-z0-9]+]] 169; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 170; DUMP: AllocTypes: NotCold 171; DUMP: ContextIds: 1 172; DUMP: CalleeEdges: 173; DUMP: CallerEdges: 174; DUMP: Edge from Callee [[BAR]] to Caller: [[BAZ:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1 175; DUMP: Clones: [[BAR2:0x[a-z0-9]+]] 176 177; DUMP: Node [[BAZ]] 178; DUMP: %call = call noundef ptr @_Z3barv() (clone 0) 179; DUMP: AllocTypes: NotCold 180; DUMP: ContextIds: 1 181; DUMP: CalleeEdges: 182; DUMP: Edge from Callee [[BAR]] to Caller: [[BAZ]] AllocTypes: NotCold ContextIds: 1 183; DUMP: CallerEdges: 184; DUMP: Edge from Callee [[BAZ]] to Caller: [[FOO:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1 185; DUMP: Clones: [[BAZ2:0x[a-z0-9]+]] 186 187; DUMP: Node [[FOO]] 188; DUMP: %call = call noundef ptr @_Z3bazv() (clone 0) 189; DUMP: AllocTypes: NotCold 190; DUMP: ContextIds: 1 191; DUMP: CalleeEdges: 192; DUMP: Edge from Callee [[BAZ]] to Caller: [[FOO]] AllocTypes: NotCold ContextIds: 1 193; DUMP: CallerEdges: 194; DUMP: Edge from Callee [[FOO]] to Caller: [[MAIN1:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 1 195; DUMP: Clones: [[FOO2:0x[a-z0-9]+]] 196 197; DUMP: Node [[MAIN1]] 198; DUMP: %call = call noundef ptr @_Z3foov() (clone 0) 199; DUMP: AllocTypes: NotCold 200; DUMP: ContextIds: 1 201; DUMP: CalleeEdges: 202; DUMP: Edge from Callee [[FOO]] to Caller: [[MAIN1]] AllocTypes: NotCold ContextIds: 1 203; DUMP: CallerEdges: 204 205; DUMP: Node [[MAIN2]] 206; DUMP: %call1 = call noundef ptr @_Z3foov() (clone 0) 207; DUMP: AllocTypes: Cold 208; DUMP: ContextIds: 2 209; DUMP: CalleeEdges: 210; DUMP: Edge from Callee [[FOO2]] to Caller: [[MAIN2]] AllocTypes: Cold ContextIds: 2 211; DUMP: CallerEdges: 212 213; DUMP: Node [[FOO2]] 214; DUMP: %call = call noundef ptr @_Z3bazv() (clone 0) 215; DUMP: AllocTypes: Cold 216; DUMP: ContextIds: 2 217; DUMP: CalleeEdges: 218; DUMP: Edge from Callee [[BAZ2]] to Caller: [[FOO2]] AllocTypes: Cold ContextIds: 2 219; DUMP: CallerEdges: 220; DUMP: Edge from Callee [[FOO2]] to Caller: [[MAIN2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 2 221; DUMP: Clone of [[FOO]] 222 223; DUMP: Node [[BAZ2]] 224; DUMP: %call = call noundef ptr @_Z3barv() (clone 0) 225; DUMP: AllocTypes: Cold 226; DUMP: ContextIds: 2 227; DUMP: CalleeEdges: 228; DUMP: Edge from Callee [[BAR2]] to Caller: [[BAZ2]] AllocTypes: Cold ContextIds: 2 229; DUMP: CallerEdges: 230; DUMP: Edge from Callee [[BAZ2]] to Caller: [[FOO2]] AllocTypes: Cold ContextIds: 2 231; DUMP: Clone of [[BAZ]] 232 233; DUMP: Node [[BAR2]] 234; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 235; DUMP: AllocTypes: Cold 236; DUMP: ContextIds: 2 237; DUMP: CalleeEdges: 238; DUMP: CallerEdges: 239; DUMP: Edge from Callee [[BAR2]] to Caller: [[BAZ2]] AllocTypes: Cold ContextIds: 2 240; DUMP: Clone of [[BAR]] 241 242 243; REMARKS: created clone _Z3barv.memprof.1 244; REMARKS: created clone _Z3bazv.memprof.1 245; REMARKS: created clone _Z3foov.memprof.1 246; REMARKS: call in clone main assigned to call function clone _Z3foov.memprof.1 247; REMARKS: call in clone _Z3foov.memprof.1 assigned to call function clone _Z3bazv.memprof.1 248; REMARKS: call in clone _Z3bazv.memprof.1 assigned to call function clone _Z3barv.memprof.1 249; REMARKS: call in clone _Z3barv.memprof.1 marked with memprof allocation attribute cold 250; REMARKS: call in clone main assigned to call function clone _Z3foov 251; REMARKS: call in clone _Z3foov assigned to call function clone _Z3bazv 252; REMARKS: call in clone _Z3bazv assigned to call function clone _Z3barv 253; REMARKS: call in clone _Z3barv marked with memprof allocation attribute notcold 254 255; SIZES: NotCold full allocation context 123 with total size 100 is NotCold after cloning 256; SIZES: Cold full allocation context 456 with total size 200 is Cold after cloning 257; SIZES: Cold full allocation context 789 with total size 300 is Cold after cloning 258 259; IR: define {{.*}} @main 260;; The first call to foo does not allocate cold memory. It should call the 261;; original functions, which ultimately call the original allocation decorated 262;; with a "notcold" attribute. 263; IR: call {{.*}} @_Z3foov() 264;; The second call to foo allocates cold memory. It should call cloned functions 265;; which ultimately call a cloned allocation decorated with a "cold" attribute. 266; IR: call {{.*}} @_Z3foov.memprof.1() 267; IR: define internal {{.*}} @_Z3barv() 268; IR: call {{.*}} @_Znam(i64 noundef 10) #[[NOTCOLD:[0-9]+]] 269; IR: define internal {{.*}} @_Z3bazv() 270; IR: call {{.*}} @_Z3barv() 271; IR: define internal {{.*}} @_Z3foov() 272; IR: call {{.*}} @_Z3bazv() 273; IR: define internal {{.*}} @_Z3barv.memprof.1() 274; IR: call {{.*}} @_Znam(i64 noundef 10) #[[COLD:[0-9]+]] 275; IR: define internal {{.*}} @_Z3bazv.memprof.1() 276; IR: call {{.*}} @_Z3barv.memprof.1() 277; IR: define internal {{.*}} @_Z3foov.memprof.1() 278; IR: call {{.*}} @_Z3bazv.memprof.1() 279; IR: attributes #[[NOTCOLD]] = { builtin "memprof"="notcold" } 280; IR: attributes #[[COLD]] = { builtin "memprof"="cold" } 281 282 283; STATS: 1 memprof-context-disambiguation - Number of cold static allocations (possibly cloned) 284; STATS: 1 memprof-context-disambiguation - Number of not cold static allocations (possibly cloned) 285; STATS: 3 memprof-context-disambiguation - Number of function clones created during whole program analysis 286 287 288; DOT: digraph "postbuild" { 289; DOT: label="postbuild"; 290; DOT: Node[[BAR:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAR]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z3barv -\> _Znam}"]; 291; DOT: Node[[BAZ:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAZ]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: 12481870273128938184\n_Z3bazv -\> _Z3barv}"]; 292; DOT: Node[[BAZ]] -> Node[[BAR]][tooltip="ContextIds: 1 2",fillcolor="mediumorchid1"]; 293; DOT: Node[[FOO:0x[a-z0-9]+]] [shape=record,tooltip="N[[FOO]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: 2732490490862098848\n_Z3foov -\> _Z3bazv}"]; 294; DOT: Node[[FOO]] -> Node[[BAZ]][tooltip="ContextIds: 1 2",fillcolor="mediumorchid1"]; 295; DOT: Node[[MAIN1:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN1]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 8632435727821051414\nmain -\> _Z3foov}"]; 296; DOT: Node[[MAIN1]] -> Node[[FOO]][tooltip="ContextIds: 1",fillcolor="brown1"]; 297; DOT: Node[[MAIN2:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN2]] ContextIds: 2",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 15025054523792398438\nmain -\> _Z3foov}"]; 298; DOT: Node[[MAIN2]] -> Node[[FOO]][tooltip="ContextIds: 2",fillcolor="cyan"]; 299; DOT: } 300 301 302; DOTCLONED: digraph "cloned" { 303; DOTCLONED: label="cloned"; 304; DOTCLONED: Node[[BAR:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAR]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z3barv -\> _Znam}"]; 305; DOTCLONED: Node[[BAZ:0x[a-z0-9]+]] [shape=record,tooltip="N[[BAZ]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 12481870273128938184\n_Z3bazv -\> _Z3barv}"]; 306; DOTCLONED: Node[[BAZ]] -> Node[[BAR]][tooltip="ContextIds: 1",fillcolor="brown1"]; 307; DOTCLONED: Node[[FOO:0x[a-z0-9]+]] [shape=record,tooltip="N[[FOO]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 2732490490862098848\n_Z3foov -\> _Z3bazv}"]; 308; DOTCLONED: Node[[FOO]] -> Node[[BAZ]][tooltip="ContextIds: 1",fillcolor="brown1"]; 309; DOTCLONED: Node[[MAIN1:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN1]] ContextIds: 1",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 8632435727821051414\nmain -\> _Z3foov}"]; 310; DOTCLONED: Node[[MAIN1]] -> Node[[FOO]][tooltip="ContextIds: 1",fillcolor="brown1"]; 311; DOTCLONED: Node[[MAIN2:0x[a-z0-9]+]] [shape=record,tooltip="N[[MAIN2]] ContextIds: 2",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 15025054523792398438\nmain -\> _Z3foov}"]; 312; DOTCLONED: Node[[MAIN2]] -> Node[[FOO2:0x[a-z0-9]+]][tooltip="ContextIds: 2",fillcolor="cyan"]; 313; DOTCLONED: Node[[FOO2]] [shape=record,tooltip="N[[FOO2]] ContextIds: 2",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: 0\n_Z3foov -\> _Z3bazv}"]; 314; DOTCLONED: Node[[FOO2]] -> Node[[BAZ2:0x[a-z0-9]+]][tooltip="ContextIds: 2",fillcolor="cyan"]; 315; DOTCLONED: Node[[BAZ2]] [shape=record,tooltip="N[[BAZ2]] ContextIds: 2",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: 0\n_Z3bazv -\> _Z3barv}"]; 316; DOTCLONED: Node[[BAZ2]] -> Node[[BAR2:0x[a-z0-9]+]][tooltip="ContextIds: 2",fillcolor="cyan"]; 317; DOTCLONED: Node[[BAR2]] [shape=record,tooltip="N[[BAR2]] ContextIds: 2",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: Alloc0\n_Z3barv -\> _Znam}"]; 318; DOTCLONED: } 319