ethdev: revert xstats by ID
[dpdk.git] / app / proc_info / main.c
1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2017 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 <stdio.h>
35 #include <string.h>
36 #include <stdint.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <inttypes.h>
40 #include <sys/queue.h>
41 #include <stdlib.h>
42 #include <getopt.h>
43 #include <unistd.h>
44
45 #include <rte_eal.h>
46 #include <rte_common.h>
47 #include <rte_debug.h>
48 #include <rte_ethdev.h>
49 #include <rte_malloc.h>
50 #include <rte_memory.h>
51 #include <rte_memzone.h>
52 #include <rte_launch.h>
53 #include <rte_tailq.h>
54 #include <rte_per_lcore.h>
55 #include <rte_lcore.h>
56 #include <rte_debug.h>
57 #include <rte_log.h>
58 #include <rte_atomic.h>
59 #include <rte_branch_prediction.h>
60 #include <rte_string_fns.h>
61 #include <rte_metrics.h>
62
63 /* Maximum long option length for option parsing. */
64 #define MAX_LONG_OPT_SZ 64
65 #define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
66
67 #define MAX_STRING_LEN 256
68
69 /**< mask of enabled ports */
70 static uint32_t enabled_port_mask;
71 /**< Enable stats. */
72 static uint32_t enable_stats;
73 /**< Enable xstats. */
74 static uint32_t enable_xstats;
75 /**< Enable collectd format*/
76 static uint32_t enable_collectd_format;
77 /**< FD to send collectd format messages to STDOUT*/
78 static int stdout_fd;
79 /**< Host id process is running on */
80 static char host_id[MAX_LONG_OPT_SZ];
81 /**< Enable metrics. */
82 static uint32_t enable_metrics;
83 /**< Enable stats reset. */
84 static uint32_t reset_stats;
85 /**< Enable xstats reset. */
86 static uint32_t reset_xstats;
87 /**< Enable memory info. */
88 static uint32_t mem_info;
89
90 /**< display usage */
91 static void
92 proc_info_usage(const char *prgname)
93 {
94         printf("%s [EAL options] -- -p PORTMASK\n"
95                 "  -m to display DPDK memory zones, segments and TAILQ information\n"
96                 "  -p PORTMASK: hexadecimal bitmask of ports to retrieve stats for\n"
97                 "  --stats: to display port statistics, enabled by default\n"
98                 "  --xstats: to display extended port statistics, disabled by "
99                         "default\n"
100                 "  --metrics: to display derived metrics of the ports, disabled by "
101                         "default\n"
102                 "  --stats-reset: to reset port statistics\n"
103                 "  --xstats-reset: to reset port extended statistics\n"
104                 "  --collectd-format: to print statistics to STDOUT in expected by collectd format\n"
105                 "  --host-id STRING: host id used to identify the system process is running on\n",
106                 prgname);
107 }
108
109 /*
110  * Parse the portmask provided at run time.
111  */
112 static int
113 parse_portmask(const char *portmask)
114 {
115         char *end = NULL;
116         unsigned long pm;
117
118         errno = 0;
119
120         /* parse hexadecimal string */
121         pm = strtoul(portmask, &end, 16);
122         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0') ||
123                 (errno != 0)) {
124                 printf("%s ERROR parsing the port mask\n", __func__);
125                 return -1;
126         }
127
128         if (pm == 0)
129                 return -1;
130
131         return pm;
132
133 }
134
135 static int
136 proc_info_preparse_args(int argc, char **argv)
137 {
138         char *prgname = argv[0];
139         int i;
140
141         for (i = 0; i < argc; i++) {
142                 /* Print stats or xstats to STDOUT in collectd format */
143                 if (!strncmp(argv[i], "--collectd-format", MAX_LONG_OPT_SZ)) {
144                         enable_collectd_format = 1;
145                         stdout_fd = dup(STDOUT_FILENO);
146                         close(STDOUT_FILENO);
147                 }
148                 if (!strncmp(argv[i], "--host-id", MAX_LONG_OPT_SZ)) {
149                         if ((i + 1) == argc) {
150                                 printf("Invalid host id or not specified\n");
151                                 proc_info_usage(prgname);
152                                 return -1;
153                         }
154                         strncpy(host_id, argv[i+1], sizeof(host_id));
155                 }
156         }
157
158         if (!strlen(host_id)) {
159                 int err = gethostname(host_id, MAX_LONG_OPT_SZ-1);
160
161                 if (err)
162                         strcpy(host_id, "unknown");
163         }
164
165         return 0;
166 }
167
168 /* Parse the argument given in the command line of the application */
169 static int
170 proc_info_parse_args(int argc, char **argv)
171 {
172         int opt;
173         int option_index;
174         char *prgname = argv[0];
175         static struct option long_option[] = {
176                 {"stats", 0, NULL, 0},
177                 {"stats-reset", 0, NULL, 0},
178                 {"xstats", 0, NULL, 0},
179                 {"metrics", 0, NULL, 0},
180                 {"xstats-reset", 0, NULL, 0},
181                 {"collectd-format", 0, NULL, 0},
182                 {"host-id", 0, NULL, 0},
183                 {NULL, 0, 0, 0}
184         };
185
186         if (argc == 1)
187                 proc_info_usage(prgname);
188
189         /* Parse command line */
190         while ((opt = getopt_long(argc, argv, "p:m",
191                         long_option, &option_index)) != EOF) {
192                 switch (opt) {
193                 /* portmask */
194                 case 'p':
195                         enabled_port_mask = parse_portmask(optarg);
196                         if (enabled_port_mask == 0) {
197                                 printf("invalid portmask\n");
198                                 proc_info_usage(prgname);
199                                 return -1;
200                         }
201                         break;
202                 case 'm':
203                         mem_info = 1;
204                         break;
205                 case 0:
206                         /* Print stats */
207                         if (!strncmp(long_option[option_index].name, "stats",
208                                         MAX_LONG_OPT_SZ))
209                                 enable_stats = 1;
210                         /* Print xstats */
211                         else if (!strncmp(long_option[option_index].name, "xstats",
212                                         MAX_LONG_OPT_SZ))
213                                 enable_xstats = 1;
214                         else if (!strncmp(long_option[option_index].name,
215                                         "metrics",
216                                         MAX_LONG_OPT_SZ))
217                                 enable_metrics = 1;
218                         /* Reset stats */
219                         if (!strncmp(long_option[option_index].name, "stats-reset",
220                                         MAX_LONG_OPT_SZ))
221                                 reset_stats = 1;
222                         /* Reset xstats */
223                         else if (!strncmp(long_option[option_index].name, "xstats-reset",
224                                         MAX_LONG_OPT_SZ))
225                                 reset_xstats = 1;
226                         break;
227
228                 default:
229                         proc_info_usage(prgname);
230                         return -1;
231                 }
232         }
233         return 0;
234 }
235
236 static void
237 meminfo_display(void)
238 {
239         printf("----------- MEMORY_SEGMENTS -----------\n");
240         rte_dump_physmem_layout(stdout);
241         printf("--------- END_MEMORY_SEGMENTS ---------\n");
242
243         printf("------------ MEMORY_ZONES -------------\n");
244         rte_memzone_dump(stdout);
245         printf("---------- END_MEMORY_ZONES -----------\n");
246
247         printf("------------- TAIL_QUEUES -------------\n");
248         rte_dump_tailq(stdout);
249         printf("---------- END_TAIL_QUEUES ------------\n");
250 }
251
252 static void
253 nic_stats_display(uint8_t port_id)
254 {
255         struct rte_eth_stats stats;
256         uint8_t i;
257
258         static const char *nic_stats_border = "########################";
259
260         rte_eth_stats_get(port_id, &stats);
261         printf("\n  %s NIC statistics for port %-2d %s\n",
262                    nic_stats_border, port_id, nic_stats_border);
263
264         printf("  RX-packets: %-10"PRIu64"  RX-errors:  %-10"PRIu64
265                "  RX-bytes:  %-10"PRIu64"\n", stats.ipackets, stats.ierrors,
266                stats.ibytes);
267         printf("  RX-nombuf:  %-10"PRIu64"\n", stats.rx_nombuf);
268         printf("  TX-packets: %-10"PRIu64"  TX-errors:  %-10"PRIu64
269                "  TX-bytes:  %-10"PRIu64"\n", stats.opackets, stats.oerrors,
270                stats.obytes);
271
272         printf("\n");
273         for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
274                 printf("  Stats reg %2d RX-packets: %-10"PRIu64
275                        "  RX-errors: %-10"PRIu64
276                        "  RX-bytes: %-10"PRIu64"\n",
277                        i, stats.q_ipackets[i], stats.q_errors[i], stats.q_ibytes[i]);
278         }
279
280         printf("\n");
281         for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
282                 printf("  Stats reg %2d TX-packets: %-10"PRIu64
283                        "  TX-bytes: %-10"PRIu64"\n",
284                        i, stats.q_opackets[i], stats.q_obytes[i]);
285         }
286
287         printf("  %s############################%s\n",
288                    nic_stats_border, nic_stats_border);
289 }
290
291 static void
292 nic_stats_clear(uint8_t port_id)
293 {
294         printf("\n Clearing NIC stats for port %d\n", port_id);
295         rte_eth_stats_reset(port_id);
296         printf("\n  NIC statistics for port %d cleared\n", port_id);
297 }
298
299 static void collectd_resolve_cnt_type(char *cnt_type, size_t cnt_type_len,
300                                       const char *cnt_name) {
301         char *type_end = strrchr(cnt_name, '_');
302
303         if ((type_end != NULL) &&
304             (strncmp(cnt_name, "rx_", strlen("rx_")) == 0)) {
305                 if (strncmp(type_end, "_errors", strlen("_errors")) == 0)
306                         strncpy(cnt_type, "if_rx_errors", cnt_type_len);
307                 else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0)
308                         strncpy(cnt_type, "if_rx_dropped", cnt_type_len);
309                 else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0)
310                         strncpy(cnt_type, "if_rx_octets", cnt_type_len);
311                 else if (strncmp(type_end, "_packets", strlen("_packets")) == 0)
312                         strncpy(cnt_type, "if_rx_packets", cnt_type_len);
313                 else if (strncmp(type_end, "_placement",
314                                  strlen("_placement")) == 0)
315                         strncpy(cnt_type, "if_rx_errors", cnt_type_len);
316                 else if (strncmp(type_end, "_buff", strlen("_buff")) == 0)
317                         strncpy(cnt_type, "if_rx_errors", cnt_type_len);
318                 else
319                         /* Does not fit obvious type: use a more generic one */
320                         strncpy(cnt_type, "derive", cnt_type_len);
321         } else if ((type_end != NULL) &&
322                 (strncmp(cnt_name, "tx_", strlen("tx_"))) == 0) {
323                 if (strncmp(type_end, "_errors", strlen("_errors")) == 0)
324                         strncpy(cnt_type, "if_tx_errors", cnt_type_len);
325                 else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0)
326                         strncpy(cnt_type, "if_tx_dropped", cnt_type_len);
327                 else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0)
328                         strncpy(cnt_type, "if_tx_octets", cnt_type_len);
329                 else if (strncmp(type_end, "_packets", strlen("_packets")) == 0)
330                         strncpy(cnt_type, "if_tx_packets", cnt_type_len);
331                 else
332                         /* Does not fit obvious type: use a more generic one */
333                         strncpy(cnt_type, "derive", cnt_type_len);
334         } else if ((type_end != NULL) &&
335                    (strncmp(cnt_name, "flow_", strlen("flow_"))) == 0) {
336                 if (strncmp(type_end, "_filters", strlen("_filters")) == 0)
337                         strncpy(cnt_type, "operations", cnt_type_len);
338                 else if (strncmp(type_end, "_errors", strlen("_errors")) == 0)
339                         strncpy(cnt_type, "errors", cnt_type_len);
340                 else if (strncmp(type_end, "_filters", strlen("_filters")) == 0)
341                         strncpy(cnt_type, "filter_result", cnt_type_len);
342         } else if ((type_end != NULL) &&
343                    (strncmp(cnt_name, "mac_", strlen("mac_"))) == 0) {
344                 if (strncmp(type_end, "_errors", strlen("_errors")) == 0)
345                         strncpy(cnt_type, "errors", cnt_type_len);
346         } else {
347                 /* Does not fit obvious type, or strrchr error: */
348                 /* use a more generic type */
349                 strncpy(cnt_type, "derive", cnt_type_len);
350         }
351 }
352
353 static void
354 nic_xstats_display(uint8_t port_id)
355 {
356         struct rte_eth_xstat_name *xstats_names;
357         struct rte_eth_xstat *xstats;
358         int len, ret, i;
359         static const char *nic_stats_border = "########################";
360
361         len = rte_eth_xstats_get_names(port_id, NULL, 0);
362         if (len < 0) {
363                 printf("Cannot get xstats count\n");
364                 return;
365         }
366         xstats = malloc(sizeof(xstats[0]) * len);
367         if (xstats == NULL) {
368                 printf("Cannot allocate memory for xstats\n");
369                 return;
370         }
371
372         xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * len);
373         if (xstats_names == NULL) {
374                 printf("Cannot allocate memory for xstat names\n");
375                 free(xstats);
376                 return;
377         }
378         if (len != rte_eth_xstats_get_names(
379                         port_id, xstats_names, len)) {
380                 printf("Cannot get xstat names\n");
381                 goto err;
382         }
383
384         printf("###### NIC extended statistics for port %-2d #########\n",
385                            port_id);
386         printf("%s############################\n",
387                            nic_stats_border);
388         ret = rte_eth_xstats_get(port_id, xstats, len);
389         if (ret < 0 || ret > len) {
390                 printf("Cannot get xstats\n");
391                 goto err;
392         }
393
394         for (i = 0; i < len; i++) {
395                 if (enable_collectd_format) {
396                         char counter_type[MAX_STRING_LEN];
397                         char buf[MAX_STRING_LEN];
398
399                         collectd_resolve_cnt_type(counter_type,
400                                                   sizeof(counter_type),
401                                                   xstats_names[i].name);
402                         sprintf(buf, "PUTVAL %s/dpdkstat-port.%u/%s-%s N:%"
403                                 PRIu64"\n", host_id, port_id, counter_type,
404                                 xstats_names[i].name, xstats[i].value);
405                         write(stdout_fd, buf, strlen(buf));
406                 } else {
407                         printf("%s: %"PRIu64"\n", xstats_names[i].name,
408                                xstats[i].value);
409                 }
410         }
411
412         printf("%s############################\n",
413                            nic_stats_border);
414 err:
415         free(xstats);
416         free(xstats_names);
417 }
418
419 static void
420 nic_xstats_clear(uint8_t port_id)
421 {
422         printf("\n Clearing NIC xstats for port %d\n", port_id);
423         rte_eth_xstats_reset(port_id);
424         printf("\n  NIC extended statistics for port %d cleared\n", port_id);
425 }
426
427 static void
428 metrics_display(int port_id)
429 {
430         struct rte_metric_value *metrics;
431         struct rte_metric_name *names;
432         int len, ret;
433         static const char *nic_stats_border = "########################";
434
435         len = rte_metrics_get_names(NULL, 0);
436         if (len < 0) {
437                 printf("Cannot get metrics count\n");
438                 return;
439         }
440         if (len == 0) {
441                 printf("No metrics to display (none have been registered)\n");
442                 return;
443         }
444
445         metrics = rte_malloc("proc_info_metrics",
446                 sizeof(struct rte_metric_value) * len, 0);
447         if (metrics == NULL) {
448                 printf("Cannot allocate memory for metrics\n");
449                 return;
450         }
451
452         names =  rte_malloc(NULL, sizeof(struct rte_metric_name) * len, 0);
453         if (names == NULL) {
454                 printf("Cannot allocate memory for metrcis names\n");
455                 rte_free(metrics);
456                 return;
457         }
458
459         if (len != rte_metrics_get_names(names, len)) {
460                 printf("Cannot get metrics names\n");
461                 rte_free(metrics);
462                 rte_free(names);
463                 return;
464         }
465
466         if (port_id == RTE_METRICS_GLOBAL)
467                 printf("###### Non port specific metrics  #########\n");
468         else
469                 printf("###### metrics for port %-2d #########\n", port_id);
470         printf("%s############################\n", nic_stats_border);
471         ret = rte_metrics_get_values(port_id, metrics, len);
472         if (ret < 0 || ret > len) {
473                 printf("Cannot get metrics values\n");
474                 rte_free(metrics);
475                 rte_free(names);
476                 return;
477         }
478
479         int i;
480         for (i = 0; i < len; i++)
481                 printf("%s: %"PRIu64"\n", names[i].name, metrics[i].value);
482
483         printf("%s############################\n", nic_stats_border);
484         rte_free(metrics);
485         rte_free(names);
486 }
487
488 int
489 main(int argc, char **argv)
490 {
491         int ret;
492         int i;
493         char c_flag[] = "-c1";
494         char n_flag[] = "-n4";
495         char mp_flag[] = "--proc-type=secondary";
496         char *argp[argc + 3];
497         uint8_t nb_ports;
498
499         /* preparse app arguments */
500         ret = proc_info_preparse_args(argc, argv);
501         if (ret < 0) {
502                 printf("Failed to parse arguments\n");
503                 return -1;
504         }
505
506         argp[0] = argv[0];
507         argp[1] = c_flag;
508         argp[2] = n_flag;
509         argp[3] = mp_flag;
510
511         for (i = 1; i < argc; i++)
512                 argp[i + 3] = argv[i];
513
514         argc += 3;
515
516         ret = rte_eal_init(argc, argp);
517         if (ret < 0)
518                 rte_panic("Cannot init EAL\n");
519
520         argc -= ret;
521         argv += (ret - 3);
522
523         if (!rte_eal_primary_proc_alive(NULL))
524                 rte_exit(EXIT_FAILURE, "No primary DPDK process is running.\n");
525
526         /* parse app arguments */
527         ret = proc_info_parse_args(argc, argv);
528         if (ret < 0)
529                 rte_exit(EXIT_FAILURE, "Invalid argument\n");
530
531         if (mem_info) {
532                 meminfo_display();
533                 return 0;
534         }
535
536         nb_ports = rte_eth_dev_count();
537         if (nb_ports == 0)
538                 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
539
540         /* If no port mask was specified*/
541         if (enabled_port_mask == 0)
542                 enabled_port_mask = 0xffff;
543
544         for (i = 0; i < nb_ports; i++) {
545                 if (enabled_port_mask & (1 << i)) {
546                         if (enable_stats)
547                                 nic_stats_display(i);
548                         else if (enable_xstats)
549                                 nic_xstats_display(i);
550                         else if (reset_stats)
551                                 nic_stats_clear(i);
552                         else if (reset_xstats)
553                                 nic_xstats_clear(i);
554                         else if (enable_metrics)
555                                 metrics_display(i);
556                 }
557         }
558
559         /* print port independent stats */
560         if (enable_metrics)
561                 metrics_display(RTE_METRICS_GLOBAL);
562
563         return 0;
564 }