The open source OpenXR runtime
1// Copyright 2019-2022, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Variable tracking code.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @ingroup aux_util
8 */
9
10#include "util/u_var.h"
11#include "util/u_debug.h"
12
13#include <string>
14#include <sstream>
15#include <vector>
16#include <unordered_map>
17#include <mutex>
18
19
20namespace xrt::auxiliary::util {
21
22
23/*
24 *
25 * Enums, Classes and Defines.
26 *
27 */
28
29/*!
30 * Simple container for the variable information.
31 */
32class Var
33{
34public:
35 struct u_var_info info = {};
36};
37
38/*!
39 * Object that has a series of tracked variables.
40 */
41class Obj
42{
43public:
44 std::string name = {};
45 std::string raw_name = {};
46 struct u_var_root_info info = {};
47 std::vector<Var> vars = {};
48};
49
50/*!
51 * Object that has a series of tracked variables.
52 */
53class Tracker
54{
55public:
56 std::unordered_map<std::string, uint32_t> counters = {};
57 std::unordered_map<ptrdiff_t, Obj> map = {};
58 std::mutex mutex = {};
59 bool on = false;
60 bool tested = false;
61
62public:
63 uint32_t
64 getNumber(const std::string &name)
65 {
66 auto s = counters.find(name);
67 uint32_t count = (s != counters.end() ? s->second : 0u) + 1u;
68 counters[name] = count;
69
70 return count;
71 }
72};
73
74/*!
75 * Global variable tracking state.
76 */
77static class Tracker gTracker;
78
79
80/*
81 *
82 * Helper functions.
83 *
84 */
85
86static bool
87get_on()
88{
89 if (gTracker.tested) {
90 return gTracker.on;
91 }
92 gTracker.on = debug_get_bool_option("XRT_TRACK_VARIABLES", false);
93 gTracker.tested = true;
94
95 return gTracker.on;
96}
97
98static void
99add_var(void *root, void *ptr, u_var_kind kind, const char *c_name)
100{
101 auto s = gTracker.map.find((ptrdiff_t)root);
102 if (s == gTracker.map.end()) {
103 return;
104 }
105
106 Var var;
107 snprintf(var.info.name, U_VAR_NAME_STRING_SIZE, "%s", c_name);
108 var.info.kind = kind;
109 var.info.ptr = ptr;
110
111 s->second.vars.push_back(var);
112}
113
114
115/*
116 *
117 * Exported functions.
118 *
119 */
120
121extern "C" void
122u_var_force_on(void)
123{
124 gTracker.on = true;
125 gTracker.tested = true;
126}
127
128extern "C" void
129u_var_add_root(void *root, const char *c_name, bool suffix_with_number)
130{
131 if (!get_on()) {
132 return;
133 }
134
135 std::unique_lock<std::mutex> lock(gTracker.mutex);
136
137 auto name = std::string(c_name);
138 auto raw_name = name;
139 uint32_t count = 0; // Zero means no number.
140
141 if (suffix_with_number) {
142 count = gTracker.getNumber(name);
143
144 std::stringstream ss;
145 ss << name << " #" << count;
146 name = ss.str();
147 }
148
149 auto &obj = gTracker.map[(ptrdiff_t)root] = Obj();
150 obj.name = name;
151 obj.raw_name = raw_name;
152 obj.info.name = obj.name.c_str();
153 obj.info.raw_name = obj.raw_name.c_str();
154 obj.info.number = count;
155}
156
157extern "C" void
158u_var_remove_root(void *root)
159{
160 if (!get_on()) {
161 return;
162 }
163
164 std::unique_lock<std::mutex> lock(gTracker.mutex);
165
166 auto s = gTracker.map.find((ptrdiff_t)root);
167 if (s == gTracker.map.end()) {
168 return;
169 }
170
171 gTracker.map.erase(s);
172}
173
174extern "C" void
175u_var_visit(u_var_root_cb enter_cb, u_var_root_cb exit_cb, u_var_elm_cb elem_cb, void *priv)
176{
177 if (!get_on()) {
178 return;
179 }
180
181 std::unique_lock<std::mutex> lock(gTracker.mutex);
182
183 std::vector<Obj *> tmp;
184 tmp.reserve(gTracker.map.size());
185
186 for (auto &n : gTracker.map) {
187 tmp.push_back(&n.second);
188 }
189
190 for (Obj *obj : tmp) {
191 enter_cb(&obj->info, priv);
192
193 for (auto &var : obj->vars) {
194 elem_cb(&var.info, priv);
195 }
196
197 exit_cb(&obj->info, priv);
198 }
199}
200
201#define ADD_FUNC(SUFFIX, TYPE, ENUM) \
202 extern "C" void u_var_add_##SUFFIX(void *obj, TYPE *ptr, const char *c_name) \
203 { \
204 if (!get_on()) { \
205 return; \
206 } \
207 add_var(obj, (void *)ptr, U_VAR_KIND_##ENUM, c_name); \
208 }
209
210U_VAR_ADD_FUNCS()
211
212#undef ADD_FUNC
213
214} // namespace xrt::auxiliary::util