@@ -112,77 +112,100 @@ struct AsyncInfoWrapperTy {
112112 __tgt_async_info *AsyncInfoPtr;
113113};
114114
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()) {
148145 assert (!Key.empty () && " Invalid info key" );
149146
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;
151151 if constexpr (std::is_same_v<T, bool >)
152- Queue. push_back ({Key, Value ? " Yes" : " No" , Units, L}) ;
152+ ValueStr = Value ? " Yes" : " No" ;
153153 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);
155155 else
156- Queue.push_back ({Key, Value, Units, L});
156+ ValueStr = Value;
157+
158+ return &Children->emplace_back (Key, ValueStr, Units);
157159 }
158160
159- const std::deque<InfoQueueEntryTy> &getQueue () const { return Queue; }
161+ std::optional<InfoTreeNode *> get (StringRef Key) {
162+ if (!Children)
163+ return std::nullopt ;
160164
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+ }
165171
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+ }
174177
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 ()) {
177181 // Compute the indentations for the current entry.
178- uint64_t KeyIndentSize = Entry. Level * IndentSize;
182+ uint64_t KeyIndentSize = Level * IndentSize;
179183 uint64_t ValIndentSize =
180- MaxKeySize - (Entry. Key .size () + KeyIndentSize) + IndentSize;
184+ MaxKeySize - (Key.size () + KeyIndentSize) + IndentSize;
181185
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 " ;
185189 }
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;
186209 }
187210};
188211
@@ -871,7 +894,7 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
871894
872895 // / Print information about the device.
873896 Error printInfo ();
874- virtual Error obtainInfoImpl (InfoQueueTy &Info ) = 0;
897+ virtual Expected<InfoTreeNode> obtainInfoImpl () = 0;
875898
876899 // / Getters of the grid values.
877900 uint32_t getWarpSize () const { return GridValues.GV_Warp_Size ; }
0 commit comments