blob: 08b83ea161fc1e7299e9ebd9089acd9fd4ec696f [file] [log] [blame]
/* Basic test suite for the Linux Scheduler Simulator
*
* A basic set of automated tests for linsched. The most important
* metric here is probably runtime, both run_delay and pcount are
* (even) more susceptible to small changes in timing that would not
* matter on a real machine.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see COPYING); if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "test_lib.h"
#include <strings.h>
#include <stdio.h>
#include <error.h>
/* one minute */
#define TEST_TICKS 60000
int *initialize_expectations(int *results, int result1, int result2,
int result3, int result4, int result5,
int result6, int result7, int result8) {
results[0] = result1;
results[1] = result2;
results[2] = result3;
results[3] = result4;
results[4] = result5;
results[5] = result6;
results[6] = result7;
results[7] = result8;
return results;
}
extern void exit(int status);
/* ensure that we get a task running on each cpu without overhead */
void test_trivial_bal(int argc, char **argv)
{
int count, mask;
struct linsched_topology topo;
int expected_results[MAX_RESULTS];
int type = parse_topology(argv[2]);
topo = linsched_topo_db[type];
count = topo.nr_cpus;
mask = (1 << count) - 1;
linsched_init(&topo);
create_tasks(count, mask, 0, 100);
linsched_run_sim(TEST_TICKS);
validate_results(initialize_expectations((int *)expected_results,
1, count, TEST_TICKS, 1, 0, 1, 1, 0));
}
/* make sure that we can run > nr_cpus sleep/run tasks which require
* <= nr_cpus actual runtime without too much overhead */
void test_basic_bal1(int argc, char **argv)
{
int count, mask;
struct linsched_topology topo;
int type = parse_topology(argv[2]);
int expected_results[MAX_RESULTS];
topo = linsched_topo_db[type];
switch (type) {
case UNIPROCESSOR:
count = topo.nr_cpus + 1;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 26080, 10, 20880, 10, 6520, 10);
break;
case DUAL_CPU:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 27274, 100, 19000, 1000, 4090, 10);
break;
case DUAL_CPU_MC:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 27274, 100, 19000, 1000, 4090, 10);
break;
case QUAD_CPU:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 30000, 1, 15000, 1000, 3000, 1);
break;
case QUAD_CPU_MC:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 30000, 1, 15000, 1000, 3000, 1);
break;
case QUAD_CPU_DUAL_SOCKET:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 36000, 1000, 6000, 700, 2600, 200);
/* Poor select_idle_sibling + vruntime interaction? */
expect_failure();
break;
case QUAD_CPU_QUAD_SOCKET:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 40000, 600, 3000, 3000, 2000, 150);
break;
case HEX_CPU_DUAL_SOCKET_SMT:
count = topo.nr_cpus + 6;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 39200, 1000, 1000, 300, 2520, 100);
break;
default:
error(-1, 0, "unknown topology\n");
}
linsched_init(&topo);
create_tasks(count, mask, 10, 20);
linsched_run_sim(TEST_TICKS);
validate_results((int *)expected_results);
}
/* Similar to the previous test, but require smaller overhead with
* longer busy/sleep intervals */
void test_basic_bal2(int argc, char **argv)
{
int count, mask;
struct linsched_topology topo;
int type = parse_topology(argv[2]);
int expected_results[MAX_RESULTS];
topo = linsched_topo_db[type];
switch (type) {
case UNIPROCESSOR:
count = topo.nr_cpus + 1;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 24200, 100, 23700, 100, 6050, 10);
break;
case DUAL_CPU:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 24200, 200, 23700, 300, 3510, 10);
break;
case DUAL_CPU_MC:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 24200, 200, 23700, 300, 3510, 10);
break;
case QUAD_CPU:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 24510, 200, 23300, 300, 2450, 10);
break;
case QUAD_CPU_MC:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 24510, 200, 23300, 300, 2450, 10);
break;
case QUAD_CPU_DUAL_SOCKET:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 38350, 1000, 2400, 500, 450, 100);
break;
case QUAD_CPU_QUAD_SOCKET:
count = topo.nr_cpus + 4;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 39000, 500, 1200, 200, 380, 80);
break;
case HEX_CPU_DUAL_SOCKET_SMT:
count = topo.nr_cpus + 6;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results,
1, count, 39000, 600, 1300, 500, 385, 65);
break;
default:
error(-1, 0, "unknown topology\n");
}
linsched_init(&topo);
create_tasks(count, mask, 100, 200);
linsched_run_sim(TEST_TICKS);
validate_results((int *)expected_results);
}
/* Similar to basic_bal1, but make sure we can also have high-usage
* cpu-locked tasks without making problems overall */
void test_bal1(int argc, char **argv)
{
int count, mask;
struct linsched_topology topo;
int type = parse_topology(argv[2]);
int expected_results1[MAX_RESULTS];
int expected_results2[MAX_RESULTS];
topo = linsched_topo_db[type];
switch (type) {
case QUAD_CPU:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results1,
1, 6, 28500, 600, 17000, 1000, 1800, 100);
initialize_expectations((int *)expected_results2,
7, 8, 32500, 600, 19000, 500, 2000, 100);
break;
case QUAD_CPU_MC:
/* XXX: Which property is making this looser than QUAD_CPU? */
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results1,
1, 6, 29000, 1000, 16500, 2000, 1800, 200);
initialize_expectations((int *)expected_results2,
7, 8, 32500, 800, 19000, 1400, 2050, 150);
break;
case QUAD_CPU_DUAL_SOCKET:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results1,
1, 10, 37300, 500, 4000, 500, 600, 50);
initialize_expectations((int *)expected_results2,
11, 12, 43000, 500, 6000, 500, 700, 50);
break;
case QUAD_CPU_QUAD_SOCKET:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results1,
1, 18, 39000, 500, 2500, 2000, 350, 70);
initialize_expectations((int *)expected_results2,
19, 20, 46750, 250, 1300, 200, 330, 100);
break;
case HEX_CPU_DUAL_SOCKET_SMT:
count = topo.nr_cpus + 2;
mask = (1 << topo.nr_cpus) - 1;
initialize_expectations((int *)expected_results1,
1, 26, 39200, 500, 1000, 500, 350, 50);
initialize_expectations((int *)expected_results2,
27, 28, 46000, 2500, 2200, 100, 430, 10);
break;
default:
error(-1, 0, "unknown topology\n");
}
linsched_init(&topo);
create_tasks(count, mask, 100, 200);
create_tasks(2, 0x3, 50, 200);
linsched_run_sim(TEST_TICKS);
validate_results((int *)expected_results1);
validate_results((int *)expected_results2);
}
void test_list(int argc, char **argv);
struct test {
char *name;
void (*fn)(int, char**);
};
struct test tests[] = {
#define TEST(x) { #x, test_##x }
TEST(trivial_bal),
TEST(basic_bal1),
TEST(basic_bal2),
TEST(bal1),
TEST(list),
};
void test_list(int argc, char **argv)
{
int i;
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
if (tests[i].fn != test_list)
puts(tests[i].name);
}
}
void usage(char **argv)
{
fprintf(stderr, "Usage: %s <test name> <topo>|list\n", argv[0]);
exit(1);
}
void linsched_test_main(int argc, char **argv)
{
int i;
if (argc < 2) {
usage(argv);
}
set_test_duration(TEST_TICKS);
set_test_name(argv[1]);
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
if (!strcmp(argv[1], tests[i].name)) {
tests[i].fn(argc, argv);
return;
}
}
usage(argv);
}