Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2015 Intel Corporation
3 : : */
4 : :
5 : : #include <string.h>
6 : : #include <stdlib.h>
7 : : #include <errno.h>
8 : :
9 : : #include <rte_string_fns.h>
10 : : #include <rte_common.h>
11 : : #include <rte_cycles.h>
12 : : #include <rte_branch_prediction.h>
13 : :
14 : : #include "rte_jobstats.h"
15 : :
16 : : #define ADD_TIME_MIN_MAX(obj, type, value) do { \
17 : : typeof(value) tmp = (value); \
18 : : (obj)->type ## _time += tmp; \
19 : : if (tmp < (obj)->min_ ## type ## _time) \
20 : : (obj)->min_ ## type ## _time = tmp; \
21 : : if (tmp > (obj)->max_ ## type ## _time) \
22 : : (obj)->max_ ## type ## _time = tmp; \
23 : : } while (0)
24 : :
25 : : #define RESET_TIME_MIN_MAX(obj, type) do { \
26 : : (obj)->type ## _time = 0; \
27 : : (obj)->min_ ## type ## _time = UINT64_MAX; \
28 : : (obj)->max_ ## type ## _time = 0; \
29 : : } while (0)
30 : :
31 : : static inline uint64_t
32 : : get_time(void)
33 : : {
34 : : rte_rmb();
35 : : return rte_get_timer_cycles();
36 : : }
37 : :
38 : : /* Those are steps used to adjust job period.
39 : : * Experiments show that for forwarding apps the up step must be less than down
40 : : * step to achieve optimal performance.
41 : : */
42 : : #define JOB_UPDATE_STEP_UP 1
43 : : #define JOB_UPDATE_STEP_DOWN 4
44 : :
45 : : /*
46 : : * Default update function that implements simple period adjustment.
47 : : */
48 : : static void
49 : 0 : default_update_function(struct rte_jobstats *job, int64_t result)
50 : : {
51 : 0 : int64_t err = job->target - result;
52 : :
53 : : /* Job is happy. Nothing to do */
54 [ # # ]: 0 : if (err == 0)
55 : : return;
56 : :
57 [ # # ]: 0 : if (err > 0) {
58 [ # # ]: 0 : if (job->period + JOB_UPDATE_STEP_UP < job->max_period)
59 : 0 : job->period += JOB_UPDATE_STEP_UP;
60 : : } else {
61 [ # # ]: 0 : if (job->min_period + JOB_UPDATE_STEP_DOWN < job->period)
62 : 0 : job->period -= JOB_UPDATE_STEP_DOWN;
63 : : }
64 : : }
65 : :
66 : : int
67 : 0 : rte_jobstats_context_init(struct rte_jobstats_context *ctx)
68 : : {
69 [ # # ]: 0 : if (ctx == NULL)
70 : : return -EINVAL;
71 : :
72 : : /* Init only needed parameters. Zero out everything else. */
73 : : memset(ctx, 0, sizeof(struct rte_jobstats_context));
74 : :
75 : 0 : rte_jobstats_context_reset(ctx);
76 : :
77 : 0 : return 0;
78 : : }
79 : :
80 : : void
81 : 0 : rte_jobstats_context_start(struct rte_jobstats_context *ctx)
82 : : {
83 : : uint64_t now;
84 : :
85 : 0 : ctx->loop_executed_jobs = 0;
86 : :
87 : : now = get_time();
88 [ # # # # ]: 0 : ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time);
89 : 0 : ctx->state_time = now;
90 : 0 : }
91 : :
92 : : void
93 : 0 : rte_jobstats_context_finish(struct rte_jobstats_context *ctx)
94 : : {
95 : : uint64_t now;
96 : :
97 [ # # ]: 0 : if (likely(ctx->loop_executed_jobs))
98 : 0 : ctx->loop_cnt++;
99 : :
100 : : now = get_time();
101 [ # # # # ]: 0 : ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time);
102 : 0 : ctx->state_time = now;
103 : 0 : }
104 : :
105 : : void
106 : 0 : rte_jobstats_context_reset(struct rte_jobstats_context *ctx)
107 : : {
108 : 0 : RESET_TIME_MIN_MAX(ctx, exec);
109 : 0 : RESET_TIME_MIN_MAX(ctx, management);
110 : 0 : ctx->start_time = get_time();
111 : 0 : ctx->state_time = ctx->start_time;
112 : 0 : ctx->job_exec_cnt = 0;
113 : 0 : ctx->loop_cnt = 0;
114 : 0 : }
115 : :
116 : : void
117 : 0 : rte_jobstats_set_target(struct rte_jobstats *job, int64_t target)
118 : : {
119 : 0 : job->target = target;
120 : 0 : }
121 : :
122 : : int
123 : 0 : rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job)
124 : : {
125 : : uint64_t now;
126 : :
127 : : /* Some sanity check. */
128 [ # # # # ]: 0 : if (unlikely(ctx == NULL || job == NULL || job->context != NULL))
129 : : return -EINVAL;
130 : :
131 : : /* Link job with context object. */
132 : 0 : job->context = ctx;
133 : :
134 : : now = get_time();
135 [ # # # # ]: 0 : ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time);
136 : 0 : ctx->state_time = now;
137 : :
138 : 0 : return 0;
139 : : }
140 : :
141 : : int
142 : 0 : rte_jobstats_abort(struct rte_jobstats *job)
143 : : {
144 : : struct rte_jobstats_context *ctx;
145 : : uint64_t now, exec_time;
146 : :
147 : : /* Some sanity check. */
148 [ # # # # ]: 0 : if (unlikely(job == NULL || job->context == NULL))
149 : : return -EINVAL;
150 : :
151 : : ctx = job->context;
152 : : now = get_time();
153 : 0 : exec_time = now - ctx->state_time;
154 [ # # # # ]: 0 : ADD_TIME_MIN_MAX(ctx, management, exec_time);
155 : 0 : ctx->state_time = now;
156 : 0 : job->context = NULL;
157 : :
158 : 0 : return 0;
159 : : }
160 : :
161 : : int
162 : 0 : rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value)
163 : : {
164 : : struct rte_jobstats_context *ctx;
165 : : uint64_t now, exec_time;
166 : : int need_update;
167 : :
168 : : /* Some sanity check. */
169 [ # # # # ]: 0 : if (unlikely(job == NULL || job->context == NULL))
170 : : return -EINVAL;
171 : :
172 : 0 : need_update = job->target != job_value;
173 : : /* Adjust period only if job is unhappy of its current period. */
174 [ # # ]: 0 : if (need_update)
175 : 0 : (*job->update_period_cb)(job, job_value);
176 : :
177 : 0 : ctx = job->context;
178 : :
179 : : /* Update execution time is considered as runtime so get time after it is
180 : : * executed. */
181 : : now = get_time();
182 : 0 : exec_time = now - ctx->state_time;
183 [ # # # # ]: 0 : ADD_TIME_MIN_MAX(job, exec, exec_time);
184 [ # # # # ]: 0 : ADD_TIME_MIN_MAX(ctx, exec, exec_time);
185 : :
186 : 0 : ctx->state_time = now;
187 : :
188 : 0 : ctx->loop_executed_jobs++;
189 : 0 : ctx->job_exec_cnt++;
190 : :
191 : 0 : job->exec_cnt++;
192 : 0 : job->context = NULL;
193 : :
194 : 0 : return need_update;
195 : : }
196 : :
197 : : void
198 : 0 : rte_jobstats_set_period(struct rte_jobstats *job, uint64_t period,
199 : : uint8_t saturate)
200 : : {
201 [ # # ]: 0 : if (saturate != 0) {
202 [ # # ]: 0 : if (period < job->min_period)
203 : : period = job->min_period;
204 : 0 : else if (period > job->max_period)
205 : : period = job->max_period;
206 : : }
207 : :
208 : 0 : job->period = period;
209 : 0 : }
210 : :
211 : : void
212 : 0 : rte_jobstats_set_min(struct rte_jobstats *job, uint64_t period)
213 : : {
214 : 0 : job->min_period = period;
215 [ # # ]: 0 : if (job->period < period)
216 : 0 : job->period = period;
217 : 0 : }
218 : :
219 : : void
220 : 0 : rte_jobstats_set_max(struct rte_jobstats *job, uint64_t period)
221 : : {
222 : 0 : job->max_period = period;
223 [ # # ]: 0 : if (job->period > period)
224 : 0 : job->period = period;
225 : 0 : }
226 : :
227 : : int
228 : 0 : rte_jobstats_init(struct rte_jobstats *job, const char *name,
229 : : uint64_t min_period, uint64_t max_period, uint64_t initial_period,
230 : : int64_t target)
231 : : {
232 [ # # ]: 0 : if (job == NULL)
233 : : return -EINVAL;
234 : :
235 : 0 : job->period = initial_period;
236 : 0 : job->min_period = min_period;
237 : 0 : job->max_period = max_period;
238 : 0 : job->target = target;
239 : 0 : job->update_period_cb = &default_update_function;
240 : 0 : rte_jobstats_reset(job);
241 [ # # ]: 0 : strlcpy(job->name, name == NULL ? "" : name, RTE_DIM(job->name));
242 : 0 : job->context = NULL;
243 : :
244 : 0 : return 0;
245 : : }
246 : :
247 : : void
248 : 0 : rte_jobstats_set_update_period_function(struct rte_jobstats *job,
249 : : rte_job_update_period_cb_t update_period_cb)
250 : : {
251 [ # # ]: 0 : if (update_period_cb == NULL)
252 : : update_period_cb = default_update_function;
253 : :
254 : 0 : job->update_period_cb = update_period_cb;
255 : 0 : }
256 : :
257 : : void
258 : 0 : rte_jobstats_reset(struct rte_jobstats *job)
259 : : {
260 : 0 : RESET_TIME_MIN_MAX(job, exec);
261 : 0 : job->exec_cnt = 0;
262 : 0 : }
|