Skip to contentSkip to conversation

oslat: Fix --cpu-list won't allow to schedule on all possible cores

PATCH In review Peter Xu 3 participants 11 messages Feb 18, 2021 – Feb 19, 2021

lore
Share & tools
lore

Peter Xu

author
#0 lore raw

PATCH 1/1 oslat: Fix --cpu-list won't allow to schedule on all possible cores

parse_cpumask() is too strict for oslat, in that use_current_cpuset() will filter out all the cores that are not allowed for current process to run. This seems to be unnecessary at least for oslat. For example, the bash process that runs the oslat program may have a sched affinity of 0-2, however it's still legal to have it start a oslat thread running on the cores outside 0-2 as long as the follow up sched_setaffinity() will succeed.

numa_parse_cpustring_all() suites exactly for this case, which should already have considered sysconf(_SC_NPROCESSORS_ONLN) limit. Use that instead.

Since at it, also remove initialization of cpu_set variable otherwise it's leaked in previous parse_cpumask too: numa_parse_cpustring_all() will return a newly allocated buffer already. Quotting from manual:

numa_parse_nodestring() parses a character string list of nodes into a bit mask. The bit mask is allocated by numa_allocate_nodemask().

numa_parse_nodestring_all() is similar to numa_parse_nodestring, but can parse all possible nodes, not only current nodeset.

---
 src/oslat/oslat.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
src/oslat/oslat.c +2 -6
index b2c5373..465a694 100644
@@ -785,7 +785,6 @@ int main(int argc, char *argv[])
 	struct thread *threads;
 	int i, n_cores;
 	struct bitmask *cpu_set = NULL;
-	int max_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 
 #ifdef FRC_MISSING
 	printf("This architecture is not yet supported. "
@@ -797,10 +796,6 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	cpu_set = numa_allocate_cpumask();
-	if (!cpu_set)
-		fatal("oslat: Could not allocate cpumask\n");
-
 	g.app_name = argv[0];
 	g.rtprio = 0;
 	g.bucket_size = BUCKET_SIZE;
@@ -817,7 +812,8 @@ int main(int argc, char *argv[])
 	if (!g.cpu_list)
 		g.cpu_list = strdup("all");
 
-	if (parse_cpumask(g.cpu_list, max_cpus, &cpu_set) != 0)
+	cpu_set = numa_parse_cpustring_all(g.cpu_list);
+	if (!cpu_set)
 		fatal("oslat: parse_cpumask failed.\n");
 	n_cores = numa_bitmask_weight(cpu_set);
 
Signature · 1 line
2.26.2
#1 lore raw

Hi Peter,

Quoted 14 lines · Peter Xu

parse_cpumask() is too strict for oslat, in that use_current_cpuset() will filter out all the cores that are not allowed for current process to run. This seems to be unnecessary at least for oslat. For example, the bash process that runs the oslat program may have a sched affinity of 0-2, however it's still legal to have it start a oslat thread running on the cores outside 0-2 as long as the follow up sched_setaffinity() will succeed.

numa_parse_cpustring_all() suites exactly for this case, which should already have considered sysconf(_SC_NPROCESSORS_ONLN) limit. Use that instead.

Since at it, also remove initialization of cpu_set variable otherwise it's leaked in previous parse_cpumask too: numa_parse_cpustring_all() will return a newly allocated buffer already. Quotting from manual:

Quoted 5 lines

numa_parse_nodestring() parses a character string list of nodes into a bit mask. The bit mask is allocated by numa_allocate_nodemask().

numa_parse_nodestring_all() is similar to numa_parse_nodestring, but can parse all possible nodes, not only current nodeset.

My 2 cents: If parse_cpumask() is to strict fix parse_cpumask() so all tools do the same thing. Note parse_cpumask() contains a couple of bugs:

"rt-numa: Use mask size for iterator limit" "rt-numa: Remove max_cpus argument from parse_cpusmask"

Thanks,
Daniel

author
#2 lore raw
Quoted 1 line · Daniel Wagner

Hi Peter,

Hi, Daniel,

Quoted 22 lines · Peter Xu
Quoted 14 lines

parse_cpumask() is too strict for oslat, in that use_current_cpuset() will filter out all the cores that are not allowed for current process to run. This seems to be unnecessary at least for oslat. For example, the bash process that runs the oslat program may have a sched affinity of 0-2, however it's still legal to have it start a oslat thread running on the cores outside 0-2 as long as the follow up sched_setaffinity() will succeed.

numa_parse_cpustring_all() suites exactly for this case, which should already have considered sysconf(_SC_NPROCESSORS_ONLN) limit. Use that instead.

Since at it, also remove initialization of cpu_set variable otherwise it's leaked in previous parse_cpumask too: numa_parse_cpustring_all() will return a newly allocated buffer already. Quotting from manual:

Quoted 5 lines

numa_parse_nodestring() parses a character string list of nodes into a bit mask. The bit mask is allocated by numa_allocate_nodemask().

numa_parse_nodestring_all() is similar to numa_parse_nodestring, but can parse all possible nodes, not only current nodeset.

Quoted 6 lines

My 2 cents: If parse_cpumask() is to strict fix parse_cpumask() so all tools do the same thing. Note parse_cpumask() contains a couple of bugs:

"rt-numa: Use mask size for iterator limit" "rt-numa: Remove max_cpus argument from parse_cpusmask"

Yes I explicitly avoided touching parse_cpumask because I don't want to change behavior of other tools if I'm not confident with that. Would above two patches fix oslat too (which I didn't check)? If so, I'll be fine to have this patch dropped. Otherwise I tend to prefer fixing oslat first. We can further rework the common code, but if existing tools are fine, then I don't think it's a bugfix, so no need to rush. While I'll count this patch as a real bugfix, so I'd hope we could consider merging it earlier.

Thanks,

Signature · 1 line
Peter Xu
#3 lore raw
Quoted 7 lines · Peter Xu

Yes I explicitly avoided touching parse_cpumask because I don't want to change behavior of other tools if I'm not confident with that. Would above two patches fix oslat too (which I didn't check)? If so, I'll be fine to have this patch dropped. Otherwise I tend to prefer fixing oslat first. We can further rework the common code, but if existing tools are fine, then I don't think it's a bugfix, so no need to rush. While I'll count this patch as a real bugfix, so I'd hope we could consider merging it earlier.

As I said, I would really appreciated if all tools behave the same way. Having oslat be special is going to be pain in the long run. Just update parse_cpumask, it's not that difficult :)

author
#4 lore raw

Daniel,

Quoted 9 lines · Daniel Wagner
Quoted 7 lines · Peter Xu

Yes I explicitly avoided touching parse_cpumask because I don't want to change behavior of other tools if I'm not confident with that. Would above two patches fix oslat too (which I didn't check)? If so, I'll be fine to have this patch dropped. Otherwise I tend to prefer fixing oslat first. We can further rework the common code, but if existing tools are fine, then I don't think it's a bugfix, so no need to rush. While I'll count this patch as a real bugfix, so I'd hope we could consider merging it earlier.

Quoted 3 lines

As I said, I would really appreciated if all tools behave the same way. Having oslat be special is going to be pain in the long run. Just update parse_cpumask, it's not that difficult :)

Oslat is broken now after the numa rework. Frankly I'm surprised it's broken so quickly with just a few commits and actually with no new feature at all but pure cleanups. Again I still appreciate all your work on this but I don't really appreciate a lot for having it broken..

Now I tried to fix it but it seems you don't really like my fix.

Would you propose yours instead? I would be more than glad if your version is better then I'm happy to drop mine. Otherwise I'll still prefer to have this patch merged to unbreak it first.

Thanks,

Signature · 1 line
Peter Xu
#5 lore raw

Hi Peter,

Quoted 1 line · Peter Xu

Now I tried to fix it but it seems you don't really like my fix.

Sorry I didn't want to say I don't like your fix. I just said, I would appreciate if things would stay consistent. But then it seems there is not much interest in this.

Quoted 3 lines

Would you propose yours instead? I would be more than glad if your version is better then I'm happy to drop mine. Otherwise I'll still prefer to have this patch merged to unbreak it first.

I don't care too much. If this patch fixes your problem don't let me stop you.

Thanks,
Daniel

author
#6 lore raw
Quoted 9 lines · Daniel Wagner

Hi Peter,

Quoted 1 line · Peter Xu

Now I tried to fix it but it seems you don't really like my fix.

Sorry I didn't want to say I don't like your fix. I just said, I would appreciate if things would stay consistent. But then it seems there is not much interest in this.

Quoted 6 lines
Quoted 3 lines

Would you propose yours instead? I would be more than glad if your version is better then I'm happy to drop mine. Otherwise I'll still prefer to have this patch merged to unbreak it first.

I don't care too much. If this patch fixes your problem don't let me stop you.

It's not really my problem, I can compile my own binary. It's just that I want to have it working as usual for anyone using it. Also it'll be great to have it fixed sooner for our downstream so our QE won't be affect. I don't want the unbreak to be delayed by any further cleanup idea anymore - I am totally not against that, but again I think they can be done on top of a working tree.

Sorry if my wording was too harsh - I apologize for that.

Thanks,

Signature · 1 line
Peter Xu
#7 lore raw
In reply to Peter Xu
Quoted 21 lines · Peter Xu

Daniel,

Quoted 9 lines · Daniel Wagner
Quoted 7 lines · Peter Xu

Yes I explicitly avoided touching parse_cpumask because I don't want to change behavior of other tools if I'm not confident with that. Would above two patches fix oslat too (which I didn't check)? If so, I'll be fine to have this patch dropped. Otherwise I tend to prefer fixing oslat first. We can further rework the common code, but if existing tools are fine, then I don't think it's a bugfix, so no need to rush. While I'll count this patch as a real bugfix, so I'd hope we could consider merging it earlier.

Quoted 3 lines

As I said, I would really appreciated if all tools behave the same way. Having oslat be special is going to be pain in the long run. Just update parse_cpumask, it's not that difficult :)

Oslat is broken now after the numa rework. Frankly I'm surprised it's broken so quickly with just a few commits and actually with no new feature at all but pure cleanups. Again I still appreciate all your work on this but I don't really appreciate a lot for having it broken..

Quoted 12 lines

Now I tried to fix it but it seems you don't really like my fix.

Would you propose yours instead? I would be more than glad if your version is better then I'm happy to drop mine. Otherwise I'll still prefer to have this patch merged to unbreak it first.

Thanks,

Signature · 1 line
Peter Xu

Hey, I accepted your patch, we're just discussing how to make things work in the best way for the whole suite in the future.

Thanks for your patches!

John

#8 lore raw
In reply to Daniel Wagner
Quoted 17 lines · Daniel Wagner

Hi Peter,

Quoted 14 lines · Peter Xu

parse_cpumask() is too strict for oslat, in that use_current_cpuset() will filter out all the cores that are not allowed for current process to run. This seems to be unnecessary at least for oslat. For example, the bash process that runs the oslat program may have a sched affinity of 0-2, however it's still legal to have it start a oslat thread running on the cores outside 0-2 as long as the follow up sched_setaffinity() will succeed.

numa_parse_cpustring_all() suites exactly for this case, which should already have considered sysconf(_SC_NPROCESSORS_ONLN) limit. Use that instead.

Since at it, also remove initialization of cpu_set variable otherwise it's leaked in previous parse_cpumask too: numa_parse_cpustring_all() will return a newly allocated buffer already. Quotting from manual:

Quoted 7 lines
Quoted 5 lines

numa_parse_nodestring() parses a character string list of nodes into a bit mask. The bit mask is allocated by numa_allocate_nodemask().

numa_parse_nodestring_all() is similar to numa_parse_nodestring, but can parse all possible nodes, not only current nodeset.

My 2 cents: If parse_cpumask() is to strict fix parse_cpumask() so all

parse_cpumask() correctly examines the current environment and creates an intersection between the requested cpus and the ones it has permission to use. Using taskset with the same parameters as passed to the tools gets around that.

I have a few comments

1. Make the programs in the suite work the same way where that makes sense, but let's not make a fetish of it, sometimes there are good reasons not to impose the conformity.

2. If the user intentionally wants to go outside of the constraints, we could use a --force option to make sure the user is aware they are doing so.

In private chats with Peter though, he pointed out that if you're always using the --force option, then maybe it makes sense for that to be the default, and in addition, should calls to setaffinity() be the test?

3. We need to think a little bit about whether and how cyclictest and friends should run in containers.

Quoted 5 lines

tools do the same thing. Note parse_cpumask() contains a couple of bugs:

"rt-numa: Use mask size for iterator limit" "rt-numa: Remove max_cpus argument from parse_cpusmask"

Are those actually bug fixes or just a different way of doing things?

Quoted 4 lines

Thanks,
Daniel

#9 lore raw
Quoted 4 lines · John Kacur
Quoted 2 lines

"rt-numa: Use mask size for iterator limit" "rt-numa: Remove max_cpus argument from parse_cpusmask"

Are those actually bug fixes or just a different way of doing things?

max_cpus is just giving you the number of available CPUs. The loop assumes that all are in the range of [0..max_cpus] which is not necessarily true. You need to iterate over all possible CPUs. That is why passing in max_cpus is pretty useless.

#10 lore raw
In reply to Peter Xu
Quoted 67 lines · Peter Xu

parse_cpumask() is too strict for oslat, in that use_current_cpuset() will filter out all the cores that are not allowed for current process to run. This seems to be unnecessary at least for oslat. For example, the bash process that runs the oslat program may have a sched affinity of 0-2, however it's still legal to have it start a oslat thread running on the cores outside 0-2 as long as the follow up sched_setaffinity() will succeed.

numa_parse_cpustring_all() suites exactly for this case, which should already have considered sysconf(_SC_NPROCESSORS_ONLN) limit. Use that instead.

Since at it, also remove initialization of cpu_set variable otherwise it's leaked in previous parse_cpumask too: numa_parse_cpustring_all() will return a newly allocated buffer already. Quotting from manual:

numa_parse_nodestring() parses a character string list of nodes into a bit mask. The bit mask is allocated by numa_allocate_nodemask().

numa_parse_nodestring_all() is similar to numa_parse_nodestring, but can parse all possible nodes, not only current nodeset.

---
 src/oslat/oslat.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
src/oslat/oslat.c +2 -6
index b2c5373..465a694 100644
@@ -785,7 +785,6 @@ int main(int argc, char *argv[])
 	struct thread *threads;
 	int i, n_cores;
 	struct bitmask *cpu_set = NULL;
-	int max_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 
 #ifdef FRC_MISSING
 	printf("This architecture is not yet supported. "
@@ -797,10 +796,6 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	cpu_set = numa_allocate_cpumask();
-	if (!cpu_set)
-		fatal("oslat: Could not allocate cpumask\n");
-
 	g.app_name = argv[0];
 	g.rtprio = 0;
 	g.bucket_size = BUCKET_SIZE;
@@ -817,7 +812,8 @@ int main(int argc, char *argv[])
 	if (!g.cpu_list)
 		g.cpu_list = strdup("all");
 
-	if (parse_cpumask(g.cpu_list, max_cpus, &cpu_set) != 0)
+	cpu_set = numa_parse_cpustring_all(g.cpu_list);
+	if (!cpu_set)
 		fatal("oslat: parse_cpumask failed.\n");
 	n_cores = numa_bitmask_weight(cpu_set);
 
Signature · 1 line
2.26.2