All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] libtracefs: Add get affinity API
@ 2022-01-18  3:00 Steven Rostedt
  2022-01-18  3:00 ` [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs Steven Rostedt
  2022-01-18  3:00 ` [PATCH 2/2] libtracefs: Fix libtracefs-instance-affinity example Steven Rostedt
  0 siblings, 2 replies; 5+ messages in thread
From: Steven Rostedt @ 2022-01-18  3:00 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Steven Rostedt

We have tracefs_instance_set_affinity() APIs but no "get_affinity()" APIs.
Change that now by adding matching get_affinity() APIs to the "set_affinity()"
ones.

Also fix a bug that was in the affinity example in the man pages.

Steven Rostedt (2):
  libtracefs: Add tracefs_instance_get_affinity() APIs
  libtracefs: Fix libtracefs-instance-affinity example

 .../libtracefs-instances-affinity.txt         |  43 +++-
 include/tracefs.h                             |   4 +
 src/tracefs-instance.c                        | 192 ++++++++++++++++++
 3 files changed, 233 insertions(+), 6 deletions(-)

-- 
2.33.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs
  2022-01-18  3:00 [PATCH 0/2] libtracefs: Add get affinity API Steven Rostedt
@ 2022-01-18  3:00 ` Steven Rostedt
  2022-01-19 12:59   ` Tzvetomir Stoyanov
  2022-01-18  3:00 ` [PATCH 2/2] libtracefs: Fix libtracefs-instance-affinity example Steven Rostedt
  1 sibling, 1 reply; 5+ messages in thread
From: Steven Rostedt @ 2022-01-18  3:00 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Steven Rostedt

Add the APIs:

  tracefs_instance_get_affinity()
  tracefs_instance_get_affinity_set()
  tracefs_instance_get_affinity_raw()

These functions can retrieve the CPU affinity that denotes what an
instance (or toplevel) has for CPUs that are enabled for tracing.

The first API returns a nice human readable list of CPUs:

 "1,4,6-8"

To denote CPUs 1,4,6,7,8

The _set() version uses CPU_SETS and the _raw() version just reads
directly from the tracing_cpumask file.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 .../libtracefs-instances-affinity.txt         |  39 +++-
 include/tracefs.h                             |   4 +
 src/tracefs-instance.c                        | 192 ++++++++++++++++++
 3 files changed, 231 insertions(+), 4 deletions(-)

diff --git a/Documentation/libtracefs-instances-affinity.txt b/Documentation/libtracefs-instances-affinity.txt
index c5fa2d8b820c..22994f877e30 100644
--- a/Documentation/libtracefs-instances-affinity.txt
+++ b/Documentation/libtracefs-instances-affinity.txt
@@ -3,8 +3,9 @@ libtracefs(3)
 
 NAME
 ----
-tracefs_instance_set_affinity, tracefs_instance_set_affinity_set, tracefs_set_affinity_raw -
-Sets the affinity for an instance or top level for what CPUs enable tracing.
+tracefs_instance_set_affinity, tracefs_instance_set_affinity_set, tracefs_set_affinity_raw,
+tracefs_instance_get_affinity, tracefs_instance_get_affinity_set, tracefs_get_affinity_raw,
+Sets or retrieves the affinity for an instance or top level for what CPUs enable tracing.
 
 SYNOPSIS
 --------
@@ -16,11 +17,14 @@ int *tracefs_instance_set_affinity*(struct tracefs_instance pass:[*]_instance_,
 int *tracefs_instance_set_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
 int *tracefs_instance_set_affinity_raw*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_mask_);
 
+char pass:[*]*tracefs_instance_get_affinity*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_instance_get_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
+char pass:[*]*tracefs_instance_get_affinity_raw*(struct tracefs_instance pass:[*]_instance_);
 --
 
 DESCRIPTION
 -----------
-These functions set the CPU affinity that limits what CPUs will have tracing enabled
+These functions set or retrieves the CPU affinity that limits what CPUs will have tracing enabled
 for a given instance defined by the _instance_ parameter. If _instance_ is NULL, then
 the top level instance is affected.
 
@@ -47,9 +51,32 @@ machine with more that 32 CPUs, to set CPUS 1-10 and CPU 40:
 
 Where the above is a hex representation of bits 1-10 and bit 40 being set.
 
+The *tracefs_instance_get_affinity()* will retrieve the affinity in a human readable
+form.
+
+For example: "1,4,6-8"
+
+The string returned must be freed with *free*(3).
+
+The *tracefs_instance_get_affinity_set()* will set all the bits in the passed in
+cpu set (from *CPU_SET*(3)). Note it will not clear any bits that are already set
+in the set but the CPUs are not. If only the bits for the CPUs that are enabled
+should be set, a CPU_ZERO_S() should be performed on the set before calling this
+function.
+
+The *tracefs_instance_get_affinity_raw()* will simply read the instance tracing_cpumask
+and return that string. The returned string must be freed with *free*(3).
+
 RETURN VALUE
 ------------
-All of these functions return 0 on success and -1 on error.
+All the set functions return 0 on success and -1 on error.
+
+The functinos *tracefs_instance_get_affinity()* and *tracefs_instance_get_affinity_raw()*
+returns an allocated string that must be freed with *free*(3), or NULL on error.
+
+The function *tracefs_instance_get_affinity_set()* returns the number of CPUs that
+were found set, or -1 on error.
+
 
 ERRORS
 ------
@@ -88,6 +115,10 @@ int main (int argc, char **argv)
 	int cpu2;
 	int i;
 
+	c = tracefs_instance_get_affinity(NULL);
+	printf("The affinity was %s\n", c);
+	free(c);
+
 	if (argc < 2) {
 		tracefs_instance_set_affinity(NULL, NULL);
 		exit(0);
diff --git a/include/tracefs.h b/include/tracefs.h
index 9c53b8413795..1848ad0aa668 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -49,6 +49,10 @@ int tracefs_instance_set_affinity_raw(struct tracefs_instance *instance,
 				      const char *mask);
 int tracefs_instance_set_affinity(struct tracefs_instance *instance,
 				  const char *cpu_str);
+char *tracefs_instance_get_affinity(struct tracefs_instance *instance);
+char *tracefs_instance_get_affinity_raw(struct tracefs_instance *instance);
+int tracefs_instance_get_affinity_set(struct tracefs_instance *instance,
+				      cpu_set_t *set, size_t set_size);
 char **tracefs_instances(const char *regex);
 
 bool tracefs_instance_exists(const char *name);
diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c
index fab615eb49ca..2d825b0e3bd0 100644
--- a/src/tracefs-instance.c
+++ b/src/tracefs-instance.c
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <ctype.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -974,3 +975,194 @@ int tracefs_instance_set_affinity(struct tracefs_instance *instance,
 	CPU_FREE(set);
 	return ret;
 }
+
+/**
+ * tracefs_instance_get_affinity_raw - read the affinity instance file
+ * @instance: The instance to get affinity of (NULL for top level)
+ *
+ * Reads the affinity file for @instance (or the top level if @instance
+ * is NULL) and returns it. The returned string must be freed with free().
+ *
+ * Returns the affinity mask on success, and must be freed with free()
+ *   or NULL on error.
+ */
+char *tracefs_instance_get_affinity_raw(struct tracefs_instance *instance)
+{
+	return tracefs_instance_file_read(instance, "tracing_cpumask", NULL);
+}
+
+static inline int update_cpu_set(int cpus, int cpu_set, int cpu,
+				 cpu_set_t *set, size_t set_size)
+{
+	int bit = 1 << cpu;
+
+	if (!(cpus & bit))
+		return 0;
+
+	CPU_SET_S(cpu_set + cpu, set_size, set);
+	return 1;
+}
+
+/**
+ * tracefs_instance_get_affinity_set - Retrieve the cpuset of an instance affinity
+ * @instance: The instance to get affinity of (NULL for top level)
+ * @set: A CPU set to put the affinity into.
+ * @set_size: The size in bytes of @set (use CPU_ALLOC_SIZE() to get this value)
+ *
+ * Reads the affinity of a given instance and updates the CPU set by the
+ * instance.
+ *
+ * Returns the number of CPUS that are set, or -1 on error.
+ */
+int tracefs_instance_get_affinity_set(struct tracefs_instance *instance,
+				      cpu_set_t *set, size_t set_size)
+{
+	char *affinity;
+	int cpu_set;
+	int cpus;
+	int cnt = 0;
+	int ch;
+	int i;
+
+	if (!set || !set_size) {
+		errno = -EINVAL;
+		return -1;
+	}
+
+	affinity = tracefs_instance_get_affinity_raw(instance);
+	if (!affinity)
+		return -1;
+
+	/*
+	 * The returned affinity should be a comma delimited
+	 * hex string. Work backwards setting the values.
+	 */
+	cpu_set = 0;
+	i = strlen(affinity);
+	for (i--; i >= 0; i--) {
+		ch = affinity[i];
+		if (isalnum(ch)) {
+			ch = tolower(ch);
+			if (isdigit(ch))
+				cpus = ch - '0';
+			else
+				cpus = ch - 'a' + 10;
+
+			cnt += update_cpu_set(cpus, cpu_set, 0, set, set_size);
+			cnt += update_cpu_set(cpus, cpu_set, 1, set, set_size);
+			cnt += update_cpu_set(cpus, cpu_set, 2, set, set_size);
+			cnt += update_cpu_set(cpus, cpu_set, 3, set, set_size);
+			/* Next nibble */
+			cpu_set += 4;
+		}
+	}
+
+	free(affinity);
+
+	return cnt;
+}
+
+static inline int update_cpu(int cpus, int cpu_set, int cpu, int s, char **set)
+{
+	char *list;
+	int bit = 1 << cpu;
+	int ret;
+
+	if (*set == (char *)-1)
+		return s;
+
+	if (cpus & bit) {
+		/* If the previous CPU is set just return s */
+		if (s >= 0)
+			return s;
+		/* Otherwise, return this cpu */
+		return cpu_set + cpu;
+	}
+
+	/* If the last CPU wasn't set, just return s */
+	if (s < 0)
+		return s;
+
+	/* Update the string */
+	if (s == cpu_set + cpu - 1) {
+		ret = asprintf(&list, "%s%s%d",
+			       *set ? *set : "", *set ? "," : "", s);
+	} else {
+		ret = asprintf(&list, "%s%s%d-%d",
+			       *set ? *set : "", *set ? "," : "",
+			       s, cpu_set + cpu - 1);
+	}
+	free(*set);
+	/* Force *set to be a failure */
+	if (ret < 0)
+		*set = (char *)-1;
+	else
+		*set = list;
+	return -1;
+}
+
+/**
+ * tracefs_instance_get_affinity - Retrieve a string of CPUs for instance affinity
+ * @instance: The instance to get affinity of (NULL for top level)
+ *
+ * Reads the affinity of a given instance and returns a CPU count of the
+ * instance. For example, if it reads "eb" it will return:
+ *      "0-1,3,5-7"
+ *
+ * If no CPUs are set, an empty string is returned "\0", and it too needs
+ * to be freed.
+ *
+ * Returns an allocate string containing the CPU affinity in "human readable"
+ *  format which needs to be freed with free(), or NULL on error.
+ */
+char *tracefs_instance_get_affinity(struct tracefs_instance *instance)
+{
+	char *affinity;
+	char *set = NULL;
+	int cpu_set;
+	int cpus;
+	int ch;
+	int s = -1;
+	int i;
+
+	affinity = tracefs_instance_get_affinity_raw(instance);
+	if (!affinity)
+		return NULL;
+
+	/*
+	 * The returned affinity should be a comma delimited
+	 * hex string. Work backwards setting the values.
+	 */
+	cpu_set = 0;
+	i = strlen(affinity);
+	for (i--; i >= 0; i--) {
+		ch = affinity[i];
+		if (isalnum(ch)) {
+			ch = tolower(ch);
+			if (isdigit(ch))
+				cpus = ch - '0';
+			else
+				cpus = ch - 'a' + 10;
+			s = update_cpu(cpus, cpu_set, 0, s, &set);
+			s = update_cpu(cpus, cpu_set, 1, s, &set);
+			s = update_cpu(cpus, cpu_set, 2, s, &set);
+			s = update_cpu(cpus, cpu_set, 3, s, &set);
+
+			if (set == (char *)-1) {
+				set = NULL;
+				goto out;
+			}
+			/* Next nibble */
+			cpu_set += 4;
+		}
+	}
+	/* Clean up in case the last CPU is set */
+	s = update_cpu(0, cpu_set, 0, s, &set);
+
+	if (!set)
+		set = strdup("");
+ out:
+	free(affinity);
+
+	return set;
+}
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] libtracefs: Fix libtracefs-instance-affinity example
  2022-01-18  3:00 [PATCH 0/2] libtracefs: Add get affinity API Steven Rostedt
  2022-01-18  3:00 ` [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs Steven Rostedt
@ 2022-01-18  3:00 ` Steven Rostedt
  1 sibling, 0 replies; 5+ messages in thread
From: Steven Rostedt @ 2022-01-18  3:00 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Steven Rostedt

The example in the libtracefs-instance-affinity man page had a bug where
it was taking argv[0] as one of the parameters for the CPUs to set. The
first parameter is the executable name, which isn't what we want.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 Documentation/libtracefs-instances-affinity.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/libtracefs-instances-affinity.txt b/Documentation/libtracefs-instances-affinity.txt
index 22994f877e30..0f3093d62035 100644
--- a/Documentation/libtracefs-instances-affinity.txt
+++ b/Documentation/libtracefs-instances-affinity.txt
@@ -146,8 +146,8 @@ int main (int argc, char **argv)
 	}
 
 	trace_seq_init(&seq);
-	for (i = 0; i < argc; i++) {
-		if (i)
+	for (i = 1; i < argc; i++) {
+		if (i > 1)
 			trace_seq_putc(&seq, ',');
 		trace_seq_puts(&seq, argv[i]);
 	}
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs
  2022-01-18  3:00 ` [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs Steven Rostedt
@ 2022-01-19 12:59   ` Tzvetomir Stoyanov
  2022-01-19 15:40     ` Steven Rostedt
  0 siblings, 1 reply; 5+ messages in thread
From: Tzvetomir Stoyanov @ 2022-01-19 12:59 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: Linux Trace Devel

On Wed, Jan 19, 2022 at 2:02 PM Steven Rostedt <rostedt@goodmis.org> wrote:
>
> Add the APIs:
>
>   tracefs_instance_get_affinity()
>   tracefs_instance_get_affinity_set()
>   tracefs_instance_get_affinity_raw()
>
> These functions can retrieve the CPU affinity that denotes what an
> instance (or toplevel) has for CPUs that are enabled for tracing.
>
> The first API returns a nice human readable list of CPUs:
>
>  "1,4,6-8"
>
> To denote CPUs 1,4,6,7,8
>
> The _set() version uses CPU_SETS and the _raw() version just reads
> directly from the tracing_cpumask file.
>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  .../libtracefs-instances-affinity.txt         |  39 +++-
>  include/tracefs.h                             |   4 +
>  src/tracefs-instance.c                        | 192 ++++++++++++++++++
>  3 files changed, 231 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/libtracefs-instances-affinity.txt b/Documentation/libtracefs-instances-affinity.txt
> index c5fa2d8b820c..22994f877e30 100644
> --- a/Documentation/libtracefs-instances-affinity.txt
> +++ b/Documentation/libtracefs-instances-affinity.txt
> @@ -3,8 +3,9 @@ libtracefs(3)
>
>  NAME
>  ----
> -tracefs_instance_set_affinity, tracefs_instance_set_affinity_set, tracefs_set_affinity_raw -
> -Sets the affinity for an instance or top level for what CPUs enable tracing.
> +tracefs_instance_set_affinity, tracefs_instance_set_affinity_set, tracefs_set_affinity_raw,
> +tracefs_instance_get_affinity, tracefs_instance_get_affinity_set, tracefs_get_affinity_raw,
> +Sets or retrieves the affinity for an instance or top level for what CPUs enable tracing.
>
>  SYNOPSIS
>  --------
> @@ -16,11 +17,14 @@ int *tracefs_instance_set_affinity*(struct tracefs_instance pass:[*]_instance_,
>  int *tracefs_instance_set_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
>  int *tracefs_instance_set_affinity_raw*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_mask_);
>
> +char pass:[*]*tracefs_instance_get_affinity*(struct tracefs_instance pass:[*]_instance_);
> +int *tracefs_instance_get_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
> +char pass:[*]*tracefs_instance_get_affinity_raw*(struct tracefs_instance pass:[*]_instance_);

These should be added also into Documentation/libtracefs.txt, under
the relevant API section. All library APIs should be listed there.

>  --
>
>  DESCRIPTION
>  -----------
> -These functions set the CPU affinity that limits what CPUs will have tracing enabled
> +These functions set or retrieves the CPU affinity that limits what CPUs will have tracing enabled

Maybe "These functions set or retrieve ..." ?

>  for a given instance defined by the _instance_ parameter. If _instance_ is NULL, then
>  the top level instance is affected.
>
> @@ -47,9 +51,32 @@ machine with more that 32 CPUs, to set CPUS 1-10 and CPU 40:
>
>  Where the above is a hex representation of bits 1-10 and bit 40 being set.
>
> +The *tracefs_instance_get_affinity()* will retrieve the affinity in a human readable
> +form.
> +
> +For example: "1,4,6-8"
> +
> +The string returned must be freed with *free*(3).
> +
> +The *tracefs_instance_get_affinity_set()* will set all the bits in the passed in
> +cpu set (from *CPU_SET*(3)). Note it will not clear any bits that are already set
> +in the set but the CPUs are not. If only the bits for the CPUs that are enabled
> +should be set, a CPU_ZERO_S() should be performed on the set before calling this
> +function.
> +
> +The *tracefs_instance_get_affinity_raw()* will simply read the instance tracing_cpumask
> +and return that string. The returned string must be freed with *free*(3).
> +
>  RETURN VALUE
>  ------------
> -All of these functions return 0 on success and -1 on error.
> +All the set functions return 0 on success and -1 on error.
> +
> +The functinos *tracefs_instance_get_affinity()* and *tracefs_instance_get_affinity_raw()*

a typo, "functions"

> +returns an allocated string that must be freed with *free*(3), or NULL on error.
> +
> +The function *tracefs_instance_get_affinity_set()* returns the number of CPUs that
> +were found set, or -1 on error.
> +
>
>  ERRORS
>  ------
> @@ -88,6 +115,10 @@ int main (int argc, char **argv)
>         int cpu2;
>         int i;
>
> +       c = tracefs_instance_get_affinity(NULL);
> +       printf("The affinity was %s\n", c);
> +       free(c);
> +
>         if (argc < 2) {
>                 tracefs_instance_set_affinity(NULL, NULL);
>                 exit(0);
> diff --git a/include/tracefs.h b/include/tracefs.h
> index 9c53b8413795..1848ad0aa668 100644
> --- a/include/tracefs.h
> +++ b/include/tracefs.h
> @@ -49,6 +49,10 @@ int tracefs_instance_set_affinity_raw(struct tracefs_instance *instance,
>                                       const char *mask);
>  int tracefs_instance_set_affinity(struct tracefs_instance *instance,
>                                   const char *cpu_str);
> +char *tracefs_instance_get_affinity(struct tracefs_instance *instance);
> +char *tracefs_instance_get_affinity_raw(struct tracefs_instance *instance);
> +int tracefs_instance_get_affinity_set(struct tracefs_instance *instance,
> +                                     cpu_set_t *set, size_t set_size);
>  char **tracefs_instances(const char *regex);
>
>  bool tracefs_instance_exists(const char *name);
> diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c
> index fab615eb49ca..2d825b0e3bd0 100644
> --- a/src/tracefs-instance.c
> +++ b/src/tracefs-instance.c
> @@ -10,6 +10,7 @@
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <unistd.h>
> +#include <ctype.h>
>  #include <errno.h>
>  #include <sys/stat.h>
>  #include <fcntl.h>
> @@ -974,3 +975,194 @@ int tracefs_instance_set_affinity(struct tracefs_instance *instance,
>         CPU_FREE(set);
>         return ret;
>  }
> +
> +/**
> + * tracefs_instance_get_affinity_raw - read the affinity instance file
> + * @instance: The instance to get affinity of (NULL for top level)
> + *
> + * Reads the affinity file for @instance (or the top level if @instance
> + * is NULL) and returns it. The returned string must be freed with free().
> + *
> + * Returns the affinity mask on success, and must be freed with free()
> + *   or NULL on error.
> + */
> +char *tracefs_instance_get_affinity_raw(struct tracefs_instance *instance)
> +{
> +       return tracefs_instance_file_read(instance, "tracing_cpumask", NULL);
> +}
> +
> +static inline int update_cpu_set(int cpus, int cpu_set, int cpu,
> +                                cpu_set_t *set, size_t set_size)
> +{
> +       int bit = 1 << cpu;
> +
> +       if (!(cpus & bit))
> +               return 0;
> +
> +       CPU_SET_S(cpu_set + cpu, set_size, set);
> +       return 1;
> +}
> +
> +/**
> + * tracefs_instance_get_affinity_set - Retrieve the cpuset of an instance affinity
> + * @instance: The instance to get affinity of (NULL for top level)
> + * @set: A CPU set to put the affinity into.
> + * @set_size: The size in bytes of @set (use CPU_ALLOC_SIZE() to get this value)
> + *
> + * Reads the affinity of a given instance and updates the CPU set by the
> + * instance.
> + *
> + * Returns the number of CPUS that are set, or -1 on error.
> + */
> +int tracefs_instance_get_affinity_set(struct tracefs_instance *instance,
> +                                     cpu_set_t *set, size_t set_size)
> +{
> +       char *affinity;
> +       int cpu_set;
> +       int cpus;
> +       int cnt = 0;
> +       int ch;
> +       int i;
> +
> +       if (!set || !set_size) {
> +               errno = -EINVAL;
> +               return -1;
> +       }
> +
> +       affinity = tracefs_instance_get_affinity_raw(instance);
> +       if (!affinity)
> +               return -1;
> +
> +       /*
> +        * The returned affinity should be a comma delimited
> +        * hex string. Work backwards setting the values.
> +        */
> +       cpu_set = 0;
> +       i = strlen(affinity);
> +       for (i--; i >= 0; i--) {
> +               ch = affinity[i];
> +               if (isalnum(ch)) {
> +                       ch = tolower(ch);
> +                       if (isdigit(ch))
> +                               cpus = ch - '0';
> +                       else
> +                               cpus = ch - 'a' + 10;
> +
> +                       cnt += update_cpu_set(cpus, cpu_set, 0, set, set_size);
> +                       cnt += update_cpu_set(cpus, cpu_set, 1, set, set_size);
> +                       cnt += update_cpu_set(cpus, cpu_set, 2, set, set_size);
> +                       cnt += update_cpu_set(cpus, cpu_set, 3, set, set_size);
> +                       /* Next nibble */
> +                       cpu_set += 4;

I think there should be a check if set_size is reached. I do not know
how CPU_SET_S is implemented and if it can handle cpu IDs bigger than
the set_size. That should never happen, but a check inside the loop is
useful just to be on the safe side.

> +               }
> +       }
> +
> +       free(affinity);
> +
> +       return cnt;
> +}
> +
> +static inline int update_cpu(int cpus, int cpu_set, int cpu, int s, char **set)
> +{
> +       char *list;
> +       int bit = 1 << cpu;
> +       int ret;
> +
> +       if (*set == (char *)-1)
> +               return s;
> +
> +       if (cpus & bit) {
> +               /* If the previous CPU is set just return s */
> +               if (s >= 0)
> +                       return s;
> +               /* Otherwise, return this cpu */
> +               return cpu_set + cpu;
> +       }
> +
> +       /* If the last CPU wasn't set, just return s */
> +       if (s < 0)
> +               return s;
> +
> +       /* Update the string */
> +       if (s == cpu_set + cpu - 1) {
> +               ret = asprintf(&list, "%s%s%d",
> +                              *set ? *set : "", *set ? "," : "", s);
> +       } else {
> +               ret = asprintf(&list, "%s%s%d-%d",
> +                              *set ? *set : "", *set ? "," : "",
> +                              s, cpu_set + cpu - 1);
> +       }
> +       free(*set);
> +       /* Force *set to be a failure */
> +       if (ret < 0)
> +               *set = (char *)-1;
> +       else
> +               *set = list;
> +       return -1;
> +}
> +
> +/**
> + * tracefs_instance_get_affinity - Retrieve a string of CPUs for instance affinity
> + * @instance: The instance to get affinity of (NULL for top level)
> + *
> + * Reads the affinity of a given instance and returns a CPU count of the
> + * instance. For example, if it reads "eb" it will return:
> + *      "0-1,3,5-7"
> + *
> + * If no CPUs are set, an empty string is returned "\0", and it too needs
> + * to be freed.
> + *
> + * Returns an allocate string containing the CPU affinity in "human readable"

Maybe that should be "Returns an allocated string ..." ?

> + *  format which needs to be freed with free(), or NULL on error.
> + */
> +char *tracefs_instance_get_affinity(struct tracefs_instance *instance)
> +{
> +       char *affinity;
> +       char *set = NULL;
> +       int cpu_set;
> +       int cpus;
> +       int ch;
> +       int s = -1;
> +       int i;
> +
> +       affinity = tracefs_instance_get_affinity_raw(instance);
> +       if (!affinity)
> +               return NULL;
> +
> +       /*
> +        * The returned affinity should be a comma delimited
> +        * hex string. Work backwards setting the values.
> +        */
> +       cpu_set = 0;
> +       i = strlen(affinity);
> +       for (i--; i >= 0; i--) {
> +               ch = affinity[i];
> +               if (isalnum(ch)) {
> +                       ch = tolower(ch);
> +                       if (isdigit(ch))
> +                               cpus = ch - '0';
> +                       else
> +                               cpus = ch - 'a' + 10;
> +                       s = update_cpu(cpus, cpu_set, 0, s, &set);
> +                       s = update_cpu(cpus, cpu_set, 1, s, &set);
> +                       s = update_cpu(cpus, cpu_set, 2, s, &set);
> +                       s = update_cpu(cpus, cpu_set, 3, s, &set);
> +
> +                       if (set == (char *)-1) {
> +                               set = NULL;
> +                               goto out;
> +                       }
> +                       /* Next nibble */
> +                       cpu_set += 4;
> +               }
> +       }
> +       /* Clean up in case the last CPU is set */
> +       s = update_cpu(0, cpu_set, 0, s, &set);
> +
> +       if (!set)
> +               set = strdup("");
> + out:
> +       free(affinity);
> +
> +       return set;
> +}
> --
> 2.33.0
>


-- 
Tzvetomir (Ceco) Stoyanov
VMware Open Source Technology Center

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs
  2022-01-19 12:59   ` Tzvetomir Stoyanov
@ 2022-01-19 15:40     ` Steven Rostedt
  0 siblings, 0 replies; 5+ messages in thread
From: Steven Rostedt @ 2022-01-19 15:40 UTC (permalink / raw)
  To: Tzvetomir Stoyanov; +Cc: Linux Trace Devel

On Wed, 19 Jan 2022 14:59:07 +0200
Tzvetomir Stoyanov <tz.stoyanov@gmail.com> wrote:

> >  SYNOPSIS
> >  --------
> > @@ -16,11 +17,14 @@ int *tracefs_instance_set_affinity*(struct tracefs_instance pass:[*]_instance_,
> >  int *tracefs_instance_set_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
> >  int *tracefs_instance_set_affinity_raw*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_mask_);
> >
> > +char pass:[*]*tracefs_instance_get_affinity*(struct tracefs_instance pass:[*]_instance_);
> > +int *tracefs_instance_get_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
> > +char pass:[*]*tracefs_instance_get_affinity_raw*(struct tracefs_instance pass:[*]_instance_);  
> 
> These should be added also into Documentation/libtracefs.txt, under
> the relevant API section. All library APIs should be listed there.

Agreed, I'll make a patch to add them.

> 
> >  --
> >
> >  DESCRIPTION
> >  -----------
> > -These functions set the CPU affinity that limits what CPUs will have tracing enabled
> > +These functions set or retrieves the CPU affinity that limits what CPUs will have tracing enabled  
> 
> Maybe "These functions set or retrieve ..." ?

Oops. Sure. I'll add a patch to fix that.

> 
> >  for a given instance defined by the _instance_ parameter. If _instance_ is NULL, then
> >  the top level instance is affected.
> >
> > @@ -47,9 +51,32 @@ machine with more that 32 CPUs, to set CPUS 1-10 and CPU 40:
> >
> >  Where the above is a hex representation of bits 1-10 and bit 40 being set.
> >
> > +The *tracefs_instance_get_affinity()* will retrieve the affinity in a human readable
> > +form.
> > +
> > +For example: "1,4,6-8"
> > +
> > +The string returned must be freed with *free*(3).
> > +
> > +The *tracefs_instance_get_affinity_set()* will set all the bits in the passed in
> > +cpu set (from *CPU_SET*(3)). Note it will not clear any bits that are already set
> > +in the set but the CPUs are not. If only the bits for the CPUs that are enabled
> > +should be set, a CPU_ZERO_S() should be performed on the set before calling this
> > +function.
> > +
> > +The *tracefs_instance_get_affinity_raw()* will simply read the instance tracing_cpumask
> > +and return that string. The returned string must be freed with *free*(3).
> > +
> >  RETURN VALUE
> >  ------------
> > -All of these functions return 0 on success and -1 on error.
> > +All the set functions return 0 on success and -1 on error.
> > +
> > +The functinos *tracefs_instance_get_affinity()* and *tracefs_instance_get_affinity_raw()*  
> 
> a typo, "functions"

Good catch.

> 
> > +returns an allocated string that must be freed with *free*(3), or NULL on error.
> > +
> > +The function *tracefs_instance_get_affinity_set()* returns the number of CPUs that
> > +were found set, or -1 on error.
> > +
> >
...

> > +/**
> > + * tracefs_instance_get_affinity_set - Retrieve the cpuset of an instance affinity
> > + * @instance: The instance to get affinity of (NULL for top level)
> > + * @set: A CPU set to put the affinity into.
> > + * @set_size: The size in bytes of @set (use CPU_ALLOC_SIZE() to get this value)
> > + *
> > + * Reads the affinity of a given instance and updates the CPU set by the
> > + * instance.
> > + *
> > + * Returns the number of CPUS that are set, or -1 on error.
> > + */
> > +int tracefs_instance_get_affinity_set(struct tracefs_instance *instance,
> > +                                     cpu_set_t *set, size_t set_size)
> > +{
> > +       char *affinity;
> > +       int cpu_set;
> > +       int cpus;
> > +       int cnt = 0;
> > +       int ch;
> > +       int i;
> > +
> > +       if (!set || !set_size) {
> > +               errno = -EINVAL;
> > +               return -1;
> > +       }
> > +
> > +       affinity = tracefs_instance_get_affinity_raw(instance);
> > +       if (!affinity)
> > +               return -1;
> > +
> > +       /*
> > +        * The returned affinity should be a comma delimited
> > +        * hex string. Work backwards setting the values.
> > +        */
> > +       cpu_set = 0;
> > +       i = strlen(affinity);
> > +       for (i--; i >= 0; i--) {
> > +               ch = affinity[i];
> > +               if (isalnum(ch)) {
> > +                       ch = tolower(ch);
> > +                       if (isdigit(ch))
> > +                               cpus = ch - '0';
> > +                       else
> > +                               cpus = ch - 'a' + 10;
> > +
> > +                       cnt += update_cpu_set(cpus, cpu_set, 0, set, set_size);
> > +                       cnt += update_cpu_set(cpus, cpu_set, 1, set, set_size);
> > +                       cnt += update_cpu_set(cpus, cpu_set, 2, set, set_size);
> > +                       cnt += update_cpu_set(cpus, cpu_set, 3, set, set_size);
> > +                       /* Next nibble */
> > +                       cpu_set += 4;  
> 
> I think there should be a check if set_size is reached. I do not know
> how CPU_SET_S is implemented and if it can handle cpu IDs bigger than
> the set_size. That should never happen, but a check inside the loop is
> useful just to be on the safe side.

So I actually thought about this, and ideally, the _S is suppose to handle
this. I read in the man page:

  The macros whose names end with "_S" are the analogs of the similarly
  named macros without the suffix.  These macros perform the same tasks as
  their analogs, but operate on the dynamically allocated CPU set(s) whose
  size is setsize bytes.

I took it as being something like strncpy() and strncmp() where the 'n'
means not to go beyond it.

Doing tests shows that it looks to do exactly that. But perhaps I should at
least not add the count if it doesn't get set. That should be easy enough
to add.


> 
> > +               }
> > +       }
> > +
> > +       free(affinity);
> > +
> > +       return cnt;
> > +}
> > +
> > +static inline int update_cpu(int cpus, int cpu_set, int cpu, int s, char **set)
> > +{
> > +       char *list;
> > +       int bit = 1 << cpu;
> > +       int ret;
> > +
> > +       if (*set == (char *)-1)
> > +               return s;
> > +
> > +       if (cpus & bit) {
> > +               /* If the previous CPU is set just return s */
> > +               if (s >= 0)
> > +                       return s;
> > +               /* Otherwise, return this cpu */
> > +               return cpu_set + cpu;
> > +       }
> > +
> > +       /* If the last CPU wasn't set, just return s */
> > +       if (s < 0)
> > +               return s;
> > +
> > +       /* Update the string */
> > +       if (s == cpu_set + cpu - 1) {
> > +               ret = asprintf(&list, "%s%s%d",
> > +                              *set ? *set : "", *set ? "," : "", s);
> > +       } else {
> > +               ret = asprintf(&list, "%s%s%d-%d",
> > +                              *set ? *set : "", *set ? "," : "",
> > +                              s, cpu_set + cpu - 1);
> > +       }
> > +       free(*set);
> > +       /* Force *set to be a failure */
> > +       if (ret < 0)
> > +               *set = (char *)-1;
> > +       else
> > +               *set = list;
> > +       return -1;
> > +}
> > +
> > +/**
> > + * tracefs_instance_get_affinity - Retrieve a string of CPUs for instance affinity
> > + * @instance: The instance to get affinity of (NULL for top level)
> > + *
> > + * Reads the affinity of a given instance and returns a CPU count of the
> > + * instance. For example, if it reads "eb" it will return:
> > + *      "0-1,3,5-7"
> > + *
> > + * If no CPUs are set, an empty string is returned "\0", and it too needs
> > + * to be freed.
> > + *
> > + * Returns an allocate string containing the CPU affinity in "human readable"  
> 
> Maybe that should be "Returns an allocated string ..." ?

Yep. Good catch.


-- Steve

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-01-19 15:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-18  3:00 [PATCH 0/2] libtracefs: Add get affinity API Steven Rostedt
2022-01-18  3:00 ` [PATCH 1/2] libtracefs: Add tracefs_instance_get_affinity() APIs Steven Rostedt
2022-01-19 12:59   ` Tzvetomir Stoyanov
2022-01-19 15:40     ` Steven Rostedt
2022-01-18  3:00 ` [PATCH 2/2] libtracefs: Fix libtracefs-instance-affinity example Steven Rostedt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.