1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 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 "test.h" 35 36 #include <stdio.h> 37 #include <unistd.h> 38 #include <inttypes.h> 39 #include <rte_cycles.h> 40 #include <rte_timer.h> 41 #include <rte_common.h> 42 #include <rte_lcore.h> 43 #include <rte_random.h> 44 #include <rte_malloc.h> 45 46 #define MAX_ITERATIONS 1000000 47 48 int outstanding_count = 0; 49 50 static void 51 timer_cb(struct rte_timer *t __rte_unused, void *param __rte_unused) 52 { 53 outstanding_count--; 54 } 55 56 #define DELAY_SECONDS 1 57 58 #ifdef RTE_EXEC_ENV_LINUXAPP 59 #define do_delay() usleep(10) 60 #else 61 #define do_delay() rte_pause() 62 #endif 63 64 static int 65 test_timer_perf(void) 66 { 67 unsigned iterations = 100; 68 unsigned i; 69 struct rte_timer *tms; 70 uint64_t start_tsc, end_tsc, delay_start; 71 unsigned lcore_id = rte_lcore_id(); 72 73 tms = rte_malloc(NULL, sizeof(*tms) * MAX_ITERATIONS, 0); 74 75 for (i = 0; i < MAX_ITERATIONS; i++) 76 rte_timer_init(&tms[i]); 77 78 const uint64_t ticks = rte_get_timer_hz() * DELAY_SECONDS; 79 const uint64_t ticks_per_ms = rte_get_tsc_hz()/1000; 80 const uint64_t ticks_per_us = ticks_per_ms/1000; 81 82 while (iterations <= MAX_ITERATIONS) { 83 84 printf("Appending %u timers\n", iterations); 85 start_tsc = rte_rdtsc(); 86 for (i = 0; i < iterations; i++) 87 rte_timer_reset(&tms[i], ticks, SINGLE, lcore_id, 88 timer_cb, NULL); 89 end_tsc = rte_rdtsc(); 90 printf("Time for %u timers: %"PRIu64" (%"PRIu64"ms), ", iterations, 91 end_tsc-start_tsc, (end_tsc-start_tsc+ticks_per_ms/2)/(ticks_per_ms)); 92 printf("Time per timer: %"PRIu64" (%"PRIu64"us)\n", 93 (end_tsc-start_tsc)/iterations, 94 ((end_tsc-start_tsc)/iterations+ticks_per_us/2)/(ticks_per_us)); 95 outstanding_count = iterations; 96 delay_start = rte_get_timer_cycles(); 97 while (rte_get_timer_cycles() < delay_start + ticks) 98 do_delay(); 99 100 start_tsc = rte_rdtsc(); 101 while (outstanding_count) 102 rte_timer_manage(); 103 end_tsc = rte_rdtsc(); 104 printf("Time for %u callbacks: %"PRIu64" (%"PRIu64"ms), ", iterations, 105 end_tsc-start_tsc, (end_tsc-start_tsc+ticks_per_ms/2)/(ticks_per_ms)); 106 printf("Time per callback: %"PRIu64" (%"PRIu64"us)\n", 107 (end_tsc-start_tsc)/iterations, 108 ((end_tsc-start_tsc)/iterations+ticks_per_us/2)/(ticks_per_us)); 109 110 printf("Resetting %u timers\n", iterations); 111 start_tsc = rte_rdtsc(); 112 for (i = 0; i < iterations; i++) 113 rte_timer_reset(&tms[i], rte_rand() % ticks, SINGLE, lcore_id, 114 timer_cb, NULL); 115 end_tsc = rte_rdtsc(); 116 printf("Time for %u timers: %"PRIu64" (%"PRIu64"ms), ", iterations, 117 end_tsc-start_tsc, (end_tsc-start_tsc+ticks_per_ms/2)/(ticks_per_ms)); 118 printf("Time per timer: %"PRIu64" (%"PRIu64"us)\n", 119 (end_tsc-start_tsc)/iterations, 120 ((end_tsc-start_tsc)/iterations+ticks_per_us/2)/(ticks_per_us)); 121 outstanding_count = iterations; 122 123 delay_start = rte_get_timer_cycles(); 124 while (rte_get_timer_cycles() < delay_start + ticks) 125 do_delay(); 126 127 rte_timer_manage(); 128 if (outstanding_count != 0) { 129 printf("Error: outstanding callback count = %d\n", outstanding_count); 130 return -1; 131 } 132 133 iterations *= 10; 134 printf("\n"); 135 } 136 137 printf("All timers processed ok\n"); 138 139 /* measure time to poll an empty timer list */ 140 start_tsc = rte_rdtsc(); 141 for (i = 0; i < iterations; i++) 142 rte_timer_manage(); 143 end_tsc = rte_rdtsc(); 144 printf("\nTime per rte_timer_manage with zero timers: %"PRIu64" cycles\n", 145 (end_tsc - start_tsc + iterations/2) / iterations); 146 147 /* measure time to poll a timer list with timers, but without 148 * calling any callbacks */ 149 rte_timer_reset(&tms[0], ticks * 100, SINGLE, lcore_id, 150 timer_cb, NULL); 151 start_tsc = rte_rdtsc(); 152 for (i = 0; i < iterations; i++) 153 rte_timer_manage(); 154 end_tsc = rte_rdtsc(); 155 printf("Time per rte_timer_manage with zero callbacks: %"PRIu64" cycles\n", 156 (end_tsc - start_tsc + iterations/2) / iterations); 157 158 return 0; 159 } 160 161 static struct test_command timer_perf_cmd = { 162 .command = "timer_perf_autotest", 163 .callback = test_timer_perf, 164 }; 165 REGISTER_TEST_COMMAND(timer_perf_cmd); 166