347 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. Also tests graph and IR5;; cloning.6;;7;; Original code looks like:8;;9;; char *D() {10;; return new char[10];11;; }12;;13;; char *F() {14;; return D();15;; }16;;17;; char *C() {18;; return D();19;; }20;;21;; char *B() {22;; return C();23;; }24;;25;; char *E() {26;; return C();27;; }28;; int main(int argc, char **argv) {29;; char *x = B(); // cold30;; char *y = E(); // cold31;; char *z = F(); // default32;; memset(x, 0, 10);33;; memset(y, 0, 10);34;; memset(z, 0, 10);35;; delete[] z;36;; sleep(10);37;; delete[] x;38;; delete[] y;39;; return 0;40;; }41;;42;; Code compiled with -mllvm -memprof-ave-lifetime-cold-threshold=5 so that the43;; memory freed after sleep(10) results in cold lifetimes.44;;45;; The code below was created by forcing inlining of C into both B and E.46;; Since both allocation contexts via C are cold, the matched memprof47;; metadata has the context pruned above C's callsite. This requires48;; matching the stack node for C to callsites where it was inlined (i.e.49;; the callsites in B and E that have callsite metadata that includes C's).50;; It also requires duplication of that node in the graph as well as the51;; duplication of the context ids along that path through the graph,52;; so that we can represent the duplicated (via inlining) C callsite.53;;54;; The IR was then reduced using llvm-reduce with the expected FileCheck input.55 56;; -stats requires asserts57; REQUIRES: asserts58 59; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \60; RUN: -memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \61; RUN: -memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \62; RUN: -stats -pass-remarks=memprof-context-disambiguation \63; RUN: %s -S 2>&1 | FileCheck %s --check-prefix=DUMP --check-prefix=IR \64; RUN: --check-prefix=STATS --check-prefix=REMARKS65 66; RUN: cat %t.ccg.prestackupdate.dot | FileCheck %s --check-prefix=DOTPRE67;; There are no changes for this test case in between from immediately after68;; the stack update through the end of graph finalization, so the69;; corresponding dot graphs should be identical.70; RUN: cat %t.ccg.poststackupdate.dot | FileCheck %s --check-prefix=DOTPOST71; RUN: cat %t.ccg.postbuild.dot | FileCheck %s --check-prefix=DOTPOST72;; We should clone D once for the cold allocations via C.73; RUN: cat %t.ccg.cloned.dot | FileCheck %s --check-prefix=DOTCLONED74 75target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"76target triple = "x86_64-unknown-linux-gnu"77 78define internal ptr @_Z1Dv() {79entry:80 %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !memprof !0, !callsite !581 ret ptr null82}83 84declare ptr @_Znam(i64)85 86define internal ptr @_Z1Fv() #0 {87entry:88 %call = call noundef ptr @_Z1Dv(), !callsite !689 ret ptr null90}91 92; Function Attrs: mustprogress noinline optnone uwtable93define internal ptr @_Z1Cv() #1 {94entry:95 %call = call noundef ptr @_Z1Dv(), !callsite !796 ret ptr null97}98 99; Function Attrs: mustprogress noinline optnone uwtable100define internal ptr @_Z1Bv() #1 {101entry:102 %call.i = call noundef ptr @_Z1Dv(), !callsite !8103 ret ptr null104}105 106; Function Attrs: mustprogress noinline optnone uwtable107define internal ptr @_Z1Ev() #1 {108entry:109 %call.i = call noundef ptr @_Z1Dv(), !callsite !9110 ret ptr null111}112 113; Function Attrs: noinline114declare i32 @main() #2115 116; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)117declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #3118 119; Function Attrs: nounwind120declare void @_ZdaPv() #4121 122declare i32 @sleep() #5123 124attributes #0 = { "disable-tail-calls"="true" }125attributes #1 = { mustprogress noinline optnone 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" }126attributes #2 = { noinline }127attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }128attributes #4 = { nounwind }129attributes #5 = { "no-trapping-math"="true" }130attributes #6 = { builtin }131 132!0 = !{!1, !3}133!1 = !{!2, !"cold"}134!2 = !{i64 6541423618768552252, i64 -6270142974039008131}135!3 = !{!4, !"notcold"}136!4 = !{i64 6541423618768552252, i64 -4903163940066524832}137!5 = !{i64 6541423618768552252}138!6 = !{i64 -4903163940066524832}139!7 = !{i64 -6270142974039008131}140!8 = !{i64 -6270142974039008131, i64 -184525619819294889}141!9 = !{i64 -6270142974039008131, i64 1905834578520680781}142 143 144;; After adding only the alloc node memprof metadata, we only have 2 contexts.145 146; DUMP: CCG before updating call stack chains:147; DUMP: Callsite Context Graph:148; DUMP: Node [[D:0x[a-z0-9]+]]149; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0)150; DUMP: AllocTypes: NotColdCold151; DUMP: ContextIds: 1 2152; DUMP: CalleeEdges:153; DUMP: CallerEdges:154; DUMP: Edge from Callee [[D]] to Caller: [[C:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 1155; DUMP: Edge from Callee [[D]] to Caller: [[F:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 2156 157; DUMP: Node [[C]]158; DUMP: null Call159; DUMP: AllocTypes: Cold160; DUMP: ContextIds: 1161; DUMP: CalleeEdges:162; DUMP: Edge from Callee [[D]] to Caller: [[C]] AllocTypes: Cold ContextIds: 1163; DUMP: CallerEdges:164 165; DUMP: Node [[F]]166; DUMP: null Call167; DUMP: AllocTypes: NotCold168; DUMP: ContextIds: 2169; DUMP: CalleeEdges:170; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2171; DUMP: CallerEdges:172 173;; After updating for callsite metadata, we should have generated context ids 3 and 4,174;; along with 2 new nodes for those callsites. All have the same allocation type175;; behavior as the original C node.176 177; DUMP: CCG before cloning:178; DUMP: Callsite Context Graph:179; DUMP: Node [[D]]180; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0)181; DUMP: AllocTypes: NotColdCold182; DUMP: ContextIds: 1 2 3 4183; DUMP: CalleeEdges:184; DUMP: CallerEdges:185; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2186; DUMP: Edge from Callee [[D]] to Caller: [[C2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 3187; DUMP: Edge from Callee [[D]] to Caller: [[B:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 4188; DUMP: Edge from Callee [[D]] to Caller: [[E:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 1189 190; DUMP: Node [[F]]191; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0)192; DUMP: AllocTypes: NotCold193; DUMP: ContextIds: 2194; DUMP: CalleeEdges:195; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2196; DUMP: CallerEdges:197 198; DUMP: Node [[C2]]199; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0)200; DUMP: AllocTypes: Cold201; DUMP: ContextIds: 3202; DUMP: CalleeEdges:203; DUMP: Edge from Callee [[D]] to Caller: [[C2]] AllocTypes: Cold ContextIds: 3204; DUMP: CallerEdges:205 206; DUMP: Node [[B]]207; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0)208; DUMP: AllocTypes: Cold209; DUMP: ContextIds: 4210; DUMP: CalleeEdges:211; DUMP: Edge from Callee [[D]] to Caller: [[B]] AllocTypes: Cold ContextIds: 4212; DUMP: CallerEdges:213 214; DUMP: Node [[E]]215; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0)216; DUMP: AllocTypes: Cold217; DUMP: ContextIds: 1218; DUMP: CalleeEdges:219; DUMP: Edge from Callee [[D]] to Caller: [[E]] AllocTypes: Cold ContextIds: 1220; DUMP: CallerEdges:221 222; DUMP: CCG after cloning:223; DUMP: Callsite Context Graph:224; DUMP: Node [[D]]225; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0)226; DUMP: AllocTypes: NotCold227; DUMP: ContextIds: 2228; DUMP: CalleeEdges:229; DUMP: CallerEdges:230; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2231; DUMP: Clones: [[D2:0x[a-z0-9]+]]232 233; DUMP: Node [[F]]234; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0)235; DUMP: AllocTypes: NotCold236; DUMP: ContextIds: 2237; DUMP: CalleeEdges:238; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2239; DUMP: CallerEdges:240 241; DUMP: Node [[C2]]242; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0)243; DUMP: AllocTypes: Cold244; DUMP: ContextIds: 3245; DUMP: CalleeEdges:246; DUMP: Edge from Callee [[D2]] to Caller: [[C2]] AllocTypes: Cold ContextIds: 3247; DUMP: CallerEdges:248 249; DUMP: Node [[B]]250; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0)251; DUMP: AllocTypes: Cold252; DUMP: ContextIds: 4253; DUMP: CalleeEdges:254; DUMP: Edge from Callee [[D2]] to Caller: [[B]] AllocTypes: Cold ContextIds: 4255; DUMP: CallerEdges:256 257; DUMP: Node [[E]]258; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0)259; DUMP: AllocTypes: Cold260; DUMP: ContextIds: 1261; DUMP: CalleeEdges:262; DUMP: Edge from Callee [[D2]] to Caller: [[E]] AllocTypes: Cold ContextIds: 1263; DUMP: CallerEdges:264 265; DUMP: Node [[D2]]266; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0)267; DUMP: AllocTypes: Cold268; DUMP: ContextIds: 1 3 4269; DUMP: CalleeEdges:270; DUMP: CallerEdges:271; DUMP: Edge from Callee [[D2]] to Caller: [[E:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 1272; DUMP: Edge from Callee [[D2]] to Caller: [[C2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 3273; DUMP: Edge from Callee [[D2]] to Caller: [[B:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 4274; DUMP: Clone of [[D]]275 276; REMARKS: created clone _Z1Dv.memprof.1277; REMARKS: call in clone _Z1Ev assigned to call function clone _Z1Dv.memprof.1278; REMARKS: call in clone _Z1Cv assigned to call function clone _Z1Dv.memprof.1279; REMARKS: call in clone _Z1Bv assigned to call function clone _Z1Dv.memprof.1280; REMARKS: call in clone _Z1Dv.memprof.1 marked with memprof allocation attribute cold281; REMARKS: call in clone _Z1Fv assigned to call function clone _Z1Dv282; REMARKS: call in clone _Z1Dv marked with memprof allocation attribute notcold283 284 285;; The allocation via F does not allocate cold memory. It should call the286;; original D, which ultimately call the original allocation decorated287;; with a "notcold" attribute.288; IR: define internal {{.*}} @_Z1Dv()289; IR: call {{.*}} @_Znam(i64 noundef 10) #[[NOTCOLD:[0-9]+]]290; IR: define internal {{.*}} @_Z1Fv()291; IR: call {{.*}} @_Z1Dv()292;; The allocations via B and E allocate cold memory. They should call the293;; cloned D, which ultimately call the cloned allocation decorated with a294;; "cold" attribute.295; IR: define internal {{.*}} @_Z1Bv()296; IR: call {{.*}} @_Z1Dv.memprof.1()297; IR: define internal {{.*}} @_Z1Ev()298; IR: call {{.*}} @_Z1Dv.memprof.1()299; IR: define internal {{.*}} @_Z1Dv.memprof.1()300; IR: call {{.*}} @_Znam(i64 noundef 10) #[[COLD:[0-9]+]]301; IR: attributes #[[NOTCOLD]] = { builtin "memprof"="notcold" }302; IR: attributes #[[COLD]] = { builtin "memprof"="cold" }303 304 305; STATS: 1 memprof-context-disambiguation - Number of cold static allocations (possibly cloned)306; STATS: 1 memprof-context-disambiguation - Number of not cold static allocations (possibly cloned)307; STATS: 1 memprof-context-disambiguation - Number of function clones created during whole program analysis308 309 310; DOTPRE: digraph "prestackupdate" {311; DOTPRE: label="prestackupdate";312; DOTPRE: Node[[D:0x[a-z0-9]+]] [shape=record,tooltip="N[[D]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",label="{OrigId: Alloc0{{.*}}\n_Z1Dv -\> _Znam}"];313; DOTPRE: Node[[C:0x[a-z0-9]+]] [shape=record,tooltip="N[[C]] ContextIds: 1",fillcolor="cyan",style="filled",label="{OrigId: 12176601099670543485{{.*}}\nnull call (external)}"];314; DOTPRE: Node[[C]] -> Node[[D]][tooltip="ContextIds: 1",fillcolor="cyan"315; DOTPRE: Node[[F:0x[a-z0-9]+]] [shape=record,tooltip="N[[F]] ContextIds: 2",fillcolor="brown1",style="filled",label="{OrigId: 13543580133643026784{{.*}}\nnull call (external)}"];316; DOTPRE: Node[[F]] -> Node[[D]][tooltip="ContextIds: 2",fillcolor="brown1"317; DOTPRE: }318 319 320; DOTPOST:digraph "post321; DOTPOST: label="post322; DOTPOST: Node[[D:0x[a-z0-9]+]] [shape=record,tooltip="N[[D]] ContextIds: 1 2 3 4",fillcolor="mediumorchid1",style="filled",label="{OrigId: Alloc0{{.*}}\n_Z1Dv -\> _Znam}"];323; DOTPOST: Node[[F:0x[a-z0-9]+]] [shape=record,tooltip="N[[F]] ContextIds: 2",fillcolor="brown1",style="filled",label="{OrigId: 13543580133643026784{{.*}}\n_Z1Fv -\> _Z1Dv}"];324; DOTPOST: Node[[F]] -> Node[[D]][tooltip="ContextIds: 2",fillcolor="brown1"325; DOTPOST: Node[[C:0x[a-z0-9]+]] [shape=record,tooltip="N[[C]] ContextIds: 3",fillcolor="cyan",style="filled",label="{OrigId: 0{{.*}}\n_Z1Cv -\> _Z1Dv}"];326; DOTPOST: Node[[C]] -> Node[[D]][tooltip="ContextIds: 3",fillcolor="cyan327; DOTPOST: Node[[B:0x[a-z0-9]+]] [shape=record,tooltip="N[[B]] ContextIds: 4",fillcolor="cyan",style="filled",label="{OrigId: 0{{.*}}\n_Z1Bv -\> _Z1Dv}"];328; DOTPOST: Node[[B]] -> Node[[D]][tooltip="ContextIds: 4",fillcolor="cyan"329; DOTPOST: Node[[E:0x[a-z0-9]+]] [shape=record,tooltip="N[[E]] ContextIds: 1",fillcolor="cyan",style="filled",label="{OrigId: 0{{.*}}\n_Z1Ev -\> _Z1Dv}"];330; DOTPOST: Node[[E]] -> Node[[D]][tooltip="ContextIds: 1",fillcolor="cyan"331; DOTPOST:}332 333 334; DOTCLONED: digraph "cloned" {335; DOTCLONED: label="cloned";336; DOTCLONED: Node[[D:0x[a-z0-9]+]] [shape=record,tooltip="N[[D]] ContextIds: 2",fillcolor="brown1",style="filled",label="{OrigId: Alloc0{{.*}}\n_Z1Dv -\> _Znam}"];337; DOTCLONED: Node[[F:0x[a-z0-9]+]] [shape=record,tooltip="N[[F]] ContextIds: 2",fillcolor="brown1",style="filled",label="{OrigId: 13543580133643026784{{.*}}\n_Z1Fv -\> _Z1Dv}"];338; DOTCLONED: Node[[F]] -> Node[[D]][tooltip="ContextIds: 2",fillcolor="brown1"339; DOTCLONED: Node[[C:0x[a-z0-9]+]] [shape=record,tooltip="N[[C]] ContextIds: 3",fillcolor="cyan",style="filled",label="{OrigId: 0{{.*}}\n_Z1Cv -\> _Z1Dv}"];340; DOTCLONED: Node[[C]] -> Node[[D2:0x[a-z0-9]+]][tooltip="ContextIds: 3",fillcolor="cyan"341; DOTCLONED: Node[[B:0x[a-z0-9]+]] [shape=record,tooltip="N[[B]] ContextIds: 4",fillcolor="cyan",style="filled",label="{OrigId: 0{{.*}}\n_Z1Bv -\> _Z1Dv}"];342; DOTCLONED: Node[[B]] -> Node[[D2]][tooltip="ContextIds: 4",fillcolor="cyan"343; DOTCLONED: Node[[E:0x[a-z0-9]+]] [shape=record,tooltip="N[[E]] ContextIds: 1",fillcolor="cyan",style="filled",label="{OrigId: 0{{.*}}\n_Z1Ev -\> _Z1Dv}"];344; DOTCLONED: Node[[E]] -> Node[[D2]][tooltip="ContextIds: 1",fillcolor="cyan"345; DOTCLONED: Node[[D2]] [shape=record,tooltip="N[[D2]] ContextIds: 1 3 4",fillcolor="cyan",color="blue",style="filled,bold,dashed",label="{OrigId: Alloc0{{.*}}\n_Z1Dv -\> _Znam}"];346; DOTCLONED: }347