[dpdk-dev,1/2] librte_headroom: New library for checking core/system/app load

Message ID 1422532206-10662-2-git-send-email-pawelx.wodkowski@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Wodkowski, PawelX Jan. 29, 2015, 11:50 a.m. UTC
  To calculate a headroom we need to have some part of code that do
something. Those parts of code are called jobs (not tasks, to avoid
confusion). Jobs are managed by headroom library, that is responsible
for executing them when needed.

The rte_headroom_next_job() function is waiting for first job
to became ready. If job is ready, time that it spent
waiting is added to overal idle time and also is saved.
Job is then executed.

Executed job must return an integer value. This value
is used to calculate next execution time (time when job will be
considered ready). For example: if job is forward job it return number
of received packets. Returned value is then compared to target value. If
returned value is different next_exec_time
is adjusted. Previously saved idle time is considered to be a job's
idle time (it is added to job's idle time).

After execution of last ready job, number of loops is incremented
and whole process starts all over again.

Please notice that given headroom is no absolute. For example:
if some app have avg 100us headroom, adding job that consume 90us will
not mean that there is 10us left. You need to run headroom profiling
again after adding this 90us-job.

Additionaly used can define own handlers:
- idle handler - function called when no job is ready to execute.
- loop hook - function called when all ready jobs are executed.
- job update period callback - if more sophisticated than default
  function is required to calculate job's execution period.

Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
 config/common_bsdapp               |    6 +
 config/common_linuxapp             |    6 +
 lib/Makefile                       |    1 +
 lib/librte_headroom/Makefile       |   50 ++++
 lib/librte_headroom/rte_headroom.c |  368 +++++++++++++++++++++++++++
 lib/librte_headroom/rte_headroom.h |  481 ++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk                      |    4 +
 7 files changed, 916 insertions(+)
 create mode 100644 lib/librte_headroom/Makefile
 create mode 100644 lib/librte_headroom/rte_headroom.c
 create mode 100644 lib/librte_headroom/rte_headroom.h
  

Patch

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 9177db1..eca9299 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -282,6 +282,12 @@  CONFIG_RTE_LIBRTE_HASH=y
 CONFIG_RTE_LIBRTE_HASH_DEBUG=n
 
 #
+# Compile librte_headroom
+#
+CONFIG_RTE_LIBRTE_HEADROOM=y
+CONFIG_RTE_HEADROOM_MAX_JOBS=32
+
+#
 # Compile librte_lpm
 #
 CONFIG_RTE_LIBRTE_LPM=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2f9643b..54c9458 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -290,6 +290,12 @@  CONFIG_RTE_LIBRTE_HASH=y
 CONFIG_RTE_LIBRTE_HASH_DEBUG=n
 
 #
+# Compile librte_headroom
+#
+CONFIG_RTE_LIBRTE_HEADROOM=y
+CONFIG_RTE_HEADROOM_MAX_JOBS=32
+
+#
 # Compile librte_lpm
 #
 CONFIG_RTE_LIBRTE_LPM=y
diff --git a/lib/Makefile b/lib/Makefile
index 0ffc982..ab9e474 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -53,6 +53,7 @@  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_HEADROOM) += librte_headroom
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_headroom/Makefile b/lib/librte_headroom/Makefile
new file mode 100644
index 0000000..f0137e3
--- /dev/null
+++ b/lib/librte_headroom/Makefile
@@ -0,0 +1,50 @@ 
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 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_headroom.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_HEADROOM) := rte_headroom.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_HEADROOM)-include := rte_headroom.h
+
+# this lib needs eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_HEADROOM) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_HEADROOM) += lib/librte_mbuf
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_headroom/rte_headroom.c b/lib/librte_headroom/rte_headroom.c
new file mode 100644
index 0000000..5f19c83
--- /dev/null
+++ b/lib/librte_headroom/rte_headroom.c
@@ -0,0 +1,368 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-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 <errno.h>
+
+#include <rte_errno.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_branch_prediction.h>
+#include <rte_debug.h>
+
+#include "rte_headroom.h"
+
+/* 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_headroom_job *job, int64_t result)
+{
+	int64_t err = job->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;
+	}
+}
+
+static uint32_t
+select_next_job(struct rte_headroom *hdr)
+{
+	const uint64_t now = rte_get_timer_cycles();
+	const uint32_t count = hdr->job_count;
+	uint32_t idx = hdr->job_idx;
+
+	for (; idx < count; idx++) {
+		if (hdr->jobs[idx].next_exec_time <= now)
+			break;
+	}
+
+	hdr->job_idx = idx;
+	return idx;
+}
+
+static void
+default_loop_hook(__rte_unused struct rte_headroom *hdr)
+{
+	rte_pause();
+}
+
+static void
+default_idle_hook(__rte_unused struct rte_headroom *hdr)
+{
+	rte_pause();
+}
+
+int
+rte_headroom_init(struct rte_headroom *hdr)
+{
+	if (hdr == NULL)
+		return -EINVAL;
+
+	memset(hdr, 0, sizeof(*hdr));
+
+	/* Set some initial values */
+	hdr->idle_hook = &default_idle_hook;
+	hdr->loop_hook = &default_loop_hook;
+
+	hdr->user_data = NULL;
+
+	return 0;
+}
+
+void
+rte_headroom_deinit(struct rte_headroom *hdr)
+{
+	RTE_VERIFY(hdr != NULL);
+
+	hdr->job_count = 0;
+	hdr->job_idx = 0;
+}
+
+void
+rte_headroom_set_user_data(struct rte_headroom *hdr, void *user_data)
+{
+	hdr->user_data = user_data;
+}
+
+void
+rte_headroom_set_loop_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t loop_end_hook)
+{
+	if (loop_end_hook == NULL)
+		loop_end_hook = default_loop_hook;
+
+	hdr->loop_hook = loop_end_hook;
+}
+
+void
+rte_headroom_set_idle_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t idle_hook)
+{
+	if (idle_hook == NULL)
+		idle_hook = default_idle_hook;
+
+	hdr->idle_hook = idle_hook;
+}
+
+static void
+update_stats(struct rte_headroom_stats *stats, uint64_t idle, uint64_t runtime)
+{
+	stats->idle += idle;
+
+	if (idle < stats->idle_min)
+		stats->idle_min = idle;
+
+	if (idle > stats->idle_max)
+		stats->idle_max = idle;
+
+	stats->run_time += runtime;
+
+	if (runtime < stats->run_time_min)
+		stats->run_time_min = runtime;
+
+	if (runtime > stats->run_time_max)
+		stats->run_time_max = runtime;
+
+	stats->exec_cnt++;
+}
+
+int
+rte_headroom_next_job(struct rte_headroom *hdr)
+{
+	uint64_t start_time, run_time, idle_time = 0, now;
+	int64_t retval;
+	struct rte_headroom_job *job;
+
+	if (unlikely(hdr == NULL))
+		return -EINVAL;
+
+	if (unlikely(hdr->job_count == 0))
+		return -ENOENT;
+
+	/* Wait for any job to be ready. */
+	if (unlikely(select_next_job(hdr) == hdr->job_count)) {
+		/* All jobs done. Update statisctics and go next loop */
+		update_stats(&hdr->stats, hdr->loop_idle, hdr->loop_runtime);
+		hdr->loop_idle = 0;
+		hdr->loop_runtime = 0;
+		hdr->job_idx = 0;
+
+		/* Execute loop end hook. */
+		(*hdr->loop_hook)(hdr);
+
+		/* Get ready job or wait for first one to became ready */
+		 while (select_next_job(hdr) == hdr->job_count) {
+			 hdr->job_idx = 0;
+			(*hdr->idle_hook)(hdr);
+		}
+	}
+
+	/* Calculate idle time counter for this job. Idle time is a time from
+	 * execution finish to next job became ready. */
+	start_time = rte_get_timer_cycles();
+	idle_time = start_time - hdr->loop_end_time;
+
+	job = &hdr->jobs[hdr->job_idx];
+	retval = (*job->job_cb)(job);
+
+	(*job->update_period_cb)(job, retval);
+	job->next_exec_time += job->period;
+
+	now = rte_get_timer_cycles();
+	if (job->next_exec_time < now)
+		job->next_exec_time = now;
+
+	run_time = now - start_time;
+
+	/* Update job stats. */
+	update_stats(&job->stats, idle_time, run_time);
+
+	/* Update this loop stats. */
+	hdr->loop_idle += idle_time;
+	hdr->loop_runtime += run_time;
+
+	/* Mark time when this iteration ended */
+	hdr->loop_end_time = rte_get_timer_cycles();
+
+	/* Try next job. */
+	hdr->job_idx++;
+
+	/* Job finished */
+	return 0;
+}
+
+struct rte_headroom_job *
+rte_headroom_find_job(struct rte_headroom *hdr,
+		rte_headroom_job_callbak_t job_cb, void *job_data)
+{
+	size_t i;
+
+	if (unlikely(job_cb == NULL)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Search the array. */
+	for (i = 0; i < hdr->job_count; i++) {
+		if (hdr->jobs[i].job_cb == job_cb &&
+			hdr->jobs[i].job_data == job_data)
+			return &hdr->jobs[i];
+	}
+
+	if (hdr->job_count == 0)
+		rte_errno = ENOENT;
+
+	return NULL;
+}
+
+struct rte_headroom_job *
+rte_headroom_find_job_by_name(struct rte_headroom *hdr,	const char *job_name)
+{
+	size_t i;
+
+	if (unlikely(job_name == NULL)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Search the array. */
+	for (i = 0; i < hdr->job_count; i++) {
+		if (hdr->jobs[i].name[0] == '\0')
+			continue;
+
+		if (strcmp(hdr->jobs[i].name, job_name) == 0)
+			return &hdr->jobs[i];
+	}
+
+	if (hdr->job_count == 0)
+		rte_errno = ENOENT;
+
+	return NULL;
+}
+
+int
+rte_headroom_add_job(struct rte_headroom *hdr, const char *name,
+	rte_headroom_job_callbak_t job_cb, void *job_data, uint64_t min_period,
+	uint64_t max_period, uint64_t initial_period, int64_t target,
+	struct rte_headroom_job **job_handle)
+{
+	struct rte_headroom_job *job;
+
+	if (hdr == NULL || job_cb == NULL)
+		return -EINVAL;
+
+	/* Add job by finding free slot. */
+	if (hdr->job_count == RTE_DIM(hdr->jobs))
+		return -ENOBUFS;
+
+	job = &hdr->jobs[hdr->job_count];
+	hdr->job_count++;
+
+	memset(job, 0, sizeof(*job));
+	job->next_exec_time = rte_get_timer_cycles();
+	job->job_cb = job_cb;
+	job->job_data = job_data;
+
+	job->update_period_cb = default_update_function;
+
+	if (initial_period <= min_period)
+		job->period = min_period;
+	else if (initial_period >= max_period)
+		job->period = max_period;
+	else
+		job->period = initial_period;
+
+	job->min_period = min_period;
+	job->max_period = max_period;
+	job->job_target = target;
+
+	if (name != NULL)
+		strncpy(job->name, name, RTE_DIM(job->name));
+	else
+		memset(job->name, 0, sizeof(job->name));
+
+	job->headroom = hdr;
+
+	if (job_handle)
+		*job_handle = job;
+	return 0;
+}
+
+int
+rte_headroom_del_job(struct rte_headroom_job *job)
+{
+	struct rte_headroom *hdr;
+	size_t cnt, idx;
+
+	if (unlikely(job == NULL))
+		return -EINVAL;
+
+	hdr = job->headroom;
+	RTE_VERIFY(hdr->jobs < job &&
+			(size_t)(job - hdr->jobs) < RTE_DIM(hdr->jobs));
+
+	idx = job - hdr->jobs;
+	cnt = hdr->job_count - idx - 1;
+	hdr->job_count--;
+
+	if (cnt > 0)
+		memmove(&hdr->jobs[idx], &hdr->jobs[idx + 1], sizeof(*job) * cnt);
+
+	return hdr->job_count;
+}
+
+void
+rte_headroom_set_update_period_function(struct rte_headroom_job *job,
+		rte_headroom_update_fn_t update_pedriod_cb)
+{
+	if (update_pedriod_cb == NULL)
+		update_pedriod_cb = default_update_function;
+
+	job->update_period_cb = update_pedriod_cb;
+}
diff --git a/lib/librte_headroom/rte_headroom.h b/lib/librte_headroom/rte_headroom.h
new file mode 100644
index 0000000..20f99fd
--- /dev/null
+++ b/lib/librte_headroom/rte_headroom.h
@@ -0,0 +1,481 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-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 HEADROOM_H_
+#define HEADROOM_H_
+
+#include <stdint.h>
+
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if RTE_HEADROOM_MAX_JOBS < 1 || RTE_HEADROOM_MAX_JOBS >= 0xFFFF
+# error Define RTE_HEADROOM_MAX_JOBS to be greater 1 and less 65535
+#endif
+
+/* Forward declarations. */
+struct rte_headroom;
+struct rte_headroom_job;
+
+typedef void (*rte_headroom_idle_hook_t)(struct rte_headroom *hdr);
+typedef void (*rte_headroom_loop_hook_t)(struct rte_headroom *hdr);
+typedef int64_t (*rte_headroom_job_callbak_t)(struct rte_headroom_job *job);
+
+/**
+ * This function should calculate new period and set it using
+ * rte_headroom_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_headroom_update_fn_t)(struct rte_headroom_job *job,
+		int64_t job_result);
+
+struct rte_headroom_stats {
+	uint64_t idle;
+	/**< Sum of idle time before this job became ready. */
+
+	uint64_t idle_min;
+	/**< Minimum idle time. */
+
+	uint64_t idle_max;
+	/**< Maximum idle time. */
+
+	uint64_t run_time;
+	/**< Total time that this job was executing. */
+
+	uint64_t run_time_min;
+	/**< Minimum execute time. */
+
+	uint64_t run_time_max;
+	/**< Minimum execute time. */
+
+	uint64_t exec_cnt;
+	/**< Task execute count. */
+};
+
+struct rte_headroom_job {
+	uint64_t next_exec_time;
+	/**< Next time when job should be executed. */
+
+	rte_headroom_job_callbak_t job_cb;
+	/**< Callback function for this job. */
+
+	void *job_data;
+	/**< Pointer to custom job's data. */
+
+	rte_headroom_update_fn_t update_period_cb;
+	/**< Period update callback. */
+
+	uint64_t period;
+	/**< Estitmated period of execution. */
+
+	uint64_t min_period;
+	/**< Minimum period. */
+
+	uint64_t max_period;
+	/**< Maximum period. */
+
+	struct rte_headroom_stats stats;
+
+	int64_t job_target;
+	/**< Desired value for this job. */
+
+#define RTE_HEADROOM_JOB_NAMESIZE 32
+	char name[RTE_HEADROOM_JOB_NAMESIZE];
+	/**< Name of this job */
+
+	struct rte_headroom *headroom;
+	/**< Hedroom object that this job belong to. */
+} __rte_cache_aligned;
+
+struct rte_headroom {
+	struct rte_headroom_job jobs[RTE_HEADROOM_MAX_JOBS];
+	/**< Array of job objects. */
+	uint32_t job_count;
+	/**< Job count. */
+	uint32_t job_idx;
+	/**< Index of job that is executing. */
+	struct rte_headroom_stats stats;
+
+	uint64_t loop_end_time;
+	/**< Time when last loop finished its execution. */
+
+	uint64_t loop_idle;
+	uint64_t loop_runtime;
+	/**< This loop idle time. */
+
+	rte_headroom_idle_hook_t idle_hook;
+	rte_headroom_loop_hook_t loop_hook;
+
+	void *user_data;
+	/**< User specified data for all user hooks. Not used by default hooks. */
+} __rte_cache_aligned;
+
+/**
+ * Allocate resource and initialize given headroom object with default
+ * values.
+ *
+ * @param hdr
+ *  The headroom object to be initialized.
+ *
+ * @return
+ *  0 if successfull or negative error value:
+ *  -EINVAL - if hdr is NULL
+ */
+int
+rte_headroom_init(struct rte_headroom *hdr);
+
+/**
+ * Deallocate any reserved resource make headroom object invalid.
+ *
+ * @pre All jobs from headroom object
+ *
+ * @param hdr The headroom object to be initialized.
+ */
+void
+rte_headroom_deinit(struct rte_headroom *hdr);
+
+/**
+ * Set new user data for headroom hooks.
+ *
+ * @param hdr
+ *  Headroom object to change a hook.
+ * @param loop_hook
+ *  New hook function. Can be NULL.
+ */
+void
+rte_headroom_set_user_data(struct rte_headroom *hdr, void *user_data);
+
+/**
+ * Set hook function executed when all jobs are executed in this loop turn.
+ *
+ * Time spent in this function is considered idle and counted as headroom. User
+ * application should not do any time consuming tasks in this hook as it can
+ * delay execution of job that became ready during time spent in this function.
+ *
+ * @param hdr
+ *  Headroom object to change a hook.
+ * @param loop_hook
+ *  New hook function. Can be NULL.
+ */
+void
+rte_headroom_set_loop_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t loop_end_hook);
+
+/**
+ * Set hook function executed when no job is ready to execute (idle loop).
+ *
+ * Time spent in this function is considered idle and counted as headroom. User
+ * application should not do any time consuming tasks in this hook as it can
+ * delay execution of job that became ready during time spent in this function.
+ *
+ * @param hdr
+ *  Headroom object to change a hook.
+ * @param idle_hook
+ *  New hook function. Can be NULL.
+ */
+void
+rte_headroom_set_idle_hook(struct rte_headroom *hdr,
+		rte_headroom_idle_hook_t idle_hook);
+
+/**
+ * Wait for next job to be ready and execute it.
+ *
+ * @param headroom
+ *  Headroom object that contains jobs.
+ *
+ * @return
+ *  0 on success or negative error code:
+ *  -EINVAL if hdr is NULL.
+ *  -ENOENT if there is no added jobs.
+ */
+int
+rte_headroom_next_job(struct rte_headroom *hdr);
+
+/**
+ * Return first job handle that match callback and data parameter.
+ *
+ * @param hdr
+ *  Headroom obcjet to be searched.
+ * @param job_cb
+ *  Job callback to find.
+ * @param job_data
+ *  Job's private data pointer to find.
+ *
+ * @return
+ *  Job object
+ *  NULL if job is not found.
+ *  NULL and set rte_errno:
+ *   EINVAL if job_cb is NULL
+ *   ENOENT if there is no jobs added to headroom object
+ */
+struct rte_headroom_job *
+rte_headroom_find_job(struct rte_headroom *hdr,
+		rte_headroom_job_callbak_t job_cb, void *job_data);
+
+/**
+ * Return first job handle that match given name. Jobs without name
+ * can't be found.
+ *
+ * @param hdr
+ *  Headroom obcjet to be searched.
+ * @param job_name
+ *  Name of job to be found.
+ *
+ * @return
+ *  Job object
+ *  NULL if job is not found.
+ *  NULL and set rte_errno:
+ *   EINVAL if job_name is NULL
+ *   ENOENT if there is no jobs added to headroom object
+ */
+struct rte_headroom_job *
+rte_headroom_find_job_by_name(struct rte_headroom *hdr,	const char *job_name);
+
+/**
+ * Return current number of jobs in headroom object.
+ * @param hdr
+ *  Headroom object to interrogate.
+ * @return
+ *  Number of jobs.
+ */
+static inline uint16_t
+rte_headroom_job_count(struct rte_headroom *hdr)
+{
+	return hdr->job_count;
+}
+
+/**
+ * Add new job to headroom object.
+ *
+ * @param hdr The headroom object to which job will be added.
+ * @param name Name of ne job. Can be NULL.
+ * @param job_cb Callback for this job.
+ * @param job_data Job's private data pointer.
+ * @param job_handle Output - added job handle. Can be NULL.
+ *
+ * @return 0 on success or negative error code:
+ *  -EINVAL if hdr or job_cb is NULL.
+ *  -ENOBUFS if there is no space in headroom object to add new job.
+ */
+int
+rte_headroom_add_job(struct rte_headroom *hdr, const char *name,
+	rte_headroom_job_callbak_t job_cb, void *job_data, uint64_t min_period,
+	uint64_t max_period, uint64_t initial_period, int64_t target,
+	struct rte_headroom_job **job_handle);
+
+/**
+ * Remove given job from headroom.
+ *
+ * @param job
+ *  Job to be removed.
+ *
+ * @return
+ *  Count of remaining jobs in headroom to which belong removed job or negative
+ *  error value:
+ *   -EINVAL job is NULL
+ */
+int
+rte_headroom_del_job(struct rte_headroom_job *job);
+
+/**
+ * Set job desired target value. Difference between target and job callback
+ * return value must be used to properly adjust job execute period value.
+ * @param job
+ *  The job object.
+ * @param target
+ *  New target.
+ */
+static inline void
+rte_headroom_set_target(struct rte_headroom_job *job, int64_t target)
+{
+	job->job_target = target;
+}
+
+/**
+ * Set execute period of given job.
+ *
+ * @param job
+ *  The job ocbject.
+ * @param period
+ *  New period value.
+ * @param saturate
+ *  If zero, skip period saturatation to min, max range.
+ */
+static inline void
+rte_headroom_set_period(struct rte_headroom_job *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;
+}
+
+/**
+ * Set minimum execute period of given job.
+ *
+ * @param job
+ *  The job ocject.
+ * @param period
+ *  New minimum period value.
+ */
+static inline void
+rte_headroom_set_min_period(struct rte_headroom_job *job, uint64_t period)
+{
+	job->min_period = period;
+	if (job->period < period)
+		job->period = period;
+}
+
+/**
+ * Set maximum execute period of given job.
+ *
+ * @param job
+ *  The job ocject.
+ * @param period
+ *  New maximum period value.
+ */
+static inline void
+rte_headroom_set_max_period(struct rte_headroom_job *job, uint64_t period)
+{
+	job->max_period = period;
+	if (job->period > period)
+		job->period = period;
+}
+
+/**
+ * Set update period callback that is invoked after task finish his job.
+ * If application want to
+ *
+ * @param job
+ *  Job object.
+ * @param update_pedriod_cb
+ *  Callback to set. If NULL restore default update function.
+ */
+void
+rte_headroom_set_update_period_function(struct rte_headroom_job *job,
+		rte_headroom_update_fn_t update_pedriod_cb);
+
+/**
+ * Retive job stats
+ *
+ * @param job
+ *  Job which statistics will be copied.
+ * @param stats
+ *  The output stats buffer.
+ *
+ */
+static inline void
+rte_headroom_get_job_stats(struct rte_headroom_job *job,
+		struct rte_headroom_stats *stats)
+{
+	rte_memcpy(stats, &job->stats, sizeof(job->stats));
+}
+
+/**
+ * Function resets job statistics.
+ *
+ * @param job
+ *  Job which statistics will be reset.
+ */
+static inline void
+rte_headroom_reset_job_stats(struct rte_headroom_job *job)
+{
+	struct rte_headroom_stats *s = &job->stats;
+
+	s->idle = 0;
+	s->idle_min = UINT64_MAX;
+	s->idle_max = 0;
+
+	s->run_time = 0;
+	s->run_time_min = UINT64_MAX;
+	s->run_time_max = 0;
+
+	s->exec_cnt = 0;
+}
+
+/**
+ * Retive headroom stats
+ *
+ * @param hdr
+ *  Headroom which statistics will be copied.
+ * @param stats
+ *  The output stats buffer.
+ */
+static inline void
+rte_headroom_get_stats(struct rte_headroom *hdr,
+		struct rte_headroom_stats *stats)
+{
+	rte_memcpy(stats, &hdr->stats, sizeof(hdr->stats));
+}
+
+/**
+ * Function resets headroom statistics.
+ *
+ * @param hdr
+ *  Headroom which statistics will be reset.
+ */
+static inline void
+rte_headroom_reset_stats(struct rte_headroom *hdr)
+{
+	struct rte_headroom_stats *s = &hdr->stats;
+
+	s->idle = 0;
+	s->idle_min = UINT64_MAX;
+	s->idle_max = 0;
+
+	s->run_time = 0;
+	s->run_time_min = UINT64_MAX;
+	s->run_time_max = 0;
+
+	s->exec_cnt = 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADROOM_H_ */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 40afb2c..bc2af88 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -103,6 +103,10 @@  ifeq ($(CONFIG_RTE_LIBRTE_HASH),y)
 LDLIBS += -lrte_hash
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_HEADROOM),y)
+LDLIBS += -lrte_headroom
+endif
+
 ifeq ($(CONFIG_RTE_LIBRTE_LPM),y)
 LDLIBS += -lrte_lpm
 endif