The open source OpenXR runtime
at prediction-2 371 lines 7.8 kB view raw
1// Copyright 2019-2023, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Small debug helpers. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup aux_util 8 * 9 * Debug get option helpers heavily inspired from mesa ones. 10 */ 11 12#include "xrt/xrt_config_os.h" 13 14#include "util/u_debug.h" 15#include "util/u_logging.h" 16 17#include <ctype.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21 22#ifdef XRT_OS_ANDROID 23#include <sys/system_properties.h> 24#endif 25 26 27DEBUG_GET_ONCE_BOOL_OPTION(print, "XRT_PRINT_OPTIONS", false) 28 29 30/* 31 * 32 * Helpers 33 * 34 */ 35 36#if defined XRT_OS_WINDOWS 37 38static const char * 39get_option_raw(char *chars, size_t char_count, const char *name) 40{ 41 size_t required_size; 42 43 getenv_s(&required_size, chars, char_count, name); 44 if (required_size == 0) { 45 return NULL; 46 } 47 48 return chars; 49} 50 51#elif defined XRT_OS_ANDROID 52 53struct android_read_arg 54{ 55 char *chars; 56 size_t char_count; 57}; 58 59static void 60android_on_property_read(void *cookie, const char *name, const char *value, uint32_t serial) 61{ 62 struct android_read_arg *a = (struct android_read_arg *)cookie; 63 64 snprintf(a->chars, a->char_count, "%s", value); 65} 66 67static const char * 68get_option_raw(char *chars, size_t char_count, const char *name) 69{ 70 char prefixed[1024]; 71 snprintf(prefixed, ARRAY_SIZE(prefixed), "debug.xrt.%s", name); 72 73 const struct prop_info *pi = __system_property_find(prefixed); 74 if (pi == NULL) { 75 return NULL; 76 } 77 78 struct android_read_arg a = {.chars = chars, .char_count = char_count}; 79 __system_property_read_callback(pi, &android_on_property_read, &a); 80 81 return chars; 82} 83 84#elif defined XRT_OS_LINUX 85 86static const char * 87get_option_raw(char *chars, size_t char_count, const char *name) 88{ 89 const char *raw = getenv(name); 90 91 if (raw == NULL) { 92 return NULL; 93 } else { 94 snprintf(chars, char_count, "%s", raw); 95 return chars; 96 } 97} 98 99#else 100#error "Please provide port of this function!" 101#endif 102 103 104static const char * 105level_to_str(enum u_logging_level level) 106{ 107 switch (level) { 108 case U_LOGGING_TRACE: return "trace"; 109 case U_LOGGING_DEBUG: return "debug"; 110 case U_LOGGING_INFO: return "info"; 111 case U_LOGGING_WARN: return "warn"; 112 case U_LOGGING_ERROR: return "error"; 113 default: return "invalid"; 114 } 115} 116 117static const char * 118tristate_to_str(enum debug_tristate_option tristate) 119{ 120 switch (tristate) { 121 case DEBUG_TRISTATE_OFF: return "OFF"; 122 case DEBUG_TRISTATE_AUTO: return "AUTO"; 123 case DEBUG_TRISTATE_ON: return "ON"; 124 default: return "invalid"; 125 } 126} 127 128/*! 129 * This function checks @p str if it matches @p matches, it returns true as long 130 * as the complete @p str is in the starts of @p matches. Empty string does not 131 * match. 132 */ 133static bool 134is_str_in_start_of(const char *str, const char *matches) 135{ 136 if (str[0] == '\0') { 137 return false; 138 } 139 140 for (int i = 0; str[i] != '\0'; i++) { 141 if (matches[i] == '\0') { 142 return false; 143 } 144 if (matches[i] != tolower(str[i])) { 145 return false; 146 } 147 } 148 149 return true; 150} 151 152 153/* 154 * 155 * 'Exported' conversion functions. 156 * 157 */ 158 159bool 160debug_string_to_bool(const char *string) 161{ 162 if (string == NULL) { 163 return false; 164 } else if (!strcmp(string, "false")) { 165 return false; 166 } else if (!strcmp(string, "FALSE")) { 167 return false; 168 } else if (!strcmp(string, "off")) { 169 return false; 170 } else if (!strcmp(string, "OFF")) { 171 return false; 172 } else if (!strcmp(string, "no")) { 173 return false; 174 } else if (!strcmp(string, "NO")) { 175 return false; 176 } else if (!strcmp(string, "n")) { 177 return false; 178 } else if (!strcmp(string, "N")) { 179 return false; 180 } else if (!strcmp(string, "f")) { 181 return false; 182 } else if (!strcmp(string, "F")) { 183 return false; 184 } else if (!strcmp(string, "0")) { 185 return false; 186 } else { 187 return true; 188 } 189} 190 191enum debug_tristate_option 192debug_string_to_tristate(const char *string) 193{ 194 if (string == NULL) { 195 return DEBUG_TRISTATE_AUTO; 196 } else if (!strcmp(string, "AUTO")) { 197 return DEBUG_TRISTATE_AUTO; 198 } else if (!strcmp(string, "auto")) { 199 return DEBUG_TRISTATE_AUTO; 200 } else if (!strcmp(string, "a")) { 201 return DEBUG_TRISTATE_AUTO; 202 } else if (!strcmp(string, "A")) { 203 return DEBUG_TRISTATE_AUTO; 204 } else { 205 if (debug_string_to_bool(string)) { 206 return DEBUG_TRISTATE_ON; 207 } else { 208 return DEBUG_TRISTATE_OFF; 209 } 210 } 211} 212 213long 214debug_string_to_num(const char *string, long _default) 215{ 216 if (string == NULL) { 217 return _default; 218 } 219 220 char *endptr; 221 long ret = strtol(string, &endptr, 0); 222 223 // Restore the default value when no digits were found. 224 if (string == endptr) { 225 return _default; 226 } 227 228 return ret; 229} 230 231float 232debug_string_to_float(const char *string, float _default) 233{ 234 if (string == NULL) { 235 return _default; 236 } 237 238 char *endptr; 239 float ret = strtof(string, &endptr); 240 241 // Restore the default value when no digits were found. 242 if (string == endptr) { 243 return _default; 244 } 245 246 return ret; 247} 248 249enum u_logging_level 250debug_string_to_log_level(const char *string, enum u_logging_level _default) 251{ 252 if (string == NULL) { 253 return _default; 254 } else if (is_str_in_start_of(string, "trace")) { 255 return U_LOGGING_TRACE; 256 } else if (is_str_in_start_of(string, "debug")) { 257 return U_LOGGING_DEBUG; 258 } else if (is_str_in_start_of(string, "info")) { 259 return U_LOGGING_INFO; 260 } else if (is_str_in_start_of(string, "warn")) { 261 return U_LOGGING_WARN; 262 } else if (is_str_in_start_of(string, "error")) { 263 return U_LOGGING_ERROR; 264 } else { 265 return _default; 266 } 267} 268 269 270/* 271 * 272 * 'Exported' debug value getters. 273 * 274 */ 275 276const char * 277debug_get_option(char *chars, size_t char_count, const char *name, const char *_default) 278{ 279 const char *raw = get_option_raw(chars, char_count, name); 280 const char *ret = raw; 281 282 if (ret == NULL) { 283 if (_default != NULL) { 284 snprintf(chars, char_count, "%s", _default); 285 ret = chars; // Return a value. 286 } 287 } 288 289 if (debug_get_bool_option_print()) { 290 U_LOG_RAW("%s=%s (%s)", name, ret, raw == NULL ? "nil" : raw); 291 } 292 293 return ret; 294} 295 296bool 297debug_get_bool_option(const char *name, bool _default) 298{ 299 char chars[DEBUG_CHAR_STORAGE_SIZE]; 300 const char *raw = get_option_raw(chars, ARRAY_SIZE(chars), name); 301 302 bool ret = raw == NULL ? _default : debug_string_to_bool(raw); 303 304 if (debug_get_bool_option_print()) { 305 U_LOG_RAW("%s=%s (%s)", name, ret ? "TRUE" : "FALSE", raw == NULL ? "nil" : raw); 306 } 307 308 return ret; 309} 310 311enum debug_tristate_option 312debug_get_tristate_option(const char *name) 313{ 314 char chars[DEBUG_CHAR_STORAGE_SIZE]; 315 const char *raw = get_option_raw(chars, ARRAY_SIZE(chars), name); 316 317 enum debug_tristate_option ret = debug_string_to_tristate(raw); 318 319 if (debug_get_bool_option_print()) { 320 const char *pretty_val = tristate_to_str(ret); 321 U_LOG_RAW("%s=%s (%s)", name, pretty_val, raw == NULL ? "nil" : raw); 322 } 323 324 return ret; 325} 326 327long 328debug_get_num_option(const char *name, long _default) 329{ 330 char chars[DEBUG_CHAR_STORAGE_SIZE]; 331 const char *raw = get_option_raw(chars, ARRAY_SIZE(chars), name); 332 333 long ret = debug_string_to_num(raw, _default); 334 335 if (debug_get_bool_option_print()) { 336 U_LOG_RAW("%s=%li (%s)", name, ret, raw == NULL ? "nil" : raw); 337 } 338 339 return ret; 340} 341 342float 343debug_get_float_option(const char *name, float _default) 344{ 345 char chars[DEBUG_CHAR_STORAGE_SIZE]; 346 const char *raw = get_option_raw(chars, ARRAY_SIZE(chars), name); 347 348 float ret = debug_string_to_float(raw, _default); 349 350 if (debug_get_bool_option_print()) { 351 U_LOG_RAW("%s=%f (%s)", name, ret, raw == NULL ? "nil" : raw); 352 } 353 354 return ret; 355} 356 357enum u_logging_level 358debug_get_log_option(const char *name, enum u_logging_level _default) 359{ 360 char chars[DEBUG_CHAR_STORAGE_SIZE]; 361 const char *raw = get_option_raw(chars, ARRAY_SIZE(chars), name); 362 363 enum u_logging_level ret = debug_string_to_log_level(raw, _default); 364 365 if (debug_get_bool_option_print()) { 366 const char *pretty_val = level_to_str(ret); 367 U_LOG_RAW("%s=%s (%s)", name, pretty_val, raw == NULL ? "nil" : raw); 368 } 369 370 return ret; 371}