1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef VK_DEBUG_VARIABLE_HPP_
16 #define VK_DEBUG_VARIABLE_HPP_
17
18 #include "ID.hpp"
19 #include "Value.hpp"
20
21 #include "System/Debug.hpp"
22
23 #include "marl/mutex.h"
24 #include "marl/tsa.h"
25
26 #include <algorithm>
27 #include <atomic>
28 #include <limits>
29 #include <memory>
30 #include <string>
31 #include <unordered_map>
32 #include <vector>
33
34 namespace vk {
35 namespace dbg {
36
37 // Variable is a named value.
38 struct Variable
39 {
40 std::string name;
41 std::shared_ptr<Value> value;
42
43 // operator bool returns true iff value is not nullptr.
operator boolvk::dbg::Variable44 operator bool() const { return value != nullptr; }
45 };
46
47 // Variables is an interface to a collection of named values.
48 class Variables
49 {
50 public:
51 using ID = dbg::ID<Variables>;
52
53 using ForeachCallback = std::function<bool(const Variable &)>;
54 using FindCallback = std::function<void(const Variable &)>;
55
56 inline Variables();
57 virtual ~Variables();
58
59 // foreach() calls cb with each of the variables in the container, while cb
60 // returns true.
61 // foreach() will return when cb returns false.
62 inline void foreach(const ForeachCallback &cb);
63
64 // foreach() calls cb with each of the variables in the container within the
65 // indexed range: [startIndex, startIndex+count), while cb returns true.
66 // foreach() will return when cb returns false.
67 virtual void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) = 0;
68
69 // get() looks up and returns the variable with the given name.
70 virtual std::shared_ptr<Value> get(const std::string &name);
71
72 // string() returns the list of variables formatted to a string using the
73 // given flags.
74 virtual std::string string(const FormatFlags &fmt /* = FormatFlags::Default */);
75
76 // The unique identifier of the variables.
77 const ID id;
78
79 private:
80 static std::atomic<int> nextID;
81 };
82
Variables()83 Variables::Variables()
84 : id(nextID++)
85 {}
86
foreach(const ForeachCallback & cb)87 void Variables::foreach(const ForeachCallback &cb)
88 {
89 foreach(0, std::numeric_limits<size_t>::max(), cb);
90 }
91
92 // VariableContainer is mutable collection of named values.
93 class VariableContainer : public Variables
94 {
95 public:
96 using ID = dbg::ID<VariableContainer>;
97
98 inline void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) override;
99 inline std::shared_ptr<Value> get(const std::string &name) override;
100
101 // put() places the variable var into the container.
102 inline void put(const Variable &var);
103
104 // put() places the variable with the given name and value into the container.
105 inline void put(const std::string &name, const std::shared_ptr<Value> &value);
106
107 // extend() adds base to the list of Variables that will be searched and
108 // traversed for variables after those in this VariableContainer are
109 // searched / traversed.
110 inline void extend(const std::shared_ptr<Variables> &base);
111
112 private:
113 struct ForeachIndex
114 {
115 size_t start;
116 size_t count;
117 };
118
119 template<typename F>
120 inline void foreach(ForeachIndex &index, const F &cb);
121
122 mutable marl::mutex mutex;
123 std::vector<Variable> variables GUARDED_BY(mutex);
124 std::unordered_map<std::string, int> indices GUARDED_BY(mutex);
125 std::vector<std::shared_ptr<Variables>> extends GUARDED_BY(mutex);
126 };
127
foreach(size_t startIndex,size_t count,const ForeachCallback & cb)128 void VariableContainer::foreach(size_t startIndex, size_t count, const ForeachCallback &cb)
129 {
130 auto index = ForeachIndex{ startIndex, count };
131 foreach(index, cb);
132 }
133
134 template<typename F>
foreach(ForeachIndex & index,const F & cb)135 void VariableContainer::foreach(ForeachIndex &index, const F &cb)
136 {
137 marl::lock lock(mutex);
138 for(size_t i = index.start; i < variables.size() && i < index.count; i++)
139 {
140 if(!cb(variables[i]))
141 {
142 return;
143 }
144 }
145
146 index.start -= std::min(index.start, variables.size());
147 index.count -= std::min(index.count, variables.size());
148
149 for(auto &base : extends)
150 {
151 base->foreach(index.start, index.count, cb);
152 }
153 }
154
get(const std::string & name)155 std::shared_ptr<Value> VariableContainer::get(const std::string &name)
156 {
157 marl::lock lock(mutex);
158 for(auto const &var : variables)
159 {
160 if(var.name == name)
161 {
162 return var.value;
163 }
164 }
165 for(auto &base : extends)
166 {
167 if(auto val = base->get(name))
168 {
169 return val;
170 }
171 }
172 return nullptr;
173 }
174
put(const Variable & var)175 void VariableContainer::put(const Variable &var)
176 {
177 ASSERT(var.value);
178
179 marl::lock lock(mutex);
180 auto it = indices.find(var.name);
181 if(it == indices.end())
182 {
183 indices.emplace(var.name, variables.size());
184 variables.push_back(var);
185 }
186 else
187 {
188 variables[it->second].value = var.value;
189 }
190 }
191
put(const std::string & name,const std::shared_ptr<Value> & value)192 void VariableContainer::put(const std::string &name,
193 const std::shared_ptr<Value> &value)
194 {
195 put({ name, value });
196 }
197
extend(const std::shared_ptr<Variables> & base)198 void VariableContainer::extend(const std::shared_ptr<Variables> &base)
199 {
200 marl::lock lock(mutex);
201 extends.emplace_back(base);
202 }
203
204 } // namespace dbg
205 } // namespace vk
206
207 #endif // VK_DEBUG_VARIABLE_HPP_
208