/*
* Copyright (c) 2015 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/pg/pg.h>
#include <vppinfra/error.h>
#include <vnet/udp/udp.h>
#include <vnet/ipsec/ikev2.h>
#include <vnet/ipsec/ikev2_priv.h>
u8 *
format_ikev2_id_type_and_data (u8 * s, va_list * args)
{
ikev2_id_t *id = va_arg (*args, ikev2_id_t *);
if (id->type == 0 || vec_len (id->data) == 0)
return format (s, "none");
s = format (s, "%U", format_ikev2_id_type, id->type);
if (id->type == IKEV2_ID_TYPE_ID_FQDN ||
id->type == IKEV2_ID_TYPE_ID_RFC822_ADDR)
{
s = format (s, " %v", id->data);
}
else
{
s =
format (s, " %U", format_hex_bytes, &id->data,
(uword) (vec_len (id->data)));
}
return s;
}
static clib_error_t *
show_ikev2_sa_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
ikev2_main_t *km = &ikev2_main;
ikev2_main_per_thread_data_t *tkm;
ikev2_sa_t *sa;
ikev2_ts_t *ts;
ikev2_child_sa_t *child;
ikev2_sa_transform_t *tr;
vec_foreach (tkm, km->per_thread_data)
{
/* *INDENT-OFF* */
pool_foreach (sa, tkm->sas, ({
u8 * s = 0;
vlib_cli_output(vm, " iip %U ispi %lx rip %U rspi %lx",
format_ip4_address, &sa->iaddr, sa->ispi,
format_ip4_address, &sa->raddr, sa->rspi);
tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
tr = ikev2_sa_get_td_for_type(sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
vlib_cli_output(vm, " %v", s);
vec_free(s);
vlib_cli_output(vm, " nonce i:%U\n r:%U",
format_hex_bytes, sa->i_nonce, vec_len(sa->i_nonce),
format_hex_bytes, sa->r_nonce, vec_len(sa->r_nonce));
vlib_cli_output(vm, " SK_d %U",
format_hex_bytes, sa->sk_d, vec_len(sa->sk_d));
vlib_cli_output(vm, " SK_a i:%U\n r:%U",
format_hex_bytes, sa->sk_ai, vec_len(sa->sk_ai),
format_hex_bytes, sa->sk_ar, vec_len(sa->sk_ar));
vlib_cli_output(vm, " SK_e i:%U\n r:%U",
format_hex_bytes, sa->sk_ei, vec_len(sa->sk_ei),
format_hex_bytes, sa->sk_er, vec_len(sa->sk_er));
vlib_cli_output(vm, " SK_p i:%U\n r:%U",
format_hex_bytes, sa->sk_pi, vec_len(sa->sk_pi),
format_hex_bytes, sa->sk_pr, vec_len(sa->sk_pr));
vlib_cli_output(vm, " identifier (i) %U",
format_ikev2_id_type_and_data, &sa->i_id);
vlib_cli_output(vm, " identifier (r) %U",
format_ikev2_id_type_and_data, &sa->r_id);
vec_foreach(child, sa->childs)
{
vlib_cli_output(vm, " child sa %u:", child - sa->childs);
tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
tr = ikev2_sa_get_td_for_type(child->r_proposals, IKEV2_TRANSFORM_TYPE_ESN);
s = format(s, "%U ", format_ikev2_sa_transform, tr);
vlib_cli_output(vm, " %v", s);
vec_free(s);
vlib_cli_output(vm, " spi(i) %lx spi(r) %lx",
child->i_proposals ? child->i_proposals[0].spi : 0,
child->r_proposals ? child->r_proposals[0].spi : 0);
vlib_cli_output(vm, " SK_e i:%U\n r:%U",
format_hex_bytes, child->sk_ei, vec_len(child->sk_ei),
format_hex_bytes, child->sk_er, vec_len(child->sk_er));
vlib_cli_output(vm, " SK_a i:%U\n r:%U",
format_hex_bytes, child->sk_ai, vec_len(child->sk_ai),
format_hex_bytes, child->sk_ar, vec_len(child->sk_ar));
vlib_cli_output(vm, " traffic selectors (i):");
vec_foreach(ts, child->tsi)
{
vlib_cli_output(vm, " %u type %u protocol_id %u addr "
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
#include <vppinfra/time.h>
#include <vppinfra/cache.h>
#include <vppinfra/error.h>
#include <vppinfra/tw_timer_2t_1w_2048sl.h>
#include <vppinfra/tw_timer_2t_2w_512sl.h>
#include <vppinfra/tw_timer_16t_2w_512sl.h>
#include <vppinfra/tw_timer_4t_3w_256sl.h>
#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
typedef struct
{
/** Handle returned from tw_start_timer */
u32 stop_timer_handle;
/** Test item should expire at this clock tick */
u64 expected_to_expire;
} tw_timer_test_elt_t;
typedef struct
{
/** Pool of test objects */
tw_timer_test_elt_t *test_elts;
/** The single-wheel */
tw_timer_wheel_2t_1w_2048sl_t single_wheel;
/** The double-wheel */
tw_timer_wheel_16t_2w_512sl_t double_wheel;
/* The triple wheel */
tw_timer_wheel_4t_3w_256sl_t triple_wheel;
/* The triple wheel with overflow vector */
tw_timer_wheel_1t_3w_1024sl_ov_t triple_ov_wheel;
/* Another two timer wheel geometry */
tw_timer_wheel_2t_2w_512sl_t two_timer_double_wheel;
/** random number seed */
u64 seed;
/** number of timers */
u32 ntimers;
/** number of "churn" iterations */
u32 niter;
/** number of clock ticks per churn iteration */
u32 ticks_per_iter;
/** cpu timer */
clib_time_t clib_time;
} tw_timer_test_main_t;
tw_timer_test_main_t tw_timer_test_main;
static void
run_single_wheel (tw_timer_wheel_2t_1w_2048sl_t * tw, u32 n_ticks)
{
u32 i;
f64 now = tw->last_run_time + 1.01;
for (i = 0; i < n_ticks; i++)
{
tw_timer_expire_timers_2t_1w_2048sl (tw, now);
now += 1.01;
}
}
static void
run_double_wheel (tw_timer_wheel_16t_2w_512sl_t * tw, u32 n_ticks)
{
u32 i;
f64 now = tw->last_run_time + 1.01;
for (i = 0; i < n_ticks; i++)
{
tw_timer_expire_timers_16t_2w_512sl (tw, now);
now += 1.01;
}
}
static void
run_two_timer_double_wheel (tw_timer_wheel_2t_2w_512sl_t * tw, u32 n_ticks)
{
u32 i;
f64 now = tw->last_run_time + 1.01;
for (i = 0; i < n_ticks; i++)
{
tw_timer_expire_timers_2t_2w_512sl (tw, now);
now += 1.01;
}
}
static void
run_triple_wheel (tw_timer_wheel_4t_3w_256sl_t * tw, u32 n_ticks)
{
u32 i;
f64 now = tw->last_run_time + 1.01;
for (i = 0; i < n_ticks; i++)
{
tw_timer_expire_timers_4t_3w_256sl (tw, now);
now += 1.01;
}
}
static void
run_triple_ov_wheel (tw_timer_wheel_1t_3w_1024sl_ov_t * tw, u32 n_ticks)
{
u32 i;
f64 now = tw->last_run_time + 1.01;
for (i = 0; i < n_ticks; i++)
{
tw_timer_expire_timers_1t_3w_1024sl_ov (tw, now);
now += 1.01;
}
}
static void
expired_timer_single_callback (u32 * expired_timers)
{
int i;
u32 pool_index, timer_id;
tw_timer_test_elt_t *e;
tw_timer_test_main_t *tm = &tw_timer_test_main;
for (i = 0; i < vec_len (expired_timers); i++)
{
pool_index = expired_timers[i] & 0x7FFFFFFF;
timer_id = expired_timers[i] >> 31;
ASSERT (timer_id == 1);
e = pool_elt_at_index (tm->test_elts, pool_index);
if (e->expected_to_expire != tm->single_wheel.current_tick)
{
fformat (stdout, "[%d] expired at %lld not %lld\n",
e - tm->test_elts, tm->single_wheel.current_tick,
e->expected_to_expire);
}
pool_put (tm->test_elts, e);
}
}
static void
expired_timer_double_callback (u32 * expired_timers)
{
int i;
u32 pool_index, timer_id;
tw_timer_test_elt_t *e;
tw_timer_test_main_t *tm = &tw_timer_test_main;
for (i = 0; i < vec_len (expired_timers); i++)
{
pool_index = expired_timers[i] & 0x0FFFFFFF;
timer_id = expired_timers[i] >> 28;
ASSERT (timer_id == 14);
e = pool_elt_at_index (tm->test_elts, pool_index);
if (e->expected_to_expire != tm->double_wheel.current_tick)
{
fformat (stdout, "[%d] expired at %lld not %lld\n",
e - tm->test_elts, tm->double_wheel.current_tick,
e->expected_to_expire);
}
pool_put (tm->test_elts, e);
}
}
static void
expired_timer_two_timer_double_callback (u32 * expired_timers)
{
int i;
u32 pool_index, timer_id;
tw_timer_test_elt_t *e;
tw_timer_test_main_t *tm = &tw_timer_test_main;
for (i = 0; i < vec_len (expired_timers); i++)
{
pool_index = expired_timers[i] & 0x7FFFFFFF;
timer_id = expired_timers[i] >> 31;
ASSERT (timer_id == 1);
e = pool_elt_at_index (tm->test_elts, pool_index);
if (e->expected_to_expire != tm->two_timer_double_wheel.current_tick)
{
fformat (stdout, "[%d] expired at %lld not %lld\n",
e - tm->test_elts, tm->two_timer_double_wheel.current_tick,
e->expected_to_expire);
}
pool_put (tm->test_elts, e);
}
}
static void
expired_timer_triple_callback (u32 * expired_timers)
{
int i;
u32 pool_index, timer_id;
tw_timer_test_elt_t *e;
tw_timer_test_main_t *tm = &tw_timer_test_main;
for (i = 0; i < vec_len (expired_timers); i++)
{
pool_index = expired_timers[i] & 0x3FFFFFFF;
timer_id = expired_timers[i] >> 30;
ASSERT (timer_id == 3);
e = pool_elt_at_index (tm->test_elts, pool_index);
if (e->expected_to_expire != tm->triple_wheel.current_tick)
{
fformat (stdout, "[%d] expired at %lld not %lld\n",
e - tm->test_elts, tm->triple_wheel.current_tick,
e->expected_to_expire);
}
pool_put (tm->test_elts, e);
}
}
static void
expired_timer_triple_ov_callback (u32 * expired_timers)
{
int i;
u32 pool_index;
tw_timer_test_elt_t *e;
tw_timer_test_main_t *tm = &tw_timer_test_main;
for (i = 0; i < vec_len (expired_timers); i++)
{
pool_index = expired_timers[i];
e = pool_elt_at_index (tm->test_elts, pool_index);
if (e->expected_to_expire != tm->triple_ov_wheel.current_tick)
{
fformat (stdout, "[%d] expired at %lld not %lld\n",
e - tm->test_elts, tm->triple_ov_wheel.current_tick,
e->expected_to_expire);
}
pool_put (tm->test_elts, e);
}
}
static clib_error_t *
test2_single (tw_timer_test_main_t * tm)
{
u32 i, j;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset;
u64 expiration_time;
u32 max_expiration_time = 0;
u32 *deleted_indices = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
expired_timer_single_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 757;
run_single_wheel (&tm->single_wheel, initial_wheel_offset);
fformat (stdout, "initial wheel time %d, fast index %d\n",
tm->single_wheel.current_tick,
tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
initial_wheel_offset = tm->single_wheel.current_tick;
fformat (stdout,
"test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & (2047);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle =
tw_timer_start_2t_1w_2048sl (&tm->single_wheel, e - tm->test_elts,
1 /* timer id */ ,
expiration_time);
}
adds += i;
for (i = 0; i < tm->niter; i++)
{
run_single_wheel (&tm->single_wheel, tm->ticks_per_iter);
j = 0;
vec_reset_length (deleted_indices);
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
tw_timer_stop_2t_1w_2048sl (&tm->single_wheel, e->stop_timer_handle);
vec_add1 (deleted_indices, e - tm->test_elts);
if (++j >= tm->ntimers / 4)
goto del_and_re_add;
}
/* *INDENT-ON* */
del_and_re_add:
for (j = 0; j < vec_len (deleted_indices); j++)
{
pool_put_index (tm->test_elts, deleted_indices[j]);
}
deletes += j;
for (j = 0; j < tm->ntimers / 4; j++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & (2047);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire =
expiration_time + tm->single_wheel.current_tick;
e->stop_timer_handle = tw_timer_start_2t_1w_2048sl
(&tm->single_wheel, e - tm->test_elts, 1 /* timer id */ ,
expiration_time);
}
adds += j;
}
vec_free (deleted_indices);
run_single_wheel (&tm->single_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->single_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->single_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_2t_1w_2048sl (&tm->single_wheel);
return 0;
}
static clib_error_t *
test2_double (tw_timer_test_main_t * tm)
{
u32 i, j;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset;
u32 expiration_time;
u32 max_expiration_time = 0;
u32 *deleted_indices = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
expired_timer_double_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 7577;
run_double_wheel (&tm->double_wheel, initial_wheel_offset);
fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
tm->double_wheel.current_tick,
tm->double_wheel.current_index[TW_TIMER_RING_FAST],
tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
initial_wheel_offset = tm->double_wheel.current_tick;
fformat (stdout,
"test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle =
tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
14 /* timer id */ ,
expiration_time);
}
adds += i;
for (i = 0; i < tm->niter; i++)
{
run_double_wheel (&tm->double_wheel, tm->ticks_per_iter);
j = 0;
vec_reset_length (deleted_indices);
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
tw_timer_stop_16t_2w_512sl (&tm->double_wheel, e->stop_timer_handle);
vec_add1 (deleted_indices, e - tm->test_elts);
if (++j >= tm->ntimers / 4)
goto del_and_re_add;
}
/* *INDENT-ON* */
del_and_re_add:
for (j = 0; j < vec_len (deleted_indices); j++)
pool_put_index (tm->test_elts, deleted_indices[j]);
deletes += j;
for (j = 0; j < tm->ntimers / 4; j++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time +
tm->double_wheel.current_tick;
e->stop_timer_handle = tw_timer_start_16t_2w_512sl
(&tm->double_wheel, e - tm->test_elts, 14 /* timer id */ ,
expiration_time);
}
adds += j;
}
vec_free (deleted_indices);
run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->double_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->double_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
return 0;
}
static u32
get_expiration_time (tw_timer_test_main_t * tm)
{
u32 expiration_time;
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
return expiration_time;
}
static clib_error_t *
test2_double_updates (tw_timer_test_main_t * tm)
{
u32 i, j;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset;
u32 expiration_time;
u32 max_expiration_time = 0, updates = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
expired_timer_double_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 7577;
run_double_wheel (&tm->double_wheel, initial_wheel_offset);
fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
tm->double_wheel.current_tick,
tm->double_wheel.current_index[TW_TIMER_RING_FAST],
tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
initial_wheel_offset = tm->double_wheel.current_tick;
fformat (stdout,
"test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
expiration_time = get_expiration_time (tm);
max_expiration_time = clib_max (expiration_time, max_expiration_time);
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle = tw_timer_start_16t_2w_512sl (&tm->double_wheel,
e - tm->test_elts,
14 /* timer id */ ,
expiration_time);
}
for (i = 0; i < tm->niter; i++)
{
run_double_wheel (&tm->double_wheel, tm->ticks_per_iter);
j = 0;
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
expiration_time = get_expiration_time (tm);
max_expiration_time = clib_max (expiration_time, max_expiration_time);
e->expected_to_expire = expiration_time
+ tm->double_wheel.current_tick;
tw_timer_update_16t_2w_512sl (&tm->double_wheel, e->stop_timer_handle,
expiration_time);
if (++j >= tm->ntimers / 4)
goto done;
}
/* *INDENT-ON* */
done:
updates += j;
}
run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d updates, %d ticks\n", updates,
tm->double_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) updates + (f64) tm->double_wheel.current_tick) / (after -
before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
return 0;
}
static clib_error_t *
test2_triple (tw_timer_test_main_t * tm)
{
u32 i, j;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset = 0;
u32 expiration_time;
u32 max_expiration_time = 0;
u32 *deleted_indices = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_4t_3w_256sl (&tm->triple_wheel,
expired_timer_triple_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 75700;
run_triple_wheel (&tm->triple_wheel, initial_wheel_offset);
fformat (stdout,
"initial wheel time %d, fi %d si %d gi %d\n",
tm->triple_wheel.current_tick,
tm->triple_wheel.current_index[TW_TIMER_RING_FAST],
tm->triple_wheel.current_index[TW_TIMER_RING_SLOW],
tm->triple_wheel.current_index[TW_TIMER_RING_GLACIER]);
initial_wheel_offset = tm->triple_wheel.current_tick;
fformat (stdout,
"test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle =
tw_timer_start_4t_3w_256sl (&tm->triple_wheel, e - tm->test_elts,
3 /* timer id */ ,
expiration_time);
}
adds += i;
for (i = 0; i < tm->niter; i++)
{
run_triple_wheel (&tm->triple_wheel, tm->ticks_per_iter);
j = 0;
vec_reset_length (deleted_indices);
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
tw_timer_stop_4t_3w_256sl (&tm->triple_wheel, e->stop_timer_handle);
vec_add1 (deleted_indices, e - tm->test_elts);
if (++j >= tm->ntimers / 4)
goto del_and_re_add;
}
/* *INDENT-ON* */
del_and_re_add:
for (j = 0; j < vec_len (deleted_indices); j++)
pool_put_index (tm->test_elts, deleted_indices[j]);
deletes += j;
for (j = 0; j < tm->ntimers / 4; j++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time +
tm->triple_wheel.current_tick;
e->stop_timer_handle = tw_timer_start_4t_3w_256sl
(&tm->triple_wheel, e - tm->test_elts, 3 /* timer id */ ,
expiration_time);
}
adds += j;
}
vec_free (deleted_indices);
run_triple_wheel (&tm->triple_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->triple_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->triple_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_4t_3w_256sl (&tm->triple_wheel);
return 0;
}
static clib_error_t *
test2_triple_ov (tw_timer_test_main_t * tm)
{
u32 i, j;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset = 0;
u32 expiration_time;
u32 max_expiration_time = 0;
u32 *deleted_indices = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
expired_timer_triple_ov_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 75700;
run_triple_ov_wheel (&tm->triple_ov_wheel, initial_wheel_offset);
fformat (stdout,
"initial wheel time %d, fi %d si %d gi %d\n",
tm->triple_ov_wheel.current_tick,
tm->triple_ov_wheel.current_index[TW_TIMER_RING_FAST],
tm->triple_ov_wheel.current_index[TW_TIMER_RING_SLOW],
tm->triple_ov_wheel.current_index[TW_TIMER_RING_GLACIER]);
initial_wheel_offset = tm->triple_ov_wheel.current_tick;
fformat (stdout,
"test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle =
tw_timer_start_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
e - tm->test_elts, 0 /* timer id */ ,
expiration_time);
}
adds += i;
for (i = 0; i < tm->niter; i++)
{
run_triple_ov_wheel (&tm->triple_ov_wheel, tm->ticks_per_iter);
j = 0;
vec_reset_length (deleted_indices);
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
tw_timer_stop_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
e->stop_timer_handle);
vec_add1 (deleted_indices, e - tm->test_elts);
if (++j >= tm->ntimers / 4)
goto del_and_re_add;
}
/* *INDENT-ON* */
del_and_re_add:
for (j = 0; j < vec_len (deleted_indices); j++)
pool_put_index (tm->test_elts, deleted_indices[j]);
deletes += j;
for (j = 0; j < tm->ntimers / 4; j++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
do
{
expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
}
while (expiration_time == 0);
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time +
tm->triple_ov_wheel.current_tick;
e->stop_timer_handle = tw_timer_start_1t_3w_1024sl_ov
(&tm->triple_ov_wheel, e - tm->test_elts, 0 /* timer id */ ,
expiration_time);
}
adds += j;
}
vec_free (deleted_indices);
run_triple_ov_wheel (&tm->triple_ov_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->triple_ov_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->triple_ov_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
TWT (tw_timer) * t;
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
t = pool_elt_at_index (tm->triple_ov_wheel.timers, e->stop_timer_handle);
fformat (stdout, " expiration_time %lld\n", t->expiration_time);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_1t_3w_1024sl_ov (&tm->triple_ov_wheel);
return 0;
}
static clib_error_t *
test1_single (tw_timer_test_main_t * tm)
{
u32 i;
tw_timer_test_elt_t *e;
u32 offset;
tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
expired_timer_single_callback,
1.0 /* timer interval */ , ~0);
/*
* Prime offset, to make sure that the wheel starts in a
* non-trivial position
*/
offset = 123;
run_single_wheel (&tm->single_wheel, offset);
fformat (stdout, "initial wheel time %d, fast index %d\n",
tm->single_wheel.current_tick,
tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
offset = tm->single_wheel.current_tick;
for (i = 0; i < tm->ntimers; i++)
{
u32 expected_to_expire;
u32 timer_arg;
timer_arg = 1 + i;
timer_arg &= 2047;
if (timer_arg == 0)
timer_arg = 1;
expected_to_expire = timer_arg + tm->single_wheel.current_tick;
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
e->expected_to_expire = expected_to_expire;
e->stop_timer_handle = tw_timer_start_2t_1w_2048sl
(&tm->single_wheel, e - tm->test_elts, 1 /* timer id */ ,
timer_arg);
}
run_single_wheel (&tm->single_wheel, tm->ntimers + 3);
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat(stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
fformat (stdout,
"final wheel time %d, fast index %d\n",
tm->single_wheel.current_tick,
tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
pool_free (tm->test_elts);
tw_timer_wheel_free_2t_1w_2048sl (&tm->single_wheel);
return 0;
}
static clib_error_t *
test1_double (tw_timer_test_main_t * tm)
{
u32 i;
tw_timer_test_elt_t *e;
u32 offset;
tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
expired_timer_double_callback,
1.0 /* timer interval */ , ~0);
/*
* Prime offset, to make sure that the wheel starts in a
* non-trivial position
*/
offset = 227989;
run_double_wheel (&tm->double_wheel, offset);
fformat (stdout, "initial wheel time %d, fast index %d\n",
tm->double_wheel.current_tick,
tm->double_wheel.current_index[TW_TIMER_RING_FAST]);
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
e->expected_to_expire = i + tm->double_wheel.current_tick + 1;
e->stop_timer_handle = tw_timer_start_16t_2w_512sl
(&tm->double_wheel, e - tm->test_elts, 14 /* timer id */ ,
i + 1);
}
run_double_wheel (&tm->double_wheel, tm->ntimers + 3);
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat(stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
fformat (stdout,
"final wheel time %d, fast index %d\n",
tm->double_wheel.current_tick,
tm->double_wheel.current_index[TW_TIMER_RING_FAST]);
pool_free (tm->test_elts);
tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
return 0;
}
static clib_error_t *
test1_two_timer_double (tw_timer_test_main_t * tm)
{
u32 i;
tw_timer_test_elt_t *e;
u32 offset;
tw_timer_wheel_init_2t_2w_512sl (&tm->two_timer_double_wheel,
expired_timer_two_timer_double_callback,
1.0 /* timer interval */ , ~0);
/*
* Prime offset, to make sure that the wheel starts in a
* non-trivial position
*/
offset = 2745;
run_two_timer_double_wheel (&tm->two_timer_double_wheel, offset);
fformat (stdout, "initial wheel time %d, fast index %d\n",
tm->two_timer_double_wheel.current_tick,
tm->two_timer_double_wheel.current_index[TW_TIMER_RING_FAST]);
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
e->expected_to_expire = i + tm->two_timer_double_wheel.current_tick + 1;
e->stop_timer_handle = tw_timer_start_2t_2w_512sl
(&tm->two_timer_double_wheel, e - tm->test_elts, 1 /* timer id */ ,
i + 1);
}
run_two_timer_double_wheel (&tm->two_timer_double_wheel, tm->ntimers + 3);
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat(stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
fformat (stdout,
"final wheel time %d, fast index %d\n",
tm->two_timer_double_wheel.current_tick,
tm->two_timer_double_wheel.current_index[TW_TIMER_RING_FAST]);
pool_free (tm->test_elts);
tw_timer_wheel_free_2t_2w_512sl (&tm->two_timer_double_wheel);
return 0;
}
static clib_error_t *
test3_triple_double (tw_timer_test_main_t * tm)
{
tw_timer_test_elt_t *e;
u32 initial_wheel_offset = 0;
u32 expiration_time;
u32 max_expiration_time = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_4t_3w_256sl (&tm->triple_wheel,
expired_timer_triple_callback,
1.0 /* timer interval */ , ~0);
initial_wheel_offset = 0;
run_triple_wheel (&tm->triple_wheel, initial_wheel_offset);
fformat (stdout,
"initial wheel time %d, fi %d si %d gi %d\n",
tm->triple_wheel.current_tick,
tm->triple_wheel.current_index[TW_TIMER_RING_FAST],
tm->triple_wheel.current_index[TW_TIMER_RING_SLOW],
tm->triple_wheel.current_index[TW_TIMER_RING_GLACIER]);
initial_wheel_offset = tm->triple_wheel.current_tick;
fformat (stdout, "Create a timer which expires at wheel-time (1, 0, 0)\n");
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
/* 1 glacier ring tick from now */
expiration_time = TW_SLOTS_PER_RING * TW_SLOTS_PER_RING;
e->expected_to_expire = expiration_time + initial_wheel_offset;
max_expiration_time = expiration_time;
e->stop_timer_handle =
tw_timer_start_4t_3w_256sl (&tm->triple_wheel, e - tm->test_elts,
3 /* timer id */ ,
expiration_time);
run_triple_wheel (&tm->triple_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->triple_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->triple_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_4t_3w_256sl (&tm->triple_wheel);
return 0;
}
static clib_error_t *
test4_double_double (tw_timer_test_main_t * tm)
{
u32 i;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset;
u32 expiration_time;
u32 max_expiration_time = 0;
u32 *deleted_indices = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
expired_timer_double_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 0;
run_double_wheel (&tm->double_wheel, initial_wheel_offset);
fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
tm->double_wheel.current_tick,
tm->double_wheel.current_index[TW_TIMER_RING_FAST],
tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
initial_wheel_offset = tm->double_wheel.current_tick;
fformat (stdout, "test timer which expires at 512 ticks\n");
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
expiration_time = 512;
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle =
tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
14 /* timer id */ ,
expiration_time);
}
adds = 1;
vec_free (deleted_indices);
run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->double_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->double_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
return 0;
}
static clib_error_t *
test5_double (tw_timer_test_main_t * tm)
{
u32 i;
tw_timer_test_elt_t *e;
u32 initial_wheel_offset;
u32 expiration_time;
u32 max_expiration_time = 0;
u32 adds = 0, deletes = 0;
f64 before, after;
clib_time_init (&tm->clib_time);
tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
expired_timer_double_callback,
1.0 /* timer interval */ , ~0);
/* Prime offset */
initial_wheel_offset = 7567;
run_double_wheel (&tm->double_wheel, initial_wheel_offset);
fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
tm->double_wheel.current_tick,
tm->double_wheel.current_index[TW_TIMER_RING_FAST],
tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
initial_wheel_offset = tm->double_wheel.current_tick;
fformat (stdout,
"test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
before = clib_time_now (&tm->clib_time);
/* Prime the pump */
for (i = 0; i < tm->ntimers; i++)
{
pool_get (tm->test_elts, e);
clib_memset (e, 0, sizeof (*e));
expiration_time = i + 1;
if (expiration_time > max_expiration_time)
max_expiration_time = expiration_time;
e->expected_to_expire = expiration_time + initial_wheel_offset;
e->stop_timer_handle =
tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
14 /* timer id */ ,
expiration_time);
}
adds += i;
run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
after = clib_time_now (&tm->clib_time);
fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
tm->double_wheel.current_tick);
fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
(after - before),
((f64) adds + (f64) deletes +
(f64) tm->double_wheel.current_tick) / (after - before));
if (pool_elts (tm->test_elts))
fformat (stdout, "Note: %d elements remain in pool\n",
pool_elts (tm->test_elts));
/* *INDENT-OFF* */
pool_foreach (e, tm->test_elts)
{
fformat (stdout, "[%d] expected to expire %d\n",
e - tm->test_elts,
e->expected_to_expire);
}
/* *INDENT-ON* */
pool_free (tm->test_elts);
tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
return 0;
}
static clib_error_t *
timer_test_command_fn (tw_timer_test_main_t * tm, unformat_input_t * input)
{
int is_test1 = 0, is_updates = 0;
int num_wheels = 1;
int is_test2 = 0;
int is_test3 = 0;
int is_test4 = 0;
int is_test5 = 0;
int overflow = 0;
clib_memset (tm, 0, sizeof (*tm));
/* Default values */
tm->ntimers = 100000;
tm->seed = 0xDEADDABEB00BFACE;
tm->niter = 1000;
tm->ticks_per_iter = 727;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "seed %lld", &tm->seed))
;
else if (unformat (input, "test1"))
is_test1 = 1;
else if (unformat (input, "test2"))
is_test2 = 1;
else if (unformat (input, "overflow"))
overflow = 1;
else if (unformat (input, "lebron"))
is_test3 = 1;
else if (unformat (input, "wilt"))
is_test4 = 1;
else if (unformat (input, "linear"))
is_test5 = 1;
else if (unformat (input, "updates"))
is_updates = 1;
else if (unformat (input, "wheels %d", &num_wheels))
;
else if (unformat (input, "ntimers %d", &tm->ntimers))
;
else if (unformat (input, "niter %d", &tm->niter))
;
else if (unformat (input, "ticks_per_iter %d", &tm->ticks_per_iter))
;
else
break;
}
if (is_test1 + is_test2 + is_test3 + is_test4 + is_test5 == 0)
return clib_error_return (0, "No test specified [test1..n]");
if (num_wheels < 1 || num_wheels > 3)
return clib_error_return (0, "unsupported... 1 or 2 wheels only");
if (is_test1)
{
if (num_wheels == 1)
return test1_single (tm);
else
{
(void) test1_double (tm);
return test1_two_timer_double (tm);
}
}
if (is_test2)
{
if (num_wheels == 1)
return test2_single (tm);
else if (num_wheels == 2)
if (is_updates)
return test2_double_updates (tm);
else
return test2_double (tm);
else if (num_wheels == 3)
{
if (overflow == 0)
return test2_triple (tm);
else
return test2_triple_ov (tm);
}
}
if (is_test3)
return test3_triple_double (tm);
if (is_test4)
return test4_double_double (tm);
if (is_test5)
return test5_double (tm);
/* NOTREACHED */
return 0;
}
#ifdef CLIB_UNIX
int
main (int argc, char *argv[])
{
unformat_input_t i;
clib_error_t *error;
tw_timer_test_main_t *tm = &tw_timer_test_main;
clib_mem_init (0, 3ULL << 30);
unformat_init_command_line (&i, argv);
error = timer_test_command_fn (tm, &i);
unformat_free (&i);
if (error)
{
clib_error_report (error);
return 1;
}
return 0;
}
#endif /* CLIB_UNIX */
/* For debugging... */
int
pifi (void *p, u32 index)
{
return pool_is_free_index (p, index);
}
u32
vl (void *p)
{
return vec_len (p);
}
uword
pe (void *v)
{
return (pool_elts (v));
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/