-
Notifications
You must be signed in to change notification settings - Fork 43
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
Client improvements 2 #229
Conversation
a7cc1c3
to
fb6f7db
Compare
0ce0852
to
bca00a7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good to me in general. Great job Troy and Cory!.
Below are some initial comments. I might have some more comments once the concept is applied to all functions...
My main concern now has to do with the error messages and the format they are printed. I have some suggestions to be more consistent with other messages, but it was easier to simply apply them in a PR to your branch than explain them here. So, please have a look and let me know what you think.
bca00a7
to
d8293aa
Compare
d8293aa
to
dd417e4
Compare
* format messages and outputs * format messages and outputs * review corrections
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still a couple details to adjust, but it looks like a good change. Nice job!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the CI is having some trouble. Definitely wait for green checkmarks before merging.
I'm still not entirely behind the namespace choice, but that's small potatoes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice Troy! The set and get mechanisms, and the mapping of all parameters is clean and functional...
I just have a few more suggested changes to clarify things from the user perspective and to avoid further errors with the default values.
clients/benchmarks/client.cpp
Outdated
("k", | ||
value<rocblas_int>()->default_value(128), | ||
"Matrix/vector size parameter.\n" | ||
" Typically, the number of Householder reflections in a transformation.\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure yet of the description of this parameter...
I would say something like:
"Matrix/vector size parameter.
Represents a sub-dimension of a problem.
The number of Householder reflections in a transformation, for example."
Also, the default value of k cannot always be 128!! It depends on the problem... I would prefer not to assign a default.
For example, for orglq
, k <= m
... So, rocsolver-bench -f orglq -m 30 -n 30
will fail if k=128
....!
The default should be calculated in the test body...
(also see other related comments below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that calculating defaults for n and k in the test body will address this problem either. For example, rocsolver-bench -f orglq -k 150
will still fail since m is not calculated based on k. We should probably require the user to provide either all size arguments or none, so rocsolver-bench -f orglq -m 30 -n 30 -k 30
and rocsolver-bench -f orglq
would be valid, but rocsolver-bench -f orglq -m 30 -n 30
and rocsolver-bench -f orglq -k 150
would not. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you are right! mmm I was hoping this not to get more complicated, but I don't like us providing default values that fail; better not to have defaults and always require the user to pass all parameters.
BTW what would happen if we call argus.get<rocblas_int>("m");
and m
has no value?
If this method returns NAN or something that we can detect, then we can ask the user to always provide the "fundamental" parameter...
So, for example, as orglq
computes a matrix with orthonormal rows, m
must be provided; orgqr
computes a matrix with orthogonal columns, so n
must be provided, etc. Everything else can be calculated. (Most functions will do well with m=128, n=128, anyways).
So, in the case of rocsolver-bench -f orglq -k 150
, we can maybe return an error saying
"A default value for -m cannot be calculated; please provide a suitable value" or something like this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW what would happen if we call argus.get<rocblas_int>("m"); and m has no value?
If this method returns NAN or something that we can detect, then we can ask the user to always provide the "fundamental" parameter...
It would throw an std::out_of_range
exception, which would trigger the program to terminate. I'm not sure if the error message would specifically state what argument was missing, but it might actually be pretty good already. If it's not good enough, we could clean that up a bit without changing it much. We'd define our own exception and if an argument was requested but not found, we'd do an explicit throw in get
, then catch the exception in main()
to print a nicer error message.
(I'm normally not a huge fan of exceptions as an error handling mechanism, but they do work fairly nicely for this sort of problem.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, in the case of
rocsolver-bench -f orglq -k 150
, we can maybe return an error saying
"A default value for -m cannot be calculated; please provide a suitable value" or something like this...
I like this idea. I think we can still keep the defaults for most functions, but for those you've mentioned I can calculate the secondary parameters and terminate the program if a secondary parameter is provided without the primary parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you agree with the idea of only require the "fundamental parameter(s)" for those problematic functions, here is a list of
[function - required parameter(s)]
laswp - k1
larft - n,k,storev
larf - m
larfb - m,n,k,side,storev
labrd - m,n
bdsqr - n,nu
latrd - n
steqr - n
orgxr/ungxr - m,n (yes, m is also required to avoid problems with lda)
orglx/unglx - m,n
orgxl/ungxl - m,n
orgbr/ungbr - m,n,storev
orgtr/ungtr - n
ormxr/unmxr - m,n,side
ormlx/unmlx - m,k,side
ormxl/unmxl - m,n,side
ormbr/unmbr - m,n,side,storev
ormtr/unmtr - m,n,side
potf2/potrf - n
getf2/getrf - m
geqr2/geqrf - m
geql2/geqlf - m
gelq2/gelqf - m
gebd2/gebrd - m
sytd2/sytrd/hetd2/hetrd - n
sygs2/sygst/hegs2/hegst - n
getri - n
getrs - n
gels - m,n
syev/heev - n
sygv/hegv - n
gesvd - m,n
So, rather almost always we will require the user to provide a size... but still we have some parameters that can default to something. It is mid-way between not requesting any parameter and requesting all parameters.
If you want, you can check whether the required parameter is really needed. For example if in potf2, 'n' is not provided, but neither 'lda', then both can get defaults... Even fancier, you can see whether one parameter can be calculated if we know the other, and so on. This can be as elaborated as we want. To me, always requesting the minimal parameters in the list is just fine.
As for the error, using the exceptions to provide the message is fine with me as long as it provides information on what is the missing required parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you want the check on lda, ldb, etc. as well? That makes it a bit more involved... I'll have to think about how to do this cleanly...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, I think we might be overengineering this a little bit. For now, adding calculations for the secondary parameters should be enough so that the client, in most cases, won't fail. I'll go ahead and do that. Perhaps we can discuss more advanced behaviours in a later meeting, as I also don't want things to become too complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you want the check on lda, ldb, etc. as well? That makes it a bit more involved... I'll have to think about how to do this cleanly...
No, I am just saying that it could be done, but for me, it is fine if we just require the user to provide the primary parameters (as in the list), and calculate a default for the other parameters if not provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, okay, that's more doable. I can add that in.
rocblas_stride stQ = argus.bsp; | ||
rocblas_stride stP = argus.bsp; | ||
rocblas_int m = argus.get<rocblas_int>("m"); | ||
rocblas_int n = argus.get<rocblas_int>("n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly,
rocblas_int m = argus.get<rocblas_int>("m", 128);
rocblas_int n = argus.get<rocblas_int>("n", 128);
Same for other functions below...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
A few non-important comments... except for LASWP which I think needs to be fixed.
After that, let's merge this PR! Good job...
{ | ||
// get arguments | ||
rocblas_local_handle handle; | ||
rocblas_int n = argus.N; | ||
rocblas_int inc = argus.incx; | ||
rocblas_int n = argus.get<rocblas_int>("n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n
can take any value here. This could be
rocblas_int n = argus.get<rocblas_int>("n",128);
if we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm uncomfortable with adding defaults that the user can't see. In cases where the default isn't a straightforward calculation, I'd prefer either no defaults (current situation) or global defaults (earlier situation, where the user can see these defaults in the help message). Defaulting to square matrices is a bit of an edge case, but we've now documented that in the help string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
rocblas_int lda = argus.lda; | ||
rocblas_int hot_calls = argus.iters; | ||
char sideC = argus.side_option; | ||
char sideC = argus.get<char>("side"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
side
can take any value here. This could be
char sideC = argus.get<char>("side",'L');
if we want.
{ | ||
// get arguments | ||
rocblas_local_handle handle; | ||
rocblas_int n = argus.N; | ||
rocblas_int inc = argus.incx; | ||
rocblas_int n = argus.get<rocblas_int>("n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n
can take any value here. This could be
rocblas_int n = argus.get<rocblas_int>("n",128);
if we want.
clients/include/testing_laswp.hpp
Outdated
rocblas_int k2 = argus.k2; | ||
rocblas_int inc = argus.incx; | ||
rocblas_int n = argus.get<rocblas_int>("n"); | ||
rocblas_int lda = argus.get<rocblas_int>("lda", 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although not required by the API, for the test to actually make sense, lda >= k2 otherwise you will be swapping non-existent rows. So, at least for the default cases, we need to ensure that no out of bond memory is accessed:
clients/staging/rocsolver-bench -f laswp -n 5 --k1 9 --k2 20
Memory access fault by GPU node-1 (Agent handle: 0x243ed30) on address 0x7f3b445ff000. Reason: Page not present or supervisor privilege.
Aborted (core dumped)
So, I guess we need
rocblas_int lda = argus.get<rocblas_int>("lda", k2);
And probably we should request k2
as well ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Should we perhaps add a check for lda < k2 in laswp's argCheck as well? Maybe not in the PR, but if it's guaranteed to cause a memory access fault then that should probably be caught by the check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The values we use in the gtest ensure we don't have problems, but users can easily get memory access faults (in code or using rocsolver-bench) if they are not careful...
LAPACK does not have a check for lda, but we can certainly add it in a future PR.
rocblas_int k1 = argus.k1; | ||
rocblas_int k2 = argus.k2; | ||
rocblas_int inc = argus.incx; | ||
rocblas_int n = argus.get<rocblas_int>("n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n
can take any value here. This could be
rocblas_int n = argus.get<rocblas_int>("n",128);
if we want.
{ | ||
// get arguments | ||
rocblas_local_handle handle; | ||
rocblas_int n = argus.N; | ||
rocblas_int n = argus.get<rocblas_int>("n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n can take any value here. This could be
rocblas_int n = argus.get<rocblas_int>("n",128); if we want.
If there are no objections, once CI passes I'll merge this PR. |
Addresses SWDEV-275379.
Summary of proposed changes: