Skip to content

Instantly share code, notes, and snippets.

@primiano
Created April 6, 2017 11:51
Show Gist options
  • Save primiano/2ad94f6f822ff6b1a730873cab611f2b to your computer and use it in GitHub Desktop.
Save primiano/2ad94f6f822ff6b1a730873cab611f2b to your computer and use it in GitHub Desktop.
tracing_macros_constexpr.cc
#include <stdint.h>
#include <stdio.h>
#include <string.h>
struct Category {
const char *name;
uint8_t is_enabled;
};
constexpr uint32_t N = 100;
constexpr Category kKnownCategories[N] = {{"foo", false}, {"bar", false}};
Category g_categories[N] = {
// Having to do these assignments is really awkward. But I don't know
// enough constexpr magic to be able to just assign the array to the
// constexpr one.
kKnownCategories[0], kKnownCategories[1],
};
constexpr uint8_t *GetEnabledPtrAtCompileTime(const char *cat, uint32_t i = 0) {
// Apologies for the nested ternary operators, but any other more readable
// option (if statements, variables) was a C++14 extension.
return (kKnownCategories[i].name == nullptr)
? nullptr
: ((cat == kKnownCategories[i].name)
? &g_categories[i].is_enabled
: (GetEnabledPtrAtCompileTime(cat, i + 1)));
}
uint8_t* __attribute__ ((noinline)) GetEnabledPtrAtRunTime(const char *cat) {
// Assume this has the proper locks for thread-safety.
for (uint32_t i = 0; i < N; i++) {
// Reached empty slot, just append the new cat.
if (g_categories[i].name == nullptr)
g_categories[i].name = cat;
if (strcmp(g_categories[i].name, cat) == 0)
return &g_categories[i].is_enabled;
}
// more than 100 categories. the real implementation has a fallback for this.
return nullptr;
}
void __attribute__ ((noinline)) AddEvent(const char *cat, const char *evt_name) {
// LOL, assume this does TraceLog::GetInstance()->AddTraceEvent(...).
printf("EVT: %s %s (ptr: %p)\n", cat, evt_name, GetEnabledPtrAtRunTime(cat));
}
#define TOKENPASTE(x, y) x##y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE_VAR TOKENPASTE2(var, __LINE__)
#define TRACE_EVENT0(cat, event_name) \
static uint8_t *UNIQUE_VAR = nullptr; \
if (GetEnabledPtrAtCompileTime(cat)) { \
UNIQUE_VAR = GetEnabledPtrAtCompileTime(cat); \
} else if (UNIQUE_VAR == nullptr) { \
UNIQUE_VAR = GetEnabledPtrAtRunTime(cat); \
printf("Dynamically getting pointer '%s' : %p\n", cat, UNIQUE_VAR); \
} \
do { \
if (*((volatile uint8_t *)UNIQUE_VAR)) \
AddEvent(cat, event_name); \
} while (0)
void foo() { TRACE_EVENT0("foo", "foo::something"); }
void baz() { TRACE_EVENT0("baz", "baz::something"); }
int main() {
for (int i = 0; i < 2; i++) {
// Initial iteration is for warming up categories.
TRACE_EVENT0("foo", "foo::something");
TRACE_EVENT0("bar", "bar::something");
TRACE_EVENT0("baz", "baz::something");
// Enable tracing:
for (uint32_t i = 0; i < N && g_categories[i].name; i++)
g_categories[i].is_enabled = true;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment