Low-Level Abstraction of Memory Access
Heatmap.hpp
Go to the documentation of this file.
1 // Copyright 2022 Bernhard Manfred Gruber
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #pragma once
5 
6 #include "../View.hpp"
7 #include "Common.hpp"
8 
9 #include <array>
10 #include <atomic>
11 #include <sstream>
12 #include <vector>
13 #if __has_include(<span>)
14 # include <span>
15 #endif
16 
17 namespace llama::mapping
18 {
27  template<
28  typename Mapping,
29  typename Mapping::ArrayExtents::value_type Granularity = 1,
30  typename TCountType = std::size_t>
31  struct Heatmap : private Mapping
32  {
33  static_assert(!hasAnyComputedField<Mapping>, "Heatmaps for computed mappings are not implemented.");
34 
35  private:
36  using size_type = typename Mapping::ArrayExtents::value_type;
37  using ArrayIndex = typename Mapping::ArrayExtents::Index;
38 
39  public:
40  using Inner = Mapping;
41  inline static constexpr std::size_t granularity = Granularity;
42  using CountType = TCountType;
44  using RecordDim = typename Mapping::RecordDim;
45 
46  // We duplicate every blob of the inner mapping with a shadow blob, where we count the accesses
47  inline static constexpr std::size_t blobCount = Mapping::blobCount * 2;
48 
49  constexpr Heatmap() = default;
50 
52  explicit Heatmap(Mapping mapping) : Mapping(std::move(mapping))
53  {
54  }
55 
56  template<typename... Args>
57  LLAMA_FN_HOST_ACC_INLINE explicit Heatmap(Args&&... innerArgs) : Mapping(std::forward<Args>(innerArgs)...)
58  {
59  }
60 
61 #if defined(__cpp_lib_concepts) && defined(__NVCOMPILER)
62  // nvc++ fails to find extents() from the base class when trying to satisfy the Mapping concept
63  LLAMA_FN_HOST_ACC_INLINE constexpr auto extents() const -> typename Mapping::ArrayExtents
64  {
65  return static_cast<const Mapping&>(*this).extents();
66  }
67 #else
68  using Mapping::extents;
69 #endif
70 
72  constexpr auto blobSize(size_type blobIndex) const -> size_type
73  {
74  if(blobIndex < size_type{Mapping::blobCount})
75  return Mapping::blobSize(blobIndex);
76  return blockHitsSize(blobIndex - size_type{Mapping::blobCount}) * sizeof(CountType);
77  }
78 
79  template<std::size_t... RecordCoords>
81  {
82  return true;
83  }
84 
85  template<std::size_t... RecordCoords, typename Blobs>
87  -> decltype(auto)
88  {
89  static_assert(
90  !std::is_const_v<Blobs>,
91  "Cannot access (even just reading) data through Heatmap from const blobs/view, since we need to write "
92  "the access counts");
93 
94  const auto [nr, offset] = Mapping::blobNrAndOffset(ai, rc);
95  using Type = GetType<typename Mapping::RecordDim, RecordCoord<RecordCoords...>>;
96 
97  auto* hits = blockHitsPtr(nr, blobs);
98  for(size_type i = 0; i < divCeil(size_type{sizeof(Type)}, Granularity); i++)
99  internal::atomicInc(hits[offset / Granularity + i]);
100 
102  return reinterpret_cast<CopyConst<std::remove_reference_t<decltype(blobs[nr][offset])>, Type>&>(
103  blobs[nr][offset]);
105  }
106 
107  // Returns the size of the block hits buffer for blob forBlobI in block counts.
108  LLAMA_FN_HOST_ACC_INLINE auto blockHitsSize(size_type forBlobI) const -> size_type
109  {
110  assert(forBlobI < Mapping::blobCount);
111  return divCeil(Mapping::blobSize(forBlobI), Granularity);
112  }
113 
115  template<typename Blobs>
116  LLAMA_FN_HOST_ACC_INLINE auto blockHitsPtr(size_type forBlobI, Blobs& blobs) const
118  {
119  return reinterpret_cast<CopyConst<Blobs, CountType>*>(&blobs[size_type{Mapping::blobCount} + forBlobI][0]);
120  }
121 
122 #ifdef __cpp_lib_span
123  template<typename Blobs>
124  auto blockHits(size_type forBlobI, Blobs& blobs) const -> std::span<CopyConst<Blobs, CountType>>
125  {
126  return {blockHitsPtr(forBlobI, blobs), blockHitsSize(forBlobI)};
127  }
128 #endif
129 
130  private:
131  static auto trimBlobRight(const CountType* bh, std::size_t size)
132  {
133  while(size > 0 && bh[size - 1] == 0)
134  size--;
135  return size;
136  }
137 
138  public:
143  template<typename Blobs, typename OStream>
145  const Blobs& blobs,
146  OStream&& os,
147  bool trimEnd = true,
148  std::size_t wrapAfterBlocks = 64) const
149  {
150  for(std::size_t i = 0; i < Mapping::blobCount; i++)
151  {
152  auto* bh = blockHitsPtr(i, blobs);
153  auto size = blockHitsSize(i);
154  if(trimEnd)
155  size = trimBlobRight(bh, size);
156  for(size_type j = 0; j < size; j++)
157  {
158  if(j > 0)
159  os << (j % wrapAfterBlocks == 0 ? '\n' : ' ');
160  os << bh[j];
161  }
162  for(size_type j = size; j < roundUpToMultiple(size, wrapAfterBlocks); j++)
163  os << " 0";
164  os << '\n';
165  }
166  }
167 
168  template<typename Blobs, typename OStream>
170  const Blobs& blobs,
171  OStream&& os,
172  bool trimEnd = true,
173  std::size_t afterBlobRoundUpTo = 64) const
174  {
175  for(std::size_t i = 0; i < Mapping::blobCount; i++)
176  {
177  auto* bh = blockHitsPtr(i, blobs);
178  auto size = blockHitsSize(i);
179  if(trimEnd)
180  size = trimBlobRight(bh, size);
181  os.write(reinterpret_cast<const char*>(bh), size * sizeof(CountType));
182 
183  // round up before starting next blob
184  CountType zero = 0;
185  for(size_type j = size; j < roundUpToMultiple(size, afterBlobRoundUpTo); j++)
186  os.write(reinterpret_cast<const char*>(&zero), sizeof(CountType));
187  }
188  }
189 
192  static constexpr std::string_view gnuplotScriptAscii = R"(#!/bin/bash
193 gnuplot -p <<EOF
194 file = '${1:-plot.bin}'
195 
196 set xtics format ""
197 set x2tics autofreq 32
198 set yrange [] reverse
199 set link x2; set link y2
200 set x2label "Byte"
201 plot file matrix with image pixels axes x2y1
202 EOF
203 )";
204 
207  static constexpr std::string_view gnuplotScriptBinary = R"(#!/bin/bash
208 gnuplot -p <<EOF
209 file = '${1:-plot.bin}'
210 rowlength = '${2:-64}'
211 maxrows = '${3:-all}'
212 format = '${4:-%uint64}'
213 
214 counts = system('stat -c "%s" ${1:-plot.bin}')/8
215 rows = counts/rowlength
216 rows = maxrows eq 'all' ? rows : (rows < maxrows ? rows : maxrows)
217 
218 set xtics format ""
219 set x2tics autofreq 32
220 set yrange [] reverse
221 set link x2; set link y2
222 set x2label "Byte"
223 plot file binary array=(rowlength,rows) format=format with image pixels axes x2y1
224 EOF
225 )";
226  };
227 
229  template<typename Mapping>
230  inline constexpr bool isHeatmap = false;
231 
233  template<typename Mapping, typename Mapping::ArrayExtents::value_type Granularity, typename CountType>
234  inline constexpr bool isHeatmap<Heatmap<Mapping, Granularity, CountType>> = true;
235 } // namespace llama::mapping
#define LLAMA_EXPORT
Definition: macros.hpp:192
#define LLAMA_BEGIN_SUPPRESS_HOST_DEVICE_WARNING
Definition: macros.hpp:141
#define LLAMA_SUPPRESS_HOST_DEVICE_WARNING
Definition: macros.hpp:122
#define LLAMA_FN_HOST_ACC_INLINE
Definition: macros.hpp:96
#define LLAMA_END_SUPPRESS_HOST_DEVICE_WARNING
Definition: macros.hpp:153
void atomicInc(CountType &i)
Definition: Common.hpp:249
constexpr bool isHeatmap
Definition: Heatmap.hpp:230
ArrayExtents(Args...) -> ArrayExtents< typename internal::IndexTypeFromArgs< std::size_t, Args... >::type,(Args{}, dyn)... >
constexpr auto divCeil(Integral a, Integral b) -> Integral
Returns the ceiling of a / b.
Definition: Core.hpp:570
std::conditional_t< std::is_const_v< FromT >, const ToT, ToT > CopyConst
Alias for ToT, adding const if FromT is const qualified.
Definition: Core.hpp:824
constexpr auto roundUpToMultiple(Integral n, Integral mult) -> Integral
Returns the integral n rounded up to be a multiple of mult.
Definition: Core.hpp:578
typename internal::GetTypeImpl< RecordDim, RecordCoordOrTags... >::type GetType
Definition: Core.hpp:388
static constexpr std::size_t granularity
Definition: Heatmap.hpp:41
typename Mapping::RecordDim RecordDim
Definition: Heatmap.hpp:44
typename Mapping::ArrayExtents ArrayExtents
Definition: Heatmap.hpp:43
constexpr Heatmap()=default
Heatmap(Mapping mapping)
Definition: Heatmap.hpp:52
auto compute(ArrayIndex ai, RecordCoord< RecordCoords... > rc, Blobs &blobs) const -> decltype(auto)
Definition: Heatmap.hpp:86
void writeGnuplotDataFileAscii(const Blobs &blobs, OStream &&os, bool trimEnd=true, std::size_t wrapAfterBlocks=64) const
Definition: Heatmap.hpp:144
static constexpr std::string_view gnuplotScriptAscii
Definition: Heatmap.hpp:192
constexpr auto blobSize(size_type blobIndex) const -> size_type
Definition: Heatmap.hpp:72
void writeGnuplotDataFileBinary(const Blobs &blobs, OStream &&os, bool trimEnd=true, std::size_t afterBlobRoundUpTo=64) const
Definition: Heatmap.hpp:169
auto blockHitsPtr(size_type forBlobI, Blobs &blobs) const -> CopyConst< Blobs, CountType > *
Definition: Heatmap.hpp:116
static constexpr std::size_t blobCount
Definition: Heatmap.hpp:47
static constexpr auto isComputed(RecordCoord< RecordCoords... >)
Definition: Heatmap.hpp:80
Heatmap(Args &&... innerArgs)
Definition: Heatmap.hpp:57
auto blockHitsSize(size_type forBlobI) const -> size_type
Definition: Heatmap.hpp:108
static constexpr std::string_view gnuplotScriptBinary
Definition: Heatmap.hpp:207
TCountType CountType
Definition: Heatmap.hpp:42