Skip to content

Instantly share code, notes, and snippets.

@primiano
Last active April 6, 2017 17:00
Show Gist options
  • Save primiano/d5c2f13dc89050c8fbfb7c70dab92288 to your computer and use it in GitHub Desktop.
Save primiano/d5c2f13dc89050c8fbfb7c70dab92288 to your computer and use it in GitHub Desktop.
tracing_macro_constexpr_for_gcc.cc
context: crbug.com/708990
#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},
{"toplevel", false},
{"cc", false},
// The remaining slots are zero-initialized and available for the dynamic categories.
};
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],
kKnownCategories[2],
kKnownCategories[3],
};
constexpr bool ConstexprStrcmp(const char* a, const char* b, int n = 0) {
return (!a[n] && !b[n]) ? true : ((a[n] == b[n]) ? ConstexprStrcmp(a, b, n + 1) : false);
}
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
: (ConstexprStrcmp(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; \
constexpr uint8_t *k_##UNIQUE_VAR = GetEnabledPtrAtCompileTime(cat); \
if (k_##UNIQUE_VAR) { \
UNIQUE_VAR = k_##UNIQUE_VAR; \
} 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)
extern "C" void __attribute__((visibility("default"))) __attribute__((noinline))
foo() {
TRACE_EVENT0("foo", "foo::something");
}
extern "C" void __attribute__((visibility("default"))) __attribute__((noinline))
baz() {
TRACE_EVENT0("baz", "baz::something");
}
int main() {
foo();
baz();
for (uint32_t i = 0; i < N && g_categories[i].name; i++)
g_categories[i].is_enabled = true;
foo();
baz();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment