Last active
April 6, 2017 17:00
-
-
Save primiano/d5c2f13dc89050c8fbfb7c70dab92288 to your computer and use it in GitHub Desktop.
tracing_macro_constexpr_for_gcc.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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