perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
# include "util.h"
2013-12-09 20:14:24 +04:00
# include <api/fs/fs.h>
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
# include "../perf.h"
# include "cpumap.h"
# include <assert.h>
# include <stdio.h>
2013-02-14 16:57:27 +04:00
# include <stdlib.h>
2015-10-25 17:51:25 +03:00
# include <linux/bitmap.h>
2015-06-23 01:36:04 +03:00
# include "asm/bug.h"
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
2016-01-26 21:51:46 +03:00
static int max_cpu_num ;
static int max_node_num ;
static int * cpunode_map ;
2011-01-03 22:49:48 +03:00
static struct cpu_map * cpu_map__default_new ( void )
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
{
2011-01-03 22:49:48 +03:00
struct cpu_map * cpus ;
int nr_cpus ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
nr_cpus = sysconf ( _SC_NPROCESSORS_ONLN ) ;
2011-01-03 22:49:48 +03:00
if ( nr_cpus < 0 )
return NULL ;
cpus = malloc ( sizeof ( * cpus ) + nr_cpus * sizeof ( int ) ) ;
if ( cpus ! = NULL ) {
int i ;
for ( i = 0 ; i < nr_cpus ; + + i )
cpus - > map [ i ] = i ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
2011-01-03 22:49:48 +03:00
cpus - > nr = nr_cpus ;
2015-06-23 01:36:04 +03:00
atomic_set ( & cpus - > refcnt , 1 ) ;
2011-01-03 22:49:48 +03:00
}
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
2011-01-03 22:49:48 +03:00
return cpus ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
}
2011-01-03 22:49:48 +03:00
static struct cpu_map * cpu_map__trim_new ( int nr_cpus , int * tmp_cpus )
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
{
2011-01-03 22:49:48 +03:00
size_t payload_size = nr_cpus * sizeof ( int ) ;
struct cpu_map * cpus = malloc ( sizeof ( * cpus ) + payload_size ) ;
if ( cpus ! = NULL ) {
cpus - > nr = nr_cpus ;
memcpy ( cpus - > map , tmp_cpus , payload_size ) ;
2015-06-23 01:36:04 +03:00
atomic_set ( & cpus - > refcnt , 1 ) ;
2011-01-03 22:49:48 +03:00
}
return cpus ;
}
2012-09-10 11:53:50 +04:00
struct cpu_map * cpu_map__read ( FILE * file )
2011-01-03 22:49:48 +03:00
{
struct cpu_map * cpus = NULL ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
int nr_cpus = 0 ;
2011-01-03 22:49:48 +03:00
int * tmp_cpus = NULL , * tmp ;
int max_entries = 0 ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
int n , cpu , prev ;
char sep ;
sep = 0 ;
prev = - 1 ;
for ( ; ; ) {
2012-09-10 11:53:50 +04:00
n = fscanf ( file , " %u%c " , & cpu , & sep ) ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
if ( n < = 0 )
break ;
if ( prev > = 0 ) {
2011-01-03 22:49:48 +03:00
int new_max = nr_cpus + cpu - prev - 1 ;
if ( new_max > = max_entries ) {
max_entries = new_max + MAX_NR_CPUS / 2 ;
tmp = realloc ( tmp_cpus , max_entries * sizeof ( int ) ) ;
if ( tmp = = NULL )
goto out_free_tmp ;
tmp_cpus = tmp ;
}
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
while ( + + prev < cpu )
2011-01-03 22:49:48 +03:00
tmp_cpus [ nr_cpus + + ] = prev ;
}
if ( nr_cpus = = max_entries ) {
max_entries + = MAX_NR_CPUS ;
tmp = realloc ( tmp_cpus , max_entries * sizeof ( int ) ) ;
if ( tmp = = NULL )
goto out_free_tmp ;
tmp_cpus = tmp ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
}
2011-01-03 22:49:48 +03:00
tmp_cpus [ nr_cpus + + ] = cpu ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
if ( n = = 2 & & sep = = ' - ' )
prev = cpu ;
else
prev = - 1 ;
if ( n = = 1 | | sep = = ' \n ' )
break ;
}
2011-01-03 22:49:48 +03:00
if ( nr_cpus > 0 )
cpus = cpu_map__trim_new ( nr_cpus , tmp_cpus ) ;
else
cpus = cpu_map__default_new ( ) ;
out_free_tmp :
free ( tmp_cpus ) ;
2012-09-10 11:53:50 +04:00
return cpus ;
}
static struct cpu_map * cpu_map__read_all_cpu_map ( void )
{
struct cpu_map * cpus = NULL ;
FILE * onlnf ;
onlnf = fopen ( " /sys/devices/system/cpu/online " , " r " ) ;
if ( ! onlnf )
return cpu_map__default_new ( ) ;
cpus = cpu_map__read ( onlnf ) ;
2011-01-03 22:49:48 +03:00
fclose ( onlnf ) ;
return cpus ;
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring
(perf stat, perf record and perf top) don't work properly unless
the online cpus are numbered 0, 1, ..., N-1. These tools ask
for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN)
and then try to create events for cpus 0, 1, ..., N-1.
This creates problems for systems where the online cpus are
numbered sparsely. For example, a POWER6 system in
single-threaded mode (i.e. only running 1 hardware thread per
core) will have only even-numbered cpus online.
This fixes the problem by reading the /sys/devices/system/cpu/online
file to find out which cpus are online. The code that does that is in
tools/perf/util/cpumap.[ch], and consists of a read_cpu_map()
function that sets up a cpumap[] array and returns the number of
online cpus. If /sys/devices/system/cpu/online can't be read or
can't be parsed successfully, it falls back to using sysconf to
ask how many cpus are online and sets up an identity map in cpumap[].
The perf record, perf stat and perf top code then calls
read_cpu_map() in the system-wide monitoring case (instead of
sysconf) and uses cpumap[] to get the cpu numbers to pass to
perf_event_open.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-10 12:36:09 +03:00
}
2010-05-28 14:00:01 +04:00
2011-01-03 22:49:48 +03:00
struct cpu_map * cpu_map__new ( const char * cpu_list )
2010-05-28 14:00:01 +04:00
{
2011-01-03 22:49:48 +03:00
struct cpu_map * cpus = NULL ;
2010-05-28 14:00:01 +04:00
unsigned long start_cpu , end_cpu = 0 ;
char * p = NULL ;
int i , nr_cpus = 0 ;
2011-01-03 22:49:48 +03:00
int * tmp_cpus = NULL , * tmp ;
int max_entries = 0 ;
2010-05-28 14:00:01 +04:00
if ( ! cpu_list )
2011-01-03 22:49:48 +03:00
return cpu_map__read_all_cpu_map ( ) ;
2010-05-28 14:00:01 +04:00
if ( ! isdigit ( * cpu_list ) )
2011-01-03 22:49:48 +03:00
goto out ;
2010-05-28 14:00:01 +04:00
while ( isdigit ( * cpu_list ) ) {
p = NULL ;
start_cpu = strtoul ( cpu_list , & p , 0 ) ;
if ( start_cpu > = INT_MAX
| | ( * p ! = ' \0 ' & & * p ! = ' , ' & & * p ! = ' - ' ) )
goto invalid ;
if ( * p = = ' - ' ) {
cpu_list = + + p ;
p = NULL ;
end_cpu = strtoul ( cpu_list , & p , 0 ) ;
if ( end_cpu > = INT_MAX | | ( * p ! = ' \0 ' & & * p ! = ' , ' ) )
goto invalid ;
if ( end_cpu < start_cpu )
goto invalid ;
} else {
end_cpu = start_cpu ;
}
for ( ; start_cpu < = end_cpu ; start_cpu + + ) {
/* check for duplicates */
for ( i = 0 ; i < nr_cpus ; i + + )
2011-01-03 22:49:48 +03:00
if ( tmp_cpus [ i ] = = ( int ) start_cpu )
2010-05-28 14:00:01 +04:00
goto invalid ;
2011-01-03 22:49:48 +03:00
if ( nr_cpus = = max_entries ) {
max_entries + = MAX_NR_CPUS ;
tmp = realloc ( tmp_cpus , max_entries * sizeof ( int ) ) ;
if ( tmp = = NULL )
goto invalid ;
tmp_cpus = tmp ;
}
tmp_cpus [ nr_cpus + + ] = ( int ) start_cpu ;
2010-05-28 14:00:01 +04:00
}
if ( * p )
+ + p ;
cpu_list = p ;
}
2011-01-03 22:49:48 +03:00
if ( nr_cpus > 0 )
cpus = cpu_map__trim_new ( nr_cpus , tmp_cpus ) ;
else
cpus = cpu_map__default_new ( ) ;
2010-05-28 14:00:01 +04:00
invalid :
2011-01-03 22:49:48 +03:00
free ( tmp_cpus ) ;
out :
return cpus ;
}
2015-10-25 17:51:25 +03:00
static struct cpu_map * cpu_map__from_entries ( struct cpu_map_entries * cpus )
{
struct cpu_map * map ;
map = cpu_map__empty_new ( cpus - > nr ) ;
if ( map ) {
unsigned i ;
2016-01-06 13:49:55 +03:00
for ( i = 0 ; i < cpus - > nr ; i + + ) {
/*
* Special treatment for - 1 , which is not real cpu number ,
* and we need to use ( int ) - 1 to initialize map [ i ] ,
* otherwise it would become 65535.
*/
if ( cpus - > cpu [ i ] = = ( u16 ) - 1 )
map - > map [ i ] = - 1 ;
else
map - > map [ i ] = ( int ) cpus - > cpu [ i ] ;
}
2015-10-25 17:51:25 +03:00
}
return map ;
}
static struct cpu_map * cpu_map__from_mask ( struct cpu_map_mask * mask )
{
struct cpu_map * map ;
int nr , nbits = mask - > nr * mask - > long_size * BITS_PER_BYTE ;
nr = bitmap_weight ( mask - > mask , nbits ) ;
map = cpu_map__empty_new ( nr ) ;
if ( map ) {
int cpu , i = 0 ;
for_each_set_bit ( cpu , mask - > mask , nbits )
map - > map [ i + + ] = cpu ;
}
return map ;
}
struct cpu_map * cpu_map__new_data ( struct cpu_map_data * data )
{
if ( data - > type = = PERF_CPU_MAP__CPUS )
return cpu_map__from_entries ( ( struct cpu_map_entries * ) data - > data ) ;
else
return cpu_map__from_mask ( ( struct cpu_map_mask * ) data - > data ) ;
}
2012-01-19 20:07:23 +04:00
size_t cpu_map__fprintf ( struct cpu_map * map , FILE * fp )
{
int i ;
size_t printed = fprintf ( fp , " %d cpu%s: " ,
map - > nr , map - > nr > 1 ? " s " : " " ) ;
for ( i = 0 ; i < map - > nr ; + + i )
printed + = fprintf ( fp , " %s%d " , i ? " , " : " " , map - > map [ i ] ) ;
return printed + fprintf ( fp , " \n " ) ;
}
2011-01-03 22:49:48 +03:00
struct cpu_map * cpu_map__dummy_new ( void )
{
struct cpu_map * cpus = malloc ( sizeof ( * cpus ) + sizeof ( int ) ) ;
if ( cpus ! = NULL ) {
cpus - > nr = 1 ;
cpus - > map [ 0 ] = - 1 ;
2015-06-23 01:36:04 +03:00
atomic_set ( & cpus - > refcnt , 1 ) ;
2011-01-03 22:49:48 +03:00
}
return cpus ;
2010-05-28 14:00:01 +04:00
}
2011-01-14 21:19:12 +03:00
2015-10-25 17:51:17 +03:00
struct cpu_map * cpu_map__empty_new ( int nr )
{
struct cpu_map * cpus = malloc ( sizeof ( * cpus ) + sizeof ( int ) * nr ) ;
if ( cpus ! = NULL ) {
int i ;
cpus - > nr = nr ;
for ( i = 0 ; i < nr ; i + + )
cpus - > map [ i ] = - 1 ;
atomic_set ( & cpus - > refcnt , 1 ) ;
}
return cpus ;
}
2015-06-23 01:36:04 +03:00
static void cpu_map__delete ( struct cpu_map * map )
2011-01-14 21:19:12 +03:00
{
2015-06-23 01:36:04 +03:00
if ( map ) {
WARN_ONCE ( atomic_read ( & map - > refcnt ) ! = 0 ,
" cpu_map refcnt unbalanced \n " ) ;
free ( map ) ;
}
}
struct cpu_map * cpu_map__get ( struct cpu_map * map )
{
if ( map )
atomic_inc ( & map - > refcnt ) ;
return map ;
}
void cpu_map__put ( struct cpu_map * map )
{
if ( map & & atomic_dec_and_test ( & map - > refcnt ) )
cpu_map__delete ( map ) ;
2011-01-14 21:19:12 +03:00
}
2013-02-06 18:46:01 +04:00
2015-09-11 16:49:45 +03:00
static int cpu__get_topology_int ( int cpu , const char * name , int * value )
2013-02-06 18:46:01 +04:00
{
char path [ PATH_MAX ] ;
2013-02-14 16:57:27 +04:00
snprintf ( path , PATH_MAX ,
2015-09-11 16:49:45 +03:00
" devices/system/cpu/cpu%d/topology/%s " , cpu , name ) ;
2013-02-06 18:46:01 +04:00
2015-09-11 16:49:45 +03:00
return sysfs__read_int ( path , value ) ;
}
2015-09-01 16:58:11 +03:00
2015-09-11 16:49:45 +03:00
int cpu_map__get_socket_id ( int cpu )
{
int value , ret = cpu__get_topology_int ( cpu , " physical_package_id " , & value ) ;
return ret ? : value ;
2015-09-01 16:58:11 +03:00
}
2015-10-16 13:41:15 +03:00
int cpu_map__get_socket ( struct cpu_map * map , int idx , void * data __maybe_unused )
2015-09-01 16:58:11 +03:00
{
int cpu ;
if ( idx > map - > nr )
return - 1 ;
cpu = map - > map [ idx ] ;
return cpu_map__get_socket_id ( cpu ) ;
2013-02-06 18:46:01 +04:00
}
2013-02-14 16:57:27 +04:00
static int cmp_ids ( const void * a , const void * b )
2013-02-06 18:46:01 +04:00
{
2013-02-14 16:57:27 +04:00
return * ( int * ) a - * ( int * ) b ;
}
2015-10-16 13:41:14 +03:00
int cpu_map__build_map ( struct cpu_map * cpus , struct cpu_map * * res ,
2015-10-16 13:41:15 +03:00
int ( * f ) ( struct cpu_map * map , int cpu , void * data ) ,
void * data )
2013-02-14 16:57:27 +04:00
{
struct cpu_map * c ;
2013-02-06 18:46:01 +04:00
int nr = cpus - > nr ;
int cpu , s1 , s2 ;
2013-02-14 16:57:27 +04:00
/* allocate as much as possible */
c = calloc ( 1 , sizeof ( * c ) + nr * sizeof ( int ) ) ;
if ( ! c )
2013-02-06 18:46:01 +04:00
return - 1 ;
for ( cpu = 0 ; cpu < nr ; cpu + + ) {
2015-10-16 13:41:15 +03:00
s1 = f ( cpus , cpu , data ) ;
2013-02-14 16:57:27 +04:00
for ( s2 = 0 ; s2 < c - > nr ; s2 + + ) {
if ( s1 = = c - > map [ s2 ] )
2013-02-06 18:46:01 +04:00
break ;
}
2013-02-14 16:57:27 +04:00
if ( s2 = = c - > nr ) {
c - > map [ c - > nr ] = s1 ;
c - > nr + + ;
2013-02-06 18:46:01 +04:00
}
}
2013-02-14 16:57:27 +04:00
/* ensure we process id in increasing order */
qsort ( c - > map , c - > nr , sizeof ( int ) , cmp_ids ) ;
2015-10-09 13:59:23 +03:00
atomic_set ( & c - > refcnt , 1 ) ;
2013-02-14 16:57:27 +04:00
* res = c ;
2013-02-06 18:46:01 +04:00
return 0 ;
}
2013-02-14 16:57:27 +04:00
2015-09-01 16:58:11 +03:00
int cpu_map__get_core_id ( int cpu )
2013-02-14 16:57:29 +04:00
{
2015-09-11 16:49:45 +03:00
int value , ret = cpu__get_topology_int ( cpu , " core_id " , & value ) ;
return ret ? : value ;
2015-09-01 16:58:11 +03:00
}
2015-10-16 13:41:15 +03:00
int cpu_map__get_core ( struct cpu_map * map , int idx , void * data )
2015-09-01 16:58:11 +03:00
{
int cpu , s ;
if ( idx > map - > nr )
2013-02-14 16:57:29 +04:00
return - 1 ;
2015-09-01 16:58:11 +03:00
cpu = map - > map [ idx ] ;
cpu = cpu_map__get_core_id ( cpu ) ;
2015-10-16 13:41:15 +03:00
s = cpu_map__get_socket ( map , idx , data ) ;
2013-02-14 16:57:29 +04:00
if ( s = = - 1 )
return - 1 ;
/*
* encode socket in upper 16 bits
* core_id is relative to socket , and
* we need a global id . So we combine
* socket + core id
*/
return ( s < < 16 ) | ( cpu & 0xffff ) ;
}
2013-02-14 16:57:27 +04:00
int cpu_map__build_socket_map ( struct cpu_map * cpus , struct cpu_map * * sockp )
{
2015-10-16 13:41:15 +03:00
return cpu_map__build_map ( cpus , sockp , cpu_map__get_socket , NULL ) ;
2013-02-14 16:57:27 +04:00
}
2013-02-14 16:57:29 +04:00
int cpu_map__build_core_map ( struct cpu_map * cpus , struct cpu_map * * corep )
{
2015-10-16 13:41:15 +03:00
return cpu_map__build_map ( cpus , corep , cpu_map__get_core , NULL ) ;
2013-02-14 16:57:29 +04:00
}
2014-04-07 22:55:21 +04:00
/* setup simple routines to easily access node numbers given a cpu number */
static int get_max_num ( char * path , int * max )
{
size_t num ;
char * buf ;
int err = 0 ;
if ( filename__read_str ( path , & buf , & num ) )
return - 1 ;
buf [ num ] = ' \0 ' ;
/* start on the right, to find highest node num */
while ( - - num ) {
if ( ( buf [ num ] = = ' , ' ) | | ( buf [ num ] = = ' - ' ) ) {
num + + ;
break ;
}
}
if ( sscanf ( & buf [ num ] , " %d " , max ) < 1 ) {
err = - 1 ;
goto out ;
}
/* convert from 0-based to 1-based */
( * max ) + + ;
out :
free ( buf ) ;
return err ;
}
/* Determine highest possible cpu in the system for sparse allocation */
static void set_max_cpu_num ( void )
{
const char * mnt ;
char path [ PATH_MAX ] ;
int ret = - 1 ;
/* set up default */
max_cpu_num = 4096 ;
mnt = sysfs__mountpoint ( ) ;
if ( ! mnt )
goto out ;
/* get the highest possible cpu number for a sparse allocation */
2014-04-07 22:55:22 +04:00
ret = snprintf ( path , PATH_MAX , " %s/devices/system/cpu/possible " , mnt ) ;
2014-04-07 22:55:21 +04:00
if ( ret = = PATH_MAX ) {
pr_err ( " sysfs path crossed PATH_MAX(%d) size \n " , PATH_MAX ) ;
goto out ;
}
ret = get_max_num ( path , & max_cpu_num ) ;
out :
if ( ret )
pr_err ( " Failed to read max cpus, using default of %d \n " , max_cpu_num ) ;
}
/* Determine highest possible node in the system for sparse allocation */
static void set_max_node_num ( void )
{
const char * mnt ;
char path [ PATH_MAX ] ;
int ret = - 1 ;
/* set up default */
max_node_num = 8 ;
mnt = sysfs__mountpoint ( ) ;
if ( ! mnt )
goto out ;
/* get the highest possible cpu number for a sparse allocation */
ret = snprintf ( path , PATH_MAX , " %s/devices/system/node/possible " , mnt ) ;
if ( ret = = PATH_MAX ) {
pr_err ( " sysfs path crossed PATH_MAX(%d) size \n " , PATH_MAX ) ;
goto out ;
}
ret = get_max_num ( path , & max_node_num ) ;
out :
if ( ret )
pr_err ( " Failed to read max nodes, using default of %d \n " , max_node_num ) ;
}
2016-01-26 21:51:46 +03:00
int cpu__max_node ( void )
{
if ( unlikely ( ! max_node_num ) )
set_max_node_num ( ) ;
return max_node_num ;
}
int cpu__max_cpu ( void )
{
if ( unlikely ( ! max_cpu_num ) )
set_max_cpu_num ( ) ;
return max_cpu_num ;
}
int cpu__get_node ( int cpu )
{
if ( unlikely ( cpunode_map = = NULL ) ) {
pr_debug ( " cpu_map not initialized \n " ) ;
return - 1 ;
}
return cpunode_map [ cpu ] ;
}
2014-04-07 22:55:21 +04:00
static int init_cpunode_map ( void )
{
int i ;
set_max_cpu_num ( ) ;
set_max_node_num ( ) ;
cpunode_map = calloc ( max_cpu_num , sizeof ( int ) ) ;
if ( ! cpunode_map ) {
pr_err ( " %s: calloc failed \n " , __func__ ) ;
return - 1 ;
}
for ( i = 0 ; i < max_cpu_num ; i + + )
cpunode_map [ i ] = - 1 ;
return 0 ;
}
int cpu__setup_cpunode_map ( void )
{
struct dirent * dent1 , * dent2 ;
DIR * dir1 , * dir2 ;
unsigned int cpu , mem ;
char buf [ PATH_MAX ] ;
char path [ PATH_MAX ] ;
const char * mnt ;
int n ;
/* initialize globals */
if ( init_cpunode_map ( ) )
return - 1 ;
mnt = sysfs__mountpoint ( ) ;
if ( ! mnt )
return 0 ;
n = snprintf ( path , PATH_MAX , " %s/devices/system/node " , mnt ) ;
if ( n = = PATH_MAX ) {
pr_err ( " sysfs path crossed PATH_MAX(%d) size \n " , PATH_MAX ) ;
return - 1 ;
}
dir1 = opendir ( path ) ;
if ( ! dir1 )
return 0 ;
/* walk tree and setup map */
while ( ( dent1 = readdir ( dir1 ) ) ! = NULL ) {
if ( dent1 - > d_type ! = DT_DIR | | sscanf ( dent1 - > d_name , " node%u " , & mem ) < 1 )
continue ;
n = snprintf ( buf , PATH_MAX , " %s/%s " , path , dent1 - > d_name ) ;
if ( n = = PATH_MAX ) {
pr_err ( " sysfs path crossed PATH_MAX(%d) size \n " , PATH_MAX ) ;
continue ;
}
dir2 = opendir ( buf ) ;
if ( ! dir2 )
continue ;
while ( ( dent2 = readdir ( dir2 ) ) ! = NULL ) {
if ( dent2 - > d_type ! = DT_LNK | | sscanf ( dent2 - > d_name , " cpu%u " , & cpu ) < 1 )
continue ;
cpunode_map [ cpu ] = mem ;
}
closedir ( dir2 ) ;
}
closedir ( dir1 ) ;
return 0 ;
}