summaryrefslogtreecommitdiff
path: root/lib/Profile/ProfileDataReader.cpp
blob: e679d9eec0d32122ba31137260c54cf611210323 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//=-- ProfileDataReader.cpp - Instrumented profiling reader -----------------=//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for reading profiling data for clang's
// instrumentation based PGO and coverage.
//
//===----------------------------------------------------------------------===//

#include "llvm/Profile/ProfileDataReader.h"
#include "llvm/Profile/ProfileData.h"
#include "llvm/Support/Endian.h"

#include <cassert>

using namespace llvm;

error_code ProfileDataReader::create(
    std::string Path, std::unique_ptr<ProfileDataReader> &Result) {
  std::unique_ptr<MemoryBuffer> Buffer;
  if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer))
    return EC;

  if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
    return profiledata_error::too_large;

  Result.reset(new ProfileDataReader(Buffer));
  if (error_code EC = Result->readIndex())
    return EC;
  return profiledata_error::success;
}

class llvm::ProfileDataCursor {
  const char *Start;
  const char *Next;
  const char *End;

  error_code skip(unsigned bytes) {
    if (Next + bytes > End)
      return profiledata_error::malformed;
    Next += bytes;
    return profiledata_error::success;
  }

  template <typename T>
  error_code read(T &Result) {
    typedef support::detail::packed_endian_specific_integral
        <T, support::little, support::unaligned> Endian_t;
    const char *Prev = Next;
    if (error_code EC = skip(sizeof(T)))
      return EC;
    Result = *reinterpret_cast<const Endian_t*>(Prev);
    return profiledata_error::success;
  }
public:
  ProfileDataCursor(const MemoryBuffer *Buf)
      : Start(Buf->getBufferStart()), Next(Start), End(Buf->getBufferEnd()) {}
  bool offsetReached(size_t Offset) { return Start + Offset <= Next; }
  bool offsetInBounds(size_t Offset) { return Start + Offset < End; }

  error_code skipToOffset(size_t Offset) {
    if (!offsetInBounds(Offset))
      return profiledata_error::malformed;
    Next = Start + Offset;
    return profiledata_error::success;
  }

  error_code skip32() { return skip(4); }
  error_code skip64() { return skip(8); }
  error_code read32(uint32_t &Result) { return read<uint32_t>(Result); }
  error_code read64(uint64_t &Result) { return read<uint64_t>(Result); }

  error_code readChars(StringRef &Result, uint32_t Len) {
    error_code EC;
    const char *Prev = Next;
    if (error_code EC = skip(Len))
      return EC;
    Result = StringRef(Prev, Len);
    return profiledata_error::success;
  }
  error_code readString(StringRef &Result) {
    uint32_t Len;
    if (error_code EC = read32(Len))
      return EC;
    return readChars(Result, Len);
  }
};

error_code ProfileDataReader::readIndex() {
  ProfileDataCursor Cursor(DataBuffer.get());
  error_code EC;
  StringRef Magic;
  uint32_t Version, IndexEnd, DataStart;

  if ((EC = Cursor.readChars(Magic, 4)))
    return EC;
  if (StringRef(PROFILEDATA_MAGIC, 4) != Magic)
    return profiledata_error::bad_magic;
  if ((EC = Cursor.read32(Version)))
    return EC;
  if (Version != PROFILEDATA_VERSION)
    return profiledata_error::unsupported_version;
  if ((EC = Cursor.read32(IndexEnd)))
    return EC;
  if ((EC = Cursor.skip32()))
    return EC;
  if ((EC = Cursor.read64(MaxFunctionCount)))
    return EC;

  DataStart = IndexEnd + (sizeof(uint64_t) - IndexEnd % sizeof(uint64_t));
  while (!Cursor.offsetReached(IndexEnd)) {
    StringRef FuncName;
    uint32_t Offset, TotalOffset;
    if ((EC = Cursor.readString(FuncName)))
      return EC;
    if ((EC = Cursor.read32(Offset)))
      return EC;
    TotalOffset = DataStart + Offset;
    if (!Cursor.offsetInBounds(TotalOffset))
      return profiledata_error::truncated;
    DataOffsets[FuncName] = TotalOffset;
  }

  return profiledata_error::success;
}

error_code ProfileDataReader::findFunctionCounts(StringRef FuncName,
                                                 uint64_t &FunctionHash,
                                                 ProfileDataCursor &Cursor) {
  error_code EC;
  // Find the relevant section of the pgo-data file.
  const auto &OffsetIter = DataOffsets.find(FuncName);
  if (OffsetIter == DataOffsets.end())
    return profiledata_error::unknown_function;
  // Go there and read the function data
  if ((EC = Cursor.skipToOffset(OffsetIter->getValue())))
    return EC;
  if ((EC = Cursor.read64(FunctionHash)))
    return EC;
  return profiledata_error::success;
}

error_code ProfileDataReader::getFunctionCounts(StringRef FuncName,
                                                uint64_t &FunctionHash,
                                                std::vector<uint64_t> &Counts) {
  ProfileDataCursor Cursor(DataBuffer.get());
  error_code EC;
  if ((EC = findFunctionCounts(FuncName, FunctionHash, Cursor)))
    return EC;

  uint64_t NumCounters;
  if ((EC = Cursor.read64(NumCounters)))
    return EC;
  for (uint64_t I = 0; I < NumCounters; ++I) {
    uint64_t Count;
    if ((EC = Cursor.read64(Count)))
      return EC;
    Counts.push_back(Count);
  }

  return profiledata_error::success;
}