/* Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
. */
#include
#include
#include
#include
#include
static int
find_max_cpu (void)
{
/* We need to start at 64 because otherwise, CPU_ALLOC
over-allocates, and and we do not see all bits returned by the
kernel. */
for (int num_cpus = 64; num_cpus <= INT_MAX / 2; num_cpus *= 2)
{
cpu_set_t *set = CPU_ALLOC (num_cpus);
size_t size = CPU_ALLOC_SIZE (num_cpus);
printf ("allocating set for %d CPUs, size %zu\n", num_cpus, size);
if (set == NULL)
{
printf ("CPU_ALLOC(%d) failed\n", num_cpus);
return -1;
}
if (sched_getaffinity (0, size, set) == 0)
{
for (int i = num_cpus - 1; i >= 0; --i)
{
if (CPU_ISSET_S (i, size, set))
{
CPU_FREE (set);
return i;
}
}
printf ("Could not find active CPU in set of size %d\n", num_cpus);
CPU_FREE (set);
return -1;
}
if (errno != EINVAL)
{
printf ("sched_getaffinity for %d CPUs: %m\n", num_cpus);
return -1;
}
CPU_FREE (set);
}
puts ("Cannot find maximum CPU number");
return -1;
}
static int
find_flippable_cpu (const cpu_set_t *set, size_t size)
{
if (CPU_COUNT_S (size, set) < 2)
return -1;
int i;
for (i = 0; !CPU_ISSET_S (i, size, set); ++i)
;
return i;
}
static bool
test_size (size_t size)
{
cpu_set_t *set = CPU_ALLOC (size);
cpu_set_t *set2 = CPU_ALLOC (size);
cpu_set_t *active_cpu_set = CPU_ALLOC (size);
int active_cpu;
if (set == NULL || set2 == NULL || active_cpu_set == NULL)
{
printf ("size %zu: CPU_ALLOC failed\n", size);
return false;
}
size = CPU_ALLOC_SIZE (size);
if (sched_getaffinity (0, size, set) < 0)
{
printf ("size %zu: sched_getaffinity: %m\n", size);
return false;
}
active_cpu = find_flippable_cpu (set, size);
if (active_cpu < 0)
{
printf ("size %zu: not enough CPUs to test affinity\n", size);
return true;
}
if (sched_setaffinity (0, size, set) < 0)
{
printf ("size %zu: sched_setaffinity: %m\n", size);
return true;
}
CPU_ZERO_S (size, active_cpu_set);
CPU_SET_S (active_cpu, size, active_cpu_set);
if (sched_setaffinity (0, size, active_cpu_set) < 0)
{
printf ("size %zu: sched_setaffinity (2): %m\n", size);
return false;
}
if (sched_getaffinity (0, size, set2) < 0)
{
printf ("size %zu: sched_getaffinity (2): %m\n", size);
return false;
}
if (!CPU_EQUAL_S(size, active_cpu_set, set2))
{
printf ("size %zu: CPU sets do not match\n", size);
return false;
}
if (sched_setaffinity (0, size, set) < 0)
{
printf ("size %zu: sched_setaffinity (3): %m\n", size);
return false;
}
if (sched_getaffinity (0, size, set2) < 0)
{
printf ("size %zu: sched_getaffinity (3): %m\n", size);
return false;
}
if (!CPU_EQUAL_S(size, set, set2))
{
printf ("size %zu: CPU sets do not match (2)\n", size);
return false;
}
CPU_FREE (set);
CPU_FREE (set2);
CPU_FREE (active_cpu_set);
return true;
}
static bool
shrink_set (int max_cpu, bool *shrunk)
{
cpu_set_t *set = CPU_ALLOC (max_cpu + 1);
size_t size = CPU_ALLOC_SIZE (max_cpu + 1);
if (set == NULL)
{
printf ("CPU_ALLOC(%d) failed\n", max_cpu);
return false;
}
if (sched_getaffinity (0, size, set) < 0)
{
printf ("sched_getaffinity: %m\n");
CPU_FREE (set);
return false;
}
*shrunk = CPU_ISSET_S (0, size, set) && CPU_ISSET_S (0, size, set);
if (!*shrunk)
{
printf ("Cannot shrink CPU set size because CPUs 0 and 1 are missing\n");
CPU_FREE (set);
return true;
}
CPU_ZERO_S (size, set);
CPU_SET_S (0, size, set);
CPU_SET_S (1, size, set);
if (sched_setaffinity (0, size, set) < 0)
{
printf ("sched_setaffinity: %m\n");
CPU_FREE (set);
return false;
}
max_cpu = find_max_cpu ();
if (max_cpu != 1)
{
printf ("Set shrinking unsuccessful, maximum CPU still %d\n", max_cpu);
CPU_FREE (set);
return false;
}
CPU_FREE (set);
return true;
}
static int
do_test (void)
{
printf ("__NCPUBITS: %d\nsizeof (__cpu_mask): %zu\n",
(int)__NCPUBITS, sizeof (__cpu_mask));
cpu_set_t set;
if (sched_getaffinity (0, sizeof (set), &set) < 0)
{
if (errno == ENOSYS)
{
puts ("sched_getaffinity not supported");
return 0;
}
printf ("sched_getaffinity: %m\n");
return 1;
}
int max_cpu = find_max_cpu ();
printf ("Detected maximum CPU number: %d\n", max_cpu);
if (max_cpu < 0)
return 1;
if (max_cpu <= 1024 && !test_size (1024))
return 1;
if (max_cpu <= 2 && !test_size (2))
return 1;
if (max_cpu <= 1024 * 1024 && !test_size (1024 * 1024))
return 1;
bool shrunk;
if (!shrink_set (max_cpu, &shrunk))
return 1;
if (shrunk)
{
if (!(test_size (1024) && test_size (2) && test_size (1024 * 1024)))
return 1;
}
return 0;
}
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"