From d7160fc7003436a94da75beed61f7194b65d178e Mon Sep 17 00:00:00 2001 From: Giuseppe Congiu Date: Fri, 21 Jul 2023 12:43:12 +0200 Subject: [PATCH] template: add template for new components --- src/components/template/README.md | 30 + src/components/template/Rules.template | 21 + src/components/template/template.c | 415 ++++++++++++ src/components/template/tests/Makefile | 18 + src/components/template/tests/simple.c | 94 +++ src/components/template/vendor_common.c | 92 +++ src/components/template/vendor_common.h | 31 + src/components/template/vendor_config.h | 11 + src/components/template/vendor_dispatch.c | 101 +++ src/components/template/vendor_dispatch.h | 27 + src/components/template/vendor_profiler_v1.c | 623 +++++++++++++++++++ src/components/template/vendor_profiler_v1.h | 23 + 12 files changed, 1486 insertions(+) create mode 100644 src/components/template/README.md create mode 100644 src/components/template/Rules.template create mode 100644 src/components/template/template.c create mode 100644 src/components/template/tests/Makefile create mode 100644 src/components/template/tests/simple.c create mode 100644 src/components/template/vendor_common.c create mode 100644 src/components/template/vendor_common.h create mode 100644 src/components/template/vendor_config.h create mode 100644 src/components/template/vendor_dispatch.c create mode 100644 src/components/template/vendor_dispatch.h create mode 100644 src/components/template/vendor_profiler_v1.c create mode 100644 src/components/template/vendor_profiler_v1.h diff --git a/src/components/template/README.md b/src/components/template/README.md new file mode 100644 index 000000000..e6190b33f --- /dev/null +++ b/src/components/template/README.md @@ -0,0 +1,30 @@ +# Template Component + +The Template component showcases a possible approach to component design that +varies from the more traditional monolitic approach, used in some existing +components. + +The Template component is split into a front-end (template.c) and a back-end +(vendor\_{dispatch,common,profiler}.c). The goal of this layered design is to +decouple changes in the vendor libraries from the existing implementation. + +If, for example, the vendor library introduces a new set of interfaces and +deprecates the old ones, a new vendor\_dispatch\_v2.c can be written to add +support for the new vendor library interface without affecting the old vendor +related code (i.e., vendor\_profiler.c). This can still be kept for backward +compatibility with older vendor library versions. The dispatch layer (i.e., +vendor\_dispatch.c) takes care of forwarding profiling calls to the right +vendor library version. + +Any code that is shared between the different vendor library versions is placed +in vendor\_common.c. This can contain common init routines (e.g., for the vendor +runtime system initialization, like cuda or hsa), utility routines and shared +data structures (e.g., device information tables). + +The template component emulates support for a generic vendor library to profile +associated device hardware counters. The implementation is fairly detailed in +stating the design decisions. For example, there is a clear separation between +the front-end and the back-end with no sharing of data between the two. The +front-end only takes care of doing some book keeping work (perhaps rearrange the +order of events as it sees fit) and calling into the back-end functions to do +actual work. diff --git a/src/components/template/Rules.template b/src/components/template/Rules.template new file mode 100644 index 000000000..8457c45c9 --- /dev/null +++ b/src/components/template/Rules.template @@ -0,0 +1,21 @@ +COMPSRCS += components/template/template.c \ + components/template/vendor_dispatch.c \ + components/template/vendor_common.c \ + components/template/vendor_profiler_v1.c + +COMPOBJS += template.o vendor_dispatch.o vendor_common.o vendor_profiler_v1.o + +CFLAGS += -g +LDFLAGS += $(LDL) + +template.o: components/template/template.c $(HEADERS) + $(CC) $(LIBCFLAGS) $(OPTFLAGS) -c $< -o $@ + +vendor_dispatch.o: components/template/vendor_dispatch.c $(HEADERS) + $(CC) $(LIBCFLAGS) $(OPTFLAGS) -c $< -o $@ + +vendor_common.o: components/template/vendor_common.c $(HEADERS) + $(CC) $(LIBCFLAGS) $(OPTFLAGS) -c $< -o $@ + +vendor_profiler_v1.o: components/template/vendor_profiler_v1.c $(HEADERS) + $(CC) $(LIBCFLAGS) $(OPTFLAGS) -c $< -o $@ diff --git a/src/components/template/template.c b/src/components/template/template.c new file mode 100644 index 000000000..3e7033e72 --- /dev/null +++ b/src/components/template/template.c @@ -0,0 +1,415 @@ +#include +#include "papi.h" +#include "papi_internal.h" +#include "papi_vector.h" +#include "papi_memory.h" +#include "extras.h" +#include "vendor_dispatch.h" + +#define TEMPLATE_MAX_COUNTERS (16) + +/* Init and finalize */ +static int templ_init_component(int cid); +static int templ_init_thread(hwd_context_t *ctx); +static int templ_init_control_state(hwd_control_state_t *ctl); +static int templ_init_private(void); +static int templ_shutdown_component(void); +static int templ_shutdown_thread(hwd_context_t *ctx); +static int templ_cleanup_eventset(hwd_control_state_t *ctl); + +/* Set and update component state */ +static int templ_update_control_state(hwd_control_state_t *ctl, NativeInfo_t *ntv_info, int ntv_count, hwd_context_t *ctx); + +/* Start and stop profiling of hardware events */ +static int templ_start(hwd_context_t *ctx, hwd_control_state_t *ctl); +static int templ_read(hwd_context_t *ctx, hwd_control_state_t *ctl, long long **val, int flags); +static int templ_stop(hwd_context_t *ctx, hwd_control_state_t *ctl); +static int templ_reset(hwd_context_t *ctx, hwd_control_state_t *ctl); + +/* Event conversion */ +static int templ_ntv_enum_events(unsigned int *event_code, int modifier); +static int templ_ntv_code_to_name(unsigned int event_code, char *name, int len); +static int templ_ntv_name_to_code(const char *name, unsigned int *event_code); +static int templ_ntv_code_to_descr(unsigned int event_code, char *descr, int len); +static int templ_ntv_code_to_info(unsigned int event_code, PAPI_event_info_t *info); + +static int templ_set_domain(hwd_control_state_t *ctl, int domain); +static int templ_ctl(hwd_context_t *ctx, int code, _papi_int_option_t *option); + +typedef struct { + int initialized; + int state; + int component_id; +} templ_context_t; + +typedef struct { + unsigned int *events_id; + int num_events; + vendord_ctx_t vendor_ctx; +} templ_control_t; + +papi_vector_t _template_vector = { + .cmp_info = { + .name = "templ", + .short_name = "templ", + .version = "1.0", + .description = "Template component for new components", + .initialized = 0, + .num_mpx_cntrs = TEMPLATE_MAX_COUNTERS, + }, + + .size = { + .context = sizeof(templ_context_t), + .control_state = sizeof(templ_control_t), + .reg_value = 1, + .reg_alloc = 1, + }, + + .init_component = templ_init_component, + .init_thread = templ_init_thread, + .init_control_state = templ_init_control_state, + .shutdown_component = templ_shutdown_component, + .shutdown_thread = templ_shutdown_thread, + .cleanup_eventset = templ_cleanup_eventset, + + .update_control_state = templ_update_control_state, + .start = templ_start, + .stop = templ_stop, + .read = templ_read, + .reset = templ_reset, + + .ntv_enum_events = templ_ntv_enum_events, + .ntv_code_to_name = templ_ntv_code_to_name, + .ntv_name_to_code = templ_ntv_name_to_code, + .ntv_code_to_descr = templ_ntv_code_to_descr, + .ntv_code_to_info = templ_ntv_code_to_info, + + .set_domain = templ_set_domain, + .ctl = templ_ctl, +}; + +static int check_n_initialize(void); + +int +templ_init_component(int cid) +{ + _template_vector.cmp_info.CmpIdx = cid; + _template_vector.cmp_info.num_native_events = -1; + _template_vector.cmp_info.num_cntrs = -1; + _templ_lock = PAPI_NUM_LOCK + NUM_INNER_LOCK + cid; + + int papi_errno = vendord_init_pre(); + if (papi_errno != PAPI_OK) { + _template_vector.cmp_info.initialized = 1; + _template_vector.cmp_info.disabled = papi_errno; + const char *err_string; + vendord_err_get_last(&err_string); + snprintf(_template_vector.cmp_info.disabled_reason, PAPI_MAX_STR_LEN, "%s", err_string); + return papi_errno; + } + + sprintf(_template_vector.cmp_info.disabled_reason, "Not initialized. Access component events to initialize it."); + _template_vector.cmp_info.disabled = PAPI_EDELAY_INIT; + return PAPI_EDELAY_INIT; +} + +int +templ_init_thread(hwd_context_t *ctx) +{ + templ_context_t *templ_ctx = (templ_context_t *) ctx; + memset(templ_ctx, 0, sizeof(*templ_ctx)); + templ_ctx->initialized = 1; + templ_ctx->component_id = _template_vector.cmp_info.CmpIdx; + return PAPI_OK; +} + +int +templ_init_control_state(hwd_control_state_t *ctl __attribute__((unused))) +{ + return check_n_initialize(); +} + +static int +evt_get_count(int *count) +{ + unsigned int event_code = 0; + + if (vendord_evt_enum(&event_code, PAPI_ENUM_FIRST) == PAPI_OK) { + ++(*count); + } + while (vendord_evt_enum(&event_code, PAPI_ENUM_EVENTS) == PAPI_OK) { + ++(*count); + } + + return PAPI_OK; +} + +int +templ_init_private(void) +{ + int papi_errno = PAPI_OK; + + _papi_hwi_lock(COMPONENT_LOCK); + + if (_template_vector.cmp_info.initialized) { + papi_errno = _template_vector.cmp_info.disabled; + goto fn_exit; + } + + papi_errno = vendord_init(); + if (papi_errno != PAPI_OK) { + _template_vector.cmp_info.disabled = papi_errno; + const char *err_string; + vendord_err_get_last(&err_string); + snprintf(_template_vector.cmp_info.disabled_reason, PAPI_MAX_STR_LEN, "%s", err_string); + goto fn_fail; + } + + int count = 0; + papi_errno = evt_get_count(&count); + _template_vector.cmp_info.num_native_events = count; + _template_vector.cmp_info.num_cntrs = count; + + fn_exit: + _template_vector.cmp_info.initialized = 1; + _template_vector.cmp_info.disabled = papi_errno; + _papi_hwi_unlock(COMPONENT_LOCK); + return papi_errno; + fn_fail: + goto fn_exit; +} + +int +templ_shutdown_component(void) +{ + _template_vector.cmp_info.initialized = 0; + return vendord_shutdown(); +} + +int +templ_shutdown_thread(hwd_context_t *ctx) +{ + templ_context_t *templ_ctx = (templ_context_t *) ctx; + templ_ctx->initialized = 0; + templ_ctx->state = 0; + return PAPI_OK; +} + +int +templ_cleanup_eventset(hwd_control_state_t *ctl) +{ + templ_control_t *templ_ctl = (templ_control_t *) ctl; + papi_free(templ_ctl->events_id); + templ_ctl->events_id = NULL; + templ_ctl->num_events = 0; + return PAPI_OK; +} + +static int update_native_events(templ_control_t *, NativeInfo_t *, int); +static int try_open_events(templ_control_t *); + +int +templ_update_control_state(hwd_control_state_t *ctl, NativeInfo_t *ntv_info, int ntv_count, hwd_context_t *ctx __attribute__((unused))) +{ + int papi_errno = check_n_initialize(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + templ_control_t *templ_ctl = (templ_control_t *) ctl; + if (templ_ctl->vendor_ctx != NULL) { + return PAPI_ECMP; + } + + papi_errno = update_native_events(templ_ctl, ntv_info, ntv_count); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + return try_open_events(templ_ctl); +} + +int +update_native_events(templ_control_t *ctl, NativeInfo_t *ntv_info, int ntv_count) +{ + int papi_errno = PAPI_OK; + + if (ntv_count != ctl->num_events) { + ctl->events_id = papi_realloc(ctl->events_id, ntv_count * sizeof(*ctl->events_id)); + if (NULL == ctl->events_id) { + papi_errno = PAPI_ENOMEM; + goto fn_fail; + } + ctl->num_events = ntv_count; + } + + int i; + for (i = 0; i < ntv_count; ++i) { + ctl->events_id[i] = ntv_info[i].ni_event; + ntv_info[i].ni_position = i; + } + + fn_exit: + return papi_errno; + fn_fail: + ctl->num_events = 0; + goto fn_exit; +} + +int +try_open_events(templ_control_t *templ_ctl) +{ + int papi_errno = PAPI_OK; + vendord_ctx_t vendor_ctx; + + papi_errno = vendord_ctx_open(templ_ctl->events_id, templ_ctl->num_events, &vendor_ctx); + if (papi_errno != PAPI_OK) { + templ_cleanup_eventset(templ_ctl); + return papi_errno; + } + + return vendord_ctx_close(vendor_ctx); +} + +int +templ_start(hwd_context_t *ctx, hwd_control_state_t *ctl) +{ + int papi_errno = PAPI_OK; + templ_context_t *templ_ctx = (templ_context_t *) ctx; + templ_control_t *templ_ctl = (templ_control_t *) ctl; + + if (templ_ctx->state & TEMPL_CTX_OPENED) { + return PAPI_EINVAL; + } + + papi_errno = vendord_ctx_open(templ_ctl->events_id, templ_ctl->num_events, &templ_ctl->vendor_ctx); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + templ_ctx->state = TEMPL_CTX_OPENED; + + papi_errno = vendord_ctx_start(templ_ctl->vendor_ctx); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + templ_ctx->state |= TEMPL_CTX_RUNNING; + + fn_exit: + return papi_errno; + fn_fail: + vendord_ctx_close(templ_ctl->vendor_ctx); + templ_ctx->state = 0; + goto fn_exit; +} + +int +templ_read(hwd_context_t *ctx __attribute__((unused)), hwd_control_state_t *ctl, long long **val, int flags __attribute__((unused))) +{ + templ_control_t *templ_ctl = (templ_control_t *) ctl; + return vendord_ctx_read(templ_ctl->vendor_ctx, val); +} + +int +templ_stop(hwd_context_t *ctx, hwd_control_state_t *ctl) +{ + int papi_errno = PAPI_OK; + templ_context_t *templ_ctx = (templ_context_t *) ctx; + templ_control_t *templ_ctl = (templ_control_t *) ctl; + + if (!(templ_ctx->state & TEMPL_CTX_OPENED)) { + return PAPI_EINVAL; + } + + papi_errno = vendord_ctx_stop(templ_ctl->vendor_ctx); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + templ_ctx->state &= ~TEMPL_CTX_RUNNING; + + papi_errno = vendord_ctx_close(templ_ctl->vendor_ctx); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + templ_ctx->state = 0; + templ_ctl->vendor_ctx = NULL; + + return papi_errno; +} + +int +templ_reset(hwd_context_t *ctx __attribute__((unused)), hwd_control_state_t *ctl) +{ + templ_control_t *templ_ctl = (templ_control_t *) ctl; + return vendord_ctx_reset(templ_ctl->vendor_ctx); +} + +int +templ_ntv_enum_events(unsigned int *event_code, int modifier) +{ + int papi_errno = check_n_initialize(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendord_evt_enum(event_code, modifier); +} + +int +templ_ntv_code_to_name(unsigned int event_code, char *name, int len) +{ + int papi_errno = check_n_initialize(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendord_evt_code_to_name(event_code, name, len); +} + +int +templ_ntv_name_to_code(const char *name, unsigned int *code) +{ + int papi_errno = check_n_initialize(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendord_evt_name_to_code(name, code); +} + +int +templ_ntv_code_to_descr(unsigned int event_code, char *descr, int len) +{ + int papi_errno = check_n_initialize(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendord_evt_code_to_descr(event_code, descr, len); +} + +int +templ_ntv_code_to_info(unsigned int event_code, PAPI_event_info_t *info) +{ + int papi_errno = check_n_initialize(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendord_evt_code_to_info(event_code, info); +} + +int +templ_set_domain(hwd_control_state_t *ctl __attribute__((unused)), int domain __attribute__((unused))) +{ + return PAPI_OK; +} + +int +templ_ctl(hwd_context_t *ctx __attribute__((unused)), int code __attribute__((unused)), _papi_int_option_t *option __attribute__((unused))) +{ + return PAPI_OK; +} + +int +check_n_initialize(void) +{ + if (!_template_vector.cmp_info.initialized) { + return templ_init_private(); + } + return _template_vector.cmp_info.disabled; +} diff --git a/src/components/template/tests/Makefile b/src/components/template/tests/Makefile new file mode 100644 index 000000000..9bd06aeb3 --- /dev/null +++ b/src/components/template/tests/Makefile @@ -0,0 +1,18 @@ +NAME=template +include ../../Makefile_comp_tests.target + +CFLAGS = $(OPTFLAGS) +CPPFLAGS += $(INCLUDE) +LDFLAGS += $(PAPILIB) $(TESTLIB) $(UTILOBJS) + +TESTS = simple +template_tests: $(TESTS) + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(OPTFLAGS) -c -o $@ $< + +simple: simple.o + $(CC) -o $@ $^ $(LDFLAGS) + +clean: + rm -f $(TESTS) *.o diff --git a/src/components/template/tests/simple.c b/src/components/template/tests/simple.c new file mode 100644 index 000000000..2a8b12ce4 --- /dev/null +++ b/src/components/template/tests/simple.c @@ -0,0 +1,94 @@ +#include +#include +#include + +int quiet; + +int main(int argc, char *argv[]) +{ + int papi_errno; + + quiet = tests_quiet(argc, argv); + + papi_errno = PAPI_library_init(PAPI_VER_CURRENT); + if (papi_errno != PAPI_VER_CURRENT) { + test_fail(__FILE__, __LINE__, "PAPI_library_init", papi_errno); + } + +#define NUM_EVENTS (4) + const char *events[NUM_EVENTS] = { + "templ:::TEMPLATE_ZERO:device=0", + "templ:::TEMPLATE_CONSTANT:device=1", + "templ:::TEMPLATE_FUNCTION:device=2:function=exp", + "templ:::TEMPLATE_FUNCTION:device=3:function=sum", + }; + + int eventset = PAPI_NULL; + papi_errno = PAPI_create_eventset(&eventset); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_create_eventset", papi_errno); + } + + for (int i = 0; i < NUM_EVENTS; ++i) { + papi_errno = PAPI_add_named_event(eventset, events[i]); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_add_named_event", papi_errno); + } + } + + long long counters[NUM_EVENTS] = { 0 }; + papi_errno = PAPI_start(eventset); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_start", papi_errno); + } + + papi_errno = PAPI_read(eventset, counters); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_read", papi_errno); + } + + for (int i = 0; i < NUM_EVENTS && !quiet; ++i) { + fprintf(stdout, "%s: %lli\n", events[i], counters[i]); + } + + papi_errno = PAPI_read(eventset, counters); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_read", papi_errno); + } + + for (int i = 0; i < NUM_EVENTS && !quiet; ++i) { + fprintf(stdout, "%s: %lli\n", events[i], counters[i]); + } + + papi_errno = PAPI_read(eventset, counters); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_read", papi_errno); + } + + for (int i = 0; i < NUM_EVENTS && !quiet; ++i) { + fprintf(stdout, "%s: %lli\n", events[i], counters[i]); + } + + papi_errno = PAPI_stop(eventset, counters); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_read", papi_errno); + } + + for (int i = 0; i < NUM_EVENTS && !quiet; ++i) { + fprintf(stdout, "%s: %lli\n", events[i], counters[i]); + } + + papi_errno = PAPI_cleanup_eventset(eventset); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_cleanup_eventset", papi_errno); + } + + papi_errno = PAPI_destroy_eventset(&eventset); + if (papi_errno != PAPI_OK) { + test_fail(__FILE__, __LINE__, "PAPI_destroy_eventset", papi_errno); + } + + PAPI_shutdown(); + test_pass(__FILE__); + return 0; +} diff --git a/src/components/template/vendor_common.c b/src/components/template/vendor_common.c new file mode 100644 index 000000000..c5aaec6b4 --- /dev/null +++ b/src/components/template/vendor_common.c @@ -0,0 +1,92 @@ +#include "vendor_common.h" + +char error_string[PAPI_MAX_STR_LEN]; +unsigned int _templ_lock; + +device_table_t device_table; +device_table_t *device_table_p; + +static int load_common_symbols(void); +static int unload_common_symbols(void); +static int initialize_device_table(void); +static int finalize_device_table(void); + +int +vendorc_init(void) +{ + int papi_errno; + + papi_errno = load_common_symbols(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + papi_errno = initialize_device_table(); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + device_table_p = &device_table; + + fn_exit: + return papi_errno; + fn_fail: + unload_common_symbols(); + goto fn_exit; +} + +int +vendorc_shutdown(void) +{ + finalize_device_table(); + device_table_p = NULL; + unload_common_symbols(); + return PAPI_OK; +} + +int +vendorc_err_get_last(const char **error) +{ + *error = error_string; + return PAPI_OK; +} + +int +load_common_symbols(void) +{ + return PAPI_OK; +} + +int +unload_common_symbols(void) +{ + return PAPI_OK; +} + +int +initialize_device_table(void) +{ +#define MAX_DEVICE_COUNT (8) + device_t *devices = papi_calloc(MAX_DEVICE_COUNT, sizeof(device_t)); + if (NULL == devices) { + return PAPI_ENOMEM; + } + + int i; + for (i = 0; i < MAX_DEVICE_COUNT; ++i) { + devices[i].id = (unsigned int) i; + } + + device_table.devices = devices; + device_table.num_devices = MAX_DEVICE_COUNT; + + return PAPI_OK; +} + +int +finalize_device_table(void) +{ + papi_free(device_table_p->devices); + device_table_p->num_devices = 0; + return PAPI_OK; +} diff --git a/src/components/template/vendor_common.h b/src/components/template/vendor_common.h new file mode 100644 index 000000000..fde8cc421 --- /dev/null +++ b/src/components/template/vendor_common.h @@ -0,0 +1,31 @@ +/* + * This file contains all the functions that are shared between + * different vendor versions of the profiling library. This can + * include vendor runtime functionalities. + */ +#ifndef __VENDOR_COMMON_H__ +#define __VENDOR_COMMON_H__ + +#include +#include "papi.h" +#include "papi_memory.h" +#include "papi_internal.h" +#include "vendor_config.h" + +typedef struct { + unsigned int id; +} device_t; + +typedef struct { + device_t *devices; + int num_devices; +} device_table_t; + +extern char error_string[PAPI_MAX_STR_LEN]; +extern device_table_t *device_table_p; + +int vendorc_init(void); +int vendorc_shutdown(void); +int vendorc_err_get_last(const char **error); + +#endif diff --git a/src/components/template/vendor_config.h b/src/components/template/vendor_config.h new file mode 100644 index 000000000..45a260508 --- /dev/null +++ b/src/components/template/vendor_config.h @@ -0,0 +1,11 @@ +#ifndef __VENDOR_CONFIG_H__ +#define __VENDOR_CONFIG_H__ + +#define TEMPL_CTX_OPENED (0x1) +#define TEMPL_CTX_RUNNING (0x2) + +#include "papi.h" + +extern unsigned int _templ_lock; + +#endif diff --git a/src/components/template/vendor_dispatch.c b/src/components/template/vendor_dispatch.c new file mode 100644 index 000000000..df1087c1f --- /dev/null +++ b/src/components/template/vendor_dispatch.c @@ -0,0 +1,101 @@ +#include "vendor_dispatch.h" +#include "vendor_common.h" +#include "vendor_profiler_v1.h" + +int +vendord_init_pre(void) +{ + return vendorp1_init_pre(); +} + +int +vendord_init(void) +{ + int papi_errno = vendorc_init(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendorp1_init(); +} + +int +vendord_shutdown(void) +{ + int papi_errno = vendorp1_shutdown(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + return vendorc_shutdown(); +} + +int +vendord_ctx_open(unsigned int *events_id, int num_events, vendord_ctx_t *ctx) +{ + return vendorp1_ctx_open(events_id, num_events, ctx); +} + +int +vendord_ctx_start(vendord_ctx_t ctx) +{ + return vendorp1_ctx_start(ctx); +} + +int +vendord_ctx_read(vendord_ctx_t ctx, long long **counters) +{ + return vendorp1_ctx_read(ctx, counters); +} + +int +vendord_ctx_stop(vendord_ctx_t ctx) +{ + return vendorp1_ctx_stop(ctx); +} + +int +vendord_ctx_reset(vendord_ctx_t ctx) +{ + return vendorp1_ctx_reset(ctx); +} + +int +vendord_ctx_close(vendord_ctx_t ctx) +{ + return vendorp1_ctx_close(ctx); +} + +int +vendord_err_get_last(const char **error) +{ + return vendorc_err_get_last(error); +} + +int +vendord_evt_enum(unsigned int *event_code, int modifier) +{ + return vendorp1_evt_enum(event_code, modifier); +} + +int +vendord_evt_code_to_name(unsigned int event_code, char *name, int len) +{ + return vendorp1_evt_code_to_name(event_code, name, len); +} + +int +vendord_evt_code_to_descr(unsigned int event_code, char *descr, int len) +{ + return vendorp1_evt_code_to_descr(event_code, descr, len); +} + +int +vendord_evt_code_to_info(unsigned int event_code, PAPI_event_info_t *info) +{ + return vendorp1_evt_code_to_info(event_code, info); +} + +int +vendord_evt_name_to_code(const char *name, unsigned int *event_code) +{ + return vendorp1_evt_name_to_code(name, event_code); +} diff --git a/src/components/template/vendor_dispatch.h b/src/components/template/vendor_dispatch.h new file mode 100644 index 000000000..cdcd1a141 --- /dev/null +++ b/src/components/template/vendor_dispatch.h @@ -0,0 +1,27 @@ +#ifndef __VENDOR_DISPATCH_H__ +#define __VENDOR_DISPATCH_H__ + +#include "vendor_config.h" + +typedef struct vendord_ctx *vendord_ctx_t; + +int vendord_init_pre(void); +int vendord_init(void); +int vendord_shutdown(void); + +int vendord_ctx_open(unsigned int *events_id, int num_events, vendord_ctx_t *ctx); +int vendord_ctx_start(vendord_ctx_t ctx); +int vendord_ctx_read(vendord_ctx_t ctx, long long **counters); +int vendord_ctx_stop(vendord_ctx_t ctx); +int vendord_ctx_reset(vendord_ctx_t ctx); +int vendord_ctx_close(vendord_ctx_t ctx); + +int vendord_err_get_last(const char **error); + +int vendord_evt_enum(unsigned int *event_code, int modifier); +int vendord_evt_code_to_name(unsigned int event_code, char *name, int len); +int vendord_evt_code_to_descr(unsigned int event_code, char *descr, int len); +int vendord_evt_code_to_info(unsigned int event_code, PAPI_event_info_t *info); +int vendord_evt_name_to_code(const char *name, unsigned int *event_code); + +#endif diff --git a/src/components/template/vendor_profiler_v1.c b/src/components/template/vendor_profiler_v1.c new file mode 100644 index 000000000..c43a0fe09 --- /dev/null +++ b/src/components/template/vendor_profiler_v1.c @@ -0,0 +1,623 @@ +/* include for rand() */ +#include +#include +#include "vendor_common.h" +#include "vendor_profiler_v1.h" + +/** + * Event identifier encoding format: + * +--------------------+-------+-+--+--+ + * | unused | dev | | |id| + * +--------------------+-------+-+--+--+ + * + * unused : 18 bits + * device : 7 bits ([0 - 127] devices) + * function : 1 bits (exponential or sum) + * qlmask : 2 bits (qualifier mask) + * nameid : 2 bits ([0 - 3] event names) + */ +#define EVENTS_WIDTH (sizeof(uint32_t) * 8) +#define DEVICE_WIDTH (7) +#define OPCODE_WIDTH (1) +#define QLMASK_WIDTH (2) +#define NAMEID_WIDTH (2) +#define UNUSED_WIDTH (EVENTS_WIDTH - DEVICE_WIDTH - OPCODE_WIDTH - QLMASK_WIDTH - NAMEID_WIDTH) +#define DEVICE_SHIFT (EVENTS_WIDTH - UNUSED_WIDTH - DEVICE_WIDTH) +#define OPCODE_SHIFT (DEVICE_SHIFT - OPCODE_WIDTH) +#define QLMASK_SHIFT (OPCODE_SHIFT - QLMASK_WIDTH) +#define NAMEID_SHIFT (QLMASK_SHIFT - NAMEID_WIDTH) +#define DEVICE_MASK ((0xFFFFFFFF >> (EVENTS_WIDTH - DEVICE_WIDTH)) << DEVICE_SHIFT) +#define OPCODE_MASK ((0xFFFFFFFF >> (EVENTS_WIDTH - OPCODE_WIDTH)) << OPCODE_SHIFT) +#define QLMASK_MASK ((0xFFFFFFFF >> (EVENTS_WIDTH - QLMASK_WIDTH)) << QLMASK_SHIFT) +#define NAMEID_MASK ((0xFFFFFFFF >> (EVENTS_WIDTH - NAMEID_WIDTH)) << NAMEID_SHIFT) +#define DEVICE_FLAG (0x2) +#define OPCODE_FLAG (0x1) +#define OPCODE_EXP (0x0) +#define OPCODE_SUM (0x1) + +typedef struct { + char name[PAPI_MAX_STR_LEN]; + char descr[PAPI_2MAX_STR_LEN]; +} ntv_event_t; + +typedef struct { + ntv_event_t *events; + int num_events; +} ntv_event_table_t; + +struct vendord_ctx { + int state; + unsigned int *events_id; + long long *counters; + int num_events; +}; + +static struct { + char *name; + char *descr; +} vendor_events[] = { + { "TEMPLATE_ZERO" , "This is a template counter, that always returns 0" }, + { "TEMPLATE_CONSTANT", "This is a template counter, that always returns a constant value of 42" }, + { "TEMPLATE_FUNCTION", "This is a template counter, that allows for different functions" }, + { NULL, NULL } +}; + +static ntv_event_table_t ntv_table; +static ntv_event_table_t *ntv_table_p; + +int +vendorp1_init_pre(void) +{ + return PAPI_OK; +} + +static int load_profiler_v1_symbols(void); +static int unload_profiler_v1_symbols(void); +static int initialize_event_table(void); +static int finalize_event_table(void); + +typedef struct { + int device; + int opcode; + int flags; + int nameid; +} event_info_t; + +static int evt_id_create(event_info_t *info, uint32_t *event_id); +static int evt_id_to_info(uint32_t event_id, event_info_t *info); +static int evt_name_to_device(const char *name, int *device); +static int evt_name_to_opcode(const char *name, int *opcode); +static int evt_name_to_basename(const char *name, char *base, int len); + +int +vendorp1_init(void) +{ + int papi_errno; + + papi_errno = load_profiler_v1_symbols(); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + papi_errno = initialize_event_table(); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + ntv_table_p = &ntv_table; + + fn_exit: + return papi_errno; + fn_fail: + finalize_event_table(); + unload_profiler_v1_symbols(); + goto fn_exit; +} + +int +vendorp1_shutdown(void) +{ + finalize_event_table(); + ntv_table_p = NULL; + unload_profiler_v1_symbols(); + return PAPI_OK; +} + +static int init_ctx(unsigned int *events_id, int num_events, vendorp_ctx_t ctx); +static int open_ctx(vendorp_ctx_t ctx); +static int close_ctx(vendorp_ctx_t ctx); +static int finalize_ctx(vendorp_ctx_t ctx); + +int +vendorp1_ctx_open(unsigned int *events_id, int num_events, vendorp_ctx_t *ctx) +{ + int papi_errno; + + /* FIXME: make sure the provided events are valid */ + + *ctx = papi_calloc(1, sizeof(struct vendord_ctx)); + if (NULL == *ctx) { + return PAPI_ENOMEM; + } + + _papi_hwi_lock(_templ_lock); + + papi_errno = init_ctx(events_id, num_events, *ctx); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + papi_errno = open_ctx(*ctx); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + (*ctx)->state |= TEMPL_CTX_OPENED; + + fn_exit: + _papi_hwi_unlock(_templ_lock); + return papi_errno; + fn_fail: + close_ctx(*ctx); + finalize_ctx(*ctx); + goto fn_exit; +} + +int +vendorp1_ctx_start(vendorp_ctx_t ctx) +{ + ctx->state |= TEMPL_CTX_RUNNING; + return PAPI_OK; +} + +int +vendorp1_ctx_read(vendorp_ctx_t ctx, long long **counters) +{ + int papi_errno; + + int i; + for (i = 0; i < ctx->num_events; ++i) { + event_info_t info; + papi_errno = evt_id_to_info(ctx->events_id[i], &info); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + if (0 == strcmp(ntv_table_p->events[info.nameid].name, "TEMPLATE_ZERO")) { + ctx->counters[i] = (long long) 0; + } else if (0 == strcmp(ntv_table_p->events[info.nameid].name, "TEMPLATE_CONSTANT")) { + ctx->counters[i] = (long long) 42; + } else if (0 == strcmp(ntv_table_p->events[info.nameid].name, "TEMPLATE_FUNCTION")) { + if (info.opcode == OPCODE_EXP) { + ctx->counters[i] = (ctx->counters[i]) ? ctx->counters[i] * 2 : 2; + } else { + ctx->counters[i] = (ctx->counters[i]) ? ctx->counters[i] + 1 : 1; + } + } + } + *counters = ctx->counters; + return PAPI_OK; +} + +int +vendorp1_ctx_stop(vendorp_ctx_t ctx) +{ + ctx->state &= ~TEMPL_CTX_RUNNING; + return PAPI_OK; +} + +int +vendorp1_ctx_reset(vendorp_ctx_t ctx) +{ + memset(ctx->counters, 0, sizeof(ctx->counters) * ctx->num_events); + return PAPI_OK; +} + +int +vendorp1_ctx_close(vendorp_ctx_t ctx) +{ + int papi_errno; + + _papi_hwi_lock(_templ_lock); + + papi_errno = close_ctx(ctx); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + ctx->state &= ~TEMPL_CTX_OPENED; + + papi_errno = finalize_ctx(ctx); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + papi_free(ctx); + + fn_exit: + _papi_hwi_unlock(_templ_lock); + return papi_errno; + fn_fail: + goto fn_exit; + +} + +int +vendorp1_evt_enum(unsigned int *event_code, int modifier) +{ + int papi_errno; + + event_info_t info; + papi_errno = evt_id_to_info(*event_code, &info); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + switch(modifier) { + case PAPI_ENUM_FIRST: + if (ntv_table_p->num_events == 0) { + papi_errno = PAPI_ENOEVNT; + } + info.device = 0; + info.opcode = 0; + info.flags = 0; + info.nameid = 0; + papi_errno = evt_id_create(&info, event_code); + break; + case PAPI_ENUM_EVENTS: + if (info.nameid + 1 >= ntv_table_p->num_events) { + papi_errno = PAPI_ENOEVNT; + break; + } + ++info.nameid; + papi_errno = evt_id_create(&info, event_code); + break; + case PAPI_NTV_ENUM_UMASKS: + if (info.flags == 0) { + info.flags = DEVICE_FLAG; + papi_errno = evt_id_create(&info, event_code); + break; + } + if (info.flags & DEVICE_FLAG && info.nameid == 2) { + info.flags = OPCODE_FLAG; + papi_errno = evt_id_create(&info, event_code); + break; + } + papi_errno = PAPI_END; + break; + default: + papi_errno = PAPI_EINVAL; + } + + return papi_errno; +} + +int +vendorp1_evt_code_to_name(unsigned int event_code, char *name, int len) +{ + int papi_errno; + + event_info_t info; + papi_errno = evt_id_to_info(event_code, &info); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + /* FIXME: make sure the event_code provided by the user is valid */ + + switch (info.flags) { + case DEVICE_FLAG | OPCODE_FLAG: + snprintf(name, len, "%s:device=%i:function=%s", + ntv_table_p->events[info.nameid].name, + info.device, (info.opcode == OPCODE_EXP) ? "exp" : "sum"); + break; + case DEVICE_FLAG: + snprintf(name, len, "%s:device=%i", + ntv_table_p->events[info.nameid].name, + info.device); + break; + case OPCODE_FLAG: + snprintf(name, len, "%s:function=%s", + ntv_table_p->events[info.nameid].name, + (info.opcode == OPCODE_EXP) ? "exp" : "sum"); + break; + default: + papi_errno = PAPI_ENOEVNT; + } + + snprintf(name, len, "%s", ntv_table_p->events[info.nameid].name); + return papi_errno; +} + +int +vendorp1_evt_code_to_descr(unsigned int event_code, char *descr, int len) +{ + int papi_errno; + + event_info_t info; + papi_errno = evt_id_to_info(event_code, &info); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + /* FIXME: make sure the event_code provided by the user is valid */ + + snprintf(descr, len, "%s", ntv_table_p->events[info.nameid].descr); + return PAPI_OK; +} + +int +vendorp1_evt_code_to_info(unsigned int event_code, PAPI_event_info_t *info) +{ + int papi_errno; + + event_info_t code_info; + papi_errno = evt_id_to_info(event_code, &code_info); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + /* FIXME: make sure the event_code provided by the user is valid */ + + switch (code_info.flags) { + case 0: + sprintf(info->symbol, "%s", ntv_table_p->events[code_info.nameid].name); + sprintf(info->long_descr, "%s", ntv_table_p->events[code_info.nameid].descr); + break; + case DEVICE_FLAG | OPCODE_FLAG: + sprintf(info->symbol, "%s:device=%i:function=%s", + ntv_table_p->events[code_info.nameid].name, + code_info.device, + (code_info.opcode == OPCODE_EXP) ? "exp" : "sum"); + sprintf(info->long_descr, "%s", ntv_table_p->events[code_info.nameid].descr); + break; + case DEVICE_FLAG: + { + int i; + char devices[PAPI_MAX_STR_LEN] = { 0 }; + for (i = 0; i < device_table_p->num_devices; ++i) { + sprintf(devices + strlen(devices), "%i,", i); + } + *(devices + strlen(devices) - 1) = 0; + sprintf(info->symbol, "%s:device=%i", ntv_table_p->events[code_info.nameid].name, code_info.device); + sprintf(info->long_descr, "%s masks:Mandatory device qualifier [%s]", + ntv_table_p->events[code_info.nameid].descr, devices); + break; + } + case OPCODE_FLAG: + sprintf(info->symbol, "%s:function=%s", + ntv_table_p->events[code_info.nameid].name, + (code_info.opcode == OPCODE_EXP) ? "exp" : "sum"); + sprintf(info->long_descr, "%s masks:Mandatory function qualifier (exp,sum)", + ntv_table_p->events[code_info.nameid].descr); + break; + default: + papi_errno = PAPI_EINVAL; + } + + return papi_errno; +} + +int +vendorp1_evt_name_to_code(const char *name, unsigned int *event_code) +{ + int papi_errno; + + char basename[PAPI_MAX_STR_LEN] = { 0 }; + papi_errno = evt_name_to_basename(name, basename, PAPI_MAX_STR_LEN); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + int device; + papi_errno = evt_name_to_device(name, &device); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + int opcode = 0; + papi_errno = evt_name_to_opcode(name, &opcode); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + int i, nameid = 0; + for (i = 0; i < ntv_table_p->num_events; ++i) { + if (0 == strcmp(ntv_table_p->events[i].name, basename)) { + nameid = i; + break; + } + } + + /* FIXME: make sure event name provided by user is valid */ + + event_info_t info = { 0, 0, 0, 0 }; + if (0 == strcmp(ntv_table_p->events[nameid].name, "TEMPLATE_FUNCTION")) { + info.device = device; + info.opcode = opcode; + info.flags = (DEVICE_FLAG | OPCODE_FLAG); + info.nameid = nameid; + papi_errno = evt_id_create(&info, event_code); + } else { + info.device = device; + info.opcode = 0; + info.flags = DEVICE_FLAG; + info.nameid = nameid; + papi_errno = evt_id_create(&info, event_code); + } + + return papi_errno; +} + +int +load_profiler_v1_symbols(void) +{ + return PAPI_OK; +} + +int +unload_profiler_v1_symbols(void) +{ + return PAPI_OK; +} + +static int get_events_count(int *num_events); +static int get_events(ntv_event_t *events, int num_events); + +int +initialize_event_table(void) +{ + int papi_errno, num_events; + + papi_errno = get_events_count(&num_events); + if (papi_errno != PAPI_OK) { + return papi_errno; + } + + ntv_event_t *events = papi_calloc(num_events, sizeof(ntv_event_t)); + if (NULL == events) { + return PAPI_ENOMEM; + } + + papi_errno = get_events(events, num_events); + if (papi_errno != PAPI_OK) { + goto fn_fail; + } + + ntv_table.events = events; + ntv_table.num_events = num_events; + + fn_exit: + return papi_errno; + fn_fail: + papi_free(events); + goto fn_exit; +} + +int +finalize_event_table(void) +{ + papi_free(ntv_table_p->events); + ntv_table_p->num_events = 0; + ntv_table_p = NULL; + return PAPI_OK; +} + +int +init_ctx(unsigned int *events_id, int num_events, vendorp_ctx_t ctx) +{ + ctx->events_id = events_id; + ctx->num_events = num_events; + ctx->counters = papi_calloc(num_events, sizeof(long long)); + if (NULL == ctx->counters) { + return PAPI_ENOMEM; + } + return PAPI_OK; +} + +int +open_ctx(vendorp_ctx_t ctx __attribute__((unused))) +{ + return PAPI_OK; +} + +int +close_ctx(vendorp_ctx_t ctx __attribute__((unused))) +{ + return PAPI_OK; +} + +int +finalize_ctx(vendorp_ctx_t ctx) +{ + ctx->events_id = NULL; + ctx->num_events = 0; + papi_free(ctx->counters); + return PAPI_OK; +} + +int +get_events_count(int *num_events) +{ + int i = 0; + while (vendor_events[i++].name != NULL); + *num_events = i - 1; + return PAPI_OK; +} + +int +get_events(ntv_event_t *events, int num_events) +{ + int i = 0; + while (vendor_events[i].name != NULL) { + snprintf(events[i].name, PAPI_MAX_STR_LEN, "%s", vendor_events[i].name); + snprintf(events[i].descr, PAPI_2MAX_STR_LEN, "%s", vendor_events[i].descr); + ++i; + } + return (num_events - i) ? PAPI_EMISC : PAPI_OK; +} + +int +evt_id_create(event_info_t *info, uint32_t *event_id) +{ + *event_id = (uint32_t)(info->device << DEVICE_SHIFT); + *event_id |= (uint32_t)(info->opcode << OPCODE_SHIFT); + *event_id |= (uint32_t)(info->flags << QLMASK_SHIFT); + *event_id |= (uint32_t)(info->nameid << NAMEID_SHIFT); + return PAPI_OK; +} + +int +evt_id_to_info(uint32_t event_id, event_info_t *info) +{ + info->device = (int)((event_id & DEVICE_MASK) >> DEVICE_SHIFT); + info->opcode = (int)((event_id & OPCODE_MASK) >> OPCODE_SHIFT); + info->flags = (int)((event_id & QLMASK_MASK) >> QLMASK_SHIFT); + info->nameid = (int)((event_id & NAMEID_MASK) >> NAMEID_SHIFT); + return PAPI_OK; +} + +int +evt_name_to_device(const char *name, int *device) +{ + *device = 0; + char *p = strstr(name, ":device="); + if (p) { + *device = (int) strtol(p + strlen(":device="), NULL, 10); + } + return PAPI_OK; +} + +int +evt_name_to_opcode(const char *name, int *opcode) +{ + char *p = strstr(name, ":function="); + if (p) { + if (strcmp(p + strlen(":function="), "exp") == 0) { + *opcode = OPCODE_EXP; + } else if (strcmp(p + strlen(":function="), "sum") == 0) { + *opcode = OPCODE_SUM; + } else { + return PAPI_ENOEVNT; + } + } + return PAPI_OK; +} + +int +evt_name_to_basename(const char *name, char *base, int len) +{ + char *p = strstr(name, ":"); + if (p) { + if (len < (int)(p - name)) { + return PAPI_EBUF; + } + strncpy(base, name, (size_t)(p - name)); + } else { + if (len < (int) strlen(name)) { + return PAPI_EBUF; + } + strncpy(base, name, (size_t) len); + } + return PAPI_OK; +} diff --git a/src/components/template/vendor_profiler_v1.h b/src/components/template/vendor_profiler_v1.h new file mode 100644 index 000000000..81bb72700 --- /dev/null +++ b/src/components/template/vendor_profiler_v1.h @@ -0,0 +1,23 @@ +#ifndef __VENDOR_PROFILER_V1_H__ +#define __VENDOR_PROFILER_V1_H__ + +typedef struct vendord_ctx *vendorp_ctx_t; + +int vendorp1_init_pre(void); +int vendorp1_init(void); +int vendorp1_shutdown(void); + +int vendorp1_ctx_open(unsigned int *events_id, int num_events, vendorp_ctx_t *ctx); +int vendorp1_ctx_start(vendorp_ctx_t ctx); +int vendorp1_ctx_read(vendorp_ctx_t ctx, long long **counters); +int vendorp1_ctx_stop(vendorp_ctx_t ctx); +int vendorp1_ctx_reset(vendorp_ctx_t ctx); +int vendorp1_ctx_close(vendorp_ctx_t ctx); + +int vendorp1_evt_enum(unsigned int *event_code, int modifier); +int vendorp1_evt_code_to_name(unsigned int event_code, char *name, int len); +int vendorp1_evt_code_to_descr(unsigned int event_code, char *descr, int len); +int vendorp1_evt_code_to_info(unsigned int event_code, PAPI_event_info_t *info); +int vendorp1_evt_name_to_code(const char *name, unsigned int *event_code); + +#endif