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

[tools] Fix tools/test and not for user-mode emulation #212

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

iamlouk
Copy link
Contributor

@iamlouk iamlouk commented Feb 25, 2025

Add preliminary support for user-mode emulation to the not tool
used in some fortran tests by adding a new mode where it spawns
the subprocess under the emulator. The original non-emulator-spawning
version is still needed for tests that use it to verify the output
using the host's diff. In the new version, the TEST_SUITE_RUN_UNDER
cmake option contents is prepended to the arguments then used to spawn
a subprocess.

Also disables the check_env test in tools/test in case of user-mode
emulation because it would run the host python interpreter in the
target emulator.

@iamlouk
Copy link
Contributor Author

iamlouk commented Feb 25, 2025

@tarunprabhu Could you maybe have a look at this? Without these changes, some tests in tools/test always fails when using -DTEST_SUITE_USER_MODE_EMULATION=On and e.g. -DTEST_SUITE_RUN_UNDER="qemu-<...> -L <...>"

Copy link
Contributor

@tarunprabhu tarunprabhu left a comment

Choose a reason for hiding this comment

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

Do we need a separate executable for this? Could we prepend the arguments when calling not instead? Or perhaps pass these on the command line? It seems as if users have to check TEST_SUITE_USER_MODE_EMULATION and TEST_SUITE_RUN_UNDER and use a different tool anyway, so user code does have to be changed.

tools/not.cpp Outdated
// In case of user-mode emulation, before spawning a new subprocess, the
// emulator needs to be preprended to the argv vector for the child.
// TEST_SUITE_RUN_UNDER will be defined to a comma-separated list of
// string litterals.
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT:

Suggested change
// string litterals.
// string literals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

No need to apologize :-)

@@ -716,10 +716,18 @@ function(gfortran_add_execute_test expect_error main others fflags ldflags)
gfortran_make_working_dir("${target}" working_dir)
get_filename_component(working_dir_name "${working_dir}" NAME)

# When running in a emulator, use the version of 'not' that will
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT:

Suggested change
# When running in a emulator, use the version of 'not' that will
# When running in an emulator, use the version of 'not' that will

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, fixed.

# When running in a emulator, use the version of 'not' that will
# spawn the subprocess under that emulator as well.
if(TEST_SUITE_USER_MODE_EMULATION AND TEST_SUITE_RUN_UNDER)
set(NOT_HELPER "not-spawning-emulator")
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps name this variable NOT_TOOL. It's not really a helper.

Suggested change
set(NOT_HELPER "not-spawning-emulator")
set(NOT_TOOL "not-spawning-emulator")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I changed the name and moved it to the root CMakeLists.txt next to the fpcmp utility name assignment.

add_dependencies(abrt not)
llvm_test_run(EXECUTABLE "$<TARGET_FILE:not>" "--crash" "$<TARGET_FILE:abrt>")
llvm_add_test_for_target(abrt)
# These test will always fail under user-mode emulation because 'not'
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure what tests you are referring to here. If you mean the check_env test that you have removed, then perhaps this comment could be moved after the abort test instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the NOT_TOOL assigned now and the check_env test being modified so that it now works under emulation, this is almost back to how it was before (just with ${NOT_TOOL instead of not).

# These test will always fail under user-mode emulation because 'not'
# spawns a subprocess outside the emulator and the check_env test
# runs the host python interpreter under the emulator for the target.
if(NOT(TEST_SUITE_USER_MODE_EMULATION AND TEST_SUITE_RUN_UNDER))
Copy link
Contributor

Choose a reason for hiding this comment

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

The negation of the conditional is a bit hard to read. Could the branches be switched with a "positive" conditional instead?

Suggested change
if(NOT(TEST_SUITE_USER_MODE_EMULATION AND TEST_SUITE_RUN_UNDER))
if(TEST_SUITE_USER_MODE_EMULATION AND TEST_SUITE_RUN_UNDER)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the NOT_TOOL assigned now and the check_env test being modified so that it now works under emulation, this is almost back to how it was before (just with ${NOT_TOOL instead of not).

llvm_add_test_for_target(abrt)
# These test will always fail under user-mode emulation because 'not'
# spawns a subprocess outside the emulator and the check_env test
# runs the host python interpreter under the emulator for the target.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does passing environment variables work with not-spawning-emulator? Is it only the test here that cannot be run? It would be good to have a test for this if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the two user-mode emulator I know/use (mostly QEMU) do forward environment variables. I replaced the python script that sets the environment variable by a small C program inspired by not.cpp, and with that, the test now also works under emulation.

@iamlouk iamlouk force-pushed the lk/tools-for-emulation branch from 01ab296 to 321227a Compare February 28, 2025 08:37
@iamlouk
Copy link
Contributor Author

iamlouk commented Feb 28, 2025

Do we need a separate executable for this? Could we prepend the arguments when calling not instead? Or perhaps pass these on the command line?

That was my first idea as well, and I can do that if its preferred. This just seamed easier to me, and other tools like fpcmp are also compiled twice (although the context/needs are different as it is compiled for different architectures).

Would a syntax similar to not [--crash] [--run-under <emulator> <emulator arg1> <emulator arg2 ...> --] <test binary> <test arg1> <test arg2 ...> be fine?

@tarunprabhu
Copy link
Contributor

Thanks for the changes.

That was my first idea as well, and I can do that if its preferred. This just seamed easier to me, and other tools like fpcmp are also compiled twice (although the context/needs are different as it is compiled for different architectures).

I think it might be better to stick with a single tool for this. I am guessing that fpcmp needs different CPU and GPU versions. That's not really the case here. This is really just adding a "wrapper" around the invocation of test_binary.

Would a syntax similar to not [--crash] [--run-under <emulator> <emulator arg1> <emulator arg2 ...> --] <test binary> <test arg1> <test arg2 ...> be fine?

I assume that <emulator> <emulator args> ... would be in quotes. Otherwise, how would we distinguish between the last <emulator arg> and the <test_binary>?

@iamlouk
Copy link
Contributor Author

iamlouk commented Mar 3, 2025

I just pushed a commit with the proposed solution so that you can have a look (single not binary, but with a flag to optionally spawn the subcommand under the emulator). The <emulator> <emulator args> ... is not in quotes, because that would require spiting arguments in the not tool. Instead, a -- (double dash) is used, a bit like commands like git checkout or so sometimes use to disambiguate in similar situations. I just tested this with and without user-mode emulation and with extra flags to the emulator.

Copy link
Contributor

@tarunprabhu tarunprabhu left a comment

Choose a reason for hiding this comment

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

Thank you for all the changes

if(TEST_SUITE_USER_MODE_EMULATION AND TEST_SUITE_RUN_UNDER)
# ${TEST_SUITE_RUN_UNDER} is needed here because test_not is not itself
# user-mode emulation aware, unlike the not tool.
llvm_test_run(EXECUTABLE ${Python_EXECUTABLE} "$<TARGET_FILE:test_not>" ${TEST_SUITE_RUN_UNDER} ${NOT_TOOL} "$<TARGET_FILE:check_env>")
Copy link
Contributor

Choose a reason for hiding this comment

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

Is ${Python_EXECUTABLE} required here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for noticing, not it is not. I just tested in a clean build to make sure.

CMakeLists.txt Outdated
# Shortcut for the path to the not executable
set(NOT_TOOL "$<TARGET_FILE:not>")
if (TEST_SUITE_USER_MODE_EMULATION AND TEST_SUITE_RUN_UNDER)
# Because 'not' spawns a subprocess for its argument, it needs to know about the
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:

The Github interface doesn't show columns, but does this comment fit within 80 characters? The rules for line width in cmake are not as strict as source files, but it would be good to stick to that width where we can.

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 reformatted this and the following two lines to make it fit.

tools/not.cpp Outdated
// subcommand. If --crash is used as well, it has to come after the
// '--run-under <...> ...' arguments. The double-dash is used to separate
// emulator arguments from cmd arguments. This order makes it easier to
// use the not tool in the test-suite.
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add sentence clarifying what the return value will be in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just did that. This works as expected with QEMU and another emulator I use downstream, I will double check if this is also the behavior of other user-mode emulators such as Gem5 SE mode or RISC-V Spike.

tools/not.cpp Outdated
@@ -29,17 +35,52 @@
#include <sys/wait.h>
#endif

#include <vector>
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move this include with the other system includes at the top of this file

tools/not.cpp Outdated
++argv;
}

// If present, the crash flag is between the emulator
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:

Does this comment need to be split across two lines? clang-format can be used to "fit" comments.

Copy link
Contributor

@tarunprabhu tarunprabhu left a comment

Choose a reason for hiding this comment

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

Thanks for all the changes and for seeing this through.

Comment on lines +19 to +20
// with the same exit status/signal than the emulated binary in case of
// a crash, and the --crash flag will behave the same way.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit

Suggested change
// with the same exit status/signal than the emulated binary in case of
// a crash, and the --crash flag will behave the same way.
// with the same exit status/signal as the emulated binary. The --crash flag
// will behave the same way.

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.

2 participants