From 517a37ae7beeb77e2b4870be11611f82c1200b3c Mon Sep 17 00:00:00 2001 From: Matthew Almond Date: Thu, 11 Jun 2020 13:01:04 -0700 Subject: [PATCH 2/2] Measure plugin --- macros.in | 1 + plugins/Makefile.am | 4 + plugins/measure.c | 231 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 plugins/measure.c diff --git a/macros.in b/macros.in index 3cc8a3555..c8a087959 100644 --- a/macros.in +++ b/macros.in @@ -1173,6 +1173,7 @@ package or when debugging this package.\ # Transaction plugin macros %__plugindir %{_libdir}/rpm-plugins +%__transaction_measure %{__plugindir}/measure.so %__transaction_systemd_inhibit %{__plugindir}/systemd_inhibit.so %__transaction_selinux %{__plugindir}/selinux.so %__transaction_syslog %{__plugindir}/syslog.so diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 06393ce8d..daed6423c 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -29,6 +29,10 @@ systemd_inhibit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/ plugins_LTLIBRARIES += systemd_inhibit.la endif +measure_la_SOURCES = measure.c +measure_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la +plugins_LTLIBRARIES += measure.la + prioreset_la_SOURCES = prioreset.c prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la plugins_LTLIBRARIES += prioreset.la diff --git a/plugins/measure.c b/plugins/measure.c new file mode 100644 index 000000000..2cdfc885e --- /dev/null +++ b/plugins/measure.c @@ -0,0 +1,231 @@ +#include "system.h" +#include "time.h" + +#include +#include +#include +#include "lib/rpmlib.h" + +#include "lib/rpmplugin.h" + +struct measurestat { + /* We're counting psm not packages because packages often run psm_pre/post + more than once and we want to accumulate the time + */ + unsigned int psm_count; + unsigned int scriptlet_count; + struct timespec plugin_start; + struct timespec psm_start; + struct timespec scriptlet_start; +}; + +static rpmRC push(const char *format, const char *value, const char *formatted) +{ + char *key = NULL; + rpmRC rc = RPMRC_FAIL; + if (formatted == NULL) { + /* yes we're okay with discarding const here */ + key = (char *)format; + } else { + if (rasprintf(&key, format, formatted) == -1) { + rpmlog( + RPMLOG_ERR, + _("measure: Failed to allocate formatted key %s, %s\n"), + format, + formatted + ); + goto exit; + } + } + if (rpmPushMacro(NULL, key, NULL, value, RMIL_GLOBAL)) { + rpmlog(RPMLOG_ERR, _("measure: Failed to set %s\n"), key); + goto exit; + } + rc = RPMRC_OK; +exit: + if (formatted != NULL) { + free(key); + } + return rc; +} + +static rpmRC diff_ms(char **ms, struct timespec *start, struct timespec *end) +{ + if (rasprintf(ms, "%ld", ( + (end->tv_sec - start->tv_sec) * 1000 + + (end->tv_nsec - start->tv_nsec) / 1000000 + )) == -1) { + rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted ms\n")); + return RPMRC_FAIL; + } + return RPMRC_OK; +} + +static rpmRC measure_init(rpmPlugin plugin, rpmts ts) +{ + rpmRC rc = RPMRC_FAIL; + struct measurestat *state = rcalloc(1, sizeof(*state)); + if (clock_gettime(CLOCK_MONOTONIC, &state->plugin_start)) { + rpmlog(RPMLOG_ERR, _("measure: Failed to get plugin_start time\n")); + goto exit; + } + state->psm_count = 0; + state->scriptlet_count = 0; + rpmPluginSetData(plugin, state); + rc = RPMRC_OK; +exit: + return rc; +} + +static void measure_cleanup(rpmPlugin plugin) +{ + struct measurestat *state = rpmPluginGetData(plugin); + free(state); +} + +static rpmRC measure_tsm_post(rpmPlugin plugin, rpmts ts, int res) +{ + struct measurestat *state = rpmPluginGetData(plugin); + char *psm_count = NULL, *scriptlet_count = NULL; + rpmRC rc = RPMRC_FAIL; + + if (rasprintf(&psm_count, "%d", state->psm_count) == -1) { + rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted psm_count\n")); + goto exit; + } + if (rasprintf(&scriptlet_count, "%d", state->scriptlet_count) == -1) { + rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted scriptlet_count\n")); + goto exit; + } + if (push("_measure_plugin_psm_count", psm_count, NULL) != RPMRC_OK) { + goto exit; + } + if (push("_measure_plugin_scriptlet_count", scriptlet_count, NULL) != RPMRC_OK) { + goto exit; + } + rc = RPMRC_OK; +exit: + free(psm_count); + free(scriptlet_count); + return rc; +} + +static rpmRC measure_psm_pre(rpmPlugin plugin, rpmte te) +{ + struct measurestat *state = rpmPluginGetData(plugin); + rpmRC rc = RPMRC_FAIL; + + if (clock_gettime(CLOCK_MONOTONIC, &state->psm_start)) { + rpmlog(RPMLOG_ERR, _("measure: Failed to get psm_start time\n")); + goto exit; + } + rc = RPMRC_OK; +exit: + return rc; +} + +static rpmRC measure_psm_post(rpmPlugin plugin, rpmte te, int res) +{ + struct measurestat *state = rpmPluginGetData(plugin); + struct timespec end; + char *offset = NULL, *duration = NULL, *prefix = NULL; + Header h = rpmteHeader(te); + rpmRC rc = RPMRC_FAIL; + + if (clock_gettime(CLOCK_MONOTONIC, &end)) { + rpmlog(RPMLOG_ERR, _("measure: Failed to get psm end time\n")); + goto exit; + } + if (rasprintf(&prefix, "_measure_plugin_package_%u", state->psm_count) == -1) { + rpmlog(RPMLOG_ERR, _("measure: Failed to allocate prefix\n")); + goto exit; + } + if (diff_ms(&offset, &state->plugin_start, &state->psm_start) != RPMRC_OK) { + goto exit; + } + if (diff_ms(&duration, &state->psm_start, &end) != RPMRC_OK) { + goto exit; + } + if (push("%s_nevra", rpmteNEVRA(te), prefix) != RPMRC_OK) { + goto exit; + } + if (push("%s_compressor", headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR), prefix) != RPMRC_OK) { + goto exit; + } + if (push("%s_offset", offset, prefix) != RPMRC_OK) { + goto exit; + } + if (push("%s_ms", duration, prefix) != RPMRC_OK) { + goto exit; + } + state->psm_count += 1; + rc = RPMRC_OK; +exit: + headerFree(h); + free(prefix); + free(duration); + free(offset); + return rc; +} + +static rpmRC measure_scriptlet_pre(rpmPlugin plugin, + const char *s_name, int type) +{ + struct measurestat *state = rpmPluginGetData(plugin); + if (clock_gettime(CLOCK_MONOTONIC, &state->scriptlet_start)) { + rpmlog(RPMLOG_ERR, _("measure: Failed to get scriptlet_start time\n")); + return RPMRC_FAIL; + } + return RPMRC_OK; +} + +static rpmRC measure_scriptlet_post(rpmPlugin plugin, + const char *s_name, int type, int res) +{ + struct measurestat *state = rpmPluginGetData(plugin); + struct timespec end; + char *offset = NULL, *duration = NULL, *prefix = NULL; + rpmRC rc = RPMRC_FAIL; + + if (clock_gettime(CLOCK_MONOTONIC, &end)) { + rpmlog(RPMLOG_ERR, _("measure: Failed to get end time\n")); + goto exit; + } + + if (rasprintf(&prefix, "_measure_plugin_scriptlet_%d", state->scriptlet_count) == -1) { + rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted prefix\n")); + goto exit; + } + if (diff_ms(&offset, &state->plugin_start, &state->scriptlet_start) != RPMRC_OK) { + goto exit; + } + if (diff_ms(&duration, &state->scriptlet_start, &end) != RPMRC_OK) { + goto exit; + } + if (push("%s_name", s_name, prefix) != RPMRC_OK) { + goto exit; + } + if (push("%s_offset", offset, prefix) != RPMRC_OK) { + goto exit; + } + if (push("%s_ms", duration, prefix) != RPMRC_OK) { + goto exit; + } + state->scriptlet_count += 1; + rc = RPMRC_OK; +exit: + free(prefix); + free(duration); + free(offset); + return rc; +} + +struct rpmPluginHooks_s measure_hooks = { + .init = measure_init, + .cleanup = measure_cleanup, + .tsm_post = measure_tsm_post, + .psm_pre = measure_psm_pre, + .psm_post = measure_psm_post, + .scriptlet_pre = measure_scriptlet_pre, + .scriptlet_post = measure_scriptlet_post, +}; -- 2.24.1