1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Intel Corporation 3 */ 4 5 #include <unistd.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <stdint.h> 9 #include <errno.h> 10 #include <sys/queue.h> 11 12 #include <rte_memory.h> 13 #include <rte_launch.h> 14 #include <rte_eal.h> 15 #include <rte_debug.h> 16 #include <rte_cycles.h> 17 18 /* allow application scheduling of the services */ 19 #include <rte_service.h> 20 21 /* Allow application registration of its own services. An application does not 22 * have to register services, but it can be useful if it wishes to run a 23 * function on a core that is otherwise in use as a service core. In this 24 * example, all services are dummy services registered by the sample app itself. 25 */ 26 #include <rte_service_component.h> 27 28 #define PROFILE_CORES_MAX 8 29 #define PROFILE_SERVICE_PER_CORE 5 30 31 /* dummy function to do "work" */ 32 static int32_t service_func(void *args) 33 { 34 RTE_SET_USED(args); 35 rte_delay_us(2000); 36 return 0; 37 } 38 39 static struct rte_service_spec services[] = { 40 {"service_1", service_func, NULL, 0, 0}, 41 {"service_2", service_func, NULL, 0, 0}, 42 {"service_3", service_func, NULL, 0, 0}, 43 {"service_4", service_func, NULL, 0, 0}, 44 {"service_5", service_func, NULL, 0, 0}, 45 }; 46 #define NUM_SERVICES RTE_DIM(services) 47 48 /* this struct holds the mapping of a particular core to all services */ 49 struct profile_for_core { 50 uint32_t mapped_services[PROFILE_SERVICE_PER_CORE]; 51 }; 52 53 /* struct that can be applied as the service core mapping. Items in this 54 * struct will be passed to the ordinary rte_service_* APIs to configure the 55 * service cores at runtime, based on the requirements. 56 * 57 * These profiles can be considered a "configuration" for the service cores, 58 * where switching profile just changes the number of cores and the mappings 59 * for each of them. As a result, the core requirements and performance of the 60 * application scales. 61 */ 62 struct profile { 63 char name[64]; 64 uint32_t num_cores; 65 struct profile_for_core cores[PROFILE_CORES_MAX]; 66 }; 67 68 static struct profile profiles[] = { 69 /* profile 0: high performance */ 70 { 71 .name = "High Performance", 72 .num_cores = 5, 73 .cores[0] = {.mapped_services = {1, 0, 0, 0, 0} }, 74 .cores[1] = {.mapped_services = {0, 1, 0, 0, 0} }, 75 .cores[2] = {.mapped_services = {0, 0, 1, 0, 0} }, 76 .cores[3] = {.mapped_services = {0, 0, 0, 1, 0} }, 77 .cores[4] = {.mapped_services = {0, 0, 0, 0, 1} }, 78 }, 79 /* profile 1: mid performance with single service priority */ 80 { 81 .name = "Mid-High Performance", 82 .num_cores = 3, 83 .cores[0] = {.mapped_services = {1, 1, 0, 0, 0} }, 84 .cores[1] = {.mapped_services = {0, 0, 1, 1, 0} }, 85 .cores[2] = {.mapped_services = {0, 0, 0, 0, 1} }, 86 .cores[3] = {.mapped_services = {0, 0, 0, 0, 0} }, 87 .cores[4] = {.mapped_services = {0, 0, 0, 0, 0} }, 88 }, 89 /* profile 2: mid performance with single service priority */ 90 { 91 .name = "Mid-Low Performance", 92 .num_cores = 2, 93 .cores[0] = {.mapped_services = {1, 1, 1, 0, 0} }, 94 .cores[1] = {.mapped_services = {1, 1, 0, 1, 1} }, 95 .cores[2] = {.mapped_services = {0, 0, 0, 0, 0} }, 96 .cores[3] = {.mapped_services = {0, 0, 0, 0, 0} }, 97 .cores[4] = {.mapped_services = {0, 0, 0, 0, 0} }, 98 }, 99 /* profile 3: scale down performance on single core */ 100 { 101 .name = "Scale down performance", 102 .num_cores = 1, 103 .cores[0] = {.mapped_services = {1, 1, 1, 1, 1} }, 104 .cores[1] = {.mapped_services = {0, 0, 0, 0, 0} }, 105 .cores[2] = {.mapped_services = {0, 0, 0, 0, 0} }, 106 .cores[3] = {.mapped_services = {0, 0, 0, 0, 0} }, 107 .cores[4] = {.mapped_services = {0, 0, 0, 0, 0} }, 108 }, 109 }; 110 #define NUM_PROFILES RTE_DIM(profiles) 111 112 static void 113 apply_profile(int profile_id) 114 { 115 uint32_t i; 116 uint32_t s; 117 int ret; 118 struct profile *p = &profiles[profile_id]; 119 const uint8_t core_off = 1; 120 121 if (p->num_cores > rte_lcore_count() - 1) { 122 printf("insufficent cores to run (%s)", 123 p->name); 124 return; 125 } 126 127 for (i = 0; i < p->num_cores; i++) { 128 uint32_t core = i + core_off; 129 ret = rte_service_lcore_add(core); 130 if (ret && ret != -EALREADY) 131 printf("core %d added ret %d\n", core, ret); 132 133 ret = rte_service_lcore_start(core); 134 if (ret && ret != -EALREADY) 135 printf("core %d start ret %d\n", core, ret); 136 137 for (s = 0; s < NUM_SERVICES; s++) { 138 if (rte_service_map_lcore_set(s, core, 139 p->cores[i].mapped_services[s])) 140 printf("failed to map lcore %d\n", core); 141 } 142 } 143 144 for ( ; i < PROFILE_CORES_MAX; i++) { 145 uint32_t core = i + core_off; 146 for (s = 0; s < NUM_SERVICES; s++) { 147 ret = rte_service_map_lcore_set(s, core, 0); 148 if (ret && ret != -EINVAL) { 149 printf("%s %d: map lcore set = %d\n", __func__, 150 __LINE__, ret); 151 } 152 } 153 ret = rte_service_lcore_stop(core); 154 if (ret && ret != -EALREADY) { 155 printf("%s %d: lcore stop = %d\n", __func__, 156 __LINE__, ret); 157 } 158 ret = rte_service_lcore_del(core); 159 if (ret && ret != -EINVAL) { 160 printf("%s %d: lcore del = %d\n", __func__, 161 __LINE__, ret); 162 } 163 } 164 } 165 166 int 167 main(int argc, char **argv) 168 { 169 int ret; 170 171 ret = rte_eal_init(argc, argv); 172 if (ret < 0) 173 rte_panic("Cannot init EAL\n"); 174 175 uint32_t i; 176 for (i = 0; i < NUM_SERVICES; i++) { 177 services[i].callback_userdata = 0; 178 uint32_t id; 179 /* Register a service as an application. 8< */ 180 ret = rte_service_component_register(&services[i], &id); 181 if (ret) 182 rte_exit(-1, "service register() failed"); 183 184 /* set the service itself to be ready to run. In the case of 185 * ethdev, eventdev etc PMDs, this will be set when the 186 * appropriate configure or setup function is called. 187 */ 188 rte_service_component_runstate_set(id, 1); 189 190 /* Collect statistics for the service */ 191 rte_service_set_stats_enable(id, 1); 192 193 /* the application sets the service to be active. Note that the 194 * previous component_runstate_set() is the PMD indicating 195 * ready, while this function is the application setting the 196 * service to run. Applications can choose to not run a service 197 * by setting runstate to 0 at any time. 198 */ 199 ret = rte_service_runstate_set(id, 1); 200 if (ret) 201 return -ENOEXEC; 202 /* >8 End of registering a service as an application. */ 203 } 204 205 i = 0; 206 while (1) { 207 const char clr[] = { 27, '[', '2', 'J', '\0' }; 208 const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' }; 209 printf("%s%s", clr, topLeft); 210 211 apply_profile(i); 212 printf("\n==> Profile: %s\n\n", profiles[i].name); 213 214 rte_delay_us_sleep(1 * US_PER_S); 215 rte_service_dump(stdout, UINT32_MAX); 216 217 rte_delay_us_sleep(5 * US_PER_S); 218 rte_service_dump(stdout, UINT32_MAX); 219 220 i++; 221 if (i >= NUM_PROFILES) 222 i = 0; 223 } 224 225 /* clean up the EAL */ 226 rte_eal_cleanup(); 227 228 return 0; 229 } 230