blob: 255ff51e2f714420801b8b5baa3e8001beb82a5b [file]
/* LinSched -- The Linux Scheduler Simulator
* Copyright (C) 2008 John M. Calandrino
* E-mail: jmc@cs.unc.edu
*
* This file contains Linux variables and functions that have been "defined
* away" or exist here in a modified form to avoid including an entire Linux
* source file that might otherwise lead to a "cascade" of dependency issues.
* It also includes certain LinSched variables to which some Linux functions
* and definitions now map.
*
* 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 <linux/gfp.h>
#include <linux/hrtimer.h>
#include "linsched.h"
int nr_node_ids;
int nr_cpu_ids;
int cpu_to_node_map[NR_CPUS];
cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
static int cpu_to_coregroup_map[NR_CPUS];
static cpumask_var_t cpu_coregroup_masks[NR_CPUS];
static int cpu_to_core_map[NR_CPUS];
cpumask_var_t cpu_core_masks[NR_CPUS];
static int node_distances[MAX_NUMNODES][MAX_NUMNODES];
int smp_num_siblings = 1;
static struct hrtimer trigger_timer[NR_CPUS];
void linsched_init_cpus(struct linsched_topology *topo)
{
int i;
for (i = 0; i < NR_CPUS; i++) {
zalloc_cpumask_var(&node_to_cpumask_map[i], GFP_KERNEL);
zalloc_cpumask_var(&cpu_coregroup_masks[i], GFP_KERNEL);
zalloc_cpumask_var(&cpu_core_masks[i], GFP_KERNEL);
}
if (topo) {
memcpy(cpu_to_node_map, topo->node_map, sizeof(topo->node_map));
memcpy(cpu_to_coregroup_map, topo->coregroup_map,
sizeof(topo->coregroup_map));
memcpy(cpu_to_core_map, topo->core_map, sizeof(topo->core_map));
memcpy(node_distances, topo->node_distances,
sizeof(topo->node_distances));
nr_cpu_ids = topo->nr_cpus;
} else {
for (i = 0; i < LINSCHED_DEFAULT_NR_CPUS; i++) {
cpu_to_core_map[i] = i;
cpu_to_coregroup_map[i] = i;
}
/* all cpus go in node 0 */
nr_cpu_ids = LINSCHED_DEFAULT_NR_CPUS;
}
for (i = 0; i < nr_cpu_ids; i++) {
cpumask_set_cpu(i, node_to_cpumask_map[cpu_to_node_map[i]]);
cpumask_set_cpu(i,
cpu_coregroup_masks[cpu_to_coregroup_map[i]]);
cpumask_set_cpu(i, cpu_core_masks[cpu_to_core_map[i]]);
set_cpu_present(i, true);
set_cpu_possible(i, true);
}
nr_node_ids = cpu_to_node_map[nr_cpu_ids - 1] + 1;
smp_num_siblings = cpumask_weight(cpu_core_masks[0]);
}
const struct cpumask *cpu_coregroup_mask(int cpu)
{
return cpu_coregroup_masks[cpu_to_coregroup_map[cpu]];
}
const struct cpumask *get_cpu_core_mask(int cpu)
{
return cpu_core_masks[cpu_to_core_map[cpu]];
}
static enum hrtimer_restart cpu_triggered(struct hrtimer *t)
{
scheduler_ipi();
return HRTIMER_NORESTART;
}
void linsched_trigger_cpu(int cpu)
{
int curr_cpu = smp_processor_id();
linsched_change_cpu(cpu);
if (!hrtimer_active(&trigger_timer[cpu])) {
hrtimer_init(&trigger_timer[cpu], CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
hrtimer_set_expires(&trigger_timer[cpu], ktime_set(0, 1));
trigger_timer[cpu].function = cpu_triggered;
hrtimer_start(&trigger_timer[cpu], ktime_set(0, 1),
HRTIMER_MODE_REL);
}
/*
* Call the scheduler ipi when queueing up tasks on the wakelist
*/
scheduler_ipi();
linsched_change_cpu(curr_cpu);
}
int __node_distance(int a, int b)
{
return node_distances[a][b];
}
void __init smp_init(void)
{
unsigned int cpu;
for_each_present_cpu(cpu) {
if (!cpu_online(cpu))
cpu_up(cpu);
}
}
void linsched_offline_cpu(int cpu)
{
cpu_down(cpu);
}
void linsched_online_cpu(int cpu)
{
cpu_up(cpu);
}