We aren't currently deduplicating contexts that are identical or nearly identical (differing inline frame information) when generating the profile. When we have multiple identical contexts we end up conservatively marking it as non-cold, even if some are much smaller in terms of bytes allocated. This was causing us to lose sight of a very large cold context, because we had a small non-cold one that only differed in the inlining (which we don't consider when matching as the inlining could change or be incomplete at that point in compilation). Likely the smaller one was from binary with much smaller usage and therefore not yet detected as cold. Deduplicate the alloc contexts for a function before applying the profile, selecting the largest one, or conservatively selecting the non-cold one if they are the same size. This caused a minor difference to an existing test (memprof_loop_unroll.ll), which now only gets one message for the duplicate context instead of 2. While here, convert to the text version of the profile.
130 lines
5.9 KiB
LLVM
130 lines
5.9 KiB
LLVM
;; Tests memprof when contains loop unroll of allocation, where the unrolled
|
|
;; allocations have the same context but different allocation types.
|
|
|
|
;; Avoid failures on big-endian systems that can't read the profile properly
|
|
; REQUIRES: x86_64-linux
|
|
|
|
; Generate the profile and the IR.
|
|
; RUN: split-file %s %t
|
|
|
|
;; Generate indexed profile
|
|
; RUN: llvm-profdata merge %t/memprof_loop_unroll.yaml -o %t.memprofdata
|
|
|
|
;; Set the minimum lifetime threshold to 0 to ensure that one context is
|
|
;; considered cold (the other will be notcold).
|
|
; RUN: opt < %t/memprof_loop_unroll.ll -passes='memprof-use<profile-filename=%t.memprofdata>' -S -memprof-report-hinted-sizes -memprof-ave-lifetime-cold-threshold=0 2>&1 | FileCheck %s
|
|
|
|
;; Conservatively annotate as not cold.
|
|
; CHECK: MemProf hinting: Total size for full allocation context hash {{.*}} and single alloc type notcold: 4
|
|
; CHECK: call {{.*}} @_Znam{{.*}} #[[ATTR:[0-9]+]]
|
|
; CHECK: attributes #[[ATTR]] = { builtin allocsize(0) "memprof"="notcold" }
|
|
; CHECK-NOT: stackIds: ()
|
|
|
|
;--- memprof_loop_unroll.yaml
|
|
---
|
|
HeapProfileRecords:
|
|
- GUID: 0x7f8d88fcc70a347b
|
|
AllocSites:
|
|
- Callstack:
|
|
- { Function: 0x7f8d88fcc70a347b, LineOffset: 2, Column: 16, IsInlineFrame: false }
|
|
- { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 5, IsInlineFrame: false }
|
|
MemInfoBlock:
|
|
AllocCount: 1
|
|
TotalSize: 4
|
|
TotalLifetime: 2
|
|
TotalLifetimeAccessDensity: 12500000000
|
|
- Callstack:
|
|
- { Function: 0x7f8d88fcc70a347b, LineOffset: 2, Column: 16, IsInlineFrame: false }
|
|
- { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 5, IsInlineFrame: false }
|
|
MemInfoBlock:
|
|
AllocCount: 1
|
|
TotalSize: 4
|
|
TotalLifetime: 2
|
|
TotalLifetimeAccessDensity: 0
|
|
- GUID: 0xdb956436e78dd5fa
|
|
CallSites:
|
|
- Frames:
|
|
- { Function: 0xdb956436e78dd5fa, LineOffset: 1, Column: 5, IsInlineFrame: false }
|
|
...
|
|
|
|
;--- memprof_loop_unroll.ll
|
|
; ModuleID = 'memprof_loop_unroll_b.cc'
|
|
source_filename = "memprof_loop_unroll_b.cc"
|
|
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
@a = external global [2 x ptr], align 16
|
|
|
|
; Function Attrs: mustprogress noinline optnone uwtable
|
|
define dso_local void @_Z3foov() #0 !dbg !10 {
|
|
entry:
|
|
%i = alloca i32, align 4
|
|
store i32 0, ptr %i, align 4, !dbg !13
|
|
br label %for.cond, !dbg !14
|
|
|
|
for.cond: ; preds = %for.inc, %entry
|
|
%0 = load i32, ptr %i, align 4, !dbg !15
|
|
%cmp = icmp slt i32 %0, 2, !dbg !17
|
|
br i1 %cmp, label %for.body, label %for.end, !dbg !18
|
|
|
|
for.body: ; preds = %for.cond
|
|
%call = call noalias noundef nonnull ptr @_Znam(i64 noundef 4) #2, !dbg !19
|
|
%1 = load i32, ptr %i, align 4, !dbg !20
|
|
%idxprom = sext i32 %1 to i64, !dbg !21
|
|
%arrayidx = getelementptr inbounds [2 x ptr], ptr @a, i64 0, i64 %idxprom, !dbg !21
|
|
store ptr %call, ptr %arrayidx, align 8, !dbg !22
|
|
br label %for.inc, !dbg !23
|
|
|
|
for.inc: ; preds = %for.body
|
|
%2 = load i32, ptr %i, align 4, !dbg !24
|
|
%inc = add nsw i32 %2, 1, !dbg !24
|
|
store i32 %inc, ptr %i, align 4, !dbg !24
|
|
br label %for.cond, !dbg !26, !llvm.loop !27
|
|
|
|
for.end: ; preds = %for.cond
|
|
ret void, !dbg !30
|
|
}
|
|
|
|
; Function Attrs: nobuiltin allocsize(0)
|
|
declare noundef nonnull ptr @_Znam(i64 noundef) #1
|
|
|
|
attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
|
attributes #1 = { nobuiltin allocsize(0) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
|
attributes #2 = { builtin allocsize(0) }
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
|
|
!llvm.ident = !{!9}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
|
|
!1 = !DIFile(filename: "memprof_loop_unroll_b.cc", directory: "/", checksumkind: CSK_MD5, checksum: "00276e590d606451dc54f3ff5f4bba25")
|
|
!2 = !{i32 7, !"Dwarf Version", i32 5}
|
|
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!4 = !{i32 1, !"wchar_size", i32 4}
|
|
!5 = !{i32 8, !"PIC Level", i32 2}
|
|
!6 = !{i32 7, !"PIE Level", i32 2}
|
|
!7 = !{i32 7, !"uwtable", i32 2}
|
|
!8 = !{i32 7, !"frame-pointer", i32 2}
|
|
!9 = !{!"clang version 18.0.0"}
|
|
!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 4, type: !11, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
|
|
!11 = !DISubroutineType(types: !12)
|
|
!12 = !{}
|
|
!13 = !DILocation(line: 5, column: 14, scope: !10)
|
|
!14 = !DILocation(line: 5, column: 10, scope: !10)
|
|
!15 = !DILocation(line: 5, column: 21, scope: !16)
|
|
!16 = !DILexicalBlockFile(scope: !10, file: !1, discriminator: 2)
|
|
!17 = !DILocation(line: 5, column: 23, scope: !16)
|
|
!18 = !DILocation(line: 5, column: 5, scope: !16)
|
|
!19 = !DILocation(line: 6, column: 16, scope: !10)
|
|
!20 = !DILocation(line: 6, column: 11, scope: !10)
|
|
!21 = !DILocation(line: 6, column: 9, scope: !10)
|
|
!22 = !DILocation(line: 6, column: 14, scope: !10)
|
|
!23 = !DILocation(line: 7, column: 5, scope: !10)
|
|
!24 = !DILocation(line: 5, column: 28, scope: !25)
|
|
!25 = !DILexicalBlockFile(scope: !10, file: !1, discriminator: 4)
|
|
!26 = !DILocation(line: 5, column: 5, scope: !25)
|
|
!27 = distinct !{!27, !28, !23, !29}
|
|
!28 = !DILocation(line: 5, column: 5, scope: !10)
|
|
!29 = !{!"llvm.loop.mustprogress"}
|
|
!30 = !DILocation(line: 8, column: 1, scope: !10)
|