Poplar and PopLibs
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DebugInfo.hpp
Go to the documentation of this file.
1// Copyright (c) 2020 Graphcore Ltd. All rights reserved.
8#ifndef poputil_DebugInfo_hpp
9#define poputil_DebugInfo_hpp
10
11#include <poplar/DebugContext.hpp>
12
13#include <poplar/GraphElements.hpp>
14#include <poplar/OptionFlags.hpp>
15#include <poplar/Program.hpp>
16#include <poplar/Tensor.hpp>
17#include <poplar/TensorCloneMethod.hpp>
18
19#if defined(__clang__)
20#define SUPPORTS_FUNCTION_BUILTINS __has_builtin(__builtin_FUNCTION)
21#elif __GNUC__ >= 7
22#define SUPPORTS_FUNCTION_BUILTINS 1
23#else
24#define SUPPORTS_FUNCTION_BUILTINS 0
25#endif
26
27namespace poputil {
28
29// template definitions of the toProfileValue that needs to be specialized
30// for types passed to the DebugInfo
31template <typename T> poplar::ProfileValue toProfileValue(const T &t);
32
33// template specializations for basic types
34template <> poplar::ProfileValue toProfileValue(const int &v);
35template <> poplar::ProfileValue toProfileValue(const unsigned int &v);
36template <> poplar::ProfileValue toProfileValue(const unsigned long &v);
37template <> poplar::ProfileValue toProfileValue(const unsigned char &v);
38template <> poplar::ProfileValue toProfileValue(const bool &v);
39template <> poplar::ProfileValue toProfileValue(const float &v);
40template <> poplar::ProfileValue toProfileValue(const double &v);
41template <> poplar::ProfileValue toProfileValue(const long long &v);
42template <> poplar::ProfileValue toProfileValue(const unsigned long long &v);
43template <> poplar::ProfileValue toProfileValue(const std::string &v);
44
45// template specializations for Poplar types
46template <> poplar::ProfileValue toProfileValue(const poplar::ComputeSet &t);
47template <> poplar::ProfileValue toProfileValue(const poplar::OptionFlags &t);
48template <> poplar::ProfileValue toProfileValue(const poplar::program::Copy &t);
49template <>
50poplar::ProfileValue toProfileValue(const poplar::program::Sequence &t);
51template <> poplar::ProfileValue toProfileValue(const poplar::Tensor &t);
52template <> poplar::ProfileValue toProfileValue(const poplar::Type &t);
53template <>
54poplar::ProfileValue toProfileValue(const poplar::TensorCloneMethod &t);
55
56// Generic case for a pointer
57template <typename T> poplar::ProfileValue toProfileValue(const T *t) {
58 if (t == nullptr) {
59 return poplar::ProfileValue("<nullptr>");
60 } else {
61 return toProfileValue(*t);
62 }
63}
64
65template <typename T> poplar::ProfileValue toProfileValue(T *const &t) {
66 if (t == nullptr) {
67 return poplar::ProfileValue("<nullptr>");
68 } else {
69 return toProfileValue(*t);
70 }
71}
72
73// Generic case for a vector
74template <typename T>
75poplar::ProfileValue toProfileValue(const std::vector<T> &vec) {
76 poplar::ProfileValue::Map v;
77 for (size_t i = 0; i < vec.size(); ++i) {
78 v.insert({std::to_string(i), toProfileValue(vec[i])});
79 }
80 return v;
81}
82
83// Specialization of vector for bools. Required on macos
84template <> poplar::ProfileValue toProfileValue(const std::vector<bool> &vec);
85
86// Generic case for a poplar::ArrayRef
87template <typename T>
88poplar::ProfileValue toProfileValue(const poplar::ArrayRef<T> &vec) {
89 poplar::ProfileValue::Vector v;
90 for (size_t i = 0; i < vec.size(); ++i) {
91 v.push_back(toProfileValue(vec[i]));
92 }
93 return v;
94}
95
96// Generic case for pair
97template <typename T1, typename T2>
98poplar::ProfileValue toProfileValue(const std::pair<T1, T2> &pair) {
99 poplar::ProfileValue::Map v;
100 v.insert({"first", toProfileValue(pair.first)});
101 v.insert({"second", toProfileValue(pair.second)});
102 return v;
103}
104
105// Generic case for std::array
106template <typename T, size_t N>
107poplar::ProfileValue toProfileValue(const std::array<T, N> &array) {
108 poplar::ProfileValue::Map v;
109 for (size_t i = 0; i < N; ++i) {
110 v.insert({std::to_string(i), toProfileValue(array[i])});
111 }
112 return v;
113}
114
115class ArgType {
116
117public:
118 std::string n;
120
121 ArgType(const std::string &name, const poplar::ProfileValue &value)
122 : n(name), pv(value) {}
123 ArgType(const std::pair<std::string, const poplar::ProfileValue> &p)
124 : n(p.first), pv(p.second) {}
125};
126
127class OpDebugInfo : public poplar::DebugInfo {
128public:
129 OpDebugInfo(const poplar::DebugContext &debugContext, std::string api);
130 OpDebugInfo &operator=(const OpDebugInfo &) = delete;
131 OpDebugInfo(const OpDebugInfo &) = delete;
132 virtual ~OpDebugInfo() = default;
133
134 void add(std::string name, const std::vector<ArgType> &args);
135 void add(std::string name, poplar::ProfileValue pv);
136};
137
138class PoplibsOpDebugInfo : public OpDebugInfo {
139
140public:
141#if SUPPORTS_FUNCTION_BUILTINS
142 PoplibsOpDebugInfo(const poplar::DebugContext &debugContext,
143 const std::vector<ArgType> &args = {},
144 const std::string &api = __builtin_FUNCTION());
145#else
146 PoplibsOpDebugInfo(const poplar::DebugContext &debugContext,
147 const std::vector<ArgType> &args = {},
148 const std::string &api = "");
149#endif
150 PoplibsOpDebugInfo &operator=(const PoplibsOpDebugInfo &) = delete;
151 PoplibsOpDebugInfo(const PoplibsOpDebugInfo &) = delete;
152 virtual ~PoplibsOpDebugInfo() = default;
153
154 void addOutputs(const std::vector<ArgType> &outputs);
155
156 // Convience method when there is only a single output
157 void addOutput(const poplar::Tensor &output);
158};
159
160} // namespace poputil
161
162#define DI_STR(S) #S
163#define DI_XSTR(S) DI_STR(S)
164
165#define DI_NUM_ARGS(...) \
166 DI_NUM_ARGS_IMPL(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, \
167 3, 2, 1, 0)
168#define DI_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
169 _13, _14, _15, _16, N, ...) \
170 N
171
172#define DI_CONCAT_IMPL(x, y) x##y
173#define DI_MACRO_CONCAT(x, y) DI_CONCAT_IMPL(x, y)
174
175#define DI_KEY_VALUE_ARG_0() \
176 {}
177#define DI_KEY_VALUE_ARG_1(T) \
178 { DI_XSTR(T), poputil::toProfileValue(T) }
179#define DI_KEY_VALUE_ARG_2(T, ...) \
180 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_1(__VA_ARGS__)
181#define DI_KEY_VALUE_ARG_3(T, ...) \
182 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_2(__VA_ARGS__)
183#define DI_KEY_VALUE_ARG_4(T, ...) \
184 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_3(__VA_ARGS__)
185#define DI_KEY_VALUE_ARG_5(T, ...) \
186 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_4(__VA_ARGS__)
187#define DI_KEY_VALUE_ARG_6(T, ...) \
188 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_5(__VA_ARGS__)
189#define DI_KEY_VALUE_ARG_7(T, ...) \
190 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_6(__VA_ARGS__)
191#define DI_KEY_VALUE_ARG_8(T, ...) \
192 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_7(__VA_ARGS__)
193#define DI_KEY_VALUE_ARG_9(T, ...) \
194 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_8(__VA_ARGS__)
195#define DI_KEY_VALUE_ARG_10(T, ...) \
196 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_9(__VA_ARGS__)
197#define DI_KEY_VALUE_ARG_11(T, ...) \
198 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_10(__VA_ARGS__)
199#define DI_KEY_VALUE_ARG_12(T, ...) \
200 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_11(__VA_ARGS__)
201#define DI_KEY_VALUE_ARG_13(T, ...) \
202 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_12(__VA_ARGS__)
203#define DI_KEY_VALUE_ARG_14(T, ...) \
204 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_13(__VA_ARGS__)
205#define DI_KEY_VALUE_ARG_15(T, ...) \
206 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_14(__VA_ARGS__)
207#define DI_KEY_VALUE_ARG_16(T, ...) \
208 DI_KEY_VALUE_ARG_1(T), DI_KEY_VALUE_ARG_15(__VA_ARGS__)
209#define DI_KEY_VALUE_ARG(...) \
210 DI_MACRO_CONCAT(DI_KEY_VALUE_ARG_, DI_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
211
212// Convience macro to turn
213// DI_ARGS(a, b, c)
214// into
215// {{"a", a}, {"b", b}, {"c"}, c}
216// Which can then be passed to the std::vector<ArgType> constructor
217
218#define DI_ARGS(...) \
219 { DI_KEY_VALUE_ARG(__VA_ARGS__) }
220
221#endif // poputil_DebugInfo_hpp
A reference to a compute set within a graph.
Definition: GraphElements.hpp:131
DebugContext gathers the common external parameters of the context of an operation.
Definition: DebugContext.hpp:221
DebugInfo stores and persists a set of data that describes the context of an operation.
Definition: DebugContext.hpp:91
A set of option/value string flags to be used in various APIs.
Definition: OptionFlags.hpp:24
ProfileValue represents a read-only JSON-like tree of values that are used to store the output of the...
Definition: ProfileValue.hpp:39
A reference to a subset of tensor elements.
Definition: Tensor.hpp:38
Class representing device data types.
Definition: Type.hpp:42
A program that copies data.
Definition: Program.hpp:283
Program that executes a sequence of programs.
Definition: Program.hpp:77
TensorCloneMethod
Define behaviour when a Tensor is cloned.
Definition: TensorCloneMethod.hpp:13
poplar::Tensor add(poplar::Graph &graph, const poplar::Tensor &A, const poplar::Tensor &B, poplar::program::Sequence &prog, const poplar::DebugContext &debugContext={}, const poplar::OptionFlags &options={})
Add each element in A to the corresponding element in B.
Definition: ElementWise.hpp:1664
ArgType
Type of argument to function program.
Definition: GraphFunction.hpp:25
General utility functions for building graphs.
Definition: GfloatExprUtil.hpp:23