Skip to content

Instantly share code, notes, and snippets.

@mejedi
Created December 29, 2014 07:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mejedi/bfc50a9e2fdcbdcaee5f to your computer and use it in GitHub Desktop.
Save mejedi/bfc50a9e2fdcbdcaee5f to your computer and use it in GitHub Desktop.
/*
* ====== 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