@@ -679,7 +679,7 @@ SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
679
679
std::error_code SampleProfileReaderBinary::readImpl () {
680
680
ProfileIsFS = ProfileIsFSDisciminator;
681
681
FunctionSamples::ProfileIsFS = ProfileIsFS;
682
- while (! at_eof () ) {
682
+ while (Data < End ) {
683
683
if (std::error_code EC = readFuncProfile (Data))
684
684
return EC;
685
685
}
@@ -727,9 +727,17 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
727
727
return EC;
728
728
break ;
729
729
case SecFuncOffsetTable:
730
- FuncOffsetsOrdered = hasSecFlag (Entry, SecFuncOffsetFlags::SecFlagOrdered);
731
- if (std::error_code EC = readFuncOffsetTable ())
732
- return EC;
730
+ // If module is absent, we are using LLVM tools, and need to read all
731
+ // profiles, so skip reading the function offset table.
732
+ if (!M) {
733
+ Data = End;
734
+ } else {
735
+ assert ((!ProfileIsCS ||
736
+ hasSecFlag (Entry, SecFuncOffsetFlags::SecFlagOrdered)) &&
737
+ " func offset table should always be sorted in CS profile" );
738
+ if (std::error_code EC = readFuncOffsetTable ())
739
+ return EC;
740
+ }
733
741
break ;
734
742
case SecFuncMetadata: {
735
743
ProfileIsProbeBased =
@@ -753,6 +761,35 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
753
761
return sampleprof_error::success;
754
762
}
755
763
764
+ bool SampleProfileReaderExtBinaryBase::useFuncOffsetList () const {
765
+ // If profile is CS, the function offset section is expected to consist of
766
+ // sequences of contexts in pre-order layout
767
+ // (e.g. [A, A:1 @ B, A:1 @ B:2.3 @ C] [D, D:1 @ E]), so that when a matched
768
+ // context in the module is found, the profiles of all its callees are
769
+ // recursively loaded. A list is needed since the order of profiles matters.
770
+ if (ProfileIsCS)
771
+ return true ;
772
+
773
+ // If the profile is MD5, use the map container to lookup functions in
774
+ // the module. A remapper has no use on MD5 names.
775
+ if (useMD5 ())
776
+ return false ;
777
+
778
+ // Profile is not MD5 and if a remapper is present, the remapped name of
779
+ // every function needed to be matched against the module, so use the list
780
+ // container since each entry is accessed.
781
+ if (Remapper)
782
+ return true ;
783
+
784
+ // Otherwise use the map container for faster lookup.
785
+ // TODO: If the cardinality of the function offset section is much smaller
786
+ // than the number of functions in the module, using the list container can
787
+ // be always faster, but we need to figure out the constant factor to
788
+ // determine the cutoff.
789
+ return false ;
790
+ }
791
+
792
+
756
793
bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule () {
757
794
if (!M)
758
795
return false ;
@@ -763,22 +800,20 @@ bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule() {
763
800
}
764
801
765
802
std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable () {
766
- // If there are more than one FuncOffsetTable, the profile read associated
767
- // with previous FuncOffsetTable has to be done before next FuncOffsetTable
768
- // is read.
803
+ // If there are more than one function offset section, the profile associated
804
+ // with the previous section has to be done reading before next one is read.
769
805
FuncOffsetTable.clear ();
806
+ FuncOffsetList.clear ();
770
807
771
808
auto Size = readNumber<uint64_t >();
772
809
if (std::error_code EC = Size .getError ())
773
810
return EC;
774
811
775
- FuncOffsetTable.reserve (*Size );
776
-
777
- if (FuncOffsetsOrdered) {
778
- OrderedFuncOffsets =
779
- std::make_unique<std::vector<std::pair<SampleContext, uint64_t >>>();
780
- OrderedFuncOffsets->reserve (*Size );
781
- }
812
+ bool UseFuncOffsetList = useFuncOffsetList ();
813
+ if (UseFuncOffsetList)
814
+ FuncOffsetList.reserve (*Size );
815
+ else
816
+ FuncOffsetTable.reserve (*Size );
782
817
783
818
for (uint64_t I = 0 ; I < *Size ; ++I) {
784
819
auto FContext (readSampleContextFromTable ());
@@ -789,12 +824,13 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
789
824
if (std::error_code EC = Offset.getError ())
790
825
return EC;
791
826
792
- FuncOffsetTable[*FContext] = *Offset;
793
- if (FuncOffsetsOrdered)
794
- OrderedFuncOffsets->emplace_back (*FContext, *Offset);
795
- }
827
+ if (UseFuncOffsetList)
828
+ FuncOffsetList.emplace_back (*FContext, *Offset);
829
+ else
830
+ FuncOffsetTable[*FContext] = *Offset;
831
+ }
796
832
797
- return sampleprof_error::success;
833
+ return sampleprof_error::success;
798
834
}
799
835
800
836
std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles () {
@@ -806,7 +842,8 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
806
842
// NameTable section is read.
807
843
bool LoadFuncsToBeUsed = collectFuncsFromModule ();
808
844
809
- // When LoadFuncsToBeUsed is false, load all the function profiles.
845
+ // When LoadFuncsToBeUsed is false, we are using LLVM tool, need to read all
846
+ // profiles.
810
847
const uint8_t *Start = Data;
811
848
if (!LoadFuncsToBeUsed) {
812
849
while (Data < End) {
@@ -823,6 +860,7 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
823
860
}
824
861
825
862
if (ProfileIsCS) {
863
+ assert (useFuncOffsetList ());
826
864
DenseSet<uint64_t > FuncGuidsToUse;
827
865
if (useMD5 ()) {
828
866
for (auto Name : FuncsToUse)
@@ -836,10 +874,8 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
836
874
// as if they were walked in preorder of a context trie. While
837
875
// traversing the trie, a link to the highest common ancestor node is
838
876
// kept so that all of its decendants will be loaded.
839
- assert (OrderedFuncOffsets.get () &&
840
- " func offset table should always be sorted in CS profile" );
841
877
const SampleContext *CommonContext = nullptr ;
842
- for (const auto &NameOffset : *OrderedFuncOffsets ) {
878
+ for (const auto &NameOffset : FuncOffsetList ) {
843
879
const auto &FContext = NameOffset.first ;
844
880
auto FName = FContext.getName ();
845
881
// For function in the current module, keep its farthest ancestor
@@ -857,35 +893,41 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
857
893
// Load profile for the current context which originated from
858
894
// the common ancestor.
859
895
const uint8_t *FuncProfileAddr = Start + NameOffset.second ;
860
- assert (FuncProfileAddr < End && " out of LBRProfile section" );
861
896
if (std::error_code EC = readFuncProfile (FuncProfileAddr))
862
897
return EC;
863
898
}
864
899
}
900
+ } else if (useMD5 ()) {
901
+ assert (!useFuncOffsetList ());
902
+ for (auto Name : FuncsToUse) {
903
+ auto GUID = std::to_string (MD5Hash (Name));
904
+ auto iter = FuncOffsetTable.find (StringRef (GUID));
905
+ if (iter == FuncOffsetTable.end ())
906
+ continue ;
907
+ const uint8_t *FuncProfileAddr = Start + iter->second ;
908
+ if (std::error_code EC = readFuncProfile (FuncProfileAddr))
909
+ return EC;
910
+ }
911
+ } else if (Remapper) {
912
+ assert (useFuncOffsetList ());
913
+ for (auto NameOffset : FuncOffsetList) {
914
+ SampleContext FContext (NameOffset.first );
915
+ auto FuncName = FContext.getName ();
916
+ if (!FuncsToUse.count (FuncName) && !Remapper->exist (FuncName))
917
+ continue ;
918
+ const uint8_t *FuncProfileAddr = Start + NameOffset.second ;
919
+ if (std::error_code EC = readFuncProfile (FuncProfileAddr))
920
+ return EC;
921
+ }
865
922
} else {
866
- if (useMD5 ()) {
867
- for (auto Name : FuncsToUse) {
868
- auto GUID = std::to_string (MD5Hash (Name));
869
- auto iter = FuncOffsetTable.find (StringRef (GUID));
870
- if (iter == FuncOffsetTable.end ())
871
- continue ;
872
- const uint8_t *FuncProfileAddr = Start + iter->second ;
873
- assert (FuncProfileAddr < End && " out of LBRProfile section" );
874
- if (std::error_code EC = readFuncProfile (FuncProfileAddr))
875
- return EC;
876
- }
877
- } else {
878
- for (auto NameOffset : FuncOffsetTable) {
879
- SampleContext FContext (NameOffset.first );
880
- auto FuncName = FContext.getName ();
881
- if (!FuncsToUse.count (FuncName) &&
882
- (!Remapper || !Remapper->exist (FuncName)))
883
- continue ;
884
- const uint8_t *FuncProfileAddr = Start + NameOffset.second ;
885
- assert (FuncProfileAddr < End && " out of LBRProfile section" );
886
- if (std::error_code EC = readFuncProfile (FuncProfileAddr))
887
- return EC;
888
- }
923
+ assert (!useFuncOffsetList ());
924
+ for (auto Name : FuncsToUse) {
925
+ auto iter = FuncOffsetTable.find (Name);
926
+ if (iter == FuncOffsetTable.end ())
927
+ continue ;
928
+ const uint8_t *FuncProfileAddr = Start + iter->second ;
929
+ if (std::error_code EC = readFuncProfile (FuncProfileAddr))
930
+ return EC;
889
931
}
890
932
}
891
933
Data = End;
0 commit comments