diff options
Diffstat (limited to 'lib/librte_jobstats')
-rw-r--r-- | lib/librte_jobstats/Makefile | 53 | ||||
-rw-r--r-- | lib/librte_jobstats/rte_jobstats.c | 293 | ||||
-rw-r--r-- | lib/librte_jobstats/rte_jobstats.h | 336 | ||||
-rw-r--r-- | lib/librte_jobstats/rte_jobstats_version.map | 26 |
4 files changed, 708 insertions, 0 deletions
diff --git a/lib/librte_jobstats/Makefile b/lib/librte_jobstats/Makefile new file mode 100644 index 00000000..136a448e --- /dev/null +++ b/lib/librte_jobstats/Makefile @@ -0,0 +1,53 @@ +# BSD LICENSE +# +# Copyright(c) 2015 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_jobstats.a + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) + +EXPORT_MAP := rte_jobstats_version.map + +LIBABIVER := 1 + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_JOBSTATS) := rte_jobstats.c + +# install this header file +SYMLINK-$(CONFIG_RTE_LIBRTE_JOBSTATS)-include := rte_jobstats.h + +# this lib needs eal +DEPDIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += lib/librte_eal + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_jobstats/rte_jobstats.c b/lib/librte_jobstats/rte_jobstats.c new file mode 100644 index 00000000..2b42050c --- /dev/null +++ b/lib/librte_jobstats/rte_jobstats.c @@ -0,0 +1,293 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include <rte_errno.h> +#include <rte_common.h> +#include <rte_eal.h> +#include <rte_log.h> +#include <rte_cycles.h> +#include <rte_branch_prediction.h> + +#include "rte_jobstats.h" + +#define ADD_TIME_MIN_MAX(obj, type, value) do { \ + typeof(value) tmp = (value); \ + (obj)->type ## _time += tmp; \ + if (tmp < (obj)->min_ ## type ## _time) \ + (obj)->min_ ## type ## _time = tmp; \ + if (tmp > (obj)->max_ ## type ## _time) \ + (obj)->max_ ## type ## _time = tmp; \ +} while (0) + +#define RESET_TIME_MIN_MAX(obj, type) do { \ + (obj)->type ## _time = 0; \ + (obj)->min_ ## type ## _time = UINT64_MAX; \ + (obj)->max_ ## type ## _time = 0; \ +} while (0) + +static inline uint64_t +get_time(void) +{ + rte_rmb(); + return rte_get_timer_cycles(); +} + +/* Those are steps used to adjust job period. + * Experiments show that for forwarding apps the up step must be less than down + * step to achieve optimal performance. + */ +#define JOB_UPDATE_STEP_UP 1 +#define JOB_UPDATE_STEP_DOWN 4 + +/* + * Default update function that implements simple period adjustment. + */ +static void +default_update_function(struct rte_jobstats *job, int64_t result) +{ + int64_t err = job->target - result; + + /* Job is happy. Nothing to do */ + if (err == 0) + return; + + if (err > 0) { + if (job->period + JOB_UPDATE_STEP_UP < job->max_period) + job->period += JOB_UPDATE_STEP_UP; + } else { + if (job->min_period + JOB_UPDATE_STEP_DOWN < job->period) + job->period -= JOB_UPDATE_STEP_DOWN; + } +} + +int +rte_jobstats_context_init(struct rte_jobstats_context *ctx) +{ + if (ctx == NULL) + return -EINVAL; + + /* Init only needed parameters. Zero out everything else. */ + memset(ctx, 0, sizeof(struct rte_jobstats_context)); + + rte_jobstats_context_reset(ctx); + + return 0; +} + +void +rte_jobstats_context_start(struct rte_jobstats_context *ctx) +{ + uint64_t now; + + ctx->loop_executed_jobs = 0; + + now = get_time(); + ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time); + ctx->state_time = now; +} + +void +rte_jobstats_context_finish(struct rte_jobstats_context *ctx) +{ + uint64_t now; + + if (likely(ctx->loop_executed_jobs)) + ctx->loop_cnt++; + + now = get_time(); + ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time); + ctx->state_time = now; +} + +void +rte_jobstats_context_reset(struct rte_jobstats_context *ctx) +{ + RESET_TIME_MIN_MAX(ctx, exec); + RESET_TIME_MIN_MAX(ctx, management); + ctx->start_time = get_time(); + ctx->state_time = ctx->start_time; + ctx->job_exec_cnt = 0; + ctx->loop_cnt = 0; +} + +void +rte_jobstats_set_target(struct rte_jobstats *job, int64_t target) +{ + job->target = target; +} + +int +rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job) +{ + uint64_t now; + + /* Some sanity check. */ + if (unlikely(ctx == NULL || job == NULL || job->context != NULL)) + return -EINVAL; + + /* Link job with context object. */ + job->context = ctx; + + now = get_time(); + ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time); + ctx->state_time = now; + + return 0; +} + +int +rte_jobstats_abort(struct rte_jobstats *job) +{ + struct rte_jobstats_context *ctx; + uint64_t now, exec_time; + + /* Some sanity check. */ + if (unlikely(job == NULL || job->context == NULL)) + return -EINVAL; + + ctx = job->context; + now = get_time(); + exec_time = now - ctx->state_time; + ADD_TIME_MIN_MAX(ctx, management, exec_time); + ctx->state_time = now; + job->context = NULL; + + return 0; +} + +int +rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value) +{ + struct rte_jobstats_context *ctx; + uint64_t now, exec_time; + int need_update; + + /* Some sanity check. */ + if (unlikely(job == NULL || job->context == NULL)) + return -EINVAL; + + need_update = job->target != job_value; + /* Adjust period only if job is unhappy of its current period. */ + if (need_update) + (*job->update_period_cb)(job, job_value); + + ctx = job->context; + + /* Update execution time is considered as runtime so get time after it is + * executed. */ + now = get_time(); + exec_time = now - ctx->state_time; + ADD_TIME_MIN_MAX(job, exec, exec_time); + ADD_TIME_MIN_MAX(ctx, exec, exec_time); + + ctx->state_time = now; + + ctx->loop_executed_jobs++; + ctx->job_exec_cnt++; + + job->exec_cnt++; + job->context = NULL; + + return need_update; +} + +void +rte_jobstats_set_period(struct rte_jobstats *job, uint64_t period, + uint8_t saturate) +{ + if (saturate != 0) { + if (period < job->min_period) + period = job->min_period; + else if (period > job->max_period) + period = job->max_period; + } + + job->period = period; +} + +void +rte_jobstats_set_min(struct rte_jobstats *job, uint64_t period) +{ + job->min_period = period; + if (job->period < period) + job->period = period; +} + +void +rte_jobstats_set_max(struct rte_jobstats *job, uint64_t period) +{ + job->max_period = period; + if (job->period > period) + job->period = period; +} + +int +rte_jobstats_init(struct rte_jobstats *job, const char *name, + uint64_t min_period, uint64_t max_period, uint64_t initial_period, + int64_t target) +{ + if (job == NULL) + return -EINVAL; + + job->period = initial_period; + job->min_period = min_period; + job->max_period = max_period; + job->target = target; + job->update_period_cb = &default_update_function; + rte_jobstats_reset(job); + snprintf(job->name, RTE_DIM(job->name), "%s", name == NULL ? "" : name); + job->context = NULL; + + return 0; +} + +void +rte_jobstats_set_update_period_function(struct rte_jobstats *job, + rte_job_update_period_cb_t update_period_cb) +{ + if (update_period_cb == NULL) + update_period_cb = default_update_function; + + job->update_period_cb = update_period_cb; +} + +void +rte_jobstats_reset(struct rte_jobstats *job) +{ + RESET_TIME_MIN_MAX(job, exec); + job->exec_cnt = 0; +} diff --git a/lib/librte_jobstats/rte_jobstats.h b/lib/librte_jobstats/rte_jobstats.h new file mode 100644 index 00000000..c2b285f8 --- /dev/null +++ b/lib/librte_jobstats/rte_jobstats.h @@ -0,0 +1,336 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JOBSTATS_H_ +#define JOBSTATS_H_ + +#include <stdint.h> + +#include <rte_memory.h> +#include <rte_memcpy.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTE_JOBSTATS_NAMESIZE 32 + +/* Forward declarations. */ +struct rte_jobstats_context; +struct rte_jobstats; + +/** + * This function should calculate new period and set it using + * rte_jobstats_set_period() function. Time spent in this function will be + * added to job's runtime. + * + * @param job + * The job data structure handler. + * @param job_result + * Result of calling job callback. + */ +typedef void (*rte_job_update_period_cb_t)(struct rte_jobstats *job, + int64_t job_result); + +struct rte_jobstats { + uint64_t period; + /**< Estimated period of execution. */ + + uint64_t min_period; + /**< Minimum period. */ + + uint64_t max_period; + /**< Maximum period. */ + + int64_t target; + /**< Desired value for this job. */ + + rte_job_update_period_cb_t update_period_cb; + /**< Period update callback. */ + + uint64_t exec_time; + /**< Total time (sum) that this job was executing. */ + + uint64_t min_exec_time; + /**< Minimum execute time. */ + + uint64_t max_exec_time; + /**< Minimum execute time. */ + + uint64_t exec_cnt; + /**< Execute count. */ + + char name[RTE_JOBSTATS_NAMESIZE]; + /**< Name of this job */ + + struct rte_jobstats_context *context; + /**< Job stats context object that is executing this job. */ +} __rte_cache_aligned; + +struct rte_jobstats_context { + /** Viariable holding time at different points: + * -# loop start time if loop was started but no job executed yet. + * -# job start time if job is currently executing. + * -# job finish time if job finished its execution. + * -# loop finish time if loop finished its execution. */ + uint64_t state_time; + + uint64_t loop_executed_jobs; + /**< Count of executed jobs in this loop. */ + + /* Statistics start. */ + + uint64_t exec_time; + /**< Total time taken to execute jobs, not including management time. */ + + uint64_t min_exec_time; + /**< Minimum loop execute time. */ + + uint64_t max_exec_time; + /**< Minimum loop execute time. */ + + /** + * Sum of time that is not the execute time (ex: from job finish to next + * job start). + * + * This time might be considered as overhead of library + job scheduling. + */ + uint64_t management_time; + + uint64_t min_management_time; + /**< Minimum management time */ + + uint64_t max_management_time; + /**< Maximum management time */ + + uint64_t start_time; + /**< Time since last reset stats. */ + + uint64_t job_exec_cnt; + /**< Total count of executed jobs. */ + + uint64_t loop_cnt; + /**< Total count of executed loops with at least one executed job. */ +} __rte_cache_aligned; + +/** + * Initialize given context object with default values. + * + * @param ctx + * Job stats context object to initialize. + * + * @return + * 0 on success + * -EINVAL if *ctx* is NULL + */ +int +rte_jobstats_context_init(struct rte_jobstats_context *ctx); + +/** + * Mark that new set of jobs start executing. + * + * @param ctx + * Job stats context object. + */ +void +rte_jobstats_context_start(struct rte_jobstats_context *ctx); + +/** + * Mark that there is no more jobs ready to execute in this turn. Calculate + * stats for this loop turn. + * + * @param ctx + * Job stats context. + */ +void +rte_jobstats_context_finish(struct rte_jobstats_context *ctx); + +/** + * Function resets job context statistics. + * + * @param ctx + * Job stats context which statistics will be reset. + */ +void +rte_jobstats_context_reset(struct rte_jobstats_context *ctx); + +/** + * Initialize given job stats object. + * + * @param job + * Job object. + * @param name + * Optional job name. + * @param min_period + * Minimum period that this job can accept. + * @param max_period + * Maximum period that this job can accept. + * @param initial_period + * Initial period. It will be checked against *min_period* and *max_period*. + * @param target + * Target value that this job try to achieve. + * + * @return + * 0 on success + * -EINVAL if *job* is NULL + */ +int +rte_jobstats_init(struct rte_jobstats *job, const char *name, + uint64_t min_period, uint64_t max_period, uint64_t initial_period, + int64_t target); + +/** + * Set job desired target value. Difference between target and job value + * value must be used to properly adjust job execute period value. + * + * @param job + * The job object. + * @param target + * New target. + */ +void +rte_jobstats_set_target(struct rte_jobstats *job, int64_t target); + +/** + * Mark that *job* is starting of its execution in context of *ctx* object. + * + * @param ctx + * Job stats context. + * @param job + * Job object. + * @return + * 0 on success + * -EINVAL if *ctx* or *job* is NULL or *job* is executing in another context + * context already, + */ +int +rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job); + +/** + * Mark that *job* finished its execution, but time of this work will be skipped + * and added to management time. + * + * @param job + * Job object. + * + * @return + * 0 on success + * -EINVAL if job is NULL or job was not started (it have no context). + */ +int +rte_jobstats_abort(struct rte_jobstats *job); + +/** + * Mark that *job* finished its execution. Context in which it was executing + * will receive stat update. After this function call *job* object is ready to + * be executed in other context. + * + * @param job + * Job object. + * @param job_value + * Job value. Job should pass in this parameter a value that it try to optimize + * for example the number of packets it processed. + * + * @return + * 0 if job's period was not updated (job target equals *job_value*) + * 1 if job's period was updated + * -EINVAL if job is NULL or job was not started (it have no context). + */ +int +rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value); + +/** + * Set execute period of given job. + * + * @param job + * The job object. + * @param period + * New period value. + * @param saturate + * If zero, skip period saturation to min, max range. + */ +void +rte_jobstats_set_period(struct rte_jobstats *job, uint64_t period, + uint8_t saturate); +/** + * Set minimum execute period of given job. Current period will be checked + * against new minimum value. + * + * @param job + * The job object. + * @param period + * New minimum period value. + */ +void +rte_jobstats_set_min(struct rte_jobstats *job, uint64_t period); +/** + * Set maximum execute period of given job. Current period will be checked + * against new maximum value. + * + * @param job + * The job object. + * @param period + * New maximum period value. + */ +void +rte_jobstats_set_max(struct rte_jobstats *job, uint64_t period); + +/** + * Set update period callback that is invoked after job finish. + * + * If application wants to do more sophisticated calculations than default + * it can provide this handler. + * + * @param job + * Job object. + * @param update_pedriod_cb + * Callback to set. If NULL restore default update function. + */ +void +rte_jobstats_set_update_period_function(struct rte_jobstats *job, + rte_job_update_period_cb_t update_period_cb); + +/** + * Function resets job statistics. + * + * @param job + * Job which statistics will be reset. + */ +void +rte_jobstats_reset(struct rte_jobstats *job); + +#ifdef __cplusplus +} +#endif + +#endif /* JOBSTATS_H_ */ diff --git a/lib/librte_jobstats/rte_jobstats_version.map b/lib/librte_jobstats/rte_jobstats_version.map new file mode 100644 index 00000000..f8944143 --- /dev/null +++ b/lib/librte_jobstats/rte_jobstats_version.map @@ -0,0 +1,26 @@ +DPDK_2.0 { + global: + + rte_jobstats_context_finish; + rte_jobstats_context_init; + rte_jobstats_context_reset; + rte_jobstats_context_start; + rte_jobstats_finish; + rte_jobstats_init; + rte_jobstats_reset; + rte_jobstats_set_max; + rte_jobstats_set_min; + rte_jobstats_set_period; + rte_jobstats_set_target; + rte_jobstats_set_update_period_function; + rte_jobstats_start; + + local: *; +}; + +DPDK_16.04 { + global: + + rte_jobstats_abort; + +} DPDK_2.0; |