/* * Copyright (C) 2014 Artem Polyakov * Copyright (c) 2014-2020 Intel, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_UTIL_TIMING_H #define PMIX_UTIL_TIMING_H #include "src/include/pmix_config.h" #include "src/class/pmix_list.h" #if PMIX_ENABLE_TIMING # define PMIX_TIMING_DESCR_MAX 1024 # define PMIX_TIMING_BUFSIZE 32 # define PMIX_TIMING_OUTBUF_SIZE (10 * 1024) typedef enum { PMIX_TIMING_TRACE, PMIX_TIMING_INTDESCR, PMIX_TIMING_INTBEGIN, PMIX_TIMING_INTEND } pmix_event_type_t; typedef struct { pmix_list_item_t super; int fib; pmix_event_type_t type; const char *func; const char *file; int line; double ts, ts_ovh; char descr[PMIX_TIMING_DESCR_MAX]; int id; } pmix_timing_event_t; typedef double (*get_ts_t)(void); typedef struct pmix_timing_t { int next_id_cntr; // not thread safe! // The whole implementation is not thread safe now // since it is supposed to be used in service // thread only. Fix in the future or now? int current_id; pmix_list_t *events; pmix_timing_event_t *buffer; size_t buffer_offset, buffer_size; get_ts_t get_ts; } pmix_timing_t; typedef struct { pmix_timing_t *t; pmix_timing_event_t *ev; int errcode; } pmix_timing_prep_t; /* Pass down our namespace and rank for pretty-print purposes */ PMIX_EXPORT void pmix_init_id(char *nspace, int rank); /** * Initialize timing structure. * * @param t pointer to the timing handler structure */ PMIX_EXPORT void pmix_timing_init(pmix_timing_t *t); /** * Prepare timing event, do all printf-like processing. * Should not be directly used - for service purposes only. * * @param t pointer to the timing handler structure * @param fmt printf-like format * @param ... other parameters that should be converted to string representation * * @retval partly filled pmix_timing_prep_t structure */ PMIX_EXPORT pmix_timing_prep_t pmix_timing_prep_ev(pmix_timing_t *t, const char *fmt, ...); /** * Prepare timing event, ignore printf-like processing. * Should not be directly used - for service purposes only. * * @param t pointer to the timing handler structure * @param fmt printf-like format * @param ... other parameters that should be converted to string representation * * @retval partly filled pmix_timing_prep_t structure */ PMIX_EXPORT pmix_timing_prep_t pmix_timing_prep_ev_end(pmix_timing_t *t, const char *fmt, ...); /** * Enqueue timing event into the list of events in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval */ PMIX_EXPORT void pmix_timing_add_step(pmix_timing_prep_t p, const char *func, const char *file, int line); /** * Enqueue the description of the interval into a list of events * in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval id of event interval */ PMIX_EXPORT int pmix_timing_descr(pmix_timing_prep_t p, const char *func, const char *file, int line); /** * Enqueue the beginning of timing interval that already has the * description and assigned id into the list of events * in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval */ PMIX_EXPORT void pmix_timing_start_id(pmix_timing_t *t, int id, const char *func, const char *file, int line); /** * Enqueue the end of timing interval that already has * description and assigned id into the list of events * in handler 't'. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval */ PMIX_EXPORT void pmix_timing_end(pmix_timing_t *t, int id, const char *func, const char *file, int line); /** * Enqueue both description and start of timing interval * into the list of events and assign its id. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval interval id */ static inline int pmix_timing_start_init(pmix_timing_prep_t p, const char *func, const char *file, int line) { int id = pmix_timing_descr(p, func, file, line); if (id < 0) return id; pmix_timing_start_id(p.t, id, func, file, line); return id; } /** * The wrapper that is used to stop last measurement in PMIX_TIMING_MNEXT. * * @param p result of pmix_timing_prep_ev * @param func function name where event occurs * @param file file name where event occurs * @param line line number in the file * * @retval interval id */ PMIX_EXPORT void pmix_timing_end_prep(pmix_timing_prep_t p, const char *func, const char *file, int line); /** * Report all events that were enqueued in the timing handler 't'. * - if fname == NULL the output will be done using pmix_output and * each line will be prefixed with "prefix" to ease grep'ing. * - otherwise the corresponding file will be used for output in "append" mode * WARRNING: not all filesystems provide enough support for that feature, some records may * disappear. * * @param t timing handler * @param account_overhead consider malloc overhead introduced by timing code * @param prefix prefix to use when no fname was specified to ease grep'ing * @param fname name of the output file (may be NULL) * * @retval PMIX_SUCCESS On success * @retval PMIX_ERROR or PMIX_ERR_OUT_OF_RESOURCE On failure */ PMIX_EXPORT pmix_status_t pmix_timing_report(pmix_timing_t *t, char *fname); /** * Report all intervals that were enqueued in the timing handler 't'. * - if fname == NULL the output will be done using pmix_output and * each line will be prefixed with "prefix" to ease grep'ing. * - otherwise the corresponding file will be used for output in "append" mode * WARRNING: not all filesystems provide enough support for that feature, some records may * disappear. * * @param t timing handler * @param account_overhead consider malloc overhead introduced by timing code * @param fname name of the output file (may be NULL) * * @retval PMIX_SUCCESS On success * @retval PMIX_ERROR or PMIX_ERR_OUT_OF_RESOURCE On failure */ PMIX_EXPORT pmix_status_t pmix_timing_deltas(pmix_timing_t *t, char *fname); /** * Release all memory allocated for the timing handler 't'. * * @param t timing handler * * @retval */ PMIX_EXPORT void pmix_timing_release(pmix_timing_t *t); /** * Macro for passing down process id - compiled out * when configured without --enable-timing */ # define PMIX_TIMING_ID(n, r) pmix_timing_id((n), (r)); /** * Main macro for use in declaring pmix timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * */ # define PMIX_TIMING_DECLARE(t) \ pmix_timing_t t; /* need semicolon here to avoid warnings when not enabled */ /** * Main macro for use in declaring external pmix timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * */ # define PMIX_TIMING_DECLARE_EXT(x, t) \ x extern pmix_timing_t t; /* need semicolon here to avoid warnings when not enabled */ /** * Main macro for use in initializing pmix timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_init() */ # define PMIX_TIMING_INIT(t) pmix_timing_init(t) /** * Macro that enqueues event with its description to the specified * timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_add_step() */ # define PMIX_TIMING_EVENT(x) \ pmix_timing_add_step(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__) /** * MDESCR: Measurement DESCRiption * Introduce new timing measurement with string description for the specified * timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_descr() */ # define PMIX_TIMING_MDESCR(x) \ pmix_timing_descr(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__) /** * MSTART_ID: Measurement START by ID. * Marks the beginning of the measurement with ID=id on the * specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_start_id() */ # define PMIX_TIMING_MSTART_ID(t, id) \ pmix_timing_start_id(t, id, __FUNCTION__, __FILE__, __LINE__) /** * MSTART: Measurement START * Introduce new timing measurement conjuncted with its start * on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_start_init() */ # define PMIX_TIMING_MSTART(x) \ pmix_timing_start_init(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__) /** * MSTOP: STOP Measurement * Finishes the most recent measurement on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_end() */ # define PMIX_TIMING_MSTOP(t) pmix_timing_end(t, -1, __FUNCTION__, __FILE__, __LINE__) /** * MSTOP_ID: STOP Measurement with ID=id. * Finishes the measurement with give ID on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_end() */ # define PMIX_TIMING_MSTOP_ID(t, id) pmix_timing_end(t, id, __FUNCTION__, __FILE__, __LINE__) /** * MNEXT: start NEXT Measurement * Convenient macro, may be implemented with the sequence of three previously * defined macros: * - finish current measurement (PMIX_TIMING_MSTOP); * - introduce new timing measurement (PMIX_TIMING_MDESCR); * - starts next measurement (PMIX_TIMING_MSTART_ID) * on the specified timing handler; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_start_init() */ # define PMIX_TIMING_MNEXT(x) \ (pmix_timing_end_prep(pmix_timing_prep_ev_end x, __FUNCTION__, __FILE__, __LINE__), \ pmix_timing_start_init(pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)) /** * The macro for use in reporting collected events with absolute values; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @param enable flag that enables/disables reporting. Used for fine-grained timing. * @see pmix_timing_report() */ # define PMIX_TIMING_REPORT(enable, t) \ { \ if (enable) { \ pmix_timing_report(t, pmix_timing_output); \ } \ } /** * The macro for use in reporting collected events with relative times; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @param enable flag that enables/disables reporting. Used for fine-grained timing. * @see pmix_timing_deltas() */ # define PMIX_TIMING_DELTAS(enable, t) \ { \ if (enable) { \ pmix_timing_deltas(t, pmix_timing_output); \ } \ } /** * Main macro for use in releasing allocated resources; * will be "compiled out" when PMIX is configured without * --enable-timing. * * @see pmix_timing_release() */ # define PMIX_TIMING_RELEASE(t) pmix_timing_release(t) #else # define PMIX_TIMING_ID(n, r) # define PMIX_TIMING_DECLARE(t) # define PMIX_TIMING_DECLARE_EXT(x, t) # define PMIX_TIMING_INIT(t) # define PMIX_TIMING_EVENT(x) # define PMIX_TIMING_MDESCR(x) # define PMIX_TIMING_MSTART_ID(t, id) # define PMIX_TIMING_MSTART(x) # define PMIX_TIMING_MSTOP(t) # define PMIX_TIMING_MSTOP_ID(t, id) # define PMIX_TIMING_MNEXT(x) # define PMIX_TIMING_REPORT(enable, t) # define PMIX_TIMING_DELTAS(enable, t) # define PMIX_TIMING_RELEASE(t) #endif #endif