Created
December 29, 2014 07:46
-
-
Save mejedi/bfc50a9e2fdcbdcaee5f to your computer and use it in GitHub Desktop.
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
/* | |
* ====== About Performance Counters ====== | |
* | |
* Technically a performance counter is an ordinary C/C++ variable. | |
* It needs a declaration | |
* | |
* DECLARE_PERF_COUNTER(int, my_counter, "my_counter"), | |
* | |
* ...and the definition: | |
* | |
* DEFINE_PERF_COUNTER(int, my_counter, "my_counter"). | |
* | |
* | |
* The above statements declare/define 'int my_counter' variable. The | |
* code accesses my_counter variable like any other variable. | |
* Additionally the performance counter directory is build automatically | |
* enabling runtime enumeration and lookups by a string name. | |
* | |
* Last but not least counters are grouped in a compact page-size | |
* aligned memory range; it is possible to map a shared memory segment | |
* on top of the counters enabling low-overhead performance data | |
* collection with an external tool. | |
* | |
*/ | |
#ifndef PERF_COUNTER_H__ | |
#define PERF_COUNTER_H__ | |
#define DECLARE_PERF_COUNTER(type, name, str_name) \ | |
extern type name __attribute__((__visibility__("hidden"))); | |
#define DEFINE_PERF_COUNTER(type, name, str_name) \ | |
DEFINE_HIDDEN_VARIABLE_IN_SECTION__(type,name,".PERFCOUNTER,\"aw\",@nobits#") \ | |
static const perf_counter_desc_t name ## _descriptor__ = { \ | |
str_name, (perf_counter_t *) &name, 0 }; \ | |
static const perf_counter_desc_t *name ## _descriptor_ref__ \ | |
__attribute__((__used__,__section__(".PERFCOUNTERDESC"))) = \ | |
&name ## _descriptor__; | |
/* Implementation follows (Here Be Dragons) */ | |
#pragma GCC visibility push(hidden) | |
#ifdef __cplusplus__ | |
extern "C" { | |
#endif /* __cplusplus__ */ | |
typedef struct perf_counter_s perf_counter_t; | |
typedef struct perf_counter_desc_s perf_counter_desc_t; | |
/* Provided by ld, see linkerscript */ | |
extern perf_counter_t perf_counter_begin__; | |
extern perf_counter_t perf_counter_end__; | |
extern const perf_counter_desc_t *perf_counter_desc_begin__; | |
extern const perf_counter_desc_t *perf_counter_desc_end__; | |
struct perf_counter_s | |
{ | |
int reserved__; | |
}; | |
struct perf_counter_desc_s | |
{ | |
const char *name; | |
perf_counter_t*ptr; | |
int flags; | |
}; | |
/* | |
* DEFINE_HIDDEN_VARIABLE_IN_SECTION__(type,name,section) - a variable | |
* definition with a section attribute in GCC, ungodly mess in the clang | |
* variant. | |
* | |
* The reason for this insanity? We want to place performance counters | |
* in the very special section, a @nobits one (@nobits sections go to | |
* .bss). GCC forces a wrong section type (@progbits), however a | |
* workaround exists since GCC fails to escape section names properly. | |
* | |
* Clang breaks the workaround (http://llvm.org/bugs/show_bug.cgi?id=16232) | |
* the only viable option was to generate the correct definition with | |
* inline assembly. | |
*/ | |
#ifdef __clang__ | |
/* | |
* Bonus insanity: it was necessary to wrap assembly statement in a | |
* dummy function (don't worry the dummy doesn't make it through into | |
* the final executable thanks to the magic of ".discard" section) | |
* (http://psomas.wordpress.com/2011/02/25/inline-assembly-gcc-attributes-linker-scripts-and-a-kernel-macro/) | |
* | |
* Even more jumping through hoops due to the need for unique function | |
* names (hello, __COUNTER__). | |
*/ | |
#define DEFINE_HIDDEN_VARIABLE_IN_SECTION__(type,name,section) \ | |
DEFINE_HIDDEN_VARIABLE_IN_SECTION_INTERNAL__(type,name,section,__COUNTER__) | |
#define DEFINE_HIDDEN_VARIABLE_IN_SECTION_INTERNAL__(type,name,section,i) \ | |
extern type name __attribute__((__visibility__("hidden"))); \ | |
static void __attribute__((__used__,__section__(".discard"))) \ | |
CONCAT__(declare_variable_in_section__, i) () { \ | |
__asm__( \ | |
".type\t" #name ", @object;\n" \ | |
"\t.pushsection\t" section "\n" \ | |
"\t.hidden\t" #name "\n" \ | |
"\t.globl\t" #name "\n" \ | |
"\t.align\t%c0;\n" \ | |
#name ":\n" \ | |
"\t.zero\t%c1\n" \ | |
"\t.size\t" #name ", %c1\n" \ | |
"\t.popsection" \ | |
::"i"(__alignof__(type)), "i"(sizeof(type))); \ | |
} | |
#define CONCAT__(a,b) a ## b | |
#elif __GNUC__ | |
/* The real cakewalk! */ | |
#define DEFINE_HIDDEN_VARIABLE_IN_SECTION__(type,name,section) \ | |
type name \ | |
__attribute__((__section__(section),__visibility__("hidden"))); | |
#else | |
#error Weird compiler | |
#endif | |
#ifdef __cplusplus__ | |
} /* extern "C" { */ | |
#endif /* __cplusplus__ */ | |
#pragma GCC visibility pop | |
#endif /* PERF_COUNTER_H__ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment