@@ -112,77 +112,100 @@ struct AsyncInfoWrapperTy {
112
112
__tgt_async_info *AsyncInfoPtr;
113
113
};
114
114
115
- // / The information level represents the level of a key-value property in the
116
- // / info tree print (i.e. indentation). The first level should be the default.
117
- enum InfoLevelKind { InfoLevel1 = 1 , InfoLevel2, InfoLevel3 };
118
-
119
- // / Class for storing device information and later be printed. An object of this
120
- // / type acts as a queue of key-value properties. Each property has a key, a
121
- // / a value, and an optional unit for the value. For printing purposes, the
122
- // / information can be classified into several levels. These levels are useful
123
- // / for defining sections and subsections. Thus, each key-value property also
124
- // / has an additional field indicating to which level belongs to. Notice that
125
- // / we use the level to determine the indentation of the key-value property at
126
- // / printing time. See the enum InfoLevelKind for the list of accepted levels.
127
- class InfoQueueTy {
128
- public:
129
- struct InfoQueueEntryTy {
130
- std::string Key;
131
- std::string Value;
132
- std::string Units;
133
- uint64_t Level;
134
- };
135
-
136
- private:
137
- std::deque<InfoQueueEntryTy> Queue;
138
-
139
- public:
140
- // / Add a new info entry to the queue. The entry requires at least a key
141
- // / string in \p Key. The value in \p Value is optional and can be any type
142
- // / that is representable as a string. The units in \p Units is optional and
143
- // / must be a string. The info level is a template parameter that defaults to
144
- // / the first level (top level).
145
- template <InfoLevelKind L = InfoLevel1, typename T = std::string>
146
- void add (const std::string &Key, T Value = T(),
147
- const std::string &Units = std::string()) {
115
+ // / Tree node for device information
116
+ // /
117
+ // / This information is either printed or used by liboffload to extract certain
118
+ // / device queries. Each property has an optional key, an optional value
119
+ // / and optional children. The children can be used to store additional
120
+ // / information (such as x, y and z components of ranges).
121
+ struct InfoTreeNode {
122
+ static constexpr uint64_t IndentSize = 4 ;
123
+
124
+ std::string Key;
125
+ std::string Value;
126
+ std::string Units;
127
+ // Need to specify a default value number of elements here as `InfoTreeNode`'s
128
+ // size is unknown. This is a vector (rather than a Key->Value map) since:
129
+ // * The keys need to be owned and thus `std::string`s
130
+ // * The order of keys is important
131
+ // * The same key can appear multiple times
132
+ std::unique_ptr<llvm::SmallVector<InfoTreeNode, 8 >> Children;
133
+
134
+ InfoTreeNode () : InfoTreeNode(" " , " " , " " ) {}
135
+ InfoTreeNode (std::string Key, std::string Value, std::string Units)
136
+ : Key(Key), Value(Value), Units(Units) {}
137
+
138
+ // / Add a new info entry as a child of this node. The entry requires at least
139
+ // / a key string in \p Key. The value in \p Value is optional and can be any
140
+ // / type that is representable as a string. The units in \p Units is optional
141
+ // / and must be a string.
142
+ template <typename T = std::string>
143
+ InfoTreeNode *add (std::string Key, T Value = T(),
144
+ const std::string &Units = std::string()) {
148
145
assert (!Key.empty () && " Invalid info key" );
149
146
150
- // Convert the value to a string depending on its type.
147
+ if (!Children)
148
+ Children = std::make_unique<llvm::SmallVector<InfoTreeNode, 8 >>();
149
+
150
+ std::string ValueStr;
151
151
if constexpr (std::is_same_v<T, bool >)
152
- Queue. push_back ({Key, Value ? " Yes" : " No" , Units, L}) ;
152
+ ValueStr = Value ? " Yes" : " No" ;
153
153
else if constexpr (std::is_arithmetic_v<T>)
154
- Queue. push_back ({Key, std::to_string (Value), Units, L} );
154
+ ValueStr = std::to_string (Value);
155
155
else
156
- Queue.push_back ({Key, Value, Units, L});
156
+ ValueStr = Value;
157
+
158
+ return &Children->emplace_back (Key, ValueStr, Units);
157
159
}
158
160
159
- const std::deque<InfoQueueEntryTy> &getQueue () const { return Queue; }
161
+ std::optional<InfoTreeNode *> get (StringRef Key) {
162
+ if (!Children)
163
+ return std::nullopt;
160
164
161
- // / Print all info entries added to the queue.
162
- void print () const {
163
- // We print four spances for each level.
164
- constexpr uint64_t IndentSize = 4 ;
165
+ auto It = std::find_if (Children->begin (), Children->end (),
166
+ [&](auto &V) { return V.Key == Key; });
167
+ if (It == Children->end ())
168
+ return std::nullopt;
169
+ return It;
170
+ }
165
171
166
- // Find the maximum key length (level + key) to compute the individual
167
- // indentation of each entry.
168
- uint64_t MaxKeySize = 0 ;
169
- for (const auto &Entry : Queue) {
170
- uint64_t KeySize = Entry.Key .size () + Entry.Level * IndentSize;
171
- if (KeySize > MaxKeySize)
172
- MaxKeySize = KeySize;
173
- }
172
+ // / Print all info entries in the tree
173
+ void print () const {
174
+ // Fake an additional indent so that values are offset from the keys
175
+ doPrint (0 , maxKeySize (1 ));
176
+ }
174
177
175
- // Print all info entries.
176
- for (const auto &Entry : Queue) {
178
+ private:
179
+ void doPrint (int Level, uint64_t MaxKeySize) const {
180
+ if (Key.size ()) {
177
181
// Compute the indentations for the current entry.
178
- uint64_t KeyIndentSize = Entry. Level * IndentSize;
182
+ uint64_t KeyIndentSize = Level * IndentSize;
179
183
uint64_t ValIndentSize =
180
- MaxKeySize - (Entry. Key .size () + KeyIndentSize) + IndentSize;
184
+ MaxKeySize - (Key.size () + KeyIndentSize) + IndentSize;
181
185
182
- llvm::outs () << std::string (KeyIndentSize, ' ' ) << Entry. Key
183
- << std::string (ValIndentSize, ' ' ) << Entry. Value
184
- << (Entry. Units .empty () ? " " : " " ) << Entry. Units << " \n " ;
186
+ llvm::outs () << std::string (KeyIndentSize, ' ' ) << Key
187
+ << std::string (ValIndentSize, ' ' ) << Value
188
+ << (Units.empty () ? " " : " " ) << Units << " \n " ;
185
189
}
190
+
191
+ // Print children
192
+ if (Children)
193
+ for (const auto &Entry : *Children)
194
+ Entry.doPrint (Level + 1 , MaxKeySize);
195
+ }
196
+
197
+ // Recursively calculates the maximum width of each key, including indentation
198
+ uint64_t maxKeySize (int Level) const {
199
+ uint64_t MaxKeySize = 0 ;
200
+
201
+ if (Children)
202
+ for (const auto &Entry : *Children) {
203
+ uint64_t KeySize = Entry.Key .size () + Level * IndentSize;
204
+ MaxKeySize = std::max (MaxKeySize, KeySize);
205
+ MaxKeySize = std::max (MaxKeySize, Entry.maxKeySize (Level + 1 ));
206
+ }
207
+
208
+ return MaxKeySize;
186
209
}
187
210
};
188
211
@@ -871,7 +894,7 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
871
894
872
895
// / Print information about the device.
873
896
Error printInfo ();
874
- virtual Error obtainInfoImpl (InfoQueueTy &Info ) = 0;
897
+ virtual Expected<InfoTreeNode> obtainInfoImpl () = 0;
875
898
876
899
// / Getters of the grid values.
877
900
uint32_t getWarpSize () const { return GridValues.GV_Warp_Size ; }
0 commit comments