1c572e92cSDiego Novillo //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2c572e92cSDiego Novillo //
3c572e92cSDiego Novillo //                      The LLVM Compiler Infrastructure
4c572e92cSDiego Novillo //
5c572e92cSDiego Novillo // This file is distributed under the University of Illinois Open Source
6c572e92cSDiego Novillo // License. See LICENSE.TXT for details.
7c572e92cSDiego Novillo //
8c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
9c572e92cSDiego Novillo //
10c572e92cSDiego Novillo // This file implements the class that writes LLVM sample profiles. It
11c572e92cSDiego Novillo // supports two file formats: text and binary. The textual representation
12c572e92cSDiego Novillo // is useful for debugging and testing purposes. The binary representation
13c572e92cSDiego Novillo // is more compact, resulting in smaller file sizes. However, they can
14c572e92cSDiego Novillo // both be used interchangeably.
15c572e92cSDiego Novillo //
16c572e92cSDiego Novillo // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
17c572e92cSDiego Novillo // supported formats.
18c572e92cSDiego Novillo //
19c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
20c572e92cSDiego Novillo 
21c572e92cSDiego Novillo #include "llvm/ProfileData/SampleProfWriter.h"
22c572e92cSDiego Novillo #include "llvm/Support/Debug.h"
23c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h"
24c572e92cSDiego Novillo #include "llvm/Support/MemoryBuffer.h"
25c572e92cSDiego Novillo #include "llvm/Support/LEB128.h"
26c572e92cSDiego Novillo #include "llvm/Support/LineIterator.h"
27c572e92cSDiego Novillo #include "llvm/Support/Regex.h"
28c572e92cSDiego Novillo 
29c572e92cSDiego Novillo using namespace llvm::sampleprof;
30c572e92cSDiego Novillo using namespace llvm;
31c572e92cSDiego Novillo 
32c572e92cSDiego Novillo /// \brief Write samples to a text file.
33d5336ae2SDiego Novillo bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
34c572e92cSDiego Novillo   if (S.empty())
35c572e92cSDiego Novillo     return true;
36c572e92cSDiego Novillo 
37d5336ae2SDiego Novillo   OS << FName << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
38c572e92cSDiego Novillo      << "\n";
39c572e92cSDiego Novillo 
40d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
41d5336ae2SDiego Novillo     LineLocation Loc = I.first;
42d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
43c572e92cSDiego Novillo     if (Loc.Discriminator == 0)
44c572e92cSDiego Novillo       OS << Loc.LineOffset << ": ";
45c572e92cSDiego Novillo     else
46c572e92cSDiego Novillo       OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
47c572e92cSDiego Novillo 
48c572e92cSDiego Novillo     OS << Sample.getSamples();
49c572e92cSDiego Novillo 
50d5336ae2SDiego Novillo     for (const auto &J : Sample.getCallTargets())
51d5336ae2SDiego Novillo       OS << " " << J.first() << ":" << J.second;
52c572e92cSDiego Novillo     OS << "\n";
53c572e92cSDiego Novillo   }
54c572e92cSDiego Novillo 
55c572e92cSDiego Novillo   return true;
56c572e92cSDiego Novillo }
57c572e92cSDiego Novillo 
58c572e92cSDiego Novillo SampleProfileWriterBinary::SampleProfileWriterBinary(StringRef F,
59c572e92cSDiego Novillo                                                      std::error_code &EC)
60c572e92cSDiego Novillo     : SampleProfileWriter(F, EC, sys::fs::F_None) {
61c572e92cSDiego Novillo   if (EC)
62c572e92cSDiego Novillo     return;
63c572e92cSDiego Novillo 
64c572e92cSDiego Novillo   // Write the file header.
65c572e92cSDiego Novillo   encodeULEB128(SPMagic(), OS);
66c572e92cSDiego Novillo   encodeULEB128(SPVersion(), OS);
67c572e92cSDiego Novillo }
68c572e92cSDiego Novillo 
69c572e92cSDiego Novillo /// \brief Write samples to a binary file.
70c572e92cSDiego Novillo ///
71c572e92cSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
72d5336ae2SDiego Novillo bool SampleProfileWriterBinary::write(StringRef FName,
73c572e92cSDiego Novillo                                       const FunctionSamples &S) {
74c572e92cSDiego Novillo   if (S.empty())
75c572e92cSDiego Novillo     return true;
76c572e92cSDiego Novillo 
77d5336ae2SDiego Novillo   OS << FName;
78c572e92cSDiego Novillo   encodeULEB128(0, OS);
79c572e92cSDiego Novillo   encodeULEB128(S.getTotalSamples(), OS);
80c572e92cSDiego Novillo   encodeULEB128(S.getHeadSamples(), OS);
81c572e92cSDiego Novillo   encodeULEB128(S.getBodySamples().size(), OS);
82d5336ae2SDiego Novillo   for (const auto &I : S.getBodySamples()) {
83d5336ae2SDiego Novillo     LineLocation Loc = I.first;
84d5336ae2SDiego Novillo     const SampleRecord &Sample = I.second;
85c572e92cSDiego Novillo     encodeULEB128(Loc.LineOffset, OS);
86c572e92cSDiego Novillo     encodeULEB128(Loc.Discriminator, OS);
87c572e92cSDiego Novillo     encodeULEB128(Sample.getSamples(), OS);
88c572e92cSDiego Novillo     encodeULEB128(Sample.getCallTargets().size(), OS);
89d5336ae2SDiego Novillo     for (const auto &J : Sample.getCallTargets()) {
90d5336ae2SDiego Novillo       std::string Callee = J.first();
91d5336ae2SDiego Novillo       unsigned CalleeSamples = J.second;
92c572e92cSDiego Novillo       OS << Callee;
93c572e92cSDiego Novillo       encodeULEB128(0, OS);
94c572e92cSDiego Novillo       encodeULEB128(CalleeSamples, OS);
95c572e92cSDiego Novillo     }
96c572e92cSDiego Novillo   }
97c572e92cSDiego Novillo 
98c572e92cSDiego Novillo   return true;
99c572e92cSDiego Novillo }
100d5336ae2SDiego Novillo 
101d5336ae2SDiego Novillo /// \brief Create a sample profile writer based on the specified format.
102d5336ae2SDiego Novillo ///
103d5336ae2SDiego Novillo /// \param Filename The file to create.
104d5336ae2SDiego Novillo ///
105d5336ae2SDiego Novillo /// \param Writer The writer to instantiate according to the specified format.
106d5336ae2SDiego Novillo ///
107d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
108d5336ae2SDiego Novillo ///
109d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
110*fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
111*fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
112d5336ae2SDiego Novillo   std::error_code EC;
113*fcd55607SDiego Novillo   std::unique_ptr<SampleProfileWriter> Writer;
114d5336ae2SDiego Novillo 
115d5336ae2SDiego Novillo   if (Format == SPF_Binary)
116d5336ae2SDiego Novillo     Writer.reset(new SampleProfileWriterBinary(Filename, EC));
117d5336ae2SDiego Novillo   else if (Format == SPF_Text)
118d5336ae2SDiego Novillo     Writer.reset(new SampleProfileWriterText(Filename, EC));
119d5336ae2SDiego Novillo   else
120d5336ae2SDiego Novillo     EC = sampleprof_error::unrecognized_format;
121d5336ae2SDiego Novillo 
122*fcd55607SDiego Novillo   if (EC)
123d5336ae2SDiego Novillo     return EC;
124*fcd55607SDiego Novillo 
125*fcd55607SDiego Novillo   return std::move(Writer);
126d5336ae2SDiego Novillo }
127