Test output format: ptest style (PASS, FAIL, SKIP) Description: Allocate memory from a node other than the current CPU is running on. Wait for numad to modify memory and CPU policy binding the process to run and allocate on the same node. Dependencies: libnuma Signed-off-by: Radu Patriu Upstream-Status: Pending Index: numa-test/test.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ numa-test/test.c 2014-02-18 17:22:49.952290472 +0200 @@ -0,0 +1,160 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define TIMEOUT (1000 * 60) /*60 seconds*/ +#define LOOP_TIME (1000 * 5) /*5 seconds*/ +#define MEM_POLICY_CHANGED 1 +#define NODE_POLICY_CHANGED 2 +#define TEST_DONE (MEM_POLICY_CHANGED | NODE_POLICY_CHANGED) + +#define TEST_PASS 0 +#define TEST_FAIL 1 +#define TEST_SKIP 2 + +#define MEM_SIZE 0.3 /* 30 % node memory */ + +unsigned int numa_bitmask_weight(const struct bitmask *bmp); + +void print_bitmask(struct bitmask *mask) +{ + /*assume 32 max nodes*/ + printf("0x%08lx", *(mask->maskp)); +} + +int test() +{ + int i, j, total_nodes, total_mem_nodes, total_cpus, prefered_node; + struct bitmask *allowed_mem_nodes, *allowed_nodes, *cpu_mask, *mem_bind, *bit_mask; + long long mem_size, page_size; + unsigned char *mem; + struct timeval start, end, res; + int local_node, local_cpu, other_node, test_complete; + + allowed_mem_nodes = numa_allocate_nodemask(); + allowed_nodes = numa_allocate_nodemask(); + mem_bind = numa_allocate_nodemask(); + cpu_mask = numa_allocate_cpumask(); + if (!(allowed_mem_nodes && allowed_nodes && mem_bind && cpu_mask)) { + printf("Error: numa_allocate failed\n"); + return TEST_FAIL; + } + + total_nodes = numa_max_node() + 1; + printf("total_nodes %d\n", total_nodes); + + total_mem_nodes = numa_num_configured_nodes(); + printf("total_mem_nodes %d\n", total_mem_nodes); + + total_cpus = numa_num_configured_cpus(); + printf("total_cpus %d\n", total_cpus); + + page_size = numa_pagesize(); + printf("page_size %llu\n", page_size); + + i = 0; + test_complete = 0; + gettimeofday(&start, NULL); + do { + printf("\n\n\nLoop %d\n", i); + + bit_mask = numa_get_mems_allowed(); + if (i && !numa_bitmask_equal(bit_mask, allowed_mem_nodes)) { + printf("\nInfo: memory policy modified\n\n"); + test_complete |= MEM_POLICY_CHANGED; + } + copy_bitmask_to_bitmask(bit_mask, allowed_mem_nodes); + printf("allowed_mem_nodes "); print_bitmask(allowed_mem_nodes); printf("\n"); + if ((0 == i) && (1 == numa_bitmask_weight(allowed_mem_nodes))) { + printf("Error: need at least two memory nodes\n"); + return TEST_SKIP; + } + + bit_mask = numa_get_run_node_mask(); + if (i && !numa_bitmask_equal(bit_mask, allowed_nodes)) { + printf("\nInfo: node/cpu policy modified\n\n"); + test_complete |= NODE_POLICY_CHANGED; + } + copy_bitmask_to_bitmask(bit_mask, allowed_nodes); + printf("allowed_nodes "); print_bitmask(allowed_nodes); printf("\n"); + + prefered_node = numa_preferred(); + printf("prefered_node %d\n", prefered_node); + + bit_mask = numa_get_membind(); + copy_bitmask_to_bitmask(bit_mask, mem_bind); + printf("mem_bind "); print_bitmask(mem_bind); printf("\n"); + + if (numa_sched_getaffinity(0, cpu_mask) < 0) { + printf("Error: numa_sched_getaffinity failed\n"); + return TEST_FAIL; + } + printf("sched_affinity "); print_bitmask(cpu_mask); printf("\n"); + + other_node = -1; + local_cpu = sched_getcpu(); + local_node = numa_node_of_cpu(local_cpu); + for (j = 0; j < total_mem_nodes; ++j) + if (numa_bitmask_isbitset(allowed_mem_nodes, j) && (j != local_node)) + other_node = j; + + printf("running on node %d, cpu %d\n", local_node, local_cpu); + printf("alloc memory from node %d\n", other_node); + + mem_size = numa_node_size64(other_node, NULL) * MEM_SIZE; + printf("test_mem_size %llu\n", mem_size); + + /* avoid mbind: Invalid argument */ + if (TEST_DONE == test_complete) + return TEST_PASS; + + mem = numa_alloc_onnode(mem_size, other_node); + if (!mem) { + printf("Error: numa_alloc_onnode failed for node %d\n", other_node); + return TEST_FAIL; + } + + gettimeofday(&end, NULL); + /* do some work */ + do { + struct timeval now; + memcpy(mem, mem + mem_size/2, mem_size/2); + gettimeofday(&now, NULL); + timersub(&now, &end, &res); + } while((res.tv_sec * 1000 + res.tv_usec / 1000) < LOOP_TIME); + + numa_free(mem, mem_size); + ++i; + gettimeofday(&end, NULL); + timersub(&end, &start, &res); + } while((res.tv_sec * 1000 + res.tv_usec / 1000) < TIMEOUT); + + return TEST_FAIL; +} + +int main() +{ + if (numa_available() < 0) { + printf("Error: numa not available\n"); + printf("SKIP: numad\n"); + return 0; + } + + switch(test()) { + case TEST_PASS: + printf("PASS: numad\n"); + break; + case TEST_SKIP: + printf("FAIL: numad\n"); + break; + default: + printf("FAIL: numad\n"); + } + + return 0; +}