This is an archive of the discontinued LLVM Phabricator instance.

[CSSPGO] split context string II - reader/writer changes
ClosedPublic

Authored by hoy on Aug 19 2021, 7:03 PM.

Details

Reviewers
wmi
wenlei
wlei
Summary

This is the profile reader/writer/llvm-profdata part of the context split work. Please refer to D107299 for the original whole patch.

Diff Detail

Event Timeline

hoy created this revision.Aug 19 2021, 7:03 PM
hoy requested review of this revision.Aug 19 2021, 7:03 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 19 2021, 7:03 PM
wmi added inline comments.Aug 20 2021, 3:09 PM
llvm/include/llvm/ProfileData/SampleProfReader.h
743

Same as SampleProfileReaderText, can we use std::list instead of std::vector so the storage underlying will not be moved after more elements are inserted?

llvm/lib/ProfileData/SampleProfReader.cpp
238

Looks like it can be a utility function in SampleProfile.h and may be reused somewhere else.

269–276

Can we make it a utility function?

452

This param is unused. Write it as readNameFromTable(bool /* IsContextName */) to make it more explicit.

hoy added inline comments.Aug 20 2021, 4:17 PM
llvm/include/llvm/ProfileData/SampleProfReader.h
743

Std::vector is good for looking up with an offset, which is needed during the load of function profiles. Also, std::vector is more efficient for the extbinary reader, since number of contexts is known beforehand. Once the CS name table section is read, the std::vector should be frozen and no more names should be appended.

llvm/lib/ProfileData/SampleProfReader.cpp
238

It's actually moved out of SampleProfile.h since it's only used by the text reader. Also the text reader should be the only part of the toolchain that needs to parse full context strings. Other parts just need to deal with ArrayRef form of context. What do you think?

452

Sounds good.

hoy added inline comments.Aug 20 2021, 4:21 PM
llvm/lib/ProfileData/SampleProfReader.cpp
452

Actually I can only do that in the header file for the function declaration. The function definition needs a real name for param.

hoy updated this revision to Diff 367922.Aug 20 2021, 4:21 PM

Addressing Wei's comment.

wmi added inline comments.Aug 23 2021, 9:50 AM
llvm/include/llvm/ProfileData/SampleProfReader.h
743

Yeah, right, std::vector is good for looking up. Now once cs name table is read, there is no other code appending names to the table. Just want to know whether we can have some additional mechanism to enforce that. Can we save the size of the table after reading cs name table and check that the table size is the same before visiting any element from the table?

llvm/lib/ProfileData/SampleProfReader.cpp
238

Ok, if it is less likely to be used by others, it is fine to keep as it is.

hoy added inline comments.Aug 23 2021, 10:27 AM
llvm/include/llvm/ProfileData/SampleProfReader.h
743

Good point. Setting the underlying object to be constant so that it is immutable once populated.

hoy updated this revision to Diff 368139.Aug 23 2021, 10:27 AM

Addressing Wei's feedback.

wmi accepted this revision.Aug 23 2021, 8:36 PM

LGTM.

This revision is now accepted and ready to land.Aug 23 2021, 8:36 PM
hoy updated this revision to Diff 368562.Aug 24 2021, 11:55 PM

Updating D108435: [CSSPGO] split context string II - reader/writer changes

hoy updated this revision to Diff 368563.Aug 24 2021, 11:57 PM

Updating D108435: [CSSPGO] split context string II - reader/writer changes

wenlei added inline comments.Aug 26 2021, 5:34 PM
llvm/include/llvm/ProfileData/SampleProfReader.h
135

In this section, we need to add documentation/spec for CSNameTable how context is stored, and how it interacts with NameTable.

507

nit: remove the blank line

578

typo: given

llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Even though we only need to deal with string context in profile reader/writer for text profile, it's probably still cleaner to keep all string context related parsing into SampleContext.

createContext is more like a ctor. I'd prefer keep string decoding, createContext in its original place in SampleContext. That way, we can construct a context from string, SampleContext::setContext remain a private helper too, and the logic here can be simpler, just like before.

SampleContext does still have getContextString and toString, so it's not really isolated from string representation, might as well keep all string stuff together there for consistency.

447

I think getNameTable exist as a virtual function only because of the use in sample loader for profile-sample-accuarate and profile-accurate-for-symsinlist. Here can we still access the NameTable directly without going through virtual call? Same for other places where NameTable is directly accessible. For writer, before this change, we indeed only have NameTable for SampleProfileWriterBinary without virtual getter, and we access it without going through virtual function call there.

452

Can we avoid this parameter altogether? For one profile, it's either going to be CS or non-CS, so the dispatch can be based on state/member of the reader instead of relying on a param for each invocation.

582

Same here, avoid IsContextName as param, but dispatch based on SampleProfileReader::ProfileIsCS

587–588

nit: this can be confusing, readNameFromTable can mislead people to think FContext is string (or vector of strings) type. the auto also isn't helping. Either spell out the type name, or rename readNameFromTable to something like readSampleContextFromTable

749

Since we have SampleProfileReader::ProfileIsCS, within reader it probable makes more sense to use the reader instance flag as opposed to the global FunctionSamples::ProfileIsCS flag.

We were not very consistent in past, might be good to clean up as you're expanding the use of ProfileIsCS.

775

OrderedNames -> OrderedContexts

1042

Let emplace_back take variadic arguments and forward to the constructor directly instead of doing a move copy?

1046

How about we emplace an empty slot before going into the inner loop, then we can operate on the vector directly (PNameVec.back().emplace_back(...)) and avoid copying temporary Context onto PNameVec?

1062–1063

nit: peal/hoist the get() so we don't have to call it for every use.

wenlei added inline comments.Aug 26 2021, 10:17 PM
llvm/include/llvm/ProfileData/SampleProfWriter.h
138–139

Now that the parameter is no longer a string name, rename the function as well, e.g. writeContextIdx?

Same for addName(const SampleContext &Context) -> addContext

llvm/lib/ProfileData/SampleProfReader.cpp
776–794

Which operation here is the most costly and visible for e2e build time? The insert/sort/find or the prefix check? What's the % of time here for both prelink and postlink?

llvm/lib/ProfileData/SampleProfWriter.cpp
249

nit: this contains leaf frame, so it's Frames instead of Callsites.

482

assert !Context.hasContext() ?

llvm/tools/llvm-profdata/llvm-profdata.cpp
524–526

I suggest rename these FName (key of the SampleProfileMap) to be FContext accordingly given this is no longer a string map. Same for other places.

hoy marked 2 inline comments as done.Aug 27 2021, 10:57 PM
hoy added inline comments.
llvm/include/llvm/ProfileData/SampleProfReader.h
135

CSNameTable is a concept of the extensible binary format, not the basic binary format, like other concepts such as func name offset table, func metadata table. We could comment about CSNameTable in the SampleProfileReaderExtBinary/SampleProfileWriterExtBinary, but I didn't find a good centralized place to do that. Seems that descriptions about other sections are scattered around the implementation code.

507

done.

578

fixed.

llvm/include/llvm/ProfileData/SampleProfWriter.h
138–139

Sounds good.

llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Makes sense. Moved back to SampleContext.

447

Yes, we can just use NameTable directly here. Actually all changes here are unnecessary. I just undid them.

452

Good point. Checking FunctionSamples::ProfileIsCS should be enough.

587–588

Fixed by using explicit type.

749

That's reasonable. Replaced all FunctionSamples::ProfileIsCS usage in the reader with the reader ProfileIsCS flag.

775

fixed.

776–794

The insert/sort/find operations are the most expansive. For thinlto postlink, they count to 15% to 20% of the whole backend running time. I haven't measured for prelink but given the similarity of prelink and postlink, they should be expansive there too.

I'm actually working on a sample writer change that emits the func offset table in the order of contexts so that we don't need the set operations here. That turns out very effective. Will send out a separate diff for it.

1046

Sounds good, that should be faster.

1062–1063

You mean save FContext.get() in a temp and use it in the loop? Thought the compiler would do it.

llvm/lib/ProfileData/SampleProfWriter.cpp
249

Frames sounds good.

482

Added the assert.

llvm/tools/llvm-profdata/llvm-profdata.cpp
524–526

Sounds good.

hoy updated this revision to Diff 369238.Aug 27 2021, 10:57 PM

Addressing Wenlei's comment.

wenlei added inline comments.Aug 29 2021, 2:42 PM
llvm/include/llvm/ProfileData/SampleProfReader.h
135

Ok, didn't realize we don't use header comment for extbin. That's fine. Yeah, it'd be good to have some comment for CSNameTable somewhere to explain the nesting structure of context and raw names.

llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Thanks. Can you move it back in D107299, so we don't see the change back and forth, just for review?

Can we also fold FName.startswith("[") in to SampleContext?

Additionally, why we do need a createContextFromString instead of using overload ctors? This is also inconsistent between how SampleContext is created from text profile (createContextFromString) vs from binary profile (ctor). What I was thinking is have SampleContext decide how to create the object, so there's no changed needed here, just like before.

587–588

Ok, but on 2nd thought, why do we call it readName while it's actually returning a context? Especially given that we've renamed addName to AddContext, writeNameIdx to writeContextIdx.

722

FName to FContext as well?

776–794

I'm actually working on a sample writer change that emits the func offset table in the order of contexts so that we don't need the set operations here. That turns out very effective.

Great. I was thinking about exactly that too. The order of binary profile is opaque to users, so we can order them in the file to save sorting on reading.

For thinlto postlink, they count to 15% to 20% of the whole backend running time.

What was the % before this work when we were all using StringRef?

1062–1063

Yeah, it's less about optimization but for readability to make the code less verbose.

hoy added inline comments.Aug 29 2021, 7:07 PM
llvm/include/llvm/ProfileData/SampleProfReader.h
135

Comment added to the definition of SampleProfileReaderExtBinaryBase::readCSNameTableSec.

llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Constructing a CS context will require additional parameter than non-CS profile, especially the underlying context vector. That is causing the inconsistency with the context split work and I'm separating the construction of CS and non-CS contexts. Currently CS context is only constructible from a SampleContextFrameVector.

Another reason is that I was hoping to construct SampleContext in a quick manner from StringRef to favor non-CS profile.

722

Oops, this was fixed in my other unified patch, somehow got dropped when rebasing. Will send an update to the other patch as you suggested.

776–794

What was the % before this work when we were all using StringRef?

It's not noticeable. Actually I didn't see the previous sorting as a hot routine in the profile. With the presorted func offset stable, we are able to achieve similar performance with the previous approach.

wenlei added inline comments.Aug 29 2021, 9:02 PM
llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Can you move it back in D107299, so we don't see the change back and forth, just for review?

Sorry my bad, I meant to say D108433.

I think the key blocker for everything to be taken care from within ctor is that you need reader to own the context created from the string. How about having a ctor with StringRef and CSNameTable as parameter - it puts the context into CSNameTable (owned by reader) for CS profile, and the CSNameTable would be ignored for non-CS profile.

The current implementation works, but reader has to be aware of the actual string representation of context. I thought it'd be cleaner if such representation is all dealt with from within SampleContext. Currently, it's indeed mostly handled by SampleContext, except it's bleeding into reader here.

587–588

I think it'd be good to establish a convention as to when we call things Name vs Context. My thought is it goes with the type, what do you think?

1014

Comment added to the definition of SampleProfileReaderExtBinaryBase::readCSNameTableSec.

Not seeing comments in the latest update. Did I miss anything?

hoy added inline comments.Aug 29 2021, 10:26 PM
llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Yeah, that's why I originally put everything related to context string parsing in the reader. I thought they were related to profile-specific representation that SampleContext shouldn't care.

I guess moving the parsing code back is better for extension and code sharing, when we have new module doing the same thing in the future. Adding a new constructor with StringRef and CSNameTable as parameter can work but feel like it's easier and more clear for the reader to know what it constructs. Hiding that from the reader is fine, but asking the reader to provide an underlying CS name table which may not be needed for non-CS sounds a bit confusing. That also kinds of exposes reader-specific implementation to SampleContext.

I think having the reader be aware of the specific representation might be reasonable, since context representation is a part of the profile format. What do you think?

587–588

Yeah, I've been using Name as an identifier of of the context and function name string, and using Context for CS profile and String for function names. But sometimes Name and String as mixed.

We are using SampleContext for both CS and non-CS. And we are also using the word context specifically for CS. Sounds like we need a more general name (instead of Name) in the reader for both of them. How about readIdFromTable?

1062–1063

Changed to using *FContext for readability, like other places. Look good?

Alternatively, we can have two variables such as FContextError and FContext.

hoy updated this revision to Diff 369373.Aug 29 2021, 10:32 PM

Updating D108435: [CSSPGO] split context string II - reader/writer changes

wenlei added inline comments.Aug 30 2021, 12:20 PM
llvm/lib/ProfileData/SampleProfReader.cpp
282–283

asking the reader to provide an underlying CS name table which may not be needed for non-CS sounds a bit confusing. That also kinds of exposes reader-specific implementation to SampleContext.

I don't see this as exposing reader-specific stuff to sample context. It'd just be the expectation of the sample context API that requires a buffer to hold newly created context.

This is in essence no different from how string buffer is passed in getRepInFormat (and only used for MD5), and I don't see it as coupling between reader and context.

I think having the reader be aware of the specific representation might be reasonable, since context representation is a part of the profile format.

I think the actual string presentation of context is not tied to the format, but rather the format is using the string representation directly. Also if string representation is considered part of format, then all of the string related stuff should be part of reader (like your earlier change). The possible reusing of string functions you mentioned also shows that the string representation is not format-specific.

587–588

I've been using Name as an identifier of of the context and function name string, and using Context for CS profile and String for function names.

The problem is you can't do that cleanly because there're cases that covers both CS and non-CS. readNameFromTable is one example.

I think that name it according to the type makes things clearer. For non-CS profile we're still using SampleContext as key in the profile map anyways. Adding a new notion of Id in addition to name and context seem unnecessary (we have Idx already which can confuse people if we add Id). So I think readSampleContextFromTable/readContextFromTable is better.

1062–1063

either works, thanks.

hoy added inline comments.Aug 30 2021, 12:42 PM
llvm/lib/ProfileData/SampleProfReader.cpp
282–283

This is in essence no different from how string buffer is passed in getRepInFormat (and only used for MD5), and I don't see it as coupling between reader and context.

getRepInFormat takes a string buffer instead of a string table which is not coupled with the reader. However, CSNameTable is an implementation detail of the reader. Having that populated and updated by SampleContext sounds like a coupling with the reader. E.g, from SampleContext point of view, it is questionable why it has to update a std::list but not a std::vector or std::set.

We can pass in a SampleContextFrameVector to the new ctor, and similar with the callsites of getRepInFormat, the reader should know where to place it, just like the current code. But then the reader has to redo some checks in the ctor. Anyway, feels that the reader will need to check if it is constructing a CS context, if we don't expose CSNameTable to SampleContext.

Since the reader is currently the only consumer, maybe just keep it in the reader for now? When we have a new user we can then decide what kind of new ctor to make?

587–588

Sounds good. Will use readSampleContextFromTable.

hoy updated this revision to Diff 369530.Aug 30 2021, 1:03 PM

Renaming readNameFromTable to readSampleContextFromTable.

wenlei added inline comments.Aug 30 2021, 1:33 PM
llvm/lib/ProfileData/SampleProfReader.cpp
282–283

Ok, I think we've probably spent too much time on this. But bear with me a bit more, still hope we can reach a consensus. :) That said, whatever we choose to do, I don't agree with your reasoning above.

However, CSNameTable is an implementation detail of the reader.

Look at it as buffer, and in this case reader happens to own and provide that buffer.

Having that populated and updated by SampleContext sounds like a coupling with the reader. E.g, from SampleContext point of view, it is questionable why it has to update a std::list but not a std::vector or std::set.

I don't think this is really a concern, nor is it a coupling tbh. Regardless of what reader does, what makes sense for a buffer type? I think std::list simply makes sense as it avoid reallocating. Yes, reader uses std::list, but this is just a choice that makes sense in general for a buffer. If we go down this level, sure every single API call is a coupling because every param has a type.

The way I look at this - sample context abstracts away the string representation (again it's independent of format, and text format just uses that string representation directly), and reader resort to sample context for anything related to that. It's probably not so important to have that logical layering enforced, but if the cost of doing that is small, why not? Clear layering makes it easy to maintain and reason about.

hoy added inline comments.Aug 30 2021, 1:53 PM
llvm/lib/ProfileData/SampleProfReader.cpp
282–283

I don't think this is really a concern, nor is it a coupling tbh. Regardless of what reader does, what makes sense for a buffer type? I think std::list simply makes sense as it avoid reallocating. Yes, reader uses std::list, but this is just a choice that makes sense in general for a buffer. If we go down this level, sure every single API call is a coupling because every param has a type.

Yeah, we probably spent too much time on this. I will make a new ctor with CSNameTable as a parameter.

hoy updated this revision to Diff 369559.Aug 30 2021, 2:46 PM

Updating D108435: [CSSPGO] split context string II - reader/writer changes

wenlei added inline comments.Aug 30 2021, 3:14 PM
llvm/include/llvm/ProfileData/SampleProf.h
533

This can be removed now?

hoy updated this revision to Diff 369582.Aug 30 2021, 4:52 PM

Updating D108435: [CSSPGO] split context string II - reader/writer changes

llvm/include/llvm/ProfileData/SampleProf.h
533

yes, it's removed from the other patch but somehow not updated here.

wenlei accepted this revision.Aug 30 2021, 6:04 PM

lgtm, thanks for working through the comments!

hoy closed this revision.Aug 31 2021, 4:19 PM