]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2015 Intel Corporation. All rights reserved. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include <string.h> | |
35 | #include <stdlib.h> | |
36 | #include <errno.h> | |
37 | ||
38 | #include <rte_errno.h> | |
39 | #include <rte_common.h> | |
40 | #include <rte_eal.h> | |
41 | #include <rte_log.h> | |
42 | #include <rte_cycles.h> | |
43 | #include <rte_branch_prediction.h> | |
44 | ||
45 | #include "rte_jobstats.h" | |
46 | ||
47 | #define ADD_TIME_MIN_MAX(obj, type, value) do { \ | |
48 | typeof(value) tmp = (value); \ | |
49 | (obj)->type ## _time += tmp; \ | |
50 | if (tmp < (obj)->min_ ## type ## _time) \ | |
51 | (obj)->min_ ## type ## _time = tmp; \ | |
52 | if (tmp > (obj)->max_ ## type ## _time) \ | |
53 | (obj)->max_ ## type ## _time = tmp; \ | |
54 | } while (0) | |
55 | ||
56 | #define RESET_TIME_MIN_MAX(obj, type) do { \ | |
57 | (obj)->type ## _time = 0; \ | |
58 | (obj)->min_ ## type ## _time = UINT64_MAX; \ | |
59 | (obj)->max_ ## type ## _time = 0; \ | |
60 | } while (0) | |
61 | ||
62 | static inline uint64_t | |
63 | get_time(void) | |
64 | { | |
65 | rte_rmb(); | |
66 | return rte_get_timer_cycles(); | |
67 | } | |
68 | ||
69 | /* Those are steps used to adjust job period. | |
70 | * Experiments show that for forwarding apps the up step must be less than down | |
71 | * step to achieve optimal performance. | |
72 | */ | |
73 | #define JOB_UPDATE_STEP_UP 1 | |
74 | #define JOB_UPDATE_STEP_DOWN 4 | |
75 | ||
76 | /* | |
77 | * Default update function that implements simple period adjustment. | |
78 | */ | |
79 | static void | |
80 | default_update_function(struct rte_jobstats *job, int64_t result) | |
81 | { | |
82 | int64_t err = job->target - result; | |
83 | ||
84 | /* Job is happy. Nothing to do */ | |
85 | if (err == 0) | |
86 | return; | |
87 | ||
88 | if (err > 0) { | |
89 | if (job->period + JOB_UPDATE_STEP_UP < job->max_period) | |
90 | job->period += JOB_UPDATE_STEP_UP; | |
91 | } else { | |
92 | if (job->min_period + JOB_UPDATE_STEP_DOWN < job->period) | |
93 | job->period -= JOB_UPDATE_STEP_DOWN; | |
94 | } | |
95 | } | |
96 | ||
97 | int | |
98 | rte_jobstats_context_init(struct rte_jobstats_context *ctx) | |
99 | { | |
100 | if (ctx == NULL) | |
101 | return -EINVAL; | |
102 | ||
103 | /* Init only needed parameters. Zero out everything else. */ | |
104 | memset(ctx, 0, sizeof(struct rte_jobstats_context)); | |
105 | ||
106 | rte_jobstats_context_reset(ctx); | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | void | |
112 | rte_jobstats_context_start(struct rte_jobstats_context *ctx) | |
113 | { | |
114 | uint64_t now; | |
115 | ||
116 | ctx->loop_executed_jobs = 0; | |
117 | ||
118 | now = get_time(); | |
119 | ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time); | |
120 | ctx->state_time = now; | |
121 | } | |
122 | ||
123 | void | |
124 | rte_jobstats_context_finish(struct rte_jobstats_context *ctx) | |
125 | { | |
126 | uint64_t now; | |
127 | ||
128 | if (likely(ctx->loop_executed_jobs)) | |
129 | ctx->loop_cnt++; | |
130 | ||
131 | now = get_time(); | |
132 | ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time); | |
133 | ctx->state_time = now; | |
134 | } | |
135 | ||
136 | void | |
137 | rte_jobstats_context_reset(struct rte_jobstats_context *ctx) | |
138 | { | |
139 | RESET_TIME_MIN_MAX(ctx, exec); | |
140 | RESET_TIME_MIN_MAX(ctx, management); | |
141 | ctx->start_time = get_time(); | |
142 | ctx->state_time = ctx->start_time; | |
143 | ctx->job_exec_cnt = 0; | |
144 | ctx->loop_cnt = 0; | |
145 | } | |
146 | ||
147 | void | |
148 | rte_jobstats_set_target(struct rte_jobstats *job, int64_t target) | |
149 | { | |
150 | job->target = target; | |
151 | } | |
152 | ||
153 | int | |
154 | rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job) | |
155 | { | |
156 | uint64_t now; | |
157 | ||
158 | /* Some sanity check. */ | |
159 | if (unlikely(ctx == NULL || job == NULL || job->context != NULL)) | |
160 | return -EINVAL; | |
161 | ||
162 | /* Link job with context object. */ | |
163 | job->context = ctx; | |
164 | ||
165 | now = get_time(); | |
166 | ADD_TIME_MIN_MAX(ctx, management, now - ctx->state_time); | |
167 | ctx->state_time = now; | |
168 | ||
169 | return 0; | |
170 | } | |
171 | ||
172 | int | |
173 | rte_jobstats_abort(struct rte_jobstats *job) | |
174 | { | |
175 | struct rte_jobstats_context *ctx; | |
176 | uint64_t now, exec_time; | |
177 | ||
178 | /* Some sanity check. */ | |
179 | if (unlikely(job == NULL || job->context == NULL)) | |
180 | return -EINVAL; | |
181 | ||
182 | ctx = job->context; | |
183 | now = get_time(); | |
184 | exec_time = now - ctx->state_time; | |
185 | ADD_TIME_MIN_MAX(ctx, management, exec_time); | |
186 | ctx->state_time = now; | |
187 | job->context = NULL; | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | int | |
193 | rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value) | |
194 | { | |
195 | struct rte_jobstats_context *ctx; | |
196 | uint64_t now, exec_time; | |
197 | int need_update; | |
198 | ||
199 | /* Some sanity check. */ | |
200 | if (unlikely(job == NULL || job->context == NULL)) | |
201 | return -EINVAL; | |
202 | ||
203 | need_update = job->target != job_value; | |
204 | /* Adjust period only if job is unhappy of its current period. */ | |
205 | if (need_update) | |
206 | (*job->update_period_cb)(job, job_value); | |
207 | ||
208 | ctx = job->context; | |
209 | ||
210 | /* Update execution time is considered as runtime so get time after it is | |
211 | * executed. */ | |
212 | now = get_time(); | |
213 | exec_time = now - ctx->state_time; | |
214 | ADD_TIME_MIN_MAX(job, exec, exec_time); | |
215 | ADD_TIME_MIN_MAX(ctx, exec, exec_time); | |
216 | ||
217 | ctx->state_time = now; | |
218 | ||
219 | ctx->loop_executed_jobs++; | |
220 | ctx->job_exec_cnt++; | |
221 | ||
222 | job->exec_cnt++; | |
223 | job->context = NULL; | |
224 | ||
225 | return need_update; | |
226 | } | |
227 | ||
228 | void | |
229 | rte_jobstats_set_period(struct rte_jobstats *job, uint64_t period, | |
230 | uint8_t saturate) | |
231 | { | |
232 | if (saturate != 0) { | |
233 | if (period < job->min_period) | |
234 | period = job->min_period; | |
235 | else if (period > job->max_period) | |
236 | period = job->max_period; | |
237 | } | |
238 | ||
239 | job->period = period; | |
240 | } | |
241 | ||
242 | void | |
243 | rte_jobstats_set_min(struct rte_jobstats *job, uint64_t period) | |
244 | { | |
245 | job->min_period = period; | |
246 | if (job->period < period) | |
247 | job->period = period; | |
248 | } | |
249 | ||
250 | void | |
251 | rte_jobstats_set_max(struct rte_jobstats *job, uint64_t period) | |
252 | { | |
253 | job->max_period = period; | |
254 | if (job->period > period) | |
255 | job->period = period; | |
256 | } | |
257 | ||
258 | int | |
259 | rte_jobstats_init(struct rte_jobstats *job, const char *name, | |
260 | uint64_t min_period, uint64_t max_period, uint64_t initial_period, | |
261 | int64_t target) | |
262 | { | |
263 | if (job == NULL) | |
264 | return -EINVAL; | |
265 | ||
266 | job->period = initial_period; | |
267 | job->min_period = min_period; | |
268 | job->max_period = max_period; | |
269 | job->target = target; | |
270 | job->update_period_cb = &default_update_function; | |
271 | rte_jobstats_reset(job); | |
272 | snprintf(job->name, RTE_DIM(job->name), "%s", name == NULL ? "" : name); | |
273 | job->context = NULL; | |
274 | ||
275 | return 0; | |
276 | } | |
277 | ||
278 | void | |
279 | rte_jobstats_set_update_period_function(struct rte_jobstats *job, | |
280 | rte_job_update_period_cb_t update_period_cb) | |
281 | { | |
282 | if (update_period_cb == NULL) | |
283 | update_period_cb = default_update_function; | |
284 | ||
285 | job->update_period_cb = update_period_cb; | |
286 | } | |
287 | ||
288 | void | |
289 | rte_jobstats_reset(struct rte_jobstats *job) | |
290 | { | |
291 | RESET_TIME_MIN_MAX(job, exec); | |
292 | job->exec_cnt = 0; | |
293 | } |