diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h --- a/llvm/include/llvm/ProfileData/SampleProf.h +++ b/llvm/include/llvm/ProfileData/SampleProf.h @@ -18,6 +18,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" @@ -182,10 +183,16 @@ /// Merge the samples in \p Other into this record. /// Optionally scale sample counts by \p Weight. - sampleprof_error merge(const SampleRecord &Other, uint64_t Weight = 1) { + sampleprof_error merge(const SampleRecord &Other, + StringSet<> *FunctionNames = nullptr, + uint64_t Weight = 1) { sampleprof_error Result = addSamples(Other.getSamples(), Weight); for (const auto &I : Other.getCallTargets()) { - MergeResult(Result, addCalledTarget(I.first(), I.second, Weight)); + StringRef FName = I.first(); + if (FunctionNames) { + FName = FunctionNames->insert(FName).first->first(); + } + MergeResult(Result, addCalledTarget(FName, I.second, Weight)); } return Result; } @@ -356,7 +363,9 @@ /// Merge the samples in \p Other into this one. /// Optionally scale samples by \p Weight. - sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight = 1) { + sampleprof_error merge(const FunctionSamples &Other, + StringSet<> *FunctionNames = nullptr, + uint64_t Weight = 1) { sampleprof_error Result = sampleprof_error::success; Name = Other.getName(); MergeResult(Result, addTotalSamples(Other.getTotalSamples(), Weight)); @@ -364,13 +373,20 @@ for (const auto &I : Other.getBodySamples()) { const LineLocation &Loc = I.first; const SampleRecord &Rec = I.second; - MergeResult(Result, BodySamples[Loc].merge(Rec, Weight)); + MergeResult(Result, BodySamples[Loc].merge(Rec, FunctionNames, Weight)); } for (const auto &I : Other.getCallsiteSamples()) { const LineLocation &Loc = I.first; FunctionSamplesMap &FSMap = functionSamplesAt(Loc); - for (const auto &Rec : I.second) - MergeResult(Result, FSMap[Rec.first].merge(Rec.second, Weight)); + for (const auto &Rec : I.second) { + if (FunctionNames) { + StringRef FName = Rec.second.getName(); + FName = FunctionNames->insert(FName).first->first(); + const_cast(Rec.second).setName(FName); + } + MergeResult(Result, + FSMap[Rec.first].merge(Rec.second, FunctionNames, Weight)); + } } return Result; } diff --git a/llvm/test/tools/llvm-profdata/Inputs/string-table-1.proftext b/llvm/test/tools/llvm-profdata/Inputs/string-table-1.proftext new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/Inputs/string-table-1.proftext @@ -0,0 +1,6 @@ +foo:10:1 + 1: 4 + 2: bar:6 +bar:5:1 + 1: 4 + 2: verylongfunctionname:1 diff --git a/llvm/test/tools/llvm-profdata/Inputs/string-table-2.proftext b/llvm/test/tools/llvm-profdata/Inputs/string-table-2.proftext new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/Inputs/string-table-2.proftext @@ -0,0 +1,3 @@ +verylongfunctionname:40:5 + 1: foobar:20 + 2: 20 diff --git a/llvm/test/tools/llvm-profdata/Inputs/string-table-output.proftext b/llvm/test/tools/llvm-profdata/Inputs/string-table-output.proftext new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/Inputs/string-table-output.proftext @@ -0,0 +1,9 @@ +verylongfunctionname:40:5 + 2: 20 + 1: foobar:20 +foo:10:1 + 1: 4 + 2: bar:6 +bar:5:1 + 1: 4 + 2: verylongfunctionname:1 diff --git a/llvm/test/tools/llvm-profdata/string-table.test b/llvm/test/tools/llvm-profdata/string-table.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/string-table.test @@ -0,0 +1,2 @@ +RUN: llvm-profdata merge -sample -text -o %t.proftext %S/Inputs/string-table-1.proftext %S/Inputs/string-table-2.proftext +RUN: diff %t.proftext %S/Inputs/string-table-output.proftext diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/LLVMContext.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" @@ -440,19 +441,18 @@ auto Writer = std::move(WriterOrErr.get()); StringMap ProfileMap; - SmallVector, 5> Readers; + + // This string set is used to save all function name strings. + // This allows not to retain in memory every ProfileReader (which + // implies having all the files in memory). + StringSet<> FunctionNames; LLVMContext Context; for (const auto &Input : Inputs) { auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, Input.Filename); - // We need to keep the readers around until after all the files are - // read so that we do not lose the function names stored in each - // reader's memory. The function names are needed to write out the - // merged profile map. - Readers.push_back(std::move(ReaderOrErr.get())); - const auto Reader = Readers.back().get(); + const auto &Reader = ReaderOrErr.get(); if (std::error_code EC = Reader->read()) exitWithErrorCode(EC, Input.Filename); @@ -466,7 +466,10 @@ : FunctionSamples(); FunctionSamples &Samples = Remapper ? Remapped : I->second; StringRef FName = Samples.getName(); - MergeResult(Result, ProfileMap[FName].merge(Samples, Input.Weight)); + FName = FunctionNames.insert(FName).first->first(); + Samples.setName(FName); + MergeResult(Result, ProfileMap[FName].merge(Samples, &FunctionNames, + Input.Weight)); if (Result != sampleprof_error::success) { std::error_code EC = make_error_code(Result); handleMergeWriterError(errorCodeToError(EC), Input.Filename, FName);