brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.7 KiB · 220dfed Raw
481 lines · cpp
1//===- MemProfUseTest.cpp - MemProf use tests -----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Transforms/Instrumentation/MemProfUse.h"10#include "llvm/Analysis/TargetLibraryInfo.h"11#include "llvm/AsmParser/Parser.h"12#include "llvm/IR/LLVMContext.h"13#include "llvm/IR/Module.h"14#include "llvm/Passes/PassBuilder.h"15#include "llvm/ProfileData/IndexedMemProfData.h"16#include "llvm/ProfileData/InstrProfReader.h"17#include "llvm/ProfileData/InstrProfWriter.h"18#include "llvm/ProfileData/MemProf.h"19#include "llvm/Support/SourceMgr.h"20#include "llvm/Testing/Support/Error.h"21 22#include "gmock/gmock.h"23#include "gtest/gtest.h"24 25namespace llvm {26namespace memprof {27namespace {28using testing::Contains;29using testing::ElementsAre;30using testing::Pair;31using testing::SizeIs;32using testing::UnorderedElementsAre;33 34TEST(MemProf, ExtractDirectCallsFromIR) {35  // The following IR is generated from:36  //37  // void f1();38  // void f2();39  // void f3();40  //41  // void foo() {42  //   f1();43  //   f2(); f3();44  // }45  StringRef IR = R"IR(46define dso_local void @_Z3foov() !dbg !10 {47entry:48  call void @_Z2f1v(), !dbg !1349  call void @_Z2f2v(), !dbg !1450  call void @_Z2f3v(), !dbg !1551  ret void, !dbg !1652}53 54declare !dbg !17 void @_Z2f1v()55 56declare !dbg !18 void @_Z2f2v()57 58declare !dbg !19 void @_Z2f3v()59 60!llvm.dbg.cu = !{!0}61!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}62!llvm.ident = !{!9}63 64!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)65!1 = !DIFile(filename: "foobar.cc", directory: "/")66!2 = !{i32 7, !"Dwarf Version", i32 5}67!3 = !{i32 2, !"Debug Info Version", i32 3}68!4 = !{i32 1, !"wchar_size", i32 4}69!5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}70!6 = !{i32 8, !"PIC Level", i32 2}71!7 = !{i32 7, !"PIE Level", i32 2}72!8 = !{i32 7, !"uwtable", i32 2}73!9 = !{!"clang"}74!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 5, type: !11, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)75!11 = !DISubroutineType(types: !12)76!12 = !{}77!13 = !DILocation(line: 6, column: 3, scope: !10)78!14 = !DILocation(line: 7, column: 3, scope: !10)79!15 = !DILocation(line: 7, column: 9, scope: !10)80!16 = !DILocation(line: 8, column: 1, scope: !10)81!17 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)82!18 = !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)83!19 = !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !1, file: !1, line: 3, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)84)IR";85 86  LLVMContext Ctx;87  SMDiagnostic Err;88  std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);89  ASSERT_TRUE(M);90 91  auto *F = M->getFunction("_Z3foov");92  ASSERT_NE(F, nullptr);93 94  TargetLibraryInfoWrapperPass WrapperPass(M->getTargetTriple());95  auto &TLI = WrapperPass.getTLI(*F);96  auto Calls = extractCallsFromIR(*M, TLI);97 98  // Expect exactly one caller.99  ASSERT_THAT(Calls, SizeIs(1));100 101  auto It = Calls.begin();102  ASSERT_NE(It, Calls.end());103 104  const auto &[CallerGUID, CallSites] = *It;105  EXPECT_EQ(CallerGUID, memprof::getGUID("_Z3foov"));106 107  // Verify that call sites show up in the ascending order of their source108  // locations.109  EXPECT_THAT(110      CallSites,111      ElementsAre(Pair(LineLocation(1, 3), memprof::getGUID("_Z2f1v")),112                  Pair(LineLocation(2, 3), memprof::getGUID("_Z2f2v")),113                  Pair(LineLocation(2, 9), memprof::getGUID("_Z2f3v"))));114}115 116TEST(MemProf, ExtractDirectCallsFromIRInline) {117  // The following IR is generated from:118  //119  // void f1();120  // static inline void f2() {121  //   // For an interesting line number.122  //   f1();123  // }124  // static inline void f3() {125  //   /****/ f2();  // For an interesting column number.126  // }127  //128  // void g1();129  // void g2();130  // static inline void g3() {131  //   /**/ g1();  // For an interesting column number.132  //   g2();133  // }134  //135  // void foo() {136  //   f3();137  //   /***/ g3();  // For an interesting column number.138  // }139  StringRef IR = R"IR(140define dso_local void @_Z3foov() local_unnamed_addr !dbg !10 {141entry:142  tail call void @_Z2f1v(), !dbg !13143  tail call void @_Z2g1v(), !dbg !18144  tail call void @_Z2g2v(), !dbg !21145  ret void, !dbg !22146}147 148declare !dbg !23 void @_Z2f1v() local_unnamed_addr149 150declare !dbg !24 void @_Z2g1v() local_unnamed_addr151 152declare !dbg !25 void @_Z2g2v() local_unnamed_addr153 154!llvm.dbg.cu = !{!0}155!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}156!llvm.ident = !{!9}157 158!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)159!1 = !DIFile(filename: "foobar.cc", directory: "/")160!2 = !{i32 7, !"Dwarf Version", i32 5}161!3 = !{i32 2, !"Debug Info Version", i32 3}162!4 = !{i32 1, !"wchar_size", i32 4}163!5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}164!6 = !{i32 8, !"PIC Level", i32 2}165!7 = !{i32 7, !"PIE Level", i32 2}166!8 = !{i32 7, !"uwtable", i32 2}167!9 = !{!"clang"}168!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 17, type: !11, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)169!11 = !DISubroutineType(types: !12)170!12 = !{}171!13 = !DILocation(line: 4, column: 3, scope: !14, inlinedAt: !15)172!14 = distinct !DISubprogram(name: "f2", linkageName: "_ZL2f2v", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)173!15 = distinct !DILocation(line: 7, column: 10, scope: !16, inlinedAt: !17)174!16 = distinct !DISubprogram(name: "f3", linkageName: "_ZL2f3v", scope: !1, file: !1, line: 6, type: !11, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)175!17 = distinct !DILocation(line: 18, column: 3, scope: !10)176!18 = !DILocation(line: 13, column: 8, scope: !19, inlinedAt: !20)177!19 = distinct !DISubprogram(name: "g3", linkageName: "_ZL2g3v", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)178!20 = distinct !DILocation(line: 19, column: 9, scope: !10)179!21 = !DILocation(line: 14, column: 3, scope: !19, inlinedAt: !20)180!22 = !DILocation(line: 20, column: 1, scope: !10)181!23 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)182!24 = !DISubprogram(name: "g1", linkageName: "_Z2g1v", scope: !1, file: !1, line: 10, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)183!25 = !DISubprogram(name: "g2", linkageName: "_Z2g2v", scope: !1, file: !1, line: 11, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)184)IR";185 186  LLVMContext Ctx;187  SMDiagnostic Err;188  std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);189  ASSERT_TRUE(M);190 191  auto *F = M->getFunction("_Z3foov");192  ASSERT_NE(F, nullptr);193 194  TargetLibraryInfoWrapperPass WrapperPass(M->getTargetTriple());195  auto &TLI = WrapperPass.getTLI(*F);196  auto Calls = extractCallsFromIR(*M, TLI);197 198  // Expect exactly 4 callers.199  ASSERT_THAT(Calls, SizeIs(4));200 201  // Verify each key-value pair.202 203  auto FooIt = Calls.find(memprof::getGUID("_Z3foov"));204  ASSERT_NE(FooIt, Calls.end());205  const auto &[FooCallerGUID, FooCallSites] = *FooIt;206  EXPECT_EQ(FooCallerGUID, memprof::getGUID("_Z3foov"));207  EXPECT_THAT(208      FooCallSites,209      ElementsAre(Pair(LineLocation(1, 3), memprof::getGUID("_ZL2f3v")),210                  Pair(LineLocation(2, 9), memprof::getGUID("_ZL2g3v"))));211 212  auto F2It = Calls.find(memprof::getGUID("_ZL2f2v"));213  ASSERT_NE(F2It, Calls.end());214  const auto &[F2CallerGUID, F2CallSites] = *F2It;215  EXPECT_EQ(F2CallerGUID, memprof::getGUID("_ZL2f2v"));216  EXPECT_THAT(F2CallSites, ElementsAre(Pair(LineLocation(2, 3),217                                            memprof::getGUID("_Z2f1v"))));218 219  auto F3It = Calls.find(memprof::getGUID("_ZL2f3v"));220  ASSERT_NE(F3It, Calls.end());221  const auto &[F3CallerGUID, F3CallSites] = *F3It;222  EXPECT_EQ(F3CallerGUID, memprof::getGUID("_ZL2f3v"));223  EXPECT_THAT(F3CallSites, ElementsAre(Pair(LineLocation(1, 10),224                                            memprof::getGUID("_ZL2f2v"))));225 226  auto G3It = Calls.find(memprof::getGUID("_ZL2g3v"));227  ASSERT_NE(G3It, Calls.end());228  const auto &[G3CallerGUID, G3CallSites] = *G3It;229  EXPECT_EQ(G3CallerGUID, memprof::getGUID("_ZL2g3v"));230  EXPECT_THAT(231      G3CallSites,232      ElementsAre(Pair(LineLocation(1, 8), memprof::getGUID("_Z2g1v")),233                  Pair(LineLocation(2, 3), memprof::getGUID("_Z2g2v"))));234}235 236TEST(MemProf, ExtractDirectCallsFromIRCallingNew) {237  // The following IR is generated from:238  //239  // int *foo() {240  //   return ::new (int);241  // }242  StringRef IR = R"IR(243define dso_local noundef ptr @_Z3foov() #0 !dbg !10 {244entry:245  %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 4) #2, !dbg !13246  ret ptr %call, !dbg !14247}248 249; Function Attrs: nobuiltin allocsize(0)250declare noundef nonnull ptr @_Znwm(i64 noundef) #1251 252attributes #0 = { mustprogress uwtable "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" }253attributes #1 = { nobuiltin allocsize(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" }254attributes #2 = { builtin allocsize(0) }255 256!llvm.dbg.cu = !{!0}257!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}258!llvm.ident = !{!9}259 260!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)261!1 = !DIFile(filename: "foobar.cc", directory: "/")262!2 = !{i32 7, !"Dwarf Version", i32 5}263!3 = !{i32 2, !"Debug Info Version", i32 3}264!4 = !{i32 1, !"wchar_size", i32 4}265!5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}266!6 = !{i32 8, !"PIC Level", i32 2}267!7 = !{i32 7, !"PIE Level", i32 2}268!8 = !{i32 7, !"uwtable", i32 2}269!9 = !{!"clang"}270!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)271!11 = !DISubroutineType(types: !12)272!12 = !{}273!13 = !DILocation(line: 2, column: 10, scope: !10)274!14 = !DILocation(line: 2, column: 3, scope: !10)275)IR";276 277  LLVMContext Ctx;278  SMDiagnostic Err;279  std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);280  ASSERT_TRUE(M);281 282  auto *F = M->getFunction("_Z3foov");283  ASSERT_NE(F, nullptr);284 285  TargetLibraryInfoWrapperPass WrapperPass(M->getTargetTriple());286  auto &TLI = WrapperPass.getTLI(*F);287  auto Calls = extractCallsFromIR(*M, TLI);288 289  // Expect exactly one caller.290  ASSERT_THAT(Calls, SizeIs(1));291 292  // Verify each key-value pair.293 294  auto FooIt = Calls.find(memprof::getGUID("_Z3foov"));295  ASSERT_NE(FooIt, Calls.end());296  const auto &[FooCallerGUID, FooCallSites] = *FooIt;297  EXPECT_EQ(FooCallerGUID, memprof::getGUID("_Z3foov"));298  EXPECT_THAT(FooCallSites, ElementsAre(Pair(LineLocation(1, 10), 0)));299}300 301// Populate those fields returned by getHotColdSchema.302MemInfoBlock makePartialMIB() {303  MemInfoBlock MIB;304  MIB.AllocCount = 1;305  MIB.TotalSize = 5;306  MIB.TotalLifetime = 10;307  MIB.TotalLifetimeAccessDensity = 23;308  return MIB;309}310 311IndexedMemProfRecord312makeRecordV2(std::initializer_list<CallStackId> AllocFrames,313             std::initializer_list<CallStackId> CallSiteFrames,314             const MemInfoBlock &Block, const MemProfSchema &Schema) {315  IndexedMemProfRecord MR;316  for (const auto &CSId : AllocFrames)317    MR.AllocSites.emplace_back(CSId, Block, Schema);318  for (const auto &CSId : CallSiteFrames)319    MR.CallSites.push_back(IndexedCallSiteInfo(CSId));320  return MR;321}322 323static const auto Err = [](Error E) {324  FAIL() << E;325  consumeError(std::move(E));326};327 328// Make sure that we can undrift direct calls.329TEST(MemProf, ComputeUndriftingMap) {330  // Suppose that the source code has changed from:331  //332  //   void bar();333  //   void baz();334  //   void zzz();335  //336  //   void foo() {337  //     /**/ bar();  // LineLocation(1, 8)338  //     zzz();       // LineLocation(2, 3)339  //     baz();       // LineLocation(3, 3)340  //   }341  //342  // to:343  //344  //   void bar();345  //   void baz();346  //347  //   void foo() {348  //     bar();        // LineLocation(1, 3)349  //     /**/ baz();   // LineLocation(2, 8)350  //   }351  //352  // Notice that the calls to bar and baz have drifted while zzz has been353  // removed.354  StringRef IR = R"IR(355define dso_local void @_Z3foov() #0 !dbg !10 {356entry:357  call void @_Z3barv(), !dbg !13358  call void @_Z3bazv(), !dbg !14359  ret void, !dbg !15360}361 362declare !dbg !16 void @_Z3barv() #1363 364declare !dbg !17 void @_Z3bazv() #1365 366attributes #0 = { mustprogress uwtable "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" }367attributes #1 = { "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" }368 369!llvm.dbg.cu = !{!0}370!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}371!llvm.ident = !{!9}372 373!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)374!1 = !DIFile(filename: "foobar.cc", directory: "/")375!2 = !{i32 7, !"Dwarf Version", i32 5}376!3 = !{i32 2, !"Debug Info Version", i32 3}377!4 = !{i32 1, !"wchar_size", i32 4}378!5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}379!6 = !{i32 8, !"PIC Level", i32 2}380!7 = !{i32 7, !"PIE Level", i32 2}381!8 = !{i32 7, !"uwtable", i32 2}382!9 = !{!"clang"}383!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 4, type: !11, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)384!11 = !DISubroutineType(types: !12)385!12 = !{}386!13 = !DILocation(line: 5, column: 3, scope: !10)387!14 = !DILocation(line: 6, column: 8, scope: !10)388!15 = !DILocation(line: 7, column: 1, scope: !10)389!16 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)390!17 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)391)IR";392 393  LLVMContext Ctx;394  SMDiagnostic SMErr;395  std::unique_ptr<Module> M = parseAssemblyString(IR, SMErr, Ctx);396  ASSERT_TRUE(M);397 398  auto *F = M->getFunction("_Z3foov");399  ASSERT_NE(F, nullptr);400 401  TargetLibraryInfoWrapperPass WrapperPass(M->getTargetTriple());402  auto &TLI = WrapperPass.getTLI(*F);403  auto Calls = extractCallsFromIR(*M, TLI);404 405  uint64_t GUIDFoo = memprof::getGUID("_Z3foov");406  uint64_t GUIDBar = memprof::getGUID("_Z3barv");407  uint64_t GUIDBaz = memprof::getGUID("_Z3bazv");408  uint64_t GUIDZzz = memprof::getGUID("_Z3zzzv");409 410  // Verify that extractCallsFromIR extracts caller-callee pairs as expected.411  EXPECT_THAT(Calls,412              UnorderedElementsAre(Pair(413                  GUIDFoo, ElementsAre(Pair(LineLocation(1, 3), GUIDBar),414                                       Pair(LineLocation(2, 8), GUIDBaz)))));415 416  llvm::InstrProfWriter Writer;417  std::unique_ptr<IndexedInstrProfReader> Reader;418 419  const MemInfoBlock MIB = makePartialMIB();420 421  Writer.setMemProfVersionRequested(Version3);422  Writer.setMemProfFullSchema(false);423 424  ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf),425                    Succeeded());426 427  const IndexedMemProfRecord IndexedMR = makeRecordV2(428      /*AllocFrames=*/{0x111, 0x222, 0x333},429      /*CallSiteFrames=*/{}, MIB, getHotColdSchema());430 431  IndexedMemProfData MemProfData;432  // The call sites within foo.433  MemProfData.Frames.try_emplace(0, GUIDFoo, 1, 8, false);434  MemProfData.Frames.try_emplace(1, GUIDFoo, 2, 3, false);435  MemProfData.Frames.try_emplace(2, GUIDFoo, 3, 3, false);436  // Line/column numbers below don't matter.437  MemProfData.Frames.try_emplace(3, GUIDBar, 9, 9, false);438  MemProfData.Frames.try_emplace(4, GUIDZzz, 9, 9, false);439  MemProfData.Frames.try_emplace(5, GUIDBaz, 9, 9, false);440  MemProfData.CallStacks.try_emplace(441      0x111, std::initializer_list<FrameId>{3, 0}); // bar called by foo442  MemProfData.CallStacks.try_emplace(443      0x222, std::initializer_list<FrameId>{4, 1}); // zzz called by foo444  MemProfData.CallStacks.try_emplace(445      0x333, std::initializer_list<FrameId>{5, 2}); // baz called by foo446  MemProfData.Records.try_emplace(0x9999, IndexedMR);447  Writer.addMemProfData(MemProfData, Err);448 449  auto Profile = Writer.writeBuffer();450 451  auto ReaderOrErr =452      IndexedInstrProfReader::create(std::move(Profile), nullptr);453  EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded());454  Reader = std::move(ReaderOrErr.get());455 456  // Verify that getMemProfCallerCalleePairs extracts caller-callee pairs as457  // expected.458  auto Pairs = Reader->getMemProfCallerCalleePairs();459  ASSERT_THAT(Pairs, SizeIs(4));460  ASSERT_THAT(461      Pairs,462      Contains(Pair(GUIDFoo, ElementsAre(Pair(LineLocation(1, 8), GUIDBar),463                                         Pair(LineLocation(2, 3), GUIDZzz),464                                         Pair(LineLocation(3, 3), GUIDBaz)))));465 466  // Verify that computeUndriftMap identifies undrifting opportunities:467  //468  //   Profile                 IR469  //   (Line: 1, Column: 8) -> (Line: 1, Column: 3)470  //   (Line: 3, Column: 3) -> (Line: 2, Column: 8)471  auto UndriftMap = computeUndriftMap(*M, Reader.get(), TLI);472  ASSERT_THAT(UndriftMap,473              UnorderedElementsAre(Pair(474                  GUIDFoo, UnorderedElementsAre(475                               Pair(LineLocation(1, 8), LineLocation(1, 3)),476                               Pair(LineLocation(3, 3), LineLocation(2, 8))))));477}478} // namespace479} // namespace memprof480} // namespace llvm481