New upstream version 18.11-rc1
[deb_dpdk.git] / examples / service_cores / main.c
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                 ret = rte_service_component_register(&services[i], &id);
180                 if (ret)
181                         rte_exit(-1, "service register() failed");
182
183                 /* set the service itself to be ready to run. In the case of
184                  * ethdev, eventdev etc PMDs, this will be set when the
185                  * appropriate configure or setup function is called.
186                  */
187                 rte_service_component_runstate_set(id, 1);
188
189                 /* Collect statistics for the service */
190                 rte_service_set_stats_enable(id, 1);
191
192                 /* the application sets the service to be active. Note that the
193                  * previous component_runstate_set() is the PMD indicating
194                  * ready, while this function is the application setting the
195                  * service to run. Applications can choose to not run a service
196                  * by setting runstate to 0 at any time.
197                  */
198                 ret = rte_service_runstate_set(id, 1);
199                 if (ret)
200                         return -ENOEXEC;
201         }
202
203         i = 0;
204         while (1) {
205                 const char clr[] = { 27, '[', '2', 'J', '\0' };
206                 const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
207                 printf("%s%s", clr, topLeft);
208
209                 apply_profile(i);
210                 printf("\n==> Profile: %s\n\n", profiles[i].name);
211
212                 sleep(1);
213                 rte_service_dump(stdout, UINT32_MAX);
214
215                 sleep(5);
216                 rte_service_dump(stdout, UINT32_MAX);
217
218                 i++;
219                 if (i >= NUM_PROFILES)
220                         i = 0;
221         }
222
223         return 0;
224 }