1 /* 2 * BSD LICENSE 3 * 4 * Copyright(c) 2017 Intel Corporation. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Intel Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <unistd.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <stdint.h> 37 #include <errno.h> 38 #include <sys/queue.h> 39 40 #include <rte_memory.h> 41 #include <rte_memzone.h> 42 #include <rte_launch.h> 43 #include <rte_eal.h> 44 #include <rte_debug.h> 45 #include <rte_cycles.h> 46 47 /* allow application scheduling of the services */ 48 #include <rte_service.h> 49 50 /* Allow application registration of its own services. An application does not 51 * have to register services, but it can be useful if it wishes to run a 52 * function on a core that is otherwise in use as a service core. In this 53 * example, all services are dummy services registered by the sample app itself. 54 */ 55 #include <rte_service_component.h> 56 57 #define PROFILE_CORES_MAX 8 58 #define PROFILE_SERVICE_PER_CORE 5 59 60 /* dummy function to do "work" */ 61 static int32_t service_func(void *args) 62 { 63 RTE_SET_USED(args); 64 rte_delay_us(2000); 65 return 0; 66 } 67 68 static struct rte_service_spec services[] = { 69 {"service_1", service_func, NULL, 0, 0}, 70 {"service_2", service_func, NULL, 0, 0}, 71 {"service_3", service_func, NULL, 0, 0}, 72 {"service_4", service_func, NULL, 0, 0}, 73 {"service_5", service_func, NULL, 0, 0}, 74 }; 75 #define NUM_SERVICES RTE_DIM(services) 76 77 /* this struct holds the mapping of a particular core to all services */ 78 struct profile_for_core { 79 uint32_t mapped_services[PROFILE_SERVICE_PER_CORE]; 80 }; 81 82 /* struct that can be applied as the service core mapping. Items in this 83 * struct will be passed to the ordinary rte_service_* APIs to configure the 84 * service cores at runtime, based on the requirements. 85 * 86 * These profiles can be considered a "configuration" for the service cores, 87 * where switching profile just changes the number of cores and the mappings 88 * for each of them. As a result, the core requirements and performance of the 89 * application scales. 90 */ 91 struct profile { 92 char name[64]; 93 uint32_t num_cores; 94 struct profile_for_core cores[PROFILE_CORES_MAX]; 95 }; 96 97 static struct profile profiles[] = { 98 /* profile 0: high performance */ 99 { 100 .name = "High Performance", 101 .num_cores = 5, 102 .cores[0] = {.mapped_services = {1, 0, 0, 0, 0} }, 103 .cores[1] = {.mapped_services = {0, 1, 0, 0, 0} }, 104 .cores[2] = {.mapped_services = {0, 0, 1, 0, 0} }, 105 .cores[3] = {.mapped_services = {0, 0, 0, 1, 0} }, 106 .cores[4] = {.mapped_services = {0, 0, 0, 0, 1} }, 107 }, 108 /* profile 1: mid performance with single service priority */ 109 { 110 .name = "Mid-High Performance", 111 .num_cores = 3, 112 .cores[0] = {.mapped_services = {1, 1, 0, 0, 0} }, 113 .cores[1] = {.mapped_services = {0, 0, 1, 1, 0} }, 114 .cores[2] = {.mapped_services = {0, 0, 0, 0, 1} }, 115 .cores[3] = {.mapped_services = {0, 0, 0, 0, 0} }, 116 .cores[4] = {.mapped_services = {0, 0, 0, 0, 0} }, 117 }, 118 /* profile 2: mid performance with single service priority */ 119 { 120 .name = "Mid-Low Performance", 121 .num_cores = 2, 122 .cores[0] = {.mapped_services = {1, 1, 1, 0, 0} }, 123 .cores[1] = {.mapped_services = {1, 1, 0, 1, 1} }, 124 .cores[2] = {.mapped_services = {0, 0, 0, 0, 0} }, 125 .cores[3] = {.mapped_services = {0, 0, 0, 0, 0} }, 126 .cores[4] = {.mapped_services = {0, 0, 0, 0, 0} }, 127 }, 128 /* profile 3: scale down performance on single core */ 129 { 130 .name = "Scale down performance", 131 .num_cores = 1, 132 .cores[0] = {.mapped_services = {1, 1, 1, 1, 1} }, 133 .cores[1] = {.mapped_services = {0, 0, 0, 0, 0} }, 134 .cores[2] = {.mapped_services = {0, 0, 0, 0, 0} }, 135 .cores[3] = {.mapped_services = {0, 0, 0, 0, 0} }, 136 .cores[4] = {.mapped_services = {0, 0, 0, 0, 0} }, 137 }, 138 }; 139 #define NUM_PROFILES RTE_DIM(profiles) 140 141 static void 142 apply_profile(int profile_id) 143 { 144 uint32_t i; 145 uint32_t s; 146 int ret; 147 struct profile *p = &profiles[profile_id]; 148 const uint8_t core_off = 1; 149 150 for (i = 0; i < p->num_cores; i++) { 151 uint32_t core = i + core_off; 152 ret = rte_service_lcore_add(core); 153 if (ret && ret != -EALREADY) 154 printf("core %d added ret %d\n", core, ret); 155 156 ret = rte_service_lcore_start(core); 157 if (ret && ret != -EALREADY) 158 printf("core %d start ret %d\n", core, ret); 159 160 for (s = 0; s < NUM_SERVICES; s++) { 161 if (rte_service_map_lcore_set(s, core, 162 p->cores[i].mapped_services[s])) 163 printf("failed to map lcore %d\n", core); 164 } 165 } 166 167 for ( ; i < PROFILE_CORES_MAX; i++) { 168 uint32_t core = i + core_off; 169 for (s = 0; s < NUM_SERVICES; s++) { 170 ret = rte_service_map_lcore_set(s, core, 0); 171 if (ret && ret != -EINVAL) { 172 printf("%s %d: map lcore set = %d\n", __func__, 173 __LINE__, ret); 174 } 175 } 176 ret = rte_service_lcore_stop(core); 177 if (ret && ret != -EALREADY) { 178 printf("%s %d: lcore stop = %d\n", __func__, 179 __LINE__, ret); 180 } 181 ret = rte_service_lcore_del(core); 182 if (ret && ret != -EINVAL) { 183 printf("%s %d: lcore del = %d\n", __func__, 184 __LINE__, ret); 185 } 186 } 187 } 188 189 int 190 main(int argc, char **argv) 191 { 192 int ret; 193 194 ret = rte_eal_init(argc, argv); 195 if (ret < 0) 196 rte_panic("Cannot init EAL\n"); 197 198 uint32_t i; 199 for (i = 0; i < NUM_SERVICES; i++) { 200 services[i].callback_userdata = 0; 201 uint32_t id; 202 ret = rte_service_component_register(&services[i], &id); 203 if (ret) 204 rte_exit(-1, "service register() failed"); 205 206 /* set the service itself to be ready to run. In the case of 207 * ethdev, eventdev etc PMDs, this will be set when the 208 * appropriate configure or setup function is called. 209 */ 210 rte_service_component_runstate_set(id, 1); 211 212 /* Collect statistics for the service */ 213 rte_service_set_stats_enable(id, 1); 214 215 /* the application sets the service to be active. Note that the 216 * previous component_runstate_set() is the PMD indicating 217 * ready, while this function is the application setting the 218 * service to run. Applications can choose to not run a service 219 * by setting runstate to 0 at any time. 220 */ 221 ret = rte_service_runstate_set(id, 1); 222 if (ret) 223 return -ENOEXEC; 224 } 225 226 i = 0; 227 while (1) { 228 const char clr[] = { 27, '[', '2', 'J', '\0' }; 229 const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' }; 230 printf("%s%s", clr, topLeft); 231 232 apply_profile(i); 233 printf("\n==> Profile: %s\n\n", profiles[i].name); 234 235 sleep(1); 236 rte_service_dump(stdout, UINT32_MAX); 237 238 sleep(5); 239 rte_service_dump(stdout, UINT32_MAX); 240 241 i++; 242 if (i >= NUM_PROFILES) 243 i = 0; 244 } 245 246 return 0; 247 } 248