1 //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the class that writes LLVM sample profiles. It 10 // supports two file formats: text and binary. The textual representation 11 // is useful for debugging and testing purposes. The binary representation 12 // is more compact, resulting in smaller file sizes. However, they can 13 // both be used interchangeably. 14 // 15 // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the 16 // supported formats. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "llvm/ProfileData/SampleProfWriter.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/ProfileData/ProfileCommon.h" 23 #include "llvm/ProfileData/SampleProf.h" 24 #include "llvm/Support/Compression.h" 25 #include "llvm/Support/Endian.h" 26 #include "llvm/Support/EndianStream.h" 27 #include "llvm/Support/ErrorOr.h" 28 #include "llvm/Support/FileSystem.h" 29 #include "llvm/Support/LEB128.h" 30 #include "llvm/Support/MD5.h" 31 #include "llvm/Support/raw_ostream.h" 32 #include <algorithm> 33 #include <cstdint> 34 #include <memory> 35 #include <set> 36 #include <system_error> 37 #include <utility> 38 #include <vector> 39 40 using namespace llvm; 41 using namespace sampleprof; 42 43 std::error_code SampleProfileWriter::writeFuncProfiles( 44 const StringMap<FunctionSamples> &ProfileMap) { 45 // Sort the ProfileMap by total samples. 46 typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; 47 std::vector<NameFunctionSamples> V; 48 for (const auto &I : ProfileMap) 49 V.push_back(std::make_pair(I.getKey(), &I.second)); 50 51 llvm::stable_sort( 52 V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 53 if (A.second->getTotalSamples() == B.second->getTotalSamples()) 54 return A.first > B.first; 55 return A.second->getTotalSamples() > B.second->getTotalSamples(); 56 }); 57 58 for (const auto &I : V) { 59 if (std::error_code EC = writeSample(*I.second)) 60 return EC; 61 } 62 return sampleprof_error::success; 63 } 64 65 std::error_code 66 SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 67 if (std::error_code EC = writeHeader(ProfileMap)) 68 return EC; 69 70 if (std::error_code EC = writeFuncProfiles(ProfileMap)) 71 return EC; 72 73 return sampleprof_error::success; 74 } 75 76 SecHdrTableEntry & 77 SampleProfileWriterExtBinaryBase::getEntryInLayout(SecType Type) { 78 auto SecIt = std::find_if( 79 SectionHdrLayout.begin(), SectionHdrLayout.end(), 80 [=](const auto &Entry) -> bool { return Entry.Type == Type; }); 81 return *SecIt; 82 } 83 84 /// Return the current position and prepare to use it as the start 85 /// position of a section. 86 uint64_t SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type) { 87 uint64_t SectionStart = OutputStream->tell(); 88 auto &Entry = getEntryInLayout(Type); 89 // Use LocalBuf as a temporary output for writting data. 90 if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) 91 LocalBufStream.swap(OutputStream); 92 return SectionStart; 93 } 94 95 std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { 96 if (!llvm::zlib::isAvailable()) 97 return sampleprof_error::zlib_unavailable; 98 std::string &UncompressedStrings = 99 static_cast<raw_string_ostream *>(LocalBufStream.get())->str(); 100 if (UncompressedStrings.size() == 0) 101 return sampleprof_error::success; 102 auto &OS = *OutputStream; 103 SmallString<128> CompressedStrings; 104 llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings, 105 zlib::BestSizeCompression); 106 if (E) 107 return sampleprof_error::compress_failed; 108 encodeULEB128(UncompressedStrings.size(), OS); 109 encodeULEB128(CompressedStrings.size(), OS); 110 OS << CompressedStrings.str(); 111 UncompressedStrings.clear(); 112 return sampleprof_error::success; 113 } 114 115 /// Add a new section into section header table. 116 std::error_code 117 SampleProfileWriterExtBinaryBase::addNewSection(SecType Type, 118 uint64_t SectionStart) { 119 auto Entry = getEntryInLayout(Type); 120 if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) { 121 LocalBufStream.swap(OutputStream); 122 if (std::error_code EC = compressAndOutput()) 123 return EC; 124 } 125 SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart, 126 OutputStream->tell() - SectionStart}); 127 return sampleprof_error::success; 128 } 129 130 std::error_code SampleProfileWriterExtBinaryBase::write( 131 const StringMap<FunctionSamples> &ProfileMap) { 132 if (std::error_code EC = writeHeader(ProfileMap)) 133 return EC; 134 135 std::string LocalBuf; 136 LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf); 137 if (std::error_code EC = writeSections(ProfileMap)) 138 return EC; 139 140 if (std::error_code EC = writeSecHdrTable()) 141 return EC; 142 143 return sampleprof_error::success; 144 } 145 146 std::error_code 147 SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) { 148 uint64_t Offset = OutputStream->tell(); 149 StringRef Name = S.getName(); 150 FuncOffsetTable[Name] = Offset - SecLBRProfileStart; 151 encodeULEB128(S.getHeadSamples(), *OutputStream); 152 return writeBody(S); 153 } 154 155 std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() { 156 auto &OS = *OutputStream; 157 158 // Write out the table size. 159 encodeULEB128(FuncOffsetTable.size(), OS); 160 161 // Write out FuncOffsetTable. 162 for (auto entry : FuncOffsetTable) { 163 writeNameIdx(entry.first); 164 encodeULEB128(entry.second, OS); 165 } 166 return sampleprof_error::success; 167 } 168 169 std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() { 170 if (!UseMD5) 171 return SampleProfileWriterBinary::writeNameTable(); 172 173 auto &OS = *OutputStream; 174 std::set<StringRef> V; 175 stablizeNameTable(V); 176 177 // Write out the MD5 name table. We wrote unencoded MD5 so reader can 178 // retrieve the name using the name index without having to read the 179 // whole name table. 180 encodeULEB128(NameTable.size(), OS); 181 support::endian::Writer Writer(OS, support::little); 182 for (auto N : V) 183 Writer.write(MD5Hash(N)); 184 return sampleprof_error::success; 185 } 186 187 std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection( 188 const StringMap<FunctionSamples> &ProfileMap) { 189 for (const auto &I : ProfileMap) { 190 addName(I.first()); 191 addNames(I.second); 192 } 193 if (auto EC = writeNameTable()) 194 return EC; 195 return sampleprof_error::success; 196 } 197 198 std::error_code 199 SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() { 200 if (ProfSymList && ProfSymList->size() > 0) 201 if (std::error_code EC = ProfSymList->write(*OutputStream)) 202 return EC; 203 204 return sampleprof_error::success; 205 } 206 207 std::error_code SampleProfileWriterExtBinaryBase::writeOneSection( 208 SecType Type, const StringMap<FunctionSamples> &ProfileMap) { 209 // The setting of SecFlagCompress should happen before markSectionStart. 210 if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress()) 211 setToCompressSection(SecProfileSymbolList); 212 213 uint64_t SectionStart = markSectionStart(Type); 214 switch (Type) { 215 case SecProfSummary: 216 computeSummary(ProfileMap); 217 if (auto EC = writeSummary()) 218 return EC; 219 break; 220 case SecNameTable: 221 if (auto EC = writeNameTableSection(ProfileMap)) 222 return EC; 223 break; 224 case SecLBRProfile: 225 SecLBRProfileStart = OutputStream->tell(); 226 if (std::error_code EC = writeFuncProfiles(ProfileMap)) 227 return EC; 228 break; 229 case SecFuncOffsetTable: 230 if (auto EC = writeFuncOffsetTable()) 231 return EC; 232 break; 233 case SecProfileSymbolList: 234 if (auto EC = writeProfileSymbolListSection()) 235 return EC; 236 break; 237 default: 238 if (auto EC = writeCustomSection(Type)) 239 return EC; 240 break; 241 } 242 if (std::error_code EC = addNewSection(Type, SectionStart)) 243 return EC; 244 return sampleprof_error::success; 245 } 246 247 std::error_code SampleProfileWriterExtBinary::writeSections( 248 const StringMap<FunctionSamples> &ProfileMap) { 249 if (auto EC = writeOneSection(SecProfSummary, ProfileMap)) 250 return EC; 251 if (auto EC = writeOneSection(SecNameTable, ProfileMap)) 252 return EC; 253 if (auto EC = writeOneSection(SecLBRProfile, ProfileMap)) 254 return EC; 255 if (auto EC = writeOneSection(SecProfileSymbolList, ProfileMap)) 256 return EC; 257 if (auto EC = writeOneSection(SecFuncOffsetTable, ProfileMap)) 258 return EC; 259 return sampleprof_error::success; 260 } 261 262 std::error_code SampleProfileWriterCompactBinary::write( 263 const StringMap<FunctionSamples> &ProfileMap) { 264 if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 265 return EC; 266 if (std::error_code EC = writeFuncOffsetTable()) 267 return EC; 268 return sampleprof_error::success; 269 } 270 271 /// Write samples to a text file. 272 /// 273 /// Note: it may be tempting to implement this in terms of 274 /// FunctionSamples::print(). Please don't. The dump functionality is intended 275 /// for debugging and has no specified form. 276 /// 277 /// The format used here is more structured and deliberate because 278 /// it needs to be parsed by the SampleProfileReaderText class. 279 std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 280 auto &OS = *OutputStream; 281 if (FunctionSamples::ProfileIsCS) 282 OS << "[" << S.getNameWithContext() << "]:" << S.getTotalSamples(); 283 else 284 OS << S.getName() << ":" << S.getTotalSamples(); 285 if (Indent == 0) 286 OS << ":" << S.getHeadSamples(); 287 OS << "\n"; 288 289 SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 290 for (const auto &I : SortedSamples.get()) { 291 LineLocation Loc = I->first; 292 const SampleRecord &Sample = I->second; 293 OS.indent(Indent + 1); 294 if (Loc.Discriminator == 0) 295 OS << Loc.LineOffset << ": "; 296 else 297 OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 298 299 OS << Sample.getSamples(); 300 301 for (const auto &J : Sample.getSortedCallTargets()) 302 OS << " " << J.first << ":" << J.second; 303 OS << "\n"; 304 } 305 306 SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 307 S.getCallsiteSamples()); 308 Indent += 1; 309 for (const auto &I : SortedCallsiteSamples.get()) 310 for (const auto &FS : I->second) { 311 LineLocation Loc = I->first; 312 const FunctionSamples &CalleeSamples = FS.second; 313 OS.indent(Indent); 314 if (Loc.Discriminator == 0) 315 OS << Loc.LineOffset << ": "; 316 else 317 OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 318 if (std::error_code EC = writeSample(CalleeSamples)) 319 return EC; 320 } 321 Indent -= 1; 322 323 return sampleprof_error::success; 324 } 325 326 std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 327 const auto &ret = NameTable.find(FName); 328 if (ret == NameTable.end()) 329 return sampleprof_error::truncated_name_table; 330 encodeULEB128(ret->second, *OutputStream); 331 return sampleprof_error::success; 332 } 333 334 void SampleProfileWriterBinary::addName(StringRef FName) { 335 NameTable.insert(std::make_pair(FName, 0)); 336 } 337 338 void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 339 // Add all the names in indirect call targets. 340 for (const auto &I : S.getBodySamples()) { 341 const SampleRecord &Sample = I.second; 342 for (const auto &J : Sample.getCallTargets()) 343 addName(J.first()); 344 } 345 346 // Recursively add all the names for inlined callsites. 347 for (const auto &J : S.getCallsiteSamples()) 348 for (const auto &FS : J.second) { 349 const FunctionSamples &CalleeSamples = FS.second; 350 addName(CalleeSamples.getName()); 351 addNames(CalleeSamples); 352 } 353 } 354 355 void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 356 // Sort the names to make NameTable deterministic. 357 for (const auto &I : NameTable) 358 V.insert(I.first); 359 int i = 0; 360 for (const StringRef &N : V) 361 NameTable[N] = i++; 362 } 363 364 std::error_code SampleProfileWriterBinary::writeNameTable() { 365 auto &OS = *OutputStream; 366 std::set<StringRef> V; 367 stablizeNameTable(V); 368 369 // Write out the name table. 370 encodeULEB128(NameTable.size(), OS); 371 for (auto N : V) { 372 OS << N; 373 encodeULEB128(0, OS); 374 } 375 return sampleprof_error::success; 376 } 377 378 std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 379 auto &OS = *OutputStream; 380 381 // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 382 auto &OFS = static_cast<raw_fd_ostream &>(OS); 383 uint64_t FuncOffsetTableStart = OS.tell(); 384 if (OFS.seek(TableOffset) == (uint64_t)-1) 385 return sampleprof_error::ostream_seek_unsupported; 386 support::endian::Writer Writer(*OutputStream, support::little); 387 Writer.write(FuncOffsetTableStart); 388 if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 389 return sampleprof_error::ostream_seek_unsupported; 390 391 // Write out the table size. 392 encodeULEB128(FuncOffsetTable.size(), OS); 393 394 // Write out FuncOffsetTable. 395 for (auto entry : FuncOffsetTable) { 396 writeNameIdx(entry.first); 397 encodeULEB128(entry.second, OS); 398 } 399 return sampleprof_error::success; 400 } 401 402 std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 403 auto &OS = *OutputStream; 404 std::set<StringRef> V; 405 stablizeNameTable(V); 406 407 // Write out the name table. 408 encodeULEB128(NameTable.size(), OS); 409 for (auto N : V) { 410 encodeULEB128(MD5Hash(N), OS); 411 } 412 return sampleprof_error::success; 413 } 414 415 std::error_code 416 SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 417 auto &OS = *OutputStream; 418 // Write file magic identifier. 419 encodeULEB128(SPMagic(Format), OS); 420 encodeULEB128(SPVersion(), OS); 421 return sampleprof_error::success; 422 } 423 424 std::error_code SampleProfileWriterBinary::writeHeader( 425 const StringMap<FunctionSamples> &ProfileMap) { 426 writeMagicIdent(Format); 427 428 computeSummary(ProfileMap); 429 if (auto EC = writeSummary()) 430 return EC; 431 432 // Generate the name table for all the functions referenced in the profile. 433 for (const auto &I : ProfileMap) { 434 addName(I.first()); 435 addNames(I.second); 436 } 437 438 writeNameTable(); 439 return sampleprof_error::success; 440 } 441 442 void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 443 for (auto &Entry : SectionHdrLayout) 444 addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 445 } 446 447 void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 448 addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 449 } 450 451 void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 452 support::endian::Writer Writer(*OutputStream, support::little); 453 454 Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 455 SecHdrTableOffset = OutputStream->tell(); 456 for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 457 Writer.write(static_cast<uint64_t>(-1)); 458 Writer.write(static_cast<uint64_t>(-1)); 459 Writer.write(static_cast<uint64_t>(-1)); 460 Writer.write(static_cast<uint64_t>(-1)); 461 } 462 } 463 464 std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 465 auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 466 uint64_t Saved = OutputStream->tell(); 467 468 // Set OutputStream to the location saved in SecHdrTableOffset. 469 if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 470 return sampleprof_error::ostream_seek_unsupported; 471 support::endian::Writer Writer(*OutputStream, support::little); 472 473 DenseMap<uint32_t, uint32_t> IndexMap; 474 for (uint32_t i = 0; i < SecHdrTable.size(); i++) { 475 IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i}); 476 } 477 478 // Write the section header table in the order specified in 479 // SectionHdrLayout. That is the sections order Reader will see. 480 // Note that the sections order in which Reader expects to read 481 // may be different from the order in which Writer is able to 482 // write, so we need to adjust the order in SecHdrTable to be 483 // consistent with SectionHdrLayout when we write SecHdrTable 484 // to the memory. 485 for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 486 uint32_t idx = IndexMap[static_cast<uint32_t>(SectionHdrLayout[i].Type)]; 487 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type)); 488 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flags)); 489 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset)); 490 Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size)); 491 } 492 493 // Reset OutputStream. 494 if (OFS.seek(Saved) == (uint64_t)-1) 495 return sampleprof_error::ostream_seek_unsupported; 496 497 return sampleprof_error::success; 498 } 499 500 std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 501 const StringMap<FunctionSamples> &ProfileMap) { 502 auto &OS = *OutputStream; 503 FileStart = OS.tell(); 504 writeMagicIdent(Format); 505 506 allocSecHdrTable(); 507 return sampleprof_error::success; 508 } 509 510 std::error_code SampleProfileWriterCompactBinary::writeHeader( 511 const StringMap<FunctionSamples> &ProfileMap) { 512 support::endian::Writer Writer(*OutputStream, support::little); 513 if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 514 return EC; 515 516 // Reserve a slot for the offset of function offset table. The slot will 517 // be populated with the offset of FuncOffsetTable later. 518 TableOffset = OutputStream->tell(); 519 Writer.write(static_cast<uint64_t>(-2)); 520 return sampleprof_error::success; 521 } 522 523 std::error_code SampleProfileWriterBinary::writeSummary() { 524 auto &OS = *OutputStream; 525 encodeULEB128(Summary->getTotalCount(), OS); 526 encodeULEB128(Summary->getMaxCount(), OS); 527 encodeULEB128(Summary->getMaxFunctionCount(), OS); 528 encodeULEB128(Summary->getNumCounts(), OS); 529 encodeULEB128(Summary->getNumFunctions(), OS); 530 std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 531 encodeULEB128(Entries.size(), OS); 532 for (auto Entry : Entries) { 533 encodeULEB128(Entry.Cutoff, OS); 534 encodeULEB128(Entry.MinCount, OS); 535 encodeULEB128(Entry.NumCounts, OS); 536 } 537 return sampleprof_error::success; 538 } 539 std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 540 auto &OS = *OutputStream; 541 542 if (std::error_code EC = writeNameIdx(S.getName())) 543 return EC; 544 545 encodeULEB128(S.getTotalSamples(), OS); 546 547 // Emit all the body samples. 548 encodeULEB128(S.getBodySamples().size(), OS); 549 for (const auto &I : S.getBodySamples()) { 550 LineLocation Loc = I.first; 551 const SampleRecord &Sample = I.second; 552 encodeULEB128(Loc.LineOffset, OS); 553 encodeULEB128(Loc.Discriminator, OS); 554 encodeULEB128(Sample.getSamples(), OS); 555 encodeULEB128(Sample.getCallTargets().size(), OS); 556 for (const auto &J : Sample.getSortedCallTargets()) { 557 StringRef Callee = J.first; 558 uint64_t CalleeSamples = J.second; 559 if (std::error_code EC = writeNameIdx(Callee)) 560 return EC; 561 encodeULEB128(CalleeSamples, OS); 562 } 563 } 564 565 // Recursively emit all the callsite samples. 566 uint64_t NumCallsites = 0; 567 for (const auto &J : S.getCallsiteSamples()) 568 NumCallsites += J.second.size(); 569 encodeULEB128(NumCallsites, OS); 570 for (const auto &J : S.getCallsiteSamples()) 571 for (const auto &FS : J.second) { 572 LineLocation Loc = J.first; 573 const FunctionSamples &CalleeSamples = FS.second; 574 encodeULEB128(Loc.LineOffset, OS); 575 encodeULEB128(Loc.Discriminator, OS); 576 if (std::error_code EC = writeBody(CalleeSamples)) 577 return EC; 578 } 579 580 return sampleprof_error::success; 581 } 582 583 /// Write samples of a top-level function to a binary file. 584 /// 585 /// \returns true if the samples were written successfully, false otherwise. 586 std::error_code 587 SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 588 encodeULEB128(S.getHeadSamples(), *OutputStream); 589 return writeBody(S); 590 } 591 592 std::error_code 593 SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 594 uint64_t Offset = OutputStream->tell(); 595 StringRef Name = S.getName(); 596 FuncOffsetTable[Name] = Offset; 597 encodeULEB128(S.getHeadSamples(), *OutputStream); 598 return writeBody(S); 599 } 600 601 /// Create a sample profile file writer based on the specified format. 602 /// 603 /// \param Filename The file to create. 604 /// 605 /// \param Format Encoding format for the profile file. 606 /// 607 /// \returns an error code indicating the status of the created writer. 608 ErrorOr<std::unique_ptr<SampleProfileWriter>> 609 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 610 std::error_code EC; 611 std::unique_ptr<raw_ostream> OS; 612 if (Format == SPF_Binary || Format == SPF_Ext_Binary || 613 Format == SPF_Compact_Binary) 614 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 615 else 616 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 617 if (EC) 618 return EC; 619 620 return create(OS, Format); 621 } 622 623 /// Create a sample profile stream writer based on the specified format. 624 /// 625 /// \param OS The output stream to store the profile data to. 626 /// 627 /// \param Format Encoding format for the profile file. 628 /// 629 /// \returns an error code indicating the status of the created writer. 630 ErrorOr<std::unique_ptr<SampleProfileWriter>> 631 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 632 SampleProfileFormat Format) { 633 std::error_code EC; 634 std::unique_ptr<SampleProfileWriter> Writer; 635 636 if (Format == SPF_Binary) 637 Writer.reset(new SampleProfileWriterRawBinary(OS)); 638 else if (Format == SPF_Ext_Binary) 639 Writer.reset(new SampleProfileWriterExtBinary(OS)); 640 else if (Format == SPF_Compact_Binary) 641 Writer.reset(new SampleProfileWriterCompactBinary(OS)); 642 else if (Format == SPF_Text) 643 Writer.reset(new SampleProfileWriterText(OS)); 644 else if (Format == SPF_GCC) 645 EC = sampleprof_error::unsupported_writing_format; 646 else 647 EC = sampleprof_error::unrecognized_format; 648 649 if (EC) 650 return EC; 651 652 Writer->Format = Format; 653 return std::move(Writer); 654 } 655 656 void SampleProfileWriter::computeSummary( 657 const StringMap<FunctionSamples> &ProfileMap) { 658 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 659 for (const auto &I : ProfileMap) { 660 const FunctionSamples &Profile = I.second; 661 Builder.addRecord(Profile); 662 } 663 Summary = Builder.getSummary(); 664 } 665