mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	sched, cpuset: customize sched domains, core
[rebased for sched-devel/latest]
 - Add a new cpuset file, having levels:
     sched_relax_domain_level
 - Modify partition_sched_domains() and build_sched_domains()
   to take attributes parameter passed from cpuset.
 - Fill newidle_idx for node domains which currently unused but
   might be required if sched_relax_domain_level become higher.
 - We can change the default level by boot option 'relax_domain_level='.
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
			
			
This commit is contained in:
		
							parent
							
								
									4d5f35533f
								
							
						
					
					
						commit
						1d3504fcf5
					
				
					 7 changed files with 161 additions and 11 deletions
				
			
		|  | @ -93,7 +93,7 @@ void build_cpu_to_node_map(void); | ||||||
| 	.cache_nice_tries	= 2,			\ | 	.cache_nice_tries	= 2,			\ | ||||||
| 	.busy_idx		= 3,			\ | 	.busy_idx		= 3,			\ | ||||||
| 	.idle_idx		= 2,			\ | 	.idle_idx		= 2,			\ | ||||||
| 	.newidle_idx		= 0, /* unused */	\ | 	.newidle_idx		= 2,			\ | ||||||
| 	.wake_idx		= 1,			\ | 	.wake_idx		= 1,			\ | ||||||
| 	.forkexec_idx		= 1,			\ | 	.forkexec_idx		= 1,			\ | ||||||
| 	.flags			= SD_LOAD_BALANCE	\ | 	.flags			= SD_LOAD_BALANCE	\ | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
| 	.cache_nice_tries	= 2,			\ | 	.cache_nice_tries	= 2,			\ | ||||||
| 	.busy_idx		= 3,			\ | 	.busy_idx		= 3,			\ | ||||||
| 	.idle_idx		= 2,			\ | 	.idle_idx		= 2,			\ | ||||||
| 	.newidle_idx		= 0,			\ | 	.newidle_idx		= 2,			\ | ||||||
| 	.wake_idx		= 1,			\ | 	.wake_idx		= 1,			\ | ||||||
| 	.forkexec_idx		= 1,			\ | 	.forkexec_idx		= 1,			\ | ||||||
| 	.flags			= SD_LOAD_BALANCE	\ | 	.flags			= SD_LOAD_BALANCE	\ | ||||||
|  |  | ||||||
|  | @ -147,7 +147,7 @@ extern unsigned long node_remap_size[]; | ||||||
| 
 | 
 | ||||||
| # define SD_CACHE_NICE_TRIES	2 | # define SD_CACHE_NICE_TRIES	2 | ||||||
| # define SD_IDLE_IDX		2 | # define SD_IDLE_IDX		2 | ||||||
| # define SD_NEWIDLE_IDX		0 | # define SD_NEWIDLE_IDX		2 | ||||||
| # define SD_FORKEXEC_IDX	1 | # define SD_FORKEXEC_IDX	1 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -704,6 +704,7 @@ enum cpu_idle_type { | ||||||
| #define SD_POWERSAVINGS_BALANCE	256	/* Balance for power savings */ | #define SD_POWERSAVINGS_BALANCE	256	/* Balance for power savings */ | ||||||
| #define SD_SHARE_PKG_RESOURCES	512	/* Domain members share cpu pkg resources */ | #define SD_SHARE_PKG_RESOURCES	512	/* Domain members share cpu pkg resources */ | ||||||
| #define SD_SERIALIZE		1024	/* Only a single load balancing instance */ | #define SD_SERIALIZE		1024	/* Only a single load balancing instance */ | ||||||
|  | #define SD_WAKE_IDLE_FAR	2048	/* Gain latency sacrificing cache hit */ | ||||||
| 
 | 
 | ||||||
| #define BALANCE_FOR_MC_POWER	\ | #define BALANCE_FOR_MC_POWER	\ | ||||||
| 	(sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0) | 	(sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0) | ||||||
|  | @ -733,6 +734,24 @@ struct sched_group { | ||||||
| 	u32 reciprocal_cpu_power; | 	u32 reciprocal_cpu_power; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum sched_domain_level { | ||||||
|  | 	SD_LV_NONE = 0, | ||||||
|  | 	SD_LV_SIBLING, | ||||||
|  | 	SD_LV_MC, | ||||||
|  | 	SD_LV_CPU, | ||||||
|  | 	SD_LV_NODE, | ||||||
|  | 	SD_LV_ALLNODES, | ||||||
|  | 	SD_LV_MAX | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct sched_domain_attr { | ||||||
|  | 	int relax_domain_level; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define SD_ATTR_INIT	(struct sched_domain_attr) {	\ | ||||||
|  | 	.relax_domain_level = -1,			\ | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct sched_domain { | struct sched_domain { | ||||||
| 	/* These fields must be setup */ | 	/* These fields must be setup */ | ||||||
| 	struct sched_domain *parent;	/* top domain must be null terminated */ | 	struct sched_domain *parent;	/* top domain must be null terminated */ | ||||||
|  | @ -750,6 +769,7 @@ struct sched_domain { | ||||||
| 	unsigned int wake_idx; | 	unsigned int wake_idx; | ||||||
| 	unsigned int forkexec_idx; | 	unsigned int forkexec_idx; | ||||||
| 	int flags;			/* See SD_* */ | 	int flags;			/* See SD_* */ | ||||||
|  | 	enum sched_domain_level level; | ||||||
| 
 | 
 | ||||||
| 	/* Runtime fields. */ | 	/* Runtime fields. */ | ||||||
| 	unsigned long last_balance;	/* init to jiffies. units in jiffies */ | 	unsigned long last_balance;	/* init to jiffies. units in jiffies */ | ||||||
|  | @ -789,7 +809,8 @@ struct sched_domain { | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern void partition_sched_domains(int ndoms_new, cpumask_t *doms_new); | extern void partition_sched_domains(int ndoms_new, cpumask_t *doms_new, | ||||||
|  | 				    struct sched_domain_attr *dattr_new); | ||||||
| extern int arch_reinit_sched_domains(void); | extern int arch_reinit_sched_domains(void); | ||||||
| 
 | 
 | ||||||
| #endif	/* CONFIG_SMP */ | #endif	/* CONFIG_SMP */ | ||||||
|  |  | ||||||
|  | @ -98,6 +98,9 @@ struct cpuset { | ||||||
| 	/* partition number for rebuild_sched_domains() */ | 	/* partition number for rebuild_sched_domains() */ | ||||||
| 	int pn; | 	int pn; | ||||||
| 
 | 
 | ||||||
|  | 	/* for custom sched domain */ | ||||||
|  | 	int relax_domain_level; | ||||||
|  | 
 | ||||||
| 	/* used for walking a cpuset heirarchy */ | 	/* used for walking a cpuset heirarchy */ | ||||||
| 	struct list_head stack_list; | 	struct list_head stack_list; | ||||||
| }; | }; | ||||||
|  | @ -478,6 +481,16 @@ static int cpusets_overlap(struct cpuset *a, struct cpuset *b) | ||||||
| 	return cpus_intersects(a->cpus_allowed, b->cpus_allowed); | 	return cpus_intersects(a->cpus_allowed, b->cpus_allowed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  | update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c) | ||||||
|  | { | ||||||
|  | 	if (!dattr) | ||||||
|  | 		return; | ||||||
|  | 	if (dattr->relax_domain_level < c->relax_domain_level) | ||||||
|  | 		dattr->relax_domain_level = c->relax_domain_level; | ||||||
|  | 	return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * rebuild_sched_domains() |  * rebuild_sched_domains() | ||||||
|  * |  * | ||||||
|  | @ -553,12 +566,14 @@ static void rebuild_sched_domains(void) | ||||||
| 	int csn;		/* how many cpuset ptrs in csa so far */ | 	int csn;		/* how many cpuset ptrs in csa so far */ | ||||||
| 	int i, j, k;		/* indices for partition finding loops */ | 	int i, j, k;		/* indices for partition finding loops */ | ||||||
| 	cpumask_t *doms;	/* resulting partition; i.e. sched domains */ | 	cpumask_t *doms;	/* resulting partition; i.e. sched domains */ | ||||||
|  | 	struct sched_domain_attr *dattr;  /* attributes for custom domains */ | ||||||
| 	int ndoms;		/* number of sched domains in result */ | 	int ndoms;		/* number of sched domains in result */ | ||||||
| 	int nslot;		/* next empty doms[] cpumask_t slot */ | 	int nslot;		/* next empty doms[] cpumask_t slot */ | ||||||
| 
 | 
 | ||||||
| 	q = NULL; | 	q = NULL; | ||||||
| 	csa = NULL; | 	csa = NULL; | ||||||
| 	doms = NULL; | 	doms = NULL; | ||||||
|  | 	dattr = NULL; | ||||||
| 
 | 
 | ||||||
| 	/* Special case for the 99% of systems with one, full, sched domain */ | 	/* Special case for the 99% of systems with one, full, sched domain */ | ||||||
| 	if (is_sched_load_balance(&top_cpuset)) { | 	if (is_sched_load_balance(&top_cpuset)) { | ||||||
|  | @ -566,6 +581,11 @@ static void rebuild_sched_domains(void) | ||||||
| 		doms = kmalloc(sizeof(cpumask_t), GFP_KERNEL); | 		doms = kmalloc(sizeof(cpumask_t), GFP_KERNEL); | ||||||
| 		if (!doms) | 		if (!doms) | ||||||
| 			goto rebuild; | 			goto rebuild; | ||||||
|  | 		dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL); | ||||||
|  | 		if (dattr) { | ||||||
|  | 			*dattr = SD_ATTR_INIT; | ||||||
|  | 			update_domain_attr(dattr, &top_cpuset); | ||||||
|  | 		} | ||||||
| 		*doms = top_cpuset.cpus_allowed; | 		*doms = top_cpuset.cpus_allowed; | ||||||
| 		goto rebuild; | 		goto rebuild; | ||||||
| 	} | 	} | ||||||
|  | @ -622,6 +642,7 @@ static void rebuild_sched_domains(void) | ||||||
| 	doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL); | 	doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL); | ||||||
| 	if (!doms) | 	if (!doms) | ||||||
| 		goto rebuild; | 		goto rebuild; | ||||||
|  | 	dattr = kmalloc(ndoms * sizeof(struct sched_domain_attr), GFP_KERNEL); | ||||||
| 
 | 
 | ||||||
| 	for (nslot = 0, i = 0; i < csn; i++) { | 	for (nslot = 0, i = 0; i < csn; i++) { | ||||||
| 		struct cpuset *a = csa[i]; | 		struct cpuset *a = csa[i]; | ||||||
|  | @ -644,12 +665,15 @@ static void rebuild_sched_domains(void) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			cpus_clear(*dp); | 			cpus_clear(*dp); | ||||||
|  | 			if (dattr) | ||||||
|  | 				*(dattr + nslot) = SD_ATTR_INIT; | ||||||
| 			for (j = i; j < csn; j++) { | 			for (j = i; j < csn; j++) { | ||||||
| 				struct cpuset *b = csa[j]; | 				struct cpuset *b = csa[j]; | ||||||
| 
 | 
 | ||||||
| 				if (apn == b->pn) { | 				if (apn == b->pn) { | ||||||
| 					cpus_or(*dp, *dp, b->cpus_allowed); | 					cpus_or(*dp, *dp, b->cpus_allowed); | ||||||
| 					b->pn = -1; | 					b->pn = -1; | ||||||
|  | 					update_domain_attr(dattr, b); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			nslot++; | 			nslot++; | ||||||
|  | @ -660,7 +684,7 @@ static void rebuild_sched_domains(void) | ||||||
| rebuild: | rebuild: | ||||||
| 	/* Have scheduler rebuild sched domains */ | 	/* Have scheduler rebuild sched domains */ | ||||||
| 	get_online_cpus(); | 	get_online_cpus(); | ||||||
| 	partition_sched_domains(ndoms, doms); | 	partition_sched_domains(ndoms, doms, dattr); | ||||||
| 	put_online_cpus(); | 	put_online_cpus(); | ||||||
| 
 | 
 | ||||||
| done: | done: | ||||||
|  | @ -668,6 +692,7 @@ static void rebuild_sched_domains(void) | ||||||
| 		kfifo_free(q); | 		kfifo_free(q); | ||||||
| 	kfree(csa); | 	kfree(csa); | ||||||
| 	/* Don't kfree(doms) -- partition_sched_domains() does that. */ | 	/* Don't kfree(doms) -- partition_sched_domains() does that. */ | ||||||
|  | 	/* Don't kfree(dattr) -- partition_sched_domains() does that. */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int started_after_time(struct task_struct *t1, | static inline int started_after_time(struct task_struct *t1, | ||||||
|  | @ -1011,6 +1036,21 @@ static int update_memory_pressure_enabled(struct cpuset *cs, char *buf) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int update_relax_domain_level(struct cpuset *cs, char *buf) | ||||||
|  | { | ||||||
|  | 	int val = simple_strtol(buf, NULL, 10); | ||||||
|  | 
 | ||||||
|  | 	if (val < 0) | ||||||
|  | 		val = -1; | ||||||
|  | 
 | ||||||
|  | 	if (val != cs->relax_domain_level) { | ||||||
|  | 		cs->relax_domain_level = val; | ||||||
|  | 		rebuild_sched_domains(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * update_flag - read a 0 or a 1 in a file and update associated flag |  * update_flag - read a 0 or a 1 in a file and update associated flag | ||||||
|  * bit:	the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, |  * bit:	the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, | ||||||
|  | @ -1202,6 +1242,7 @@ typedef enum { | ||||||
| 	FILE_CPU_EXCLUSIVE, | 	FILE_CPU_EXCLUSIVE, | ||||||
| 	FILE_MEM_EXCLUSIVE, | 	FILE_MEM_EXCLUSIVE, | ||||||
| 	FILE_SCHED_LOAD_BALANCE, | 	FILE_SCHED_LOAD_BALANCE, | ||||||
|  | 	FILE_SCHED_RELAX_DOMAIN_LEVEL, | ||||||
| 	FILE_MEMORY_PRESSURE_ENABLED, | 	FILE_MEMORY_PRESSURE_ENABLED, | ||||||
| 	FILE_MEMORY_PRESSURE, | 	FILE_MEMORY_PRESSURE, | ||||||
| 	FILE_SPREAD_PAGE, | 	FILE_SPREAD_PAGE, | ||||||
|  | @ -1256,6 +1297,9 @@ static ssize_t cpuset_common_file_write(struct cgroup *cont, | ||||||
| 	case FILE_SCHED_LOAD_BALANCE: | 	case FILE_SCHED_LOAD_BALANCE: | ||||||
| 		retval = update_flag(CS_SCHED_LOAD_BALANCE, cs, buffer); | 		retval = update_flag(CS_SCHED_LOAD_BALANCE, cs, buffer); | ||||||
| 		break; | 		break; | ||||||
|  | 	case FILE_SCHED_RELAX_DOMAIN_LEVEL: | ||||||
|  | 		retval = update_relax_domain_level(cs, buffer); | ||||||
|  | 		break; | ||||||
| 	case FILE_MEMORY_MIGRATE: | 	case FILE_MEMORY_MIGRATE: | ||||||
| 		retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer); | 		retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer); | ||||||
| 		break; | 		break; | ||||||
|  | @ -1354,6 +1398,9 @@ static ssize_t cpuset_common_file_read(struct cgroup *cont, | ||||||
| 	case FILE_SCHED_LOAD_BALANCE: | 	case FILE_SCHED_LOAD_BALANCE: | ||||||
| 		*s++ = is_sched_load_balance(cs) ? '1' : '0'; | 		*s++ = is_sched_load_balance(cs) ? '1' : '0'; | ||||||
| 		break; | 		break; | ||||||
|  | 	case FILE_SCHED_RELAX_DOMAIN_LEVEL: | ||||||
|  | 		s += sprintf(s, "%d", cs->relax_domain_level); | ||||||
|  | 		break; | ||||||
| 	case FILE_MEMORY_MIGRATE: | 	case FILE_MEMORY_MIGRATE: | ||||||
| 		*s++ = is_memory_migrate(cs) ? '1' : '0'; | 		*s++ = is_memory_migrate(cs) ? '1' : '0'; | ||||||
| 		break; | 		break; | ||||||
|  | @ -1424,6 +1471,13 @@ static struct cftype cft_sched_load_balance = { | ||||||
| 	.private = FILE_SCHED_LOAD_BALANCE, | 	.private = FILE_SCHED_LOAD_BALANCE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct cftype cft_sched_relax_domain_level = { | ||||||
|  | 	.name = "sched_relax_domain_level", | ||||||
|  | 	.read = cpuset_common_file_read, | ||||||
|  | 	.write = cpuset_common_file_write, | ||||||
|  | 	.private = FILE_SCHED_RELAX_DOMAIN_LEVEL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static struct cftype cft_memory_migrate = { | static struct cftype cft_memory_migrate = { | ||||||
| 	.name = "memory_migrate", | 	.name = "memory_migrate", | ||||||
| 	.read = cpuset_common_file_read, | 	.read = cpuset_common_file_read, | ||||||
|  | @ -1475,6 +1529,9 @@ static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont) | ||||||
| 		return err; | 		return err; | ||||||
| 	if ((err = cgroup_add_file(cont, ss, &cft_sched_load_balance)) < 0) | 	if ((err = cgroup_add_file(cont, ss, &cft_sched_load_balance)) < 0) | ||||||
| 		return err; | 		return err; | ||||||
|  | 	if ((err = cgroup_add_file(cont, ss, | ||||||
|  | 					&cft_sched_relax_domain_level)) < 0) | ||||||
|  | 		return err; | ||||||
| 	if ((err = cgroup_add_file(cont, ss, &cft_memory_pressure)) < 0) | 	if ((err = cgroup_add_file(cont, ss, &cft_memory_pressure)) < 0) | ||||||
| 		return err; | 		return err; | ||||||
| 	if ((err = cgroup_add_file(cont, ss, &cft_spread_page)) < 0) | 	if ((err = cgroup_add_file(cont, ss, &cft_spread_page)) < 0) | ||||||
|  | @ -1559,6 +1616,7 @@ static struct cgroup_subsys_state *cpuset_create( | ||||||
| 	nodes_clear(cs->mems_allowed); | 	nodes_clear(cs->mems_allowed); | ||||||
| 	cs->mems_generation = cpuset_mems_generation++; | 	cs->mems_generation = cpuset_mems_generation++; | ||||||
| 	fmeter_init(&cs->fmeter); | 	fmeter_init(&cs->fmeter); | ||||||
|  | 	cs->relax_domain_level = -1; | ||||||
| 
 | 
 | ||||||
| 	cs->parent = parent; | 	cs->parent = parent; | ||||||
| 	number_of_cpusets++; | 	number_of_cpusets++; | ||||||
|  | @ -1631,6 +1689,7 @@ int __init cpuset_init(void) | ||||||
| 	fmeter_init(&top_cpuset.fmeter); | 	fmeter_init(&top_cpuset.fmeter); | ||||||
| 	top_cpuset.mems_generation = cpuset_mems_generation++; | 	top_cpuset.mems_generation = cpuset_mems_generation++; | ||||||
| 	set_bit(CS_SCHED_LOAD_BALANCE, &top_cpuset.flags); | 	set_bit(CS_SCHED_LOAD_BALANCE, &top_cpuset.flags); | ||||||
|  | 	top_cpuset.relax_domain_level = -1; | ||||||
| 
 | 
 | ||||||
| 	err = register_filesystem(&cpuset_fs_type); | 	err = register_filesystem(&cpuset_fs_type); | ||||||
| 	if (err < 0) | 	if (err < 0) | ||||||
|  |  | ||||||
|  | @ -6771,6 +6771,7 @@ static noinline void sd_init_##type(struct sched_domain *sd)	\ | ||||||
| {								\ | {								\ | ||||||
| 	memset(sd, 0, sizeof(*sd));				\ | 	memset(sd, 0, sizeof(*sd));				\ | ||||||
| 	*sd = SD_##type##_INIT;					\ | 	*sd = SD_##type##_INIT;					\ | ||||||
|  | 	sd->level = SD_LV_##type;				\ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SD_INIT_FUNC(CPU) | SD_INIT_FUNC(CPU) | ||||||
|  | @ -6819,11 +6820,42 @@ struct allmasks { | ||||||
| #define	SCHED_CPUMASK_VAR(v, a) 	cpumask_t *v = (cpumask_t *) \ | #define	SCHED_CPUMASK_VAR(v, a) 	cpumask_t *v = (cpumask_t *) \ | ||||||
| 			((unsigned long)(a) + offsetof(struct allmasks, v)) | 			((unsigned long)(a) + offsetof(struct allmasks, v)) | ||||||
| 
 | 
 | ||||||
|  | static int default_relax_domain_level = -1; | ||||||
|  | 
 | ||||||
|  | static int __init setup_relax_domain_level(char *str) | ||||||
|  | { | ||||||
|  | 	default_relax_domain_level = simple_strtoul(str, NULL, 0); | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | __setup("relax_domain_level=", setup_relax_domain_level); | ||||||
|  | 
 | ||||||
|  | static void set_domain_attribute(struct sched_domain *sd, | ||||||
|  | 				 struct sched_domain_attr *attr) | ||||||
|  | { | ||||||
|  | 	int request; | ||||||
|  | 
 | ||||||
|  | 	if (!attr || attr->relax_domain_level < 0) { | ||||||
|  | 		if (default_relax_domain_level < 0) | ||||||
|  | 			return; | ||||||
|  | 		else | ||||||
|  | 			request = default_relax_domain_level; | ||||||
|  | 	} else | ||||||
|  | 		request = attr->relax_domain_level; | ||||||
|  | 	if (request < sd->level) { | ||||||
|  | 		/* turn off idle balance on this domain */ | ||||||
|  | 		sd->flags &= ~(SD_WAKE_IDLE|SD_BALANCE_NEWIDLE); | ||||||
|  | 	} else { | ||||||
|  | 		/* turn on idle balance on this domain */ | ||||||
|  | 		sd->flags |= (SD_WAKE_IDLE_FAR|SD_BALANCE_NEWIDLE); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Build sched domains for a given set of cpus and attach the sched domains |  * Build sched domains for a given set of cpus and attach the sched domains | ||||||
|  * to the individual cpus |  * to the individual cpus | ||||||
|  */ |  */ | ||||||
| static int build_sched_domains(const cpumask_t *cpu_map) | static int __build_sched_domains(const cpumask_t *cpu_map, | ||||||
|  | 				 struct sched_domain_attr *attr) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	struct root_domain *rd; | 	struct root_domain *rd; | ||||||
|  | @ -6887,6 +6919,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
| 				SD_NODES_PER_DOMAIN*cpus_weight(*nodemask)) { | 				SD_NODES_PER_DOMAIN*cpus_weight(*nodemask)) { | ||||||
| 			sd = &per_cpu(allnodes_domains, i); | 			sd = &per_cpu(allnodes_domains, i); | ||||||
| 			SD_INIT(sd, ALLNODES); | 			SD_INIT(sd, ALLNODES); | ||||||
|  | 			set_domain_attribute(sd, attr); | ||||||
| 			sd->span = *cpu_map; | 			sd->span = *cpu_map; | ||||||
| 			cpu_to_allnodes_group(i, cpu_map, &sd->groups, tmpmask); | 			cpu_to_allnodes_group(i, cpu_map, &sd->groups, tmpmask); | ||||||
| 			p = sd; | 			p = sd; | ||||||
|  | @ -6896,6 +6929,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
| 
 | 
 | ||||||
| 		sd = &per_cpu(node_domains, i); | 		sd = &per_cpu(node_domains, i); | ||||||
| 		SD_INIT(sd, NODE); | 		SD_INIT(sd, NODE); | ||||||
|  | 		set_domain_attribute(sd, attr); | ||||||
| 		sched_domain_node_span(cpu_to_node(i), &sd->span); | 		sched_domain_node_span(cpu_to_node(i), &sd->span); | ||||||
| 		sd->parent = p; | 		sd->parent = p; | ||||||
| 		if (p) | 		if (p) | ||||||
|  | @ -6906,6 +6940,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
| 		p = sd; | 		p = sd; | ||||||
| 		sd = &per_cpu(phys_domains, i); | 		sd = &per_cpu(phys_domains, i); | ||||||
| 		SD_INIT(sd, CPU); | 		SD_INIT(sd, CPU); | ||||||
|  | 		set_domain_attribute(sd, attr); | ||||||
| 		sd->span = *nodemask; | 		sd->span = *nodemask; | ||||||
| 		sd->parent = p; | 		sd->parent = p; | ||||||
| 		if (p) | 		if (p) | ||||||
|  | @ -6916,6 +6951,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
| 		p = sd; | 		p = sd; | ||||||
| 		sd = &per_cpu(core_domains, i); | 		sd = &per_cpu(core_domains, i); | ||||||
| 		SD_INIT(sd, MC); | 		SD_INIT(sd, MC); | ||||||
|  | 		set_domain_attribute(sd, attr); | ||||||
| 		sd->span = cpu_coregroup_map(i); | 		sd->span = cpu_coregroup_map(i); | ||||||
| 		cpus_and(sd->span, sd->span, *cpu_map); | 		cpus_and(sd->span, sd->span, *cpu_map); | ||||||
| 		sd->parent = p; | 		sd->parent = p; | ||||||
|  | @ -6927,6 +6963,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
| 		p = sd; | 		p = sd; | ||||||
| 		sd = &per_cpu(cpu_domains, i); | 		sd = &per_cpu(cpu_domains, i); | ||||||
| 		SD_INIT(sd, SIBLING); | 		SD_INIT(sd, SIBLING); | ||||||
|  | 		set_domain_attribute(sd, attr); | ||||||
| 		sd->span = per_cpu(cpu_sibling_map, i); | 		sd->span = per_cpu(cpu_sibling_map, i); | ||||||
| 		cpus_and(sd->span, sd->span, *cpu_map); | 		cpus_and(sd->span, sd->span, *cpu_map); | ||||||
| 		sd->parent = p; | 		sd->parent = p; | ||||||
|  | @ -7124,8 +7161,15 @@ static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int build_sched_domains(const cpumask_t *cpu_map) | ||||||
|  | { | ||||||
|  | 	return __build_sched_domains(cpu_map, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static cpumask_t *doms_cur;	/* current sched domains */ | static cpumask_t *doms_cur;	/* current sched domains */ | ||||||
| static int ndoms_cur;		/* number of sched domains in 'doms_cur' */ | static int ndoms_cur;		/* number of sched domains in 'doms_cur' */ | ||||||
|  | static struct sched_domain_attr *dattr_cur;	/* attribues of custom domains
 | ||||||
|  | 						   in 'doms_cur' */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Special case: If a kmalloc of a doms_cur partition (array of |  * Special case: If a kmalloc of a doms_cur partition (array of | ||||||
|  | @ -7153,6 +7197,7 @@ static int arch_init_sched_domains(const cpumask_t *cpu_map) | ||||||
| 	if (!doms_cur) | 	if (!doms_cur) | ||||||
| 		doms_cur = &fallback_doms; | 		doms_cur = &fallback_doms; | ||||||
| 	cpus_andnot(*doms_cur, *cpu_map, cpu_isolated_map); | 	cpus_andnot(*doms_cur, *cpu_map, cpu_isolated_map); | ||||||
|  | 	dattr_cur = NULL; | ||||||
| 	err = build_sched_domains(doms_cur); | 	err = build_sched_domains(doms_cur); | ||||||
| 	register_sched_domain_sysctl(); | 	register_sched_domain_sysctl(); | ||||||
| 
 | 
 | ||||||
|  | @ -7182,6 +7227,22 @@ static void detach_destroy_domains(const cpumask_t *cpu_map) | ||||||
| 	arch_destroy_sched_domains(cpu_map, &tmpmask); | 	arch_destroy_sched_domains(cpu_map, &tmpmask); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* handle null as "default" */ | ||||||
|  | static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur, | ||||||
|  | 			struct sched_domain_attr *new, int idx_new) | ||||||
|  | { | ||||||
|  | 	struct sched_domain_attr tmp; | ||||||
|  | 
 | ||||||
|  | 	/* fast path */ | ||||||
|  | 	if (!new && !cur) | ||||||
|  | 		return 1; | ||||||
|  | 
 | ||||||
|  | 	tmp = SD_ATTR_INIT; | ||||||
|  | 	return !memcmp(cur ? (cur + idx_cur) : &tmp, | ||||||
|  | 			new ? (new + idx_new) : &tmp, | ||||||
|  | 			sizeof(struct sched_domain_attr)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Partition sched domains as specified by the 'ndoms_new' |  * Partition sched domains as specified by the 'ndoms_new' | ||||||
|  * cpumasks in the array doms_new[] of cpumasks. This compares |  * cpumasks in the array doms_new[] of cpumasks. This compares | ||||||
|  | @ -7203,7 +7264,8 @@ static void detach_destroy_domains(const cpumask_t *cpu_map) | ||||||
|  * |  * | ||||||
|  * Call with hotplug lock held |  * Call with hotplug lock held | ||||||
|  */ |  */ | ||||||
| void partition_sched_domains(int ndoms_new, cpumask_t *doms_new) | void partition_sched_domains(int ndoms_new, cpumask_t *doms_new, | ||||||
|  | 			     struct sched_domain_attr *dattr_new) | ||||||
| { | { | ||||||
| 	int i, j; | 	int i, j; | ||||||
| 
 | 
 | ||||||
|  | @ -7216,12 +7278,14 @@ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new) | ||||||
| 		ndoms_new = 1; | 		ndoms_new = 1; | ||||||
| 		doms_new = &fallback_doms; | 		doms_new = &fallback_doms; | ||||||
| 		cpus_andnot(doms_new[0], cpu_online_map, cpu_isolated_map); | 		cpus_andnot(doms_new[0], cpu_online_map, cpu_isolated_map); | ||||||
|  | 		dattr_new = NULL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Destroy deleted domains */ | 	/* Destroy deleted domains */ | ||||||
| 	for (i = 0; i < ndoms_cur; i++) { | 	for (i = 0; i < ndoms_cur; i++) { | ||||||
| 		for (j = 0; j < ndoms_new; j++) { | 		for (j = 0; j < ndoms_new; j++) { | ||||||
| 			if (cpus_equal(doms_cur[i], doms_new[j])) | 			if (cpus_equal(doms_cur[i], doms_new[j]) | ||||||
|  | 			    && dattrs_equal(dattr_cur, i, dattr_new, j)) | ||||||
| 				goto match1; | 				goto match1; | ||||||
| 		} | 		} | ||||||
| 		/* no match - a current sched domain not in new doms_new[] */ | 		/* no match - a current sched domain not in new doms_new[] */ | ||||||
|  | @ -7233,11 +7297,13 @@ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new) | ||||||
| 	/* Build new domains */ | 	/* Build new domains */ | ||||||
| 	for (i = 0; i < ndoms_new; i++) { | 	for (i = 0; i < ndoms_new; i++) { | ||||||
| 		for (j = 0; j < ndoms_cur; j++) { | 		for (j = 0; j < ndoms_cur; j++) { | ||||||
| 			if (cpus_equal(doms_new[i], doms_cur[j])) | 			if (cpus_equal(doms_new[i], doms_cur[j]) | ||||||
|  | 			    && dattrs_equal(dattr_new, i, dattr_cur, j)) | ||||||
| 				goto match2; | 				goto match2; | ||||||
| 		} | 		} | ||||||
| 		/* no match - add a new doms_new */ | 		/* no match - add a new doms_new */ | ||||||
| 		build_sched_domains(doms_new + i); | 		__build_sched_domains(doms_new + i, | ||||||
|  | 					dattr_new ? dattr_new + i : NULL); | ||||||
| match2: | match2: | ||||||
| 		; | 		; | ||||||
| 	} | 	} | ||||||
|  | @ -7245,7 +7311,9 @@ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new) | ||||||
| 	/* Remember the new sched domains */ | 	/* Remember the new sched domains */ | ||||||
| 	if (doms_cur != &fallback_doms) | 	if (doms_cur != &fallback_doms) | ||||||
| 		kfree(doms_cur); | 		kfree(doms_cur); | ||||||
|  | 	kfree(dattr_cur);	/* kfree(NULL) is safe */ | ||||||
| 	doms_cur = doms_new; | 	doms_cur = doms_new; | ||||||
|  | 	dattr_cur = dattr_new; | ||||||
| 	ndoms_cur = ndoms_new; | 	ndoms_cur = ndoms_new; | ||||||
| 
 | 
 | ||||||
| 	register_sched_domain_sysctl(); | 	register_sched_domain_sysctl(); | ||||||
|  |  | ||||||
|  | @ -940,7 +940,9 @@ static int wake_idle(int cpu, struct task_struct *p) | ||||||
| 		return cpu; | 		return cpu; | ||||||
| 
 | 
 | ||||||
| 	for_each_domain(cpu, sd) { | 	for_each_domain(cpu, sd) { | ||||||
| 		if (sd->flags & SD_WAKE_IDLE) { | 		if ((sd->flags & SD_WAKE_IDLE) | ||||||
|  | 		    || ((sd->flags & SD_WAKE_IDLE_FAR) | ||||||
|  | 			&& !task_hot(p, task_rq(p)->clock, sd))) { | ||||||
| 			cpus_and(tmp, sd->span, p->cpus_allowed); | 			cpus_and(tmp, sd->span, p->cpus_allowed); | ||||||
| 			for_each_cpu_mask(i, tmp) { | 			for_each_cpu_mask(i, tmp) { | ||||||
| 				if (idle_cpu(i)) { | 				if (idle_cpu(i)) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Hidetoshi Seto
						Hidetoshi Seto