/* * 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 #include #include #include #include #include #include #include #include #if __GNUC__ < 4 #define SQRT(a) a #else #define SQRT(a) sqrt(a) #endif typedef struct { uword n_iter; u32 n_events; u32 seed; u32 verbose; /* Time is "synthetic" e.g. not taken from CPU timer. */ u32 synthetic_time; clib_time_t time; timing_wheel_t timing_wheel; u64 *events; f64 max_time; f64 wait_time; f64 total_iterate_time; f64 time_iterate_start; f64 time_per_status_update; f64 time_next_status_update; } test_timing_wheel_main_t; typedef struct { f64 dt; f64 fraction; u64 count; } test_timing_wheel_tmp_t; static void set_event (test_timing_wheel_main_t * tm, uword i) { timing_wheel_t *w = &tm->timing_wheel; u64 cpu_time; cpu_time = w->current_time_index << w->log2_clocks_per_bin; if (tm->synthetic_time) cpu_time += random_u32 (&tm->seed) % tm->n_iter; else cpu_time += random_f64 (&tm->seed) * tm->max_time * tm->time.clocks_per_second; timing_wheel_insert (w, cpu_time, i); timing_wheel_validate (w); tm->events[i] = cpu_time; } static int test_timing_wheel_tmp_cmp (void *a1, void *a2) { test_timing_wheel_tmp_t *f1 = a1; test_timing_wheel_tmp_t *f2 = a2; return f1->dt < f2->dt ? -1 : (f1->dt > f2->dt ? +1 : 0); } clib_error_t * test_timing_wheel_main (unformat_input_t * input) { clib_error_t *error = 0; test_timing_wheel_main_t _tm, *tm = &_tm; timing_wheel_t *w = &tm->timing_wheel; uword iter, i; memset (tm, 0, sizeof (tm[0])); tm->n_iter = 10; tm->time_per_status_update = 0; tm->n_events = 100; tm->seed = 1; tm->synthetic_time = 1; tm->max_time = 1; tm->wait_time = 1e-3; w->validate = 0; w->n_wheel_elt_time_bits = 32; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "iter %wd", &tm->n_iter)) ; else if (unformat (input, "events %d", &tm->n_events)) ; else if (unformat (input, "elt-time-bits %d", &w->n_wheel_elt_time_bits)) ; else if (unformat (input, "seed %d", &tm->seed)) ; else if (unformat (input, "verbose")) tm->verbose = 1; else if (unformat (input, "validate")) w->validate = 1; else if (unformat (input, "real-time")) tm->synthetic_time = 0; else if (unformat (input, "synthetic-time")) tm->synthetic_time = 1; else if (unformat (input, "max-time %f", &tm->max_time)) ; else if (unformat (input, "wait-time %f", &tm->wait_time)) ; else if (unformat (input, "iter-time %f", &tm->total_iterate_time)) ; else if (unformat (input, "print %f", &tm->time_per_status_update)) ; else { error = clib_error_create ("unknown input `%U'\n", format_unformat_error, input); goto done; } } if (!tm->seed) tm->seed = random_default_seed (); clib_time_init (&tm->time); if (tm->synthetic_time) { w->min_sched_time = tm->time.seconds_per_clock; w->max_sched_time = w->min_sched_time * 256; timing_wheel_init (w, 0, tm->time.clocks_per_second); } else { timing_wheel_init (w, clib_cpu_time_now (), tm->time.clocks_per_second); } clib_warning ("iter %wd, events %d, seed %u, %U", tm->n_iter, tm->n_events, tm->seed, format_timing_wheel, &tm->timing_wheel, /* verbose */ 0); /* Make some events. */ vec_resize (tm->events, tm->n_events); for (i = 0; i < vec_len (tm->events); i++) set_event (tm, i); { u32 *expired = 0; f64 ave_error = 0; f64 rms_error = 0; f64 max_error = 0, min_error = 1e30; u32 *error_hist = 0; uword n_expired = 0; uword *expired_bitmap[2] = { 0 }; uword n_events_in_wheel = vec_len (tm->events); vec_resize (expired, 32); vec_resize (error_hist, 1024); tm->time_iterate_start = clib_time_now (&tm->time); tm->time_next_status_update = tm->time_iterate_start + tm->time_per_status_update; if (tm->total_iterate_time != 0) tm->n_iter = ~0; for (iter = 0; iter < tm->n_iter || n_events_in_wheel > 0; iter++) { u64 cpu_time, min_next_time[2]; if (tm->synthetic_time) cpu_time = iter << w->log2_clocks_per_bin; else cpu_time = clib_cpu_time_now (); _vec_len (expired) = 0; expired = timing_wheel_advance (w, cpu