|
@@ -5556,15 +5556,20 @@ static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */
|
|
|
|
|
|
#ifdef CONFIG_SCHED_DEBUG
|
|
|
|
|
|
-static __read_mostly int sched_domain_debug_enabled;
|
|
|
+static __read_mostly int sched_debug_enabled;
|
|
|
|
|
|
-static int __init sched_domain_debug_setup(char *str)
|
|
|
+static int __init sched_debug_setup(char *str)
|
|
|
{
|
|
|
- sched_domain_debug_enabled = 1;
|
|
|
+ sched_debug_enabled = 1;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
-early_param("sched_debug", sched_domain_debug_setup);
|
|
|
+early_param("sched_debug", sched_debug_setup);
|
|
|
+
|
|
|
+static inline bool sched_debug(void)
|
|
|
+{
|
|
|
+ return sched_debug_enabled;
|
|
|
+}
|
|
|
|
|
|
static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
|
|
|
struct cpumask *groupmask)
|
|
@@ -5657,7 +5662,7 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
|
|
|
{
|
|
|
int level = 0;
|
|
|
|
|
|
- if (!sched_domain_debug_enabled)
|
|
|
+ if (!sched_debug_enabled)
|
|
|
return;
|
|
|
|
|
|
if (!sd) {
|
|
@@ -5678,6 +5683,10 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
|
|
|
}
|
|
|
#else /* !CONFIG_SCHED_DEBUG */
|
|
|
# define sched_domain_debug(sd, cpu) do { } while (0)
|
|
|
+static inline bool sched_debug(void)
|
|
|
+{
|
|
|
+ return false;
|
|
|
+}
|
|
|
#endif /* CONFIG_SCHED_DEBUG */
|
|
|
|
|
|
static int sd_degenerate(struct sched_domain *sd)
|
|
@@ -6373,7 +6382,6 @@ static struct sched_domain_topology_level *sched_domain_topology = default_topol
|
|
|
#ifdef CONFIG_NUMA
|
|
|
|
|
|
static int sched_domains_numa_levels;
|
|
|
-static int sched_domains_numa_scale;
|
|
|
static int *sched_domains_numa_distance;
|
|
|
static struct cpumask ***sched_domains_numa_masks;
|
|
|
static int sched_domains_curr_level;
|
|
@@ -6438,6 +6446,42 @@ static const struct cpumask *sd_numa_mask(int cpu)
|
|
|
return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)];
|
|
|
}
|
|
|
|
|
|
+static void sched_numa_warn(const char *str)
|
|
|
+{
|
|
|
+ static int done = false;
|
|
|
+ int i,j;
|
|
|
+
|
|
|
+ if (done)
|
|
|
+ return;
|
|
|
+
|
|
|
+ done = true;
|
|
|
+
|
|
|
+ printk(KERN_WARNING "ERROR: %s\n\n", str);
|
|
|
+
|
|
|
+ for (i = 0; i < nr_node_ids; i++) {
|
|
|
+ printk(KERN_WARNING " ");
|
|
|
+ for (j = 0; j < nr_node_ids; j++)
|
|
|
+ printk(KERN_CONT "%02d ", node_distance(i,j));
|
|
|
+ printk(KERN_CONT "\n");
|
|
|
+ }
|
|
|
+ printk(KERN_WARNING "\n");
|
|
|
+}
|
|
|
+
|
|
|
+static bool find_numa_distance(int distance)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (distance == node_distance(0, 0))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ for (i = 0; i < sched_domains_numa_levels; i++) {
|
|
|
+ if (sched_domains_numa_distance[i] == distance)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
static void sched_init_numa(void)
|
|
|
{
|
|
|
int next_distance, curr_distance = node_distance(0, 0);
|
|
@@ -6445,7 +6489,6 @@ static void sched_init_numa(void)
|
|
|
int level = 0;
|
|
|
int i, j, k;
|
|
|
|
|
|
- sched_domains_numa_scale = curr_distance;
|
|
|
sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL);
|
|
|
if (!sched_domains_numa_distance)
|
|
|
return;
|
|
@@ -6456,23 +6499,41 @@ static void sched_init_numa(void)
|
|
|
*
|
|
|
* Assumes node_distance(0,j) includes all distances in
|
|
|
* node_distance(i,j) in order to avoid cubic time.
|
|
|
- *
|
|
|
- * XXX: could be optimized to O(n log n) by using sort()
|
|
|
*/
|
|
|
next_distance = curr_distance;
|
|
|
for (i = 0; i < nr_node_ids; i++) {
|
|
|
for (j = 0; j < nr_node_ids; j++) {
|
|
|
- int distance = node_distance(0, j);
|
|
|
- if (distance > curr_distance &&
|
|
|
- (distance < next_distance ||
|
|
|
- next_distance == curr_distance))
|
|
|
- next_distance = distance;
|
|
|
+ for (k = 0; k < nr_node_ids; k++) {
|
|
|
+ int distance = node_distance(i, k);
|
|
|
+
|
|
|
+ if (distance > curr_distance &&
|
|
|
+ (distance < next_distance ||
|
|
|
+ next_distance == curr_distance))
|
|
|
+ next_distance = distance;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * While not a strong assumption it would be nice to know
|
|
|
+ * about cases where if node A is connected to B, B is not
|
|
|
+ * equally connected to A.
|
|
|
+ */
|
|
|
+ if (sched_debug() && node_distance(k, i) != distance)
|
|
|
+ sched_numa_warn("Node-distance not symmetric");
|
|
|
+
|
|
|
+ if (sched_debug() && i && !find_numa_distance(distance))
|
|
|
+ sched_numa_warn("Node-0 not representative");
|
|
|
+ }
|
|
|
+ if (next_distance != curr_distance) {
|
|
|
+ sched_domains_numa_distance[level++] = next_distance;
|
|
|
+ sched_domains_numa_levels = level;
|
|
|
+ curr_distance = next_distance;
|
|
|
+ } else break;
|
|
|
}
|
|
|
- if (next_distance != curr_distance) {
|
|
|
- sched_domains_numa_distance[level++] = next_distance;
|
|
|
- sched_domains_numa_levels = level;
|
|
|
- curr_distance = next_distance;
|
|
|
- } else break;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In case of sched_debug() we verify the above assumption.
|
|
|
+ */
|
|
|
+ if (!sched_debug())
|
|
|
+ break;
|
|
|
}
|
|
|
/*
|
|
|
* 'level' contains the number of unique distances, excluding the
|