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

Client improvements 2 #229

Merged
merged 43 commits into from
Mar 23, 2021
Merged

Client improvements 2 #229

merged 43 commits into from
Mar 23, 2021

Conversation

tfalders
Copy link
Collaborator

@tfalders tfalders commented Mar 8, 2021

Addresses SWDEV-275379.

Summary of proposed changes:

  • Improved emulation of boost's variables_map (I plan to port these changes over to rocBLAS and hipBLAS if accepted)
  • Convert Arguments class into a map of variables with easy-to-use get and set methods
    • New argument variables only need to be added to client.cpp
    • Getter method can return a default value if an actual value has not been provided
    • Slight drawback in the form of more verbose code and increased compilation time
    • Some argument variables (namely, test options) are still kept as public fields for ease-of-use

@tfalders tfalders added noCI Disable Jenkins for this PR. noOptimizations Disable optimized kernels for small sizes for some routines labels Mar 8, 2021
clients/rocblascommon/program_options.hpp Outdated Show resolved Hide resolved
clients/rocblascommon/program_options.hpp Outdated Show resolved Hide resolved
clients/rocblascommon/program_options.hpp Outdated Show resolved Hide resolved
clients/rocblascommon/program_options.hpp Outdated Show resolved Hide resolved
clients/include/testing_gesvd.hpp Show resolved Hide resolved
Copy link
Collaborator

@jzuniga-amd jzuniga-amd left a 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.

clients/benchmarks/client.cpp Outdated Show resolved Hide resolved
clients/benchmarks/client.cpp Outdated Show resolved Hide resolved
clients/gtest/orgbr_ungbr_gtest.cpp Show resolved Hide resolved
clients/include/rocsolver_arguments.hpp Outdated Show resolved Hide resolved
@tfalders tfalders removed the noCI Disable Jenkins for this PR. label Mar 15, 2021
@tfalders tfalders marked this pull request as ready for review March 15, 2021 22:13
Copy link
Collaborator

@cgmb cgmb left a 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!

clients/rocblascommon/program_options.hpp Outdated Show resolved Hide resolved
clients/benchmarks/client.cpp Outdated Show resolved Hide resolved
clients/gtest/bdsqr_gtest.cpp Show resolved Hide resolved
clients/include/rocsolver_arguments.hpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@cgmb cgmb left a 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.

Copy link
Collaborator

@jzuniga-amd jzuniga-amd left a 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.

("k",
value<rocblas_int>()->default_value(128),
"Matrix/vector size parameter.\n"
" Typically, the number of Householder reflections in a transformation.\n"
Copy link
Collaborator

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)

Copy link
Collaborator Author

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?

Copy link
Collaborator

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...

Copy link
Collaborator

@cgmb cgmb Mar 19, 2021

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.)

Copy link
Collaborator Author

@tfalders tfalders Mar 19, 2021

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

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...

Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

clients/benchmarks/client.cpp Show resolved Hide resolved
clients/benchmarks/client.cpp Outdated Show resolved Hide resolved
clients/benchmarks/client.cpp Outdated Show resolved Hide resolved
clients/benchmarks/client.cpp Outdated Show resolved Hide resolved
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");
Copy link
Collaborator

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...

clients/include/testing_labrd.hpp Outdated Show resolved Hide resolved
clients/include/testing_orglx_unglx.hpp Outdated Show resolved Hide resolved
clients/include/testing_orgxl_ungxl.hpp Show resolved Hide resolved
clients/include/testing_ormlx_unmlx.hpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@jzuniga-amd jzuniga-amd left a 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");
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator

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");
Copy link
Collaborator

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");
Copy link
Collaborator

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.

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);
Copy link
Collaborator

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 ?

Copy link
Collaborator Author

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.

Copy link
Collaborator

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");
Copy link
Collaborator

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_latrd.hpp Outdated Show resolved Hide resolved
{
// get arguments
rocblas_local_handle handle;
rocblas_int n = argus.N;
rocblas_int n = argus.get<rocblas_int>("n");
Copy link
Collaborator

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.

@tfalders
Copy link
Collaborator Author

If there are no objections, once CI passes I'll merge this PR.

@tfalders tfalders merged commit 12afdab into ROCm:develop Mar 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
noOptimizations Disable optimized kernels for small sizes for some routines
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants