diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2012-05-31 15:20:16 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-06 10:52:30 -0400 |
commit | d039ac60800fe8ed8522ec3b9ca796aaf748c18b (patch) | |
tree | b00845d9466d1abed5dbfda1e3c68713333460bc /kernel | |
parent | c3decf0dfbc95736b7c0ab68fa4e5854c4734da9 (diff) |
sched: Validate assumptions in sched_init_numa()
Add some code to validate assumptions we're making and output
warnings if they are not.
If this trigger we want to know about it.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Alex Shi <lkml.alex@gmail.com>
Link: http://lkml.kernel.org/n/tip-6uc3wk5s9udxtdl9cnku0vtt@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched/core.c | 99 |
1 files changed, 80 insertions, 19 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 725ee7c1c8cf..2bdd17616437 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -5556,15 +5556,20 @@ static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */ | |||
5556 | 5556 | ||
5557 | #ifdef CONFIG_SCHED_DEBUG | 5557 | #ifdef CONFIG_SCHED_DEBUG |
5558 | 5558 | ||
5559 | static __read_mostly int sched_domain_debug_enabled; | 5559 | static __read_mostly int sched_debug_enabled; |
5560 | 5560 | ||
5561 | static int __init sched_domain_debug_setup(char *str) | 5561 | static int __init sched_debug_setup(char *str) |
5562 | { | 5562 | { |
5563 | sched_domain_debug_enabled = 1; | 5563 | sched_debug_enabled = 1; |
5564 | 5564 | ||
5565 | return 0; | 5565 | return 0; |
5566 | } | 5566 | } |
5567 | early_param("sched_debug", sched_domain_debug_setup); | 5567 | early_param("sched_debug", sched_debug_setup); |
5568 | |||
5569 | static inline bool sched_debug(void) | ||
5570 | { | ||
5571 | return sched_debug_enabled; | ||
5572 | } | ||
5568 | 5573 | ||
5569 | static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, | 5574 | static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, |
5570 | struct cpumask *groupmask) | 5575 | struct cpumask *groupmask) |
@@ -5657,7 +5662,7 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu) | |||
5657 | { | 5662 | { |
5658 | int level = 0; | 5663 | int level = 0; |
5659 | 5664 | ||
5660 | if (!sched_domain_debug_enabled) | 5665 | if (!sched_debug_enabled) |
5661 | return; | 5666 | return; |
5662 | 5667 | ||
5663 | if (!sd) { | 5668 | if (!sd) { |
@@ -5678,6 +5683,10 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu) | |||
5678 | } | 5683 | } |
5679 | #else /* !CONFIG_SCHED_DEBUG */ | 5684 | #else /* !CONFIG_SCHED_DEBUG */ |
5680 | # define sched_domain_debug(sd, cpu) do { } while (0) | 5685 | # define sched_domain_debug(sd, cpu) do { } while (0) |
5686 | static inline bool sched_debug(void) | ||
5687 | { | ||
5688 | return false; | ||
5689 | } | ||
5681 | #endif /* CONFIG_SCHED_DEBUG */ | 5690 | #endif /* CONFIG_SCHED_DEBUG */ |
5682 | 5691 | ||
5683 | static int sd_degenerate(struct sched_domain *sd) | 5692 | static int sd_degenerate(struct sched_domain *sd) |
@@ -6373,7 +6382,6 @@ static struct sched_domain_topology_level *sched_domain_topology = default_topol | |||
6373 | #ifdef CONFIG_NUMA | 6382 | #ifdef CONFIG_NUMA |
6374 | 6383 | ||
6375 | static int sched_domains_numa_levels; | 6384 | static int sched_domains_numa_levels; |
6376 | static int sched_domains_numa_scale; | ||
6377 | static int *sched_domains_numa_distance; | 6385 | static int *sched_domains_numa_distance; |
6378 | static struct cpumask ***sched_domains_numa_masks; | 6386 | static struct cpumask ***sched_domains_numa_masks; |
6379 | static int sched_domains_curr_level; | 6387 | static int sched_domains_curr_level; |
@@ -6438,6 +6446,42 @@ static const struct cpumask *sd_numa_mask(int cpu) | |||
6438 | return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)]; | 6446 | return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)]; |
6439 | } | 6447 | } |
6440 | 6448 | ||
6449 | static void sched_numa_warn(const char *str) | ||
6450 | { | ||
6451 | static int done = false; | ||
6452 | int i,j; | ||
6453 | |||
6454 | if (done) | ||
6455 | return; | ||
6456 | |||
6457 | done = true; | ||
6458 | |||
6459 | printk(KERN_WARNING "ERROR: %s\n\n", str); | ||
6460 | |||
6461 | for (i = 0; i < nr_node_ids; i++) { | ||
6462 | printk(KERN_WARNING " "); | ||
6463 | for (j = 0; j < nr_node_ids; j++) | ||
6464 | printk(KERN_CONT "%02d ", node_distance(i,j)); | ||
6465 | printk(KERN_CONT "\n"); | ||
6466 | } | ||
6467 | printk(KERN_WARNING "\n"); | ||
6468 | } | ||
6469 | |||
6470 | static bool find_numa_distance(int distance) | ||
6471 | { | ||
6472 | int i; | ||
6473 | |||
6474 | if (distance == node_distance(0, 0)) | ||
6475 | return true; | ||
6476 | |||
6477 | for (i = 0; i < sched_domains_numa_levels; i++) { | ||
6478 | if (sched_domains_numa_distance[i] == distance) | ||
6479 | return true; | ||
6480 | } | ||
6481 | |||
6482 | return false; | ||
6483 | } | ||
6484 | |||
6441 | static void sched_init_numa(void) | 6485 | static void sched_init_numa(void) |
6442 | { | 6486 | { |
6443 | int next_distance, curr_distance = node_distance(0, 0); | 6487 | int next_distance, curr_distance = node_distance(0, 0); |
@@ -6445,7 +6489,6 @@ static void sched_init_numa(void) | |||
6445 | int level = 0; | 6489 | int level = 0; |
6446 | int i, j, k; | 6490 | int i, j, k; |
6447 | 6491 | ||
6448 | sched_domains_numa_scale = curr_distance; | ||
6449 | sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL); | 6492 | sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL); |
6450 | if (!sched_domains_numa_distance) | 6493 | if (!sched_domains_numa_distance) |
6451 | return; | 6494 | return; |
@@ -6456,23 +6499,41 @@ static void sched_init_numa(void) | |||
6456 | * | 6499 | * |
6457 | * Assumes node_distance(0,j) includes all distances in | 6500 | * Assumes node_distance(0,j) includes all distances in |
6458 | * node_distance(i,j) in order to avoid cubic time. | 6501 | * node_distance(i,j) in order to avoid cubic time. |
6459 | * | ||
6460 | * XXX: could be optimized to O(n log n) by using sort() | ||
6461 | */ | 6502 | */ |
6462 | next_distance = curr_distance; | 6503 | next_distance = curr_distance; |
6463 | for (i = 0; i < nr_node_ids; i++) { | 6504 | for (i = 0; i < nr_node_ids; i++) { |
6464 | for (j = 0; j < nr_node_ids; j++) { | 6505 | for (j = 0; j < nr_node_ids; j++) { |
6465 | int distance = node_distance(0, j); | 6506 | for (k = 0; k < nr_node_ids; k++) { |
6466 | if (distance > curr_distance && | 6507 | int distance = node_distance(i, k); |
6467 | (distance < next_distance || | 6508 | |
6468 | next_distance == curr_distance)) | 6509 | if (distance > curr_distance && |
6469 | next_distance = distance; | 6510 | (distance < next_distance || |
6511 | next_distance == curr_distance)) | ||
6512 | next_distance = distance; | ||
6513 | |||
6514 | /* | ||
6515 | * While not a strong assumption it would be nice to know | ||
6516 | * about cases where if node A is connected to B, B is not | ||
6517 | * equally connected to A. | ||
6518 | */ | ||
6519 | if (sched_debug() && node_distance(k, i) != distance) | ||
6520 | sched_numa_warn("Node-distance not symmetric"); | ||
6521 | |||
6522 | if (sched_debug() && i && !find_numa_distance(distance)) | ||
6523 | sched_numa_warn("Node-0 not representative"); | ||
6524 | } | ||
6525 | if (next_distance != curr_distance) { | ||
6526 | sched_domains_numa_distance[level++] = next_distance; | ||
6527 | sched_domains_numa_levels = level; | ||
6528 | curr_distance = next_distance; | ||
6529 | } else break; | ||
6470 | } | 6530 | } |
6471 | if (next_distance != curr_distance) { | 6531 | |
6472 | sched_domains_numa_distance[level++] = next_distance; | 6532 | /* |
6473 | sched_domains_numa_levels = level; | 6533 | * In case of sched_debug() we verify the above assumption. |
6474 | curr_distance = next_distance; | 6534 | */ |
6475 | } else break; | 6535 | if (!sched_debug()) |
6536 | break; | ||
6476 | } | 6537 | } |
6477 | /* | 6538 | /* |
6478 | * 'level' contains the number of unique distances, excluding the | 6539 | * 'level' contains the number of unique distances, excluding the |