diff mbox series

[ovs-dev,1/2] dpdk: Add debug appctl to get socket statistics.

Message ID 20210425162828.31982-2-elibr@nvidia.com
State Changes Requested
Headers show
Series dpdk debug stats commands | expand

Commit Message

Eli Britstein April 25, 2021, 4:28 p.m. UTC
New appctl 'dpdk/get-socket-stats' implemented to get result of
'rte_malloc_get_socket_stats()' function for socket passed as an
argument. If no arguments passed, get the results for all available
sockets.

Could be used for debugging.

Signed-off-by: Eli Britstein <elibr@nvidia.com>
Reviewed-by: Salem Sol <salems@nvidia.com>
---
 NEWS                 |  2 ++
 lib/dpdk-unixctl.man |  4 +++
 lib/dpdk.c           | 60 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)

Comments

Eelco Chaudron April 30, 2021, 12:51 p.m. UTC | #1
On 25 Apr 2021, at 18:28, Eli Britstein wrote:

> New appctl 'dpdk/get-socket-stats' implemented to get result of
> 'rte_malloc_get_socket_stats()' function for socket passed as an
> argument. If no arguments passed, get the results for all available
> sockets.

The information is malloc() stats per cpu socket, so I would rename the 
command to
dpdk/get-malloc-stats (comment in patch 2 for the name there).

> Could be used for debugging.
>
> Signed-off-by: Eli Britstein <elibr@nvidia.com>
> Reviewed-by: Salem Sol <salems@nvidia.com>
> ---
>  NEWS                 |  2 ++
>  lib/dpdk-unixctl.man |  4 +++
>  lib/dpdk.c           | 60 
> ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 66 insertions(+)
>
> diff --git a/NEWS b/NEWS
> index 95cf922aa..e0c0f0408 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -9,6 +9,8 @@ Post-v2.15.0
>       * New option '--no-record-hostname' to disable hostname 
> configuration
>         in ovsdb on startup.
>       * New command 'record-hostname-if-not-set' to update hostname in 
> ovsdb.
> +   - DPDK:
> +     * New debug appctl command 'dpdk/get-socket-stats'.
>
>  v2.15.0 - 15 Feb 2021
> diff --git a/lib/dpdk-unixctl.man b/lib/dpdk-unixctl.man
> index 2d6d576f2..37f02d6c7 100644
> --- a/lib/dpdk-unixctl.man
> +++ b/lib/dpdk-unixctl.man
> @@ -10,5 +10,9 @@ list of words separated by spaces: a word can be 
> either a logging \fBlevel\fR
>  \fBnotice\fR, \fBinfo\fR or \fBdebug\fR) or a \fBpattern\fR matching 
> DPDK
>  components (see \fBdpdk/log-list\fR command on \fBovs\-appctl\fR(8)) 
> separated
>  by a colon from the logging \fBlevel\fR to apply.
> +.IP "\fBdpdk/get-socket-stats\fR [\fIsocket\fR]"
> +Prints the statistics information about DPDK socket \fIsocket\fR.
> +If called without arguments, information of all the available sockets 
> will
> +be printed.
>  .RE
>  .
> diff --git a/lib/dpdk.c b/lib/dpdk.c
> index 319540394..5a6b2015c 100644
> --- a/lib/dpdk.c
> +++ b/lib/dpdk.c
> @@ -25,6 +25,7 @@
>  #include <rte_cpuflags.h>
>  #include <rte_errno.h>
>  #include <rte_log.h>
> +#include <rte_malloc.h>
>  #include <rte_memzone.h>
>  #include <rte_version.h>
>
> @@ -356,6 +357,63 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, 
> int argc, const char *argv[],
>      unixctl_command_reply(conn, NULL);
>  }
>
> +static void +dpdk_unixctl_get_socket_stats(struct unixctl_conn *conn,
> +                              int argc, const char *argv[],
> +                              void *aux OVS_UNUSED)

Guess function also need to change as we are not getting sockets stats, 
but malloc stats per socket.

> +{
> +    struct rte_malloc_socket_stats socket_stats;
> +    unsigned int socket_max = rte_socket_count();
> +    unsigned int socket_min = 0;
> +    unsigned int socket;
> +    size_t size;
> +    FILE *stream;
> +    char *response = NULL;
> +
> +    if (argc == 2) {
> +        socket_min = atoi(argv[1]);
> +        socket_max = socket_min + 1;
> +    }
> +
> +    stream = open_memstream(&response, &size);
> +    if (!stream) {
> +        response = xasprintf("Unable to open memstream: %s.",
> +                             ovs_strerror(errno));
> +        unixctl_command_reply_error(conn, response);
> +        goto out;

Don’t think we need a stream in this case, see below.
> +    }
> +
> +    for (socket = socket_min; socket < socket_max; socket++) {
> +        if (rte_malloc_get_socket_stats(socket, &socket_stats)) {
> +            response = xasprintf("Unable to get stats for socket %d: 
> %s.",
> +                                 socket, ovs_strerror(errno));
> +            fclose(stream);
> +            unixctl_command_reply_error(conn, response);

If I put in an invalid socket id, the error message is not printed. Did 
not further research, but if I replace “response” here with a const 
string it gets printed.

> +            goto out;
> +        }
> +        fprintf(stream,
> +                "Socket = %d\n"
> +                "heap_totalsz_bytes = %lu\n"
> +                "heap_freesz_bytes = %lu\n"
> +                "greatest_free_size = %lu\n"
> +                "free_count = %u\n"
> +                "alloc_count = %u\n"
> +                "heap_allocsz_bytes = %lu\n", socket,
> +                socket_stats.heap_totalsz_bytes,
> +                socket_stats.heap_freesz_bytes,
> +                socket_stats.greatest_free_size,
> +                socket_stats.free_count,
> +                socket_stats.alloc_count,
> +                socket_stats.heap_allocsz_bytes);

I think here you do not need to put it to a stream, but you should use 
the normal APIs for this, see dpif_netdev_pmd_info() for an example, 
i.e., pass the result to the unixctl_command_reply().

> +    }
> +
> +    fclose(stream);
> +
> +    unixctl_command_reply(conn, response);
> +out:
> +    free(response);
> +}
> +
>  static bool
>  dpdk_init__(const struct smap *ovs_other_config)
>  {
> @@ -525,6 +583,8 @@ dpdk_init__(const struct smap *ovs_other_config)
>                               dpdk_unixctl_mem_stream, rte_log_dump);
>      unixctl_command_register("dpdk/log-set", "{level | 
> pattern:level}", 0,
>                               INT_MAX, dpdk_unixctl_log_set, NULL);
> +    unixctl_command_register("dpdk/get-socket-stats", "[socket]", 0, 
> INT_MAX,
> +                             dpdk_unixctl_get_socket_stats, NULL);
>
>      /* We are called from the main thread here */
>      RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID;
> -- 
> 2.28.0.2311.g225365fb51
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Eelco Chaudron April 30, 2021, 1:11 p.m. UTC | #2
On 30 Apr 2021, at 14:51, Eelco Chaudron wrote:

> On 25 Apr 2021, at 18:28, Eli Britstein wrote:
>
>> New appctl 'dpdk/get-socket-stats' implemented to get result of
>> 'rte_malloc_get_socket_stats()' function for socket passed as an
>> argument. If no arguments passed, get the results for all available
>> sockets.
>
> The information is malloc() stats per cpu socket, so I would rename 
> the command to
> dpdk/get-malloc-stats (comment in patch 2 for the name there).
>
>> Could be used for debugging.
>>
>> Signed-off-by: Eli Britstein <elibr@nvidia.com>
>> Reviewed-by: Salem Sol <salems@nvidia.com>
>> ---
>>  NEWS                 |  2 ++
>>  lib/dpdk-unixctl.man |  4 +++
>>  lib/dpdk.c           | 60 
>> ++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 66 insertions(+)
>>
>> diff --git a/NEWS b/NEWS
>> index 95cf922aa..e0c0f0408 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -9,6 +9,8 @@ Post-v2.15.0
>>       * New option '--no-record-hostname' to disable hostname 
>> configuration
>>         in ovsdb on startup.
>>       * New command 'record-hostname-if-not-set' to update hostname 
>> in ovsdb.
>> +   - DPDK:
>> +     * New debug appctl command 'dpdk/get-socket-stats'.
>>
>>  v2.15.0 - 15 Feb 2021
>> diff --git a/lib/dpdk-unixctl.man b/lib/dpdk-unixctl.man
>> index 2d6d576f2..37f02d6c7 100644
>> --- a/lib/dpdk-unixctl.man
>> +++ b/lib/dpdk-unixctl.man
>> @@ -10,5 +10,9 @@ list of words separated by spaces: a word can be 
>> either a logging \fBlevel\fR
>>  \fBnotice\fR, \fBinfo\fR or \fBdebug\fR) or a \fBpattern\fR matching 
>> DPDK
>>  components (see \fBdpdk/log-list\fR command on \fBovs\-appctl\fR(8)) 
>> separated
>>  by a colon from the logging \fBlevel\fR to apply.
>> +.IP "\fBdpdk/get-socket-stats\fR [\fIsocket\fR]"
>> +Prints the statistics information about DPDK socket \fIsocket\fR.
>> +If called without arguments, information of all the available 
>> sockets will
>> +be printed.
>>  .RE
>>  .
>> diff --git a/lib/dpdk.c b/lib/dpdk.c
>> index 319540394..5a6b2015c 100644
>> --- a/lib/dpdk.c
>> +++ b/lib/dpdk.c
>> @@ -25,6 +25,7 @@
>>  #include <rte_cpuflags.h>
>>  #include <rte_errno.h>
>>  #include <rte_log.h>
>> +#include <rte_malloc.h>
>>  #include <rte_memzone.h>
>>  #include <rte_version.h>
>>
>> @@ -356,6 +357,63 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, 
>> int argc, const char *argv[],
>>      unixctl_command_reply(conn, NULL);
>>  }
>>
>> +static void +dpdk_unixctl_get_socket_stats(struct unixctl_conn 
>> *conn,
>> +                              int argc, const char *argv[],
>> +                              void *aux OVS_UNUSED)
>
> Guess function also need to change as we are not getting sockets 
> stats, but malloc stats per socket.
>
>> +{
>> +    struct rte_malloc_socket_stats socket_stats;
>> +    unsigned int socket_max = rte_socket_count();
>> +    unsigned int socket_min = 0;
>> +    unsigned int socket;
>> +    size_t size;
>> +    FILE *stream;
>> +    char *response = NULL;
>> +
>> +    if (argc == 2) {
>> +        socket_min = atoi(argv[1]);
>> +        socket_max = socket_min + 1;
>> +    }
>> +
>> +    stream = open_memstream(&response, &size);
>> +    if (!stream) {
>> +        response = xasprintf("Unable to open memstream: %s.",
>> +                             ovs_strerror(errno));
>> +        unixctl_command_reply_error(conn, response);
>> +        goto out;
>
> Don’t think we need a stream in this case, see below.
>> +    }
>> +
>> +    for (socket = socket_min; socket < socket_max; socket++) {
>> +        if (rte_malloc_get_socket_stats(socket, &socket_stats)) {
>> +            response = xasprintf("Unable to get stats for socket %d: 
>> %s.",
>> +                                 socket, ovs_strerror(errno));
>> +            fclose(stream);
>> +            unixctl_command_reply_error(conn, response);
>
> If I put in an invalid socket id, the error message is not printed. 
> Did not further research, but if I replace “response” here with a 
> const string it gets printed.

Looking about it again, you might need to close the stream first, 
free(response), then call xasprintf() followed by 
unixctl_command_reply_error().
>
>> +            goto out;
>> +        }
>> +        fprintf(stream,
>> +                "Socket = %d\n"
>> +                "heap_totalsz_bytes = %lu\n"
>> +                "heap_freesz_bytes = %lu\n"
>> +                "greatest_free_size = %lu\n"
>> +                "free_count = %u\n"
>> +                "alloc_count = %u\n"
>> +                "heap_allocsz_bytes = %lu\n", socket,
>> +                socket_stats.heap_totalsz_bytes,
>> +                socket_stats.heap_freesz_bytes,
>> +                socket_stats.greatest_free_size,
>> +                socket_stats.free_count,
>> +                socket_stats.alloc_count,
>> +                socket_stats.heap_allocsz_bytes);
>
> I think here you do not need to put it to a stream, but you should use 
> the normal APIs for this, see dpif_netdev_pmd_info() for an example, 
> i.e., pass the result to the unixctl_command_reply().
>
>> +    }
>> +
>> +    fclose(stream);
>> +
>> +    unixctl_command_reply(conn, response);
>> +out:
>> +    free(response);
>> +}
>> +
>>  static bool
>>  dpdk_init__(const struct smap *ovs_other_config)
>>  {
>> @@ -525,6 +583,8 @@ dpdk_init__(const struct smap *ovs_other_config)
>>                               dpdk_unixctl_mem_stream, rte_log_dump);
>>      unixctl_command_register("dpdk/log-set", "{level | 
>> pattern:level}", 0,
>>                               INT_MAX, dpdk_unixctl_log_set, NULL);
>> +    unixctl_command_register("dpdk/get-socket-stats", "[socket]", 0, 
>> INT_MAX,
>> +                             dpdk_unixctl_get_socket_stats, NULL);
>>
>>      /* We are called from the main thread here */
>>      RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID;
>> -- 
>> 2.28.0.2311.g225365fb51
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index 95cf922aa..e0c0f0408 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@  Post-v2.15.0
      * New option '--no-record-hostname' to disable hostname configuration
        in ovsdb on startup.
      * New command 'record-hostname-if-not-set' to update hostname in ovsdb.
+   - DPDK:
+     * New debug appctl command 'dpdk/get-socket-stats'.
 
 
 v2.15.0 - 15 Feb 2021
diff --git a/lib/dpdk-unixctl.man b/lib/dpdk-unixctl.man
index 2d6d576f2..37f02d6c7 100644
--- a/lib/dpdk-unixctl.man
+++ b/lib/dpdk-unixctl.man
@@ -10,5 +10,9 @@  list of words separated by spaces: a word can be either a logging \fBlevel\fR
 \fBnotice\fR, \fBinfo\fR or \fBdebug\fR) or a \fBpattern\fR matching DPDK
 components (see \fBdpdk/log-list\fR command on \fBovs\-appctl\fR(8)) separated
 by a colon from the logging \fBlevel\fR to apply.
+.IP "\fBdpdk/get-socket-stats\fR [\fIsocket\fR]"
+Prints the statistics information about DPDK socket \fIsocket\fR.
+If called without arguments, information of all the available sockets will
+be printed.
 .RE
 .
diff --git a/lib/dpdk.c b/lib/dpdk.c
index 319540394..5a6b2015c 100644
--- a/lib/dpdk.c
+++ b/lib/dpdk.c
@@ -25,6 +25,7 @@ 
 #include <rte_cpuflags.h>
 #include <rte_errno.h>
 #include <rte_log.h>
+#include <rte_malloc.h>
 #include <rte_memzone.h>
 #include <rte_version.h>
 
@@ -356,6 +357,63 @@  dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[],
     unixctl_command_reply(conn, NULL);
 }
 
+static void
+dpdk_unixctl_get_socket_stats(struct unixctl_conn *conn,
+                              int argc, const char *argv[],
+                              void *aux OVS_UNUSED)
+{
+    struct rte_malloc_socket_stats socket_stats;
+    unsigned int socket_max = rte_socket_count();
+    unsigned int socket_min = 0;
+    unsigned int socket;
+    size_t size;
+    FILE *stream;
+    char *response = NULL;
+
+    if (argc == 2) {
+        socket_min = atoi(argv[1]);
+        socket_max = socket_min + 1;
+    }
+
+    stream = open_memstream(&response, &size);
+    if (!stream) {
+        response = xasprintf("Unable to open memstream: %s.",
+                             ovs_strerror(errno));
+        unixctl_command_reply_error(conn, response);
+        goto out;
+    }
+
+    for (socket = socket_min; socket < socket_max; socket++) {
+        if (rte_malloc_get_socket_stats(socket, &socket_stats)) {
+            response = xasprintf("Unable to get stats for socket %d: %s.",
+                                 socket, ovs_strerror(errno));
+            fclose(stream);
+            unixctl_command_reply_error(conn, response);
+            goto out;
+        }
+        fprintf(stream,
+                "Socket = %d\n"
+                "heap_totalsz_bytes = %lu\n"
+                "heap_freesz_bytes = %lu\n"
+                "greatest_free_size = %lu\n"
+                "free_count = %u\n"
+                "alloc_count = %u\n"
+                "heap_allocsz_bytes = %lu\n", socket,
+                socket_stats.heap_totalsz_bytes,
+                socket_stats.heap_freesz_bytes,
+                socket_stats.greatest_free_size,
+                socket_stats.free_count,
+                socket_stats.alloc_count,
+                socket_stats.heap_allocsz_bytes);
+    }
+
+    fclose(stream);
+
+    unixctl_command_reply(conn, response);
+out:
+    free(response);
+}
+
 static bool
 dpdk_init__(const struct smap *ovs_other_config)
 {
@@ -525,6 +583,8 @@  dpdk_init__(const struct smap *ovs_other_config)
                              dpdk_unixctl_mem_stream, rte_log_dump);
     unixctl_command_register("dpdk/log-set", "{level | pattern:level}", 0,
                              INT_MAX, dpdk_unixctl_log_set, NULL);
+    unixctl_command_register("dpdk/get-socket-stats", "[socket]", 0, INT_MAX,
+                             dpdk_unixctl_get_socket_stats, NULL);
 
     /* We are called from the main thread here */
     RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID;