diff mbox series

[1/2] libtracefs: Add tracefs_instance_get_affinity() APIs

Message ID 20220118030005.1603821-2-rostedt@goodmis.org (mailing list archive)
State Accepted
Commit 71689cababf54c6bd2341809e793caf8aa7dedd5
Headers show
Series libtracefs: Add get affinity API | expand

Commit Message

Steven Rostedt Jan. 18, 2022, 3 a.m. UTC
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(-)

Comments

Tzvetomir Stoyanov (VMware) Jan. 19, 2022, 12:59 p.m. UTC | #1
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
>
Steven Rostedt Jan. 19, 2022, 3:40 p.m. UTC | #2
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
diff mbox series

Patch

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;
+}