Home | History | Annotate | Download | only in getcpu
      1 // SPDX-License-Identifier: GPL-2.0-or-later
      2 /*
      3  * Copyright  International Business Machines  Corp., 2007, 2008
      4  *
      5  * Test Description:
      6  *  The test process is affined to a CPU. It then calls getcpu and
      7  *  checks that the CPU and node (if supported) match the expected
      8  *  values.
      9  */
     10 
     11 #define _GNU_SOURCE
     12 #include <dirent.h>
     13 #include <errno.h>
     14 #include <sched.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <sys/types.h>
     18 #include "lapi/syscalls.h"
     19 #include "lapi/cpuset.h"
     20 #include "tst_test.h"
     21 
     22 static inline int get_cpu(unsigned *cpu_id,
     23 			  unsigned *node_id LTP_ATTRIBUTE_UNUSED,
     24 			  void *cache_struct LTP_ATTRIBUTE_UNUSED)
     25 {
     26 #if defined(__i386__)
     27 	return syscall(__NR_getcpu, cpu_id, node_id, cache_struct);
     28 #else
     29 	*cpu_id = sched_getcpu();
     30 #endif
     31 	return 0;
     32 }
     33 
     34 static unsigned int max_cpuid(size_t size, cpu_set_t * set)
     35 {
     36 	unsigned int index, max = 0;
     37 	for (index = 0; index < size * 8; index++)
     38 		if (CPU_ISSET_S(index, size, set))
     39 			max = index;
     40 	return max;
     41 }
     42 
     43 /*
     44  * This will set the affinity to max cpu on which process can run
     45  * and return that cpu id to the calling process
     46  */
     47 static unsigned int set_cpu_affinity(void)
     48 {
     49 	unsigned cpu_max;
     50 	cpu_set_t *set;
     51 	size_t size;
     52 	int nrcpus = 1024;
     53 
     54 realloc:
     55 	set = CPU_ALLOC(nrcpus);
     56 	if (!set)
     57 		tst_brk(TBROK | TERRNO, "CPU_ALLOC()");
     58 
     59 	size = CPU_ALLOC_SIZE(nrcpus);
     60 	CPU_ZERO_S(size, set);
     61 	if (sched_getaffinity(0, size, set) < 0) {
     62 		CPU_FREE(set);
     63 		if (errno == EINVAL && nrcpus < (1024 << 8)) {
     64 			nrcpus = nrcpus << 2;
     65 			goto realloc;
     66 		}
     67 		tst_brk(TBROK | TERRNO, "sched_getaffinity()");
     68 	}
     69 	cpu_max = max_cpuid(size, set);
     70 	CPU_ZERO_S(size, set);
     71 	CPU_SET_S(cpu_max, size, set);
     72 	if (sched_setaffinity(0, size, set) < 0) {
     73 		CPU_FREE(set);
     74 		tst_brk(TBROK | TERRNO, "sched_setaffinity()");
     75 	}
     76 	CPU_FREE(set);
     77 	return cpu_max;
     78 }
     79 
     80 #ifdef __i386__
     81 static unsigned int get_nodeid(unsigned int cpu_id)
     82 {
     83 	DIR *directory_parent, *directory_node;
     84 	struct dirent *de, *dn;
     85 	char directory_path[PATH_MAX];
     86 	unsigned int cpu;
     87 	int node_id = 0;
     88 
     89 	directory_parent = opendir("/sys/devices/system/node");
     90 	if (!directory_parent) {
     91 		tst_res(TINFO,
     92 			"/sys not mounted or not a numa system. "
     93 			"Assuming one node");
     94 		tst_res(TINFO, "Error opening: /sys/devices/system/node :%s",
     95 			strerror(errno));
     96 		/* Assume CPU belongs to the only node, node zero. */
     97 		return 0;
     98 	} else {
     99 		while ((de = readdir(directory_parent)) != NULL) {
    100 			if (strncmp(de->d_name, "node", 4))
    101 				continue;
    102 			sprintf(directory_path, "/sys/devices/system/node/%s",
    103 				de->d_name);
    104 			directory_node = opendir(directory_path);
    105 			while ((dn = readdir(directory_node)) != NULL) {
    106 				if (strncmp(dn->d_name, "cpu", 3))
    107 					continue;
    108 				cpu = strtoul(dn->d_name + 3, NULL, 0);
    109 				if (cpu == cpu_id) {
    110 					node_id =
    111 					    strtoul(de->d_name + 4, NULL, 0);
    112 					break;
    113 				}
    114 			}
    115 			closedir(directory_node);
    116 		}
    117 		closedir(directory_parent);
    118 	}
    119 	return node_id;
    120 }
    121 #endif
    122 
    123 static void run(void)
    124 {
    125 	unsigned int cpu_id, node_id = 0;
    126 	unsigned int cpu_set;
    127 #ifdef __i386__
    128 	unsigned int node_set;
    129 #endif
    130 
    131 	cpu_set = set_cpu_affinity();
    132 #ifdef __i386__
    133 	node_set = get_nodeid(cpu_set);
    134 #endif
    135 
    136 	TEST(get_cpu(&cpu_id, &node_id, NULL));
    137 	if (TST_RET == 0) {
    138 		if (cpu_id != cpu_set)
    139 			tst_res(TFAIL, "getcpu() returned wrong value"
    140 				" expected cpuid:%d, returned value cpuid: %d",
    141 				cpu_set, cpu_id);
    142 #ifdef __i386__
    143 		else if (node_id != node_set)
    144 			tst_res(TFAIL, "getcpu() returned wrong value"
    145 				" expected  node id:%d returned  node id:%d",
    146 				node_set, node_id);
    147 #endif
    148 		else
    149 			tst_res(TPASS, "getcpu() returned proper"
    150 				" cpuid:%d, node id:%d", cpu_id,
    151 				node_id);
    152 	} else {
    153 		tst_res(TFAIL, "getcpu() Failed, errno=%d:%s",
    154 			TST_ERR, strerror(TST_ERR));
    155 	}
    156 }
    157 
    158 static void setup(void)
    159 {
    160 	if (tst_kvercmp(2, 6, 20) < 0)
    161 		tst_brk(TCONF, "kernel >= 2.6.20 required");
    162 }
    163 
    164 static struct tst_test test = {
    165 	.test_all = run,
    166 	.setup = setup,
    167 };
    168