Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codify the pony(min)threads behavior #3303

Merged
merged 3 commits into from
Sep 27, 2019
Merged

Codify the pony(min)threads behavior #3303

merged 3 commits into from
Sep 27, 2019

Conversation

alexsnaps
Copy link
Contributor

@alexsnaps alexsnaps commented Sep 6, 2019

Draft in order to fix #3152

This won't work… I have many questions already but, wrt the issue at hand:

  • Should we introduce some value as a magic value for "not provided" (e.g. -1, tho it's currently a uint32_t;
  • Only allow for --ponynoscale when --ponyminthreads wasn't provided?
  • What about if --ponyminthreads == --ponythreads and yet --ponynoscale is provided; these two would effectively mean the same thing…

Trying to get the discussion going… I'll then wrap this up (and update the usage and other docs if these exists)

@@ -93,6 +96,7 @@ static int parse_opts(int argc, char** argv, options_t* opt)
{
case OPT_THREADS: opt->threads = atoi(s.arg_val); break;
case OPT_MINTHREADS: opt->min_threads = atoi(s.arg_val); break;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken this silently overflows… (e.g. if -1 negative values are provided)

@@ -148,6 +152,17 @@ PONY_API int pony_init(int argc, char** argv)
exit(0);
}

if (opt.noscale)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the description on the issue, I think this shouldn't take precedence… yet dunno how I can make sure it actually was explicitly set (with 0 being the default currently). Also what should it do it opt.min_threads == opt.threads, as that'd be the equivalent of opt.noscale


if (opt.min_threads > opt.threads)
{
printf("Can't have --ponyminthreads > --ponythreads (%d > %d)\n", opt.min_threads, opt.threads);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like other errors aren't on stderr, but should they be?
Also is -1 as a return fine?

@alexsnaps
Copy link
Contributor Author

Took a shot at prohibiting --ponyminthreads && --ponynoscale at the same time… Let me know what you think and if that all makes sense, let's update the doc.

@@ -1076,7 +1076,7 @@ pony_ctx_t* ponyint_sched_init(uint32_t threads, bool noyield, bool nopin,

// If minimum thread count is > thread count, cap it at thread count
if(min_threads > threads)
min_threads = threads;
min_threads = threads; // this becomes the equivalent of --ponynoscale
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this entirely now then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As, with the current implementation, this would be triggered in such a case:

$ ./helloworld --ponyminthreads=2048                                                
Hello, world.

Would it be better to bail out here instead? wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a proposal: an explicit check against physical cores:

$ ./helloworld --ponyminthreads=2048
Can't have --ponyminthreads > physical cores (2048 > 6)

I think this makes the most sense.

@SeanTAllen
Copy link
Member

Magic value for what but being provided?

By default minthreads default should be 0.

I think your other questions are answered in the ticket. See #3152 (comment)

@alexsnaps
Copy link
Contributor Author

alexsnaps commented Sep 7, 2019

Should have added a note, I think the latest stuff does that:

$ ./helloworld --ponyminthreads=0 --ponytherads=2
Hello, world.

From sync. We believe there should be a flag for "don't scale my threads".
And --ponyminthreads will error out if it is greater than --ponythreads.

$ ./helloworld --ponyminthreads=20 --ponytherads=2
Can't have --ponyminthreads > --ponythreads (20 > 0)

--ponynoscale is the current idea for turning off scaling.

$ ./helloworld --ponynoscale --ponythreads=20 
Hello, world.
$ ./helloworld --ponynoscale                 
Hello, world.

if --ponynoscale is used on application startup then it should be a startup error to use --ponyminthreads.

$ ./helloworld --ponyminthreads=20 --ponynoscale  
--ponyminthreads & --ponynoscale are mutually exclusive
 $./helloworld --ponyminthreads=20 --ponythreads=20 --ponynoscale
--ponyminthreads & --ponynoscale are mutually exclusive
$ echo $?
255

I just use a bool to see whether --ponyminthreads=0 was set by the user explicitly (as 0 is fine). I think that covers it just fine…

Open questions:

  • return code? -1 (-> 255) reused the default of the switch statement, but they mean different thing. Should there be or is there a return value (>0) for these kinda errors?
  • Should we deal with negatives properly? How? Validate the argument was >= 0?
$ ./helloworld --ponyminthreads=-1 --ponythreads=20
Can't have --ponyminthreads > --ponythreads (4294967295 > 20)

Someone may want to review my error messages too… Never feel I do a good job at these!
And… Sean, enjoy your vacation… don't look at this now! ;)

@alexsnaps
Copy link
Contributor Author

Alright, I think that's fairly complete. Added the check for when not specifying --ponythreads as so:

$ ./helloworld --ponyminthreads=2048
Can't have --ponyminthreads > physical cores (2048 > 6)

Let me know what you think!

{
if (minthreads_set)
{
printf("--ponyminthreads & --ponynoscale are mutually exclusive\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

@@ -150,6 +172,12 @@ PONY_API int pony_init(int argc, char** argv)

ponyint_cpu_init();

if (opt.threads == 0 && opt.min_threads > ponyint_cpu_count())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be added the CHANGELOG.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it!

@SeanTAllen
Copy link
Member

Alex this looks pretty good.

Small thing. You are checking to see if minthreads is greater than cores. We discussed and think that that should be if threads is greater than number of cores, it should be disallowed.

Once that is in, do you feel comfortable updating the performance cheat sheet section related to this?

https://www.ponylang.io/reference/pony-performance-cheatsheet/#ponythreads

Copy link
Contributor Author

@alexsnaps alexsnaps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small thing. You are checking to see if minthreads is greater than cores. We discussed and think that that should be if threads is greater than number of cores, it should be disallowed.

So I'd this on top of the current code that checks for --ponyminthreads being larger than the amount of cores, right? The reason I added this is when people specify min threads without specifying --ponythreads. I guess it indeed also makes sense in the latter case tho. So again, currently the code does this:

$ ./helloworld --ponyminthreads=2048
Can't have --ponyminthreads > physical cores (2048 > 6)

I can add this behavior, which I think is indeed just as sensible:

$ ./helloworld --ponythreads=2048
Can't have --ponythreads > physical cores (2048 > 6)

Which I think is what you are asking for… I could also set opt.threads to be the amount of cores in start.c. I'm trying to avoid that this code silently "scales things" down… e.g. if the --ponyminthreads > than the amount of cores and --ponythreads defaulting to the amount of cores being unspecified with the arguments provided while starting up the process...

I'll add this to this PR in any case, but want to make sure we're all in agreement here.

Two questions remain unaddressed:

  • Should we return -1, i.e 255 as the process' return code on failures related to the runtime config?
  • Should we add checks for these args not being less than 0 rather than just assign the (signed) int from atoi to an unsigned int field?

Thanks for the review already!

@@ -150,6 +172,12 @@ PONY_API int pony_init(int argc, char** argv)

ponyint_cpu_init();

if (opt.threads == 0 && opt.min_threads > ponyint_cpu_count())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it!

@SeanTAllen
Copy link
Member

I'm not sure of all the permutations of things to check for. Minthreads without setting threads is something I'd never do. But I guess you could do it (although in my mind it would be odd) so I can see how having that check makes sense.

-1 for return exit seems fine to me. Can always be changed later.

Are you asking if there should be checks to make sure someone doesn't do --ponyminthreads=-1 ?

@alexsnaps
Copy link
Contributor Author

I'm not sure of all the permutations of things to check for. Minthreads without setting threads is something I'd never do. But I guess you could do it (although in my mind it would be odd) so I can see how having that check makes sense.

I agree it's not really sensible to me neither, but would it in virtualized environments? Where I don't ever want less than 2 threads, but say for some reason I'm deploying on a single vCPU node? Dunno… nothing prohibits setting --ponyminthreads w/o --ponythreads or should it become a requirement to set both?

In anycase, I think 36d9123 does what you wanted (i.e. check for --ponythreads being <= cores available…

Are you asking if there should be checks to make sure someone doesn't do --ponyminthreads=-1 ?

Yeah, cause currently:

$ ./helloworld --ponythreads=-1
Can't have --ponythreads (the number of threads you'd be running with) > physical cores (4294967295 > 6)

Which might be surprising to some (tho to others, the issue is probably very obvious!)

@alexsnaps
Copy link
Contributor Author

btw, I realize the --ponyminthreads can be clarified at the doc level, i.e. --ponyminthreads=2048 is either the value provided or the --ponythreads, whatever is smaller and where the latter defaults to the number of cores… I can take a shot at trying to clarifying it this way, and get rid of the actual check

@SeanTAllen
Copy link
Member

I'm not worried about the negative value issue, but checking it isn't less than 0 and reporting on that would be a nice UI improvement. I think that would make sense as a commit unto itself.

@SeanTAllen
Copy link
Member

btw, I realize the --ponyminthreads can be clarified at the doc level, i.e. --ponyminthreads=2048 is either the value provided or the --ponythreads, whatever is smaller and where the latter defaults to the number of cores… I can take a shot at trying to clarifying it this way, and get rid of the actual check

I didn't follow that. Sorry, can you try saying in another way?

--ponyminthreads=2048 is either the value provided or the --ponythreads, whatever is smaller and where the latter defaults to the number of cores

sounds wrong to me. if ponyminthreads is greater than ponythreads, that should error out. which is not what i think you are saying in the quoted bit.

@alexsnaps
Copy link
Contributor Author

alexsnaps commented Sep 18, 2019

I didn't follow that. Sorry, can you try saying in another way?

I can avoid the explicit check, and let the code in scheduler.c reduce minthreads to threads "silently" (the code I added was trying to avoid silently changing user settings), if you think that's preferable. But in that case I'd be explicit about it in the docs…

sounds wrong to me. if ponyminthreads is greater than ponythreads, that should error out. which is not what i think you are saying in the quoted bit.

Right, but ponythreads is "only" set in scheduler.c in case it was not explicitly specified…


Cool, I'll prepare all of this in a cleaned up commit history and with all the changes discussed.
I'll summarize in another comment here and (hopefully) the doc changes make it all clear in any case. Thanks for the review 🙏 !

(I'll start tonight, but … will probably push it all only tomorrow)

@SeanTAllen
Copy link
Member

I can avoid the explicit check, and let the code in scheduler.c reduce minthreads to threads "silently" (the code I added was trying to avoid silently changing user settings), if you think that's preferable. But in that case I'd be explicit about it in the docs…

Still not sure I follow. But, I'm in favor of explicit checks and explicit errors as a general rule of thumb.

Right, but ponythreads is "only" set in scheduler.c in case it was not explicitly specified…

Sorry @alexsnaps. I still didn't follow that.

@alexsnaps
Copy link
Contributor Author

alexsnaps commented Sep 18, 2019

Still not sure I follow. But, I'm in favor of explicit checks and explicit errors as a general rule of thumb.

No worries, that last bit:

I'm in favor of explicit checks and explicit errors

Is what I'm arguing for too! So I'll just:

  • consolidate,
  • update all the docs,
  • add a summary to this PR of the changes;

And hopefully we can agree this all makes sense :)
Code speaks best…

As I said on Zulip tho, and as you can now see here, I trust my code more than my English sentences, so please, please, double review the error messages! :)

@SeanTAllen
Copy link
Member

Sounds good @alexsnaps!

@alexsnaps
Copy link
Contributor Author

alexsnaps commented Sep 21, 2019

Consolidated output & errors on my 6 core CPU:

$ ./helloworld 
Hello, world.

Behavior is unchanged


 $ ./helloworld --ponyminthreads=12
Can't have --ponyminthreads > --ponythreads (12 > 6)

--ponythreads took the default value, i.e. the numbers of physical cores, in this case 6. So we can't have --ponyminthreads be higher than 6


$ ./helloworld --ponyminthreads=4 
Hello, world.

This is fine, given --ponythreads took the default value, i.e. the numbers of physical cores, in this case 6.


 $ ./helloworld --ponyminthreads=4 --ponythreads=6
Hello, world.

Explicit case, all good as --ponythreads is <= physical cores on my machine!


 $ ./helloworld --ponyminthreads=4 --ponythreads=3
Can't have --ponyminthreads > --ponythreads (4 > 3)

Explicit case, but with erronous values provided


$ ./helloworld --ponyminthreads=3 --ponythreads=12
Can't have --ponythreads > physical cores, the number of threads you'd be running with (12 > 6)

Explicit case, but with --ponythreads being larger than the physical cores on the machine.


$ ./helloworld --ponyminthreads=3 --ponythreads=3 --ponynoscale
--ponyminthreads & --ponynoscale are mutually exclusive

Incompatible arguments provided


 $ ./helloworld --ponyminthreads=4 --ponythreads=3 --ponynoscale 
--ponyminthreads & --ponynoscale are mutually exclusive

Explicit case with erronous values and incompatible args. The latter error wins…


 $ ./helloworld --ponythreads=3 --ponynoscale               
Hello, world.

--ponynoscale sets --ponyminthreads to the value provided in --ponythreads, i.e. 3


./helloworld --ponynoscale               
Hello, world.

--ponynoscale sets --ponyminthreads to the implicit value of --ponythreads, i.e. 6 physical cores on my machine.

I'll still:

  • add the bound check on provided values (atoi signedness issue)
  • clean up commits
  • update docs

@SeanTAllen
Copy link
Member

@alexsnaps let me know when you are ready for another review (and maybe even... a merge!)

@alexsnaps
Copy link
Contributor Author

let me know when you are ready for another review (and maybe even... a merge!)

Wrapping up the doc & unsigned atoi at the airport (and on the flight if need be) right now… I think this should be fine in the next couple of hours… 

@alexsnaps
Copy link
Contributor Author

I’m again a disappointment. Didn’t get to finish the unsigned int atoi the way I wanted, so I think it might be best to do this as a separate PR to not hold this one back.

So if you think that behavior sounds good, let’s say this is ready for actual review and possibly a merge. I’ll open the PR against the other repo tomorrow (as I forgot to clone it prior boarding). wdyt?

And sorry about the slow follow up here.

@SeanTAllen
Copy link
Member

@alexsnaps couple of things before full review.

1- are you comfortable rebasing against master to resolve the CHANGELOG.md conflict?
2- can you add some nice release notes for this change to #3295

@SeanTAllen
Copy link
Member

@alexsnaps fyi, im planning on reviewing this today or tomorrow. i'd like for it to go out with the 0.32.0 release.

Like so:
$ ./helloworld --ponythreads=2048
Can't have --ponythreads > physical cores (2048 > 6)
@@ -107,6 +112,16 @@ static int parse_opts(int argc, char** argv, options_t* opt)
}
}

if (opt->noscale)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit. this can be fixed in another PR. this { should be on the preceding line.

if (opt->noscale)
{
if (minthreads_set)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit. this can be fixed in another PR. this { should be on the preceding line.

opt.threads = ponyint_cpu_count();
}
else if (opt.threads > ponyint_cpu_count())
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit. this can be fixed in another PR. this { should be on the preceding line.

}

if (opt.min_threads > opt.threads)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit. this can be fixed in another PR. this { should be on the preceding line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was the style most present in the code base. Not my preference neither… but I try to keep things consistent in a code base, if only one file. If we want { on the same line (my preference 😃 and which is what I understand you are asking for) should I do a single commit formatting pass throughout the file?

@SeanTAllen
Copy link
Member

@alexsnaps this looks good. there's a few small { related formatting changes, can you do those in another PR? i'm going to merge this as the core of it is solid. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

--ponyminthreads is confusing
2 participants