From 5d64c7868f67749a6c99eb4ee5998b518ab6c71c Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Tue, 11 Sep 2018 20:27:09 +0200 Subject: [PATCH] thread: Add show threads api Change-Id: I3124238ab4d43bcef5590bad33a4ff0b5d8b7d15 Signed-off-by: Mohsin Kazmi --- src/plugins/dpdk/device/cli.c | 2 +- src/plugins/dpdk/device/common.c | 2 +- src/plugins/nat/nat_api.c | 2 +- src/vat/api_format.c | 72 ++++++++++++++++++++++++++++++++++++++++ src/vlib/node_cli.c | 4 +-- src/vlib/threads.c | 32 +++++++++++++++--- src/vlib/threads.h | 8 +++-- src/vlib/threads_cli.c | 54 ++++-------------------------- src/vpp/api/api.c | 66 +++++++++++++++++++++++++++++++++++- src/vpp/api/custom_dump.c | 10 ++++++ src/vpp/api/vpe.api | 50 +++++++++++++++++++++++++++- 11 files changed, 239 insertions(+), 63 deletions(-) diff --git a/src/plugins/dpdk/device/cli.c b/src/plugins/dpdk/device/cli.c index c3df1ab27cc..7e168afb64e 100644 --- a/src/plugins/dpdk/device/cli.c +++ b/src/plugins/dpdk/device/cli.c @@ -727,7 +727,7 @@ show_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, cpu < (dm->hqos_cpu_first_index + dm->hqos_cpu_count)) vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu, vlib_worker_threads[cpu].name, - vlib_worker_threads[cpu].lcore_id); + vlib_worker_threads[cpu].cpu_id); vec_foreach (dq, dm->devices_by_hqos_cpu[cpu]) { diff --git a/src/plugins/dpdk/device/common.c b/src/plugins/dpdk/device/common.c index c64f1d0246b..8699dc8689b 100644 --- a/src/plugins/dpdk/device/common.c +++ b/src/plugins/dpdk/device/common.c @@ -119,7 +119,7 @@ dpdk_device_setup (dpdk_device_t * xd) dpdk_mempool_private_t *privp; uword tidx = vnet_get_device_input_thread_index (dm->vnet_main, xd->hw_if_index, j); - unsigned lcore = vlib_worker_threads[tidx].lcore_id; + unsigned lcore = vlib_worker_threads[tidx].cpu_id; u16 socket_id = rte_lcore_to_socket_id (lcore); rv = diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index 4c532ed7e2b..e642eddb95a 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -206,7 +206,7 @@ send_nat_worker_details (u32 worker_index, vl_api_registration_t * reg, rmp->_vl_msg_id = ntohs (VL_API_NAT_WORKER_DETAILS + sm->msg_id_base); rmp->context = context; rmp->worker_index = htonl (worker_index); - rmp->lcore_id = htonl (w->lcore_id); + rmp->lcore_id = htonl (w->cpu_id); strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1); vl_api_send_msg (reg, (u8 *) rmp); diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 99ede1ea7fd..583185e4d5f 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -1319,6 +1319,76 @@ static void vl_api_show_version_reply_t_handler_json vam->result_ready = 1; } +static void vl_api_show_threads_reply_t_handler + (vl_api_show_threads_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + int i, count = 0; + + if (retval >= 0) + count = ntohl (mp->count); + + for (i = 0; i < count; i++) + print (vam->ofp, + "\n%-2d %-11s %-11s %-5d %-6d %-4d %-6d", + ntohl (mp->thread_data[i].id), mp->thread_data[i].name, + mp->thread_data[i].type, ntohl (mp->thread_data[i].pid), + ntohl (mp->thread_data[i].cpu_id), ntohl (mp->thread_data[i].core), + ntohl (mp->thread_data[i].cpu_socket)); + + vam->retval = retval; + vam->result_ready = 1; +} + +static void vl_api_show_threads_reply_t_handler_json + (vl_api_show_threads_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + vl_api_thread_data_t *td; + int i, count = ntohl (mp->count); + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "count", count); + + for (i = 0; i < count; i++) + { + td = &mp->thread_data[i]; + vat_json_object_add_uint (&node, "id", ntohl (td->id)); + vat_json_object_add_string_copy (&node, "name", td->name); + vat_json_object_add_string_copy (&node, "type", td->type); + vat_json_object_add_uint (&node, "pid", ntohl (td->pid)); + vat_json_object_add_int (&node, "cpu_id", ntohl (td->cpu_id)); + vat_json_object_add_int (&node, "core", ntohl (td->id)); + vat_json_object_add_int (&node, "cpu_socket", ntohl (td->cpu_socket)); + } + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static int +api_show_threads (vat_main_t * vam) +{ + vl_api_show_threads_t *mp; + int ret; + + print (vam->ofp, + "\n%-2s %-11s %-11s %-5s %-6s %-4s %-6s", + "ID", "Name", "Type", "LWP", "cpu_id", "Core", "Socket"); + + M (SHOW_THREADS, mp); + + S (mp); + W (ret); + return ret; +} + static void vl_api_ip4_arp_event_t_handler (vl_api_ip4_arp_event_t * mp) { @@ -5655,6 +5725,7 @@ _(CREATE_VHOST_USER_IF_REPLY, create_vhost_user_if_reply) \ _(MODIFY_VHOST_USER_IF_REPLY, modify_vhost_user_if_reply) \ _(DELETE_VHOST_USER_IF_REPLY, delete_vhost_user_if_reply) \ _(SHOW_VERSION_REPLY, show_version_reply) \ +_(SHOW_THREADS_REPLY, show_threads_reply) \ _(L2_FIB_TABLE_DETAILS, l2_fib_table_details) \ _(VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, vxlan_gpe_add_del_tunnel_reply) \ _(VXLAN_GPE_TUNNEL_DETAILS, vxlan_gpe_tunnel_details) \ @@ -23742,6 +23813,7 @@ _(modify_vhost_user_if, \ _(delete_vhost_user_if, " | sw_if_index ") \ _(sw_interface_vhost_user_dump, "") \ _(show_version, "") \ +_(show_threads, "") \ _(vxlan_gpe_add_del_tunnel, \ "local remote | group \n" \ "{ | mcast_sw_if_index } }\n" \ diff --git a/src/vlib/node_cli.c b/src/vlib/node_cli.c index 3dbf672d441..00199d999d1 100644 --- a/src/vlib/node_cli.c +++ b/src/vlib/node_cli.c @@ -345,9 +345,9 @@ show_node_runtime (vlib_main_t * vm, if (j > 0) vlib_cli_output (vm, "---------------"); - if (w->lcore_id > -1) + if (w->cpu_id > -1) vlib_cli_output (vm, "Thread %d %s (lcore %u)", j, w->name, - w->lcore_id); + w->cpu_id); else vlib_cli_output (vm, "Thread %d %s", j, w->name); } diff --git a/src/vlib/threads.c b/src/vlib/threads.c index def8927e29f..055998adac8 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -305,7 +306,7 @@ vlib_thread_init (vlib_main_t * vm) w = vlib_worker_threads; w->thread_mheap = clib_mem_get_heap (); w->thread_stack = vlib_thread_stacks[0]; - w->lcore_id = tm->main_lcore; + w->cpu_id = tm->main_lcore; w->lwp = syscall (SYS_gettid); w->thread_id = pthread_self (); tm->n_vlib_mains = 1; @@ -600,21 +601,42 @@ vlib_worker_thread_bootstrap_fn (void *arg) return rv; } +static void +vlib_get_thread_core_socket (vlib_worker_thread_t * w, unsigned cpu_id) +{ + const char *sys_cpu_path = "/sys/devices/system/cpu/cpu"; + u8 *p = 0; + int core_id = -1, socket_id = -1; + + p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, cpu_id, 0); + clib_sysfs_read ((char *) p, "%d", &core_id); + vec_reset_length (p); + p = + format (p, "%s%u/topology/physical_package_id%c", sys_cpu_path, cpu_id, + 0); + clib_sysfs_read ((char *) p, "%d", &socket_id); + vec_free (p); + + w->core_id = core_id; + w->socket_id = socket_id; +} + static clib_error_t * -vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned lcore_id) +vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id) { vlib_thread_main_t *tm = &vlib_thread_main; void *(*fp_arg) (void *) = fp; - w->lcore_id = lcore_id; + w->cpu_id = cpu_id; + vlib_get_thread_core_socket (w, cpu_id); if (tm->cb.vlib_launch_thread_cb && !w->registration->use_pthreads) - return tm->cb.vlib_launch_thread_cb (fp, (void *) w, lcore_id); + return tm->cb.vlib_launch_thread_cb (fp, (void *) w, cpu_id); else { pthread_t worker; cpu_set_t cpuset; CPU_ZERO (&cpuset); - CPU_SET (lcore_id, &cpuset); + CPU_SET (cpu_id, &cpuset); if (pthread_create (&worker, NULL /* attr */ , fp_arg, (void *) w)) return clib_error_return_unix (0, "pthread_create"); diff --git a/src/vlib/threads.h b/src/vlib/threads.h index 7de0412362e..71b5d0c8261 100644 --- a/src/vlib/threads.h +++ b/src/vlib/threads.h @@ -108,7 +108,9 @@ typedef struct volatile u32 *node_reforks_required; long lwp; - int lcore_id; + int cpu_id; + int core_id; + int socket_id; pthread_t thread_id; } vlib_worker_thread_t; @@ -270,8 +272,8 @@ typedef enum typedef struct { clib_error_t *(*vlib_launch_thread_cb) (void *fp, vlib_worker_thread_t * w, - unsigned lcore_id); - clib_error_t *(*vlib_thread_set_lcore_cb) (u32 thread, u16 lcore); + unsigned cpu_id); + clib_error_t *(*vlib_thread_set_lcore_cb) (u32 thread, u16 cpu); } vlib_thread_callbacks_t; typedef struct diff --git a/src/vlib/threads_cli.c b/src/vlib/threads_cli.c index bb9ddbc6e3c..a47d86401bc 100644 --- a/src/vlib/threads_cli.c +++ b/src/vlib/threads_cli.c @@ -15,7 +15,6 @@ #define _GNU_SOURCE #include -#include #include #include @@ -64,57 +63,16 @@ show_threads_fn (vlib_main_t * vm, line = format (line, "%-25U", format_sched_policy_and_priority, w->lwp); - int lcore = -1; - cpu_set_t cpuset; - CPU_ZERO (&cpuset); - int ret = -1; - - ret = - pthread_getaffinity_np (w->thread_id, sizeof (cpu_set_t), &cpuset); - if (!ret) - { - int c; - for (c = 0; c < CPU_SETSIZE; c++) - if (CPU_ISSET (c, &cpuset)) - { - if (lcore > -1) - { - lcore = -2; - break; - } - lcore = c; - } - } - else - { - lcore = w->lcore_id; - } - - if (lcore > -1) + int cpu_id = w->cpu_id; + if (cpu_id > -1) { - const char *sys_cpu_path = "/sys/devices/system/cpu/cpu"; - int socket_id = -1; - int core_id = -1; - u8 *p = 0; - - p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, lcore, 0); - clib_sysfs_read ((char *) p, "%d", &core_id); - - vec_reset_length (p); - p = - format (p, - "%s%u/topology/physical_package_id%c", - sys_cpu_path, lcore, 0); - clib_sysfs_read ((char *) p, "%d", &socket_id); - vec_free (p); - - line = format (line, "%-7u%-7u%-7u%", lcore, core_id, socket_id); + int core_id = w->core_id; + int socket_id = w->socket_id; + line = format (line, "%-7u%-7u%-7u%", cpu_id, core_id, socket_id); } else { - line = - format (line, "%-7s%-7s%-7s%", (lcore == -2) ? "M" : "n/a", "n/a", - "n/a"); + line = format (line, "%-7s%-7s%-7s%", "n/a", "n/a", "n/a"); } vlib_cli_output (vm, "%v", line); diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index d69b84fd0b9..86865099532 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -2,7 +2,7 @@ *------------------------------------------------------------------ * api.c - message handler registration * - * Copyright (c) 2010-2016 Cisco and/or its affiliates. + * Copyright (c) 2010-2018 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -80,6 +80,7 @@ _(CLI_INBAND, cli_inband) \ _(GET_NODE_INDEX, get_node_index) \ _(ADD_NODE_NEXT, add_node_next) \ _(SHOW_VERSION, show_version) \ +_(SHOW_THREADS, show_threads) \ _(GET_NODE_GRAPH, get_node_graph) \ _(GET_NEXT_INDEX, get_next_index) \ @@ -254,6 +255,69 @@ vl_api_show_version_t_handler (vl_api_show_version_t * mp) /* *INDENT-ON* */ } +static void +get_thread_data (vl_api_thread_data_t * td, int index) +{ + vlib_worker_thread_t *w = vlib_worker_threads + index; + td->id = htonl (index); + if (w->name) + strncpy ((char *) td->name, (char *) w->name, ARRAY_LEN (td->name) - 1); + if (w->registration) + strncpy ((char *) td->type, (char *) w->registration->name, + ARRAY_LEN (td->type) - 1); + td->pid = htonl (w->lwp); + td->cpu_id = htonl (w->cpu_id); + td->core = htonl (w->core_id); + td->cpu_socket = htonl (w->socket_id); +} + +static void +vl_api_show_threads_t_handler (vl_api_show_threads_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + int rv = 0, count = 0; + +#if !defined(__powerpc64__) + vl_api_registration_t *reg; + vl_api_show_threads_reply_t *rmp; + vl_api_thread_data_t *td; + int i, msg_size = 0; + count = vec_len (vlib_worker_threads); + if (!count) + return; + + msg_size = sizeof (*rmp) + sizeof (rmp->thread_data[0]) * count; + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + rmp = vl_msg_api_alloc (msg_size); + memset (rmp, 0, msg_size); + rmp->_vl_msg_id = htons (VL_API_SHOW_THREADS_REPLY); + rmp->context = mp->context; + rmp->count = htonl (count); + td = rmp->thread_data; + + for (i = 0; i < count; i++) + { + get_thread_data (&td[i], i); + } + + vl_api_send_msg (reg, (u8 *) rmp); +#else + + /* unimplemented support */ + rv = -9; + clib_warning ("power pc does not support show threads api"); + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_SHOW_THREADS_REPLY, + ({ + rmp->count = htonl(count); + })); + /* *INDENT-ON* */ +#endif +} + static void vl_api_get_node_index_t_handler (vl_api_get_node_index_t * mp) { diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index baa675c908d..aa635668593 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -2154,6 +2154,16 @@ static void *vl_api_show_version_t_print FINISH; } +static void *vl_api_show_threads_t_print + (vl_api_show_threads_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: show_threads "); + + FINISH; +} + static void *vl_api_vxlan_gpe_add_del_tunnel_t_print (vl_api_vxlan_gpe_add_del_tunnel_t * mp, void *handle) { diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 2eb14bc2fd4..488af1727bc 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -19,7 +19,7 @@ called through a shared memory interface. */ -option version = "1.0.0"; +option version = "1.1.0"; /* * Note: API placement cleanup in progress @@ -193,6 +193,54 @@ define show_version_reply u8 build_directory[256]; }; + +/** \brief show_threads display the information about vpp + threads running on system along with their process id, + cpu id, physical core and cpu socket. +*/ +define show_threads +{ + u32 client_index; + u32 context; +}; + +/** \brief thread data + @param id - thread index + @param name - thread name i.e. vpp_main or vpp_wk_0 + @param type - thread type i.e. workers or stats + @param pid - thread Process Id + @param cpu_id - thread pinned to cpu. + "CPUs or Logical cores are the number of physical cores times + the number of threads that can run on each core through + the use of hyperthreading." (from unix.stackexchange.com) + @param core - thread pinned to actual physical core. + @param cpu_socket - thread is running on which cpu socket. +*/ +typeonly define thread_data +{ + u32 id; + u8 name[64]; + u8 type[64]; + u32 pid; + u32 cpu_id; + u32 core; + u32 cpu_socket; +}; + +/** \brief show_threads_reply + @param context - returned sender context, to match reply w/ request + @param retval - return code + @param count - number of threads in thread_data array + @param thread_data - array of thread data +*/ +define show_threads_reply +{ + u32 context; + i32 retval; + u32 count; + vl_api_thread_data_t thread_data[count]; +}; + define get_node_graph { u32 client_index; -- 2.16.6