dpdk/app/test/test_timer_secondary.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2019 Intel Corporation
   3 */
   4
   5#include <stdio.h>
   6#include <string.h>
   7
   8#include <rte_eal.h>
   9#include <rte_lcore.h>
  10#include <rte_debug.h>
  11#include <rte_memzone.h>
  12#include <rte_atomic.h>
  13#include <rte_timer.h>
  14#include <rte_cycles.h>
  15#include <rte_mempool.h>
  16#include <rte_random.h>
  17
  18#include "test.h"
  19#include "process.h"
  20
  21#define NUM_TIMERS              (1 << 20) /* ~1M timers */
  22#define NUM_LCORES_NEEDED       3
  23#define TEST_INFO_MZ_NAME       "test_timer_info_mz"
  24#define MSECPERSEC              1E3
  25
  26#define launch_proc(ARGV) process_dup(ARGV, RTE_DIM(ARGV), __func__)
  27
  28struct test_info {
  29        unsigned int main_lcore;
  30        unsigned int mgr_lcore;
  31        unsigned int sec_lcore;
  32        uint32_t timer_data_id;
  33        volatile int expected_count;
  34        volatile int expired_count;
  35        struct rte_mempool *tim_mempool;
  36        struct rte_timer *expired_timers[NUM_TIMERS];
  37        int expired_timers_idx;
  38        volatile int exit_flag;
  39};
  40
  41static int
  42timer_secondary_spawn_wait(unsigned int lcore)
  43{
  44        char coremask[10];
  45#ifdef RTE_EXEC_ENV_LINUXAPP
  46        char tmp[PATH_MAX] = {0};
  47        char prefix[PATH_MAX] = {0};
  48
  49        get_current_prefix(tmp, sizeof(tmp));
  50
  51        snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp);
  52#else
  53        const char *prefix = "";
  54#endif
  55        char const *argv[] = {
  56                prgname,
  57                "-c", coremask,
  58                "--proc-type=secondary",
  59                prefix
  60        };
  61
  62        snprintf(coremask, sizeof(coremask), "%x", (1 << lcore));
  63
  64        return launch_proc(argv);
  65}
  66
  67static void
  68handle_expired_timer(struct rte_timer *tim)
  69{
  70        struct test_info *test_info = tim->arg;
  71
  72        test_info->expired_count++;
  73        test_info->expired_timers[test_info->expired_timers_idx++] = tim;
  74}
  75
  76static int
  77timer_manage_loop(void *arg)
  78{
  79#define TICK_MSECS 1
  80        uint64_t tick_cycles = TICK_MSECS * rte_get_timer_hz() / MSECPERSEC;
  81        uint64_t prev_tsc = 0, cur_tsc, diff_tsc;
  82        struct test_info *test_info = arg;
  83
  84        while (!test_info->exit_flag) {
  85                cur_tsc = rte_rdtsc();
  86                diff_tsc = cur_tsc - prev_tsc;
  87
  88                if (diff_tsc > tick_cycles) {
  89                        /* Scan timer list for expired timers */
  90                        rte_timer_alt_manage(test_info->timer_data_id,
  91                                             NULL,
  92                                             0,
  93                                             handle_expired_timer);
  94
  95                        /* Return expired timer objects back to mempool */
  96                        rte_mempool_put_bulk(test_info->tim_mempool,
  97                                             (void **)test_info->expired_timers,
  98                                             test_info->expired_timers_idx);
  99
 100                        test_info->expired_timers_idx = 0;
 101
 102                        prev_tsc = cur_tsc;
 103                }
 104
 105                rte_pause();
 106        }
 107
 108        return 0;
 109}
 110
 111int
 112test_timer_secondary(void)
 113{
 114        int proc_type = rte_eal_process_type();
 115        const struct rte_memzone *mz;
 116        struct test_info *test_info;
 117        int ret;
 118
 119        if (proc_type == RTE_PROC_PRIMARY) {
 120                if (rte_lcore_count() < NUM_LCORES_NEEDED) {
 121                        printf("Not enough cores for test_timer_secondary, expecting at least %u\n",
 122                               NUM_LCORES_NEEDED);
 123                        return TEST_SKIPPED;
 124                }
 125
 126                mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info),
 127                                         SOCKET_ID_ANY, 0);
 128                test_info = mz->addr;
 129                TEST_ASSERT_NOT_NULL(test_info, "Couldn't allocate memory for "
 130                                     "test data");
 131
 132                test_info->tim_mempool = rte_mempool_create("test_timer_mp",
 133                                NUM_TIMERS, sizeof(struct rte_timer), 0, 0,
 134                                NULL, NULL, NULL, NULL, rte_socket_id(), 0);
 135
 136                ret = rte_timer_data_alloc(&test_info->timer_data_id);
 137                TEST_ASSERT_SUCCESS(ret, "Failed to allocate timer data "
 138                                    "instance");
 139
 140                unsigned int *main_lcorep = &test_info->main_lcore;
 141                unsigned int *mgr_lcorep = &test_info->mgr_lcore;
 142                unsigned int *sec_lcorep = &test_info->sec_lcore;
 143
 144                *main_lcorep = rte_get_main_lcore();
 145                *mgr_lcorep = rte_get_next_lcore(*main_lcorep, 1, 1);
 146                *sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1);
 147
 148                ret = rte_eal_remote_launch(timer_manage_loop,
 149                                            (void *)test_info,
 150                                            *mgr_lcorep);
 151                TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop");
 152
 153                ret = timer_secondary_spawn_wait(*sec_lcorep);
 154                TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed");
 155
 156                rte_delay_ms(2000);
 157
 158                test_info->exit_flag = 1;
 159                rte_eal_wait_lcore(*mgr_lcorep);
 160
 161#ifdef RTE_LIBRTE_TIMER_DEBUG
 162                rte_timer_alt_dump_stats(test_info->timer_data_id, stdout);
 163#endif
 164
 165                return test_info->expected_count == test_info->expired_count ?
 166                        TEST_SUCCESS : TEST_FAILED;
 167
 168        } else if (proc_type == RTE_PROC_SECONDARY) {
 169                uint64_t ticks, timeout_ms;
 170                struct rte_timer *tim;
 171                int i;
 172
 173                mz = rte_memzone_lookup(TEST_INFO_MZ_NAME);
 174                test_info = mz->addr;
 175                TEST_ASSERT_NOT_NULL(test_info, "Couldn't lookup memzone for "
 176                                     "test info");
 177
 178                for (i = 0; i < NUM_TIMERS; i++) {
 179                        rte_mempool_get(test_info->tim_mempool, (void **)&tim);
 180
 181                        rte_timer_init(tim);
 182
 183                        /* generate timeouts between 10 and 160 ms */
 184                        timeout_ms = ((rte_rand() & 0xF) + 1) * 10;
 185                        ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC;
 186
 187                        ret = rte_timer_alt_reset(test_info->timer_data_id,
 188                                                  tim, ticks, SINGLE,
 189                                                  test_info->mgr_lcore, NULL,
 190                                                  test_info);
 191                        if (ret < 0)
 192                                return TEST_FAILED;
 193
 194                        test_info->expected_count++;
 195
 196                        /* randomly leave timer running or stop it */
 197                        if (rte_rand() & 1)
 198                                continue;
 199
 200                        ret = rte_timer_alt_stop(test_info->timer_data_id,
 201                                                 tim);
 202                        if (ret == 0) {
 203                                test_info->expected_count--;
 204                                rte_mempool_put(test_info->tim_mempool,
 205                                                (void *)tim);
 206                        }
 207
 208                }
 209
 210                return TEST_SUCCESS;
 211        }
 212
 213        return TEST_FAILED;
 214}
 215
 216REGISTER_TEST_COMMAND(timer_secondary_autotest, test_timer_secondary);
 217