Allow xenalyze to be include (at build time) plugins that can do per-record actions and a summary. These plugins can be in C or C++. The plugins entry points are in struct plugin and pointers to all the plugins linked in xenalyze are placed in a "plugin" section so plugin_init() can find them all. A new command line option (-p, --plugin=PLUGIN) is added to enable one or more plugins. A sample plugin (skeleton) is included (mostly because at least one plugin must be present for the build to work). Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- Makefile | 10 +++--- analyze.h | 55 ++++++++++++++++++++++++++++++++++ plugin.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ plugin.h | 48 +++++++++++++++++++++++++++++ plugin.hh | 42 ++++++++++++++++++++++++++ plugins/skeleton.cc | 31 +++++++++++++++++++ xenalyze.c | 72 +++++++++++++------------------------------- 7 files changed, 287 insertions(+), 55 deletions(-) diff -r f4feecb06e49 Makefile --- a/Makefile Tue Apr 24 18:37:35 2012 +0100 +++ b/Makefile Wed Apr 25 10:42:54 2012 +0100 @@ -1,6 +1,6 @@ CC = gcc -CFLAGS += -g -O2 +CFLAGS += -g -O2 -I. CFLAGS += -fno-strict-aliasing CFLAGS += -std=gnu99 CFLAGS += -Wall -Wstrict-prototypes @@ -11,9 +11,11 @@ CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEF CFLAGS += -mno-tls-direct-seg-refs CFLAGS += -Werror +CXXFLAGS := -g -O2 -I. -Wall -Werror -std=c++0x + BIN = xenalyze dump-raw -HDRS = trace.h analyze.h mread.h +HDRS = trace.h analyze.h mread.h plugin.h plugin.hh all: $(BIN) @@ -24,5 +26,5 @@ clean: %: %.c $(HDRS) Makefile $(CC) $(CFLAGS) -o $@ $< -xenalyze: xenalyze.o mread.o - $(CC) $(CFLAGS) -o $@ $^ +xenalyze: xenalyze.o mread.o plugin.o plugins/skeleton.o + $(CXX) $(CFLAGS) -o $@ $^ diff -r f4feecb06e49 analyze.h --- a/analyze.h Tue Apr 24 18:37:35 2012 +0100 +++ b/analyze.h Wed Apr 25 10:42:54 2012 +0100 @@ -1,5 +1,8 @@ #ifndef __ANALYZE_H # define __ANALYZE_H + +#include <stdint.h> + #define TRC_GEN_MAIN 0 #define TRC_SCHED_MAIN 1 #define TRC_DOM0OP_MAIN 2 @@ -47,4 +50,56 @@ enum { }; #define TRC_HVM_OP_DESTROY_PROC (TRC_HVM_HANDLER + 0x100) + +typedef unsigned long long tsc_t; + +/* -- on-disk trace buffer definitions -- */ +struct trace_record { + union { + struct { + unsigned event:28, + extra_words:3, + cycle_flag:1; + union { + struct { + uint32_t tsc_lo, tsc_hi; + uint32_t data[7]; + } tsc; + struct { + uint32_t data[7]; + } notsc; + } u; + }; + uint32_t raw[8]; + }; +}; + +/* -- General info about a current record -- */ +struct time_struct { + unsigned long long time; + unsigned int s, ns; +}; + +#define DUMP_HEADER_MAX 256 + +struct record_info { + int cpu; + tsc_t tsc; + union { + unsigned event; + struct { + unsigned minor:12, + sub:4, + main:12, + unused:4; + } evt; + }; + int extra_words; + int size; + uint32_t *d; + char dump_header[DUMP_HEADER_MAX]; + struct time_struct t; + struct trace_record rec; +}; + #endif diff -r f4feecb06e49 plugin.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin.cc Wed Apr 25 10:42:54 2012 +0100 @@ -0,0 +1,84 @@ +/* + * Xenalyze plugin infrastructure. + * + * Copyright (C) 2012, Citrix Systems R&D Ltd, UK + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#include <stdio.h> +#include <string.h> +#include <list> + +#include "plugin.hh" + +typedef std::list<struct plugin *> plugin_list; + +static plugin_list available; +static plugin_list enabled; + +bool plugin_enable(const char *name) +{ + for (auto p = available.begin(); p != available.end(); p++) { + struct plugin *plugin = *p; + if (strcmp(plugin->name, name) == 0) { + enabled.push_back(plugin); + if (plugin->enable) { + plugin->enable(plugin); + } + return true; + } + } + return false; +} + +void plugin_process(const struct record_info *ri) +{ + for (auto p = enabled.begin(); p != enabled.end(); p++) { + struct plugin *plugin = *p; + if (plugin->process) { + plugin->process(plugin, ri); + } + } +} + +void plugin_summary(void) +{ + for (auto p = enabled.begin(); p != enabled.end(); p++) { + struct plugin *plugin = *p; + if (plugin->summary) { + printf("Summary for %s plugin:\n", plugin->name); + plugin->summary(plugin); + } + } +} + +static void plugin_add(struct plugin *plugin) +{ + available.push_back(plugin); +} + +void plugin_init(void) +{ + extern struct plugin *__start_plugin; + extern struct plugin *__stop_plugin; + struct plugin **p; + + for (p = &__start_plugin; p < &__stop_plugin; p++) { + plugin_add(*p); + } +} + +void plugin_process_wrapper(struct plugin *plugin, const struct record_info *ri) +{ + xenalyze_plugin *p = static_cast<xenalyze_plugin*>(plugin->data); + p->process(ri); +} + +void plugin_summary_wrapper(struct plugin *plugin) +{ + xenalyze_plugin *p = static_cast<xenalyze_plugin*>(plugin->data); + p->summary(); + delete p; +} diff -r f4feecb06e49 plugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin.h Wed Apr 25 10:42:54 2012 +0100 @@ -0,0 +1,48 @@ +/* + * Xenalyze plugin C API. + * + * Copyright (C) 2012, Citrix Systems R&D Ltd, UK + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#ifndef PLUGIN_H +#define PLUGIN_H + +#include <stdbool.h> + +#include "analyze.h" +#include "helpers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct plugin; + +typedef void (*plugin_enable_f)(struct plugin *plugin); +typedef void (*plugin_process_f)(struct plugin *plugin, const struct record_info *ri); +typedef void (*plugin_summary_f)(struct plugin *plugin); + +struct plugin { + const char *name; + plugin_enable_f enable; + plugin_process_f process; + plugin_summary_f summary; + void *data; +}; + +#define DEFINE_PLUGIN(p) \ + struct plugin *__plugin_ ## p __attribute__((section("plugin"))) = &p + +void plugin_init(void); +bool plugin_enable(const char *name); +void plugin_process(const struct record_info *ri); +void plugin_summary(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* #ifndef PLUGIN_H */ diff -r f4feecb06e49 plugin.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin.hh Wed Apr 25 10:42:54 2012 +0100 @@ -0,0 +1,42 @@ +/* + * Xenalyze plugin C++ API. + * + * Copyright (C) 2012, Citrix Systems R&D Ltd, UK + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#ifndef PLUGIN_HH +#define PLUGIN_HH + +#include "plugin.h" + +class xenalyze_plugin { +public: + virtual ~xenalyze_plugin() {} + + virtual void process(const struct record_info *ri) = 0; + virtual void summary() = 0; +}; + +#define DEFINE_CXX_PLUGIN(name, cls) \ + static void __plugin_ ## cls ## _enable(struct plugin *plugin) \ + { \ + plugin->data = new cls(); \ + } \ + \ + static struct plugin __plugin ## cls = { \ + name, \ + __plugin_ ## cls ## _enable, \ + plugin_process_wrapper, \ + plugin_summary_wrapper, \ + }; \ + DEFINE_PLUGIN(__plugin ## cls) + +extern "C" { +void plugin_process_wrapper(struct plugin *plugin, const struct record_info *ri); +void plugin_summary_wrapper(struct plugin *plugin); +} + +#endif /* #ifndef PLUGIN_HH */ diff -r f4feecb06e49 plugins/skeleton.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/skeleton.cc Wed Apr 25 10:42:54 2012 +0100 @@ -0,0 +1,31 @@ +/* + * Skeleton xenalyze plugin. + * + * Copyright (C) 2012, Citrix Systems R&D Ltd, UK + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#include "plugin.hh" + +class skeleton_plugin : xenalyze_plugin { +public: + skeleton_plugin() {} + ~skeleton_plugin() {} + + void process(const struct record_info *ri); + void summary(void); +}; + +void skeleton_plugin::process(const struct record_info *ri) +{ + /* Put per-trace record stuff here. */ +} + +void skeleton_plugin::summary(void) +{ + /* Print a summary of the results (if applicable). */ +} + +DEFINE_CXX_PLUGIN("skeleton", skeleton_plugin); diff -r f4feecb06e49 xenalyze.c --- a/xenalyze.c Tue Apr 24 18:37:35 2012 +0100 +++ b/xenalyze.c Wed Apr 25 10:42:54 2012 +0100 @@ -32,6 +32,7 @@ #include "trace.h" #include "analyze.h" #include "mread.h" +#include "plugin.h" #include <errno.h> #include <strings.h> #include <string.h> @@ -40,8 +41,6 @@ struct mread_ctrl; -typedef unsigned long long tsc_t; - #define DEFAULT_CPU_HZ 2400000000LL #define ADDR_SPACE_BITS 48 #define DEFAULT_SAMPLE_SIZE 10240 @@ -260,57 +259,8 @@ struct { .interval = { .msec = DEFAULT_INTERVAL_LENGTH }, }; -/* -- on-disk trace buffer definitions -- */ -struct trace_record { - union { - struct { - unsigned event:28, - extra_words:3, - cycle_flag:1; - union { - struct { - uint32_t tsc_lo, tsc_hi; - uint32_t data[7]; - } tsc; - struct { - uint32_t data[7]; - } notsc; - } u; - }; - uint32_t raw[8]; - }; -}; - FILE *warn = NULL; -/* -- General info about a current record -- */ -struct time_struct { - unsigned long long time; - unsigned int s, ns; -}; - -#define DUMP_HEADER_MAX 256 - -struct record_info { - int cpu; - tsc_t tsc; - union { - unsigned event; - struct { - unsigned minor:12, - sub:4, - main:12, - unused:4; - } evt; - }; - int extra_words; - int size; - uint32_t *d; - char dump_header[DUMP_HEADER_MAX]; - struct time_struct t; - struct trace_record rec; -}; - /* -- Summary data -- */ struct cycle_framework { tsc_t first_tsc, last_tsc, total_cycles; @@ -8901,6 +8851,8 @@ void process_record(struct pcpu_info *p) default: process_generic(ri); } + + plugin_process(ri); } UPDATE_VOLUME(p, toplevel[toplevel], ri->size); @@ -9484,6 +9436,7 @@ enum { OPT_DUMP_ALL=''a'', OPT_INTERVAL_LENGTH=''i'', OPT_SUMMARY=''s'', + OPT_PLUGIN=''p'', }; enum { @@ -9954,6 +9907,15 @@ error_t cmd_parser(int key, char *arg, s opt.tsc_loop_fatal = 1; break; + case OPT_PLUGIN: + if (plugin_enable(arg)) { + G.output_defined = 1; + } else { + fprintf(stderr, "ERROR: No such plugin `%s''.\n", arg); + exit(1); + } + break; + case ARGP_KEY_ARG: { /* FIXME - strcpy */ @@ -10246,6 +10208,10 @@ const struct argp_option cmd_opts[] = { .arg = "errlevel", .doc = "Sets tolerance for errors found in the file. Default is 3; max is 6.", }, + { .name = "plugin", + .key = OPT_PLUGIN, + .arg = "PLUGIN", + .doc = "Enable a decoder or summary plugin.", }, { 0 }, }; @@ -10265,6 +10231,8 @@ int main(int argc, char *argv[]) { /* Start with warn at stderr. */ warn = stderr; + plugin_init(); + argp_parse(&parser_def, argc, argv, 0, NULL, NULL); if (G.trace_file == NULL) @@ -10301,6 +10269,8 @@ int main(int argc, char *argv[]) { if(opt.summary) summary(); + plugin_summary(); + if(opt.report_pcpu) report_pcpu();