Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf bench numa: Fixup discontiguous/sparse numa nodes

Certain systems are designed to have sparse/discontiguous nodes. On
such systems, 'perf bench numa' hangs, shows wrong number of nodes and
shows values for non-existent nodes. Handle this by only taking nodes
that are exposed by kernel to userspace.

Signed-off-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
Reviewed-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Acked-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1edbcd353c009e109e93d78f2f46381930c340fe.1511368645.git.sathnaga@linux.vnet.ibm.com
Signed-off-by: Balamuruhan S <bala24@linux.vnet.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Satheesh Rajendran and committed by
Arnaldo Carvalho de Melo
321a7c35 bdaab8c4

+51 -5
+51 -5
tools/perf/bench/numa.c
··· 216 216 NULL 217 217 }; 218 218 219 + /* 220 + * To get number of numa nodes present. 221 + */ 222 + static int nr_numa_nodes(void) 223 + { 224 + int i, nr_nodes = 0; 225 + 226 + for (i = 0; i < g->p.nr_nodes; i++) { 227 + if (numa_bitmask_isbitset(numa_nodes_ptr, i)) 228 + nr_nodes++; 229 + } 230 + 231 + return nr_nodes; 232 + } 233 + 234 + /* 235 + * To check if given numa node is present. 236 + */ 237 + static int is_node_present(int node) 238 + { 239 + return numa_bitmask_isbitset(numa_nodes_ptr, node); 240 + } 241 + 242 + /* 243 + * To check given numa node has cpus. 244 + */ 245 + static bool node_has_cpus(int node) 246 + { 247 + struct bitmask *cpu = numa_allocate_cpumask(); 248 + unsigned int i; 249 + 250 + if (cpu && !numa_node_to_cpus(node, cpu)) { 251 + for (i = 0; i < cpu->size; i++) { 252 + if (numa_bitmask_isbitset(cpu, i)) 253 + return true; 254 + } 255 + } 256 + 257 + return false; /* lets fall back to nocpus safely */ 258 + } 259 + 219 260 static cpu_set_t bind_to_cpu(int target_cpu) 220 261 { 221 262 cpu_set_t orig_mask, mask; ··· 285 244 286 245 static cpu_set_t bind_to_node(int target_node) 287 246 { 288 - int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes; 247 + int cpus_per_node = g->p.nr_cpus / nr_numa_nodes(); 289 248 cpu_set_t orig_mask, mask; 290 249 int cpu; 291 250 int ret; 292 251 293 - BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus); 252 + BUG_ON(cpus_per_node * nr_numa_nodes() != g->p.nr_cpus); 294 253 BUG_ON(!cpus_per_node); 295 254 296 255 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask); ··· 690 649 int i; 691 650 692 651 for (i = 0; i < mul; i++) { 693 - if (t >= g->p.nr_tasks) { 652 + if (t >= g->p.nr_tasks || !node_has_cpus(bind_node)) { 694 653 printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node); 695 654 goto out; 696 655 } ··· 1005 964 sum = 0; 1006 965 1007 966 for (node = 0; node < g->p.nr_nodes; node++) { 967 + if (!is_node_present(node)) 968 + continue; 1008 969 nr = nodes[node]; 1009 970 nr_min = min(nr, nr_min); 1010 971 nr_max = max(nr, nr_max); ··· 1027 984 process_groups = 0; 1028 985 1029 986 for (node = 0; node < g->p.nr_nodes; node++) { 1030 - int processes = count_node_processes(node); 987 + int processes; 1031 988 989 + if (!is_node_present(node)) 990 + continue; 991 + processes = count_node_processes(node); 1032 992 nr = nodes[node]; 1033 993 tprintf(" %2d/%-2d", nr, processes); 1034 994 ··· 1337 1291 1338 1292 printf("\n ###\n"); 1339 1293 printf(" # %d %s will execute (on %d nodes, %d CPUs):\n", 1340 - g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus); 1294 + g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", nr_numa_nodes(), g->p.nr_cpus); 1341 1295 printf(" # %5dx %5ldMB global shared mem operations\n", 1342 1296 g->p.nr_loops, g->p.bytes_global/1024/1024); 1343 1297 printf(" # %5dx %5ldMB process shared mem operations\n",