1717#include " llvm/ProfileData/InstrProf.h"
1818#include " llvm/ProfileData/PGOCtxProfWriter.h"
1919#include " llvm/Support/Error.h"
20+ #include " llvm/Support/ErrorHandling.h"
21+ #include " llvm/Support/YAMLTraits.h"
22+ #include < iterator>
23+ #include < utility>
2024
2125using namespace llvm ;
2226
@@ -176,3 +180,86 @@ PGOCtxProfileReader::loadContexts() {
176180 }
177181 return std::move (Ret);
178182}
183+
184+ namespace {
185+ // We want to pass `const` values PGOCtxProfContext references to the yaml
186+ // converter, and the regular yaml mapping APIs are designed to handle both
187+ // serialization and deserialization, which prevents using const for
188+ // serialization. Using an intermediate datastructure is overkill, both
189+ // space-wise and design complexity-wise. Instead, we use the lower-level APIs.
190+ void toYaml (yaml::Output &Out, const PGOCtxProfContext &Ctx);
191+
192+ void toYaml (yaml::Output &Out,
193+ const PGOCtxProfContext::CallTargetMapTy &CallTargets) {
194+ Out.beginSequence ();
195+ size_t Index = 0 ;
196+ void *SaveData = nullptr ;
197+ for (const auto &[_, Ctx] : CallTargets) {
198+ Out.preflightElement (Index++, SaveData);
199+ toYaml (Out, Ctx);
200+ Out.postflightElement (nullptr );
201+ }
202+ Out.endSequence ();
203+ }
204+
205+ void toYaml (yaml::Output &Out,
206+ const PGOCtxProfContext::CallsiteMapTy &Callsites) {
207+ auto AllCS = ::llvm::make_first_range (Callsites);
208+ auto MaxIt = ::llvm::max_element (AllCS);
209+ assert (MaxIt != AllCS.end () && " We should have a max value because the "
210+ " callsites collection is not empty." );
211+ void *SaveData = nullptr ;
212+ Out.beginSequence ();
213+ for (auto I = 0U ; I <= *MaxIt; ++I) {
214+ Out.preflightElement (I, SaveData);
215+ auto It = Callsites.find (I);
216+ if (It == Callsites.end ()) {
217+ // This will produce a `[ ]` sequence, which is what we want here.
218+ Out.beginFlowSequence ();
219+ Out.endFlowSequence ();
220+ } else {
221+ toYaml (Out, It->second );
222+ }
223+ Out.postflightElement (nullptr );
224+ }
225+ Out.endSequence ();
226+ }
227+
228+ void toYaml (yaml::Output &Out, const PGOCtxProfContext &Ctx) {
229+ yaml::EmptyContext Empty;
230+ Out.beginMapping ();
231+ void *SaveInfo = nullptr ;
232+ bool UseDefault = false ;
233+ {
234+ Out.preflightKey (" Guid" , /* Required=*/ true , /* SameAsDefault=*/ false ,
235+ UseDefault, SaveInfo);
236+ auto Guid = Ctx.guid ();
237+ yaml::yamlize (Out, Guid, true , Empty);
238+ Out.postflightKey (nullptr );
239+ }
240+ {
241+ Out.preflightKey (" Counters" , true , false , UseDefault, SaveInfo);
242+ Out.beginFlowSequence ();
243+ for (size_t I = 0U , E = Ctx.counters ().size (); I < E; ++I) {
244+ Out.preflightFlowElement (I, SaveInfo);
245+ uint64_t V = Ctx.counters ()[I];
246+ yaml::yamlize (Out, V, true , Empty);
247+ Out.postflightFlowElement (SaveInfo);
248+ }
249+ Out.endFlowSequence ();
250+ Out.postflightKey (nullptr );
251+ }
252+ if (!Ctx.callsites ().empty ()) {
253+ Out.preflightKey (" Callsites" , true , false , UseDefault, SaveInfo);
254+ toYaml (Out, Ctx.callsites ());
255+ Out.postflightKey (nullptr );
256+ }
257+ Out.endMapping ();
258+ }
259+ } // namespace
260+
261+ void llvm::convertCtxProfToYaml (
262+ raw_ostream &OS, const PGOCtxProfContext::CallTargetMapTy &Profiles) {
263+ yaml::Output Out (OS);
264+ toYaml (Out, Profiles);
265+ }
0 commit comments