Skip to content

[lldb][test] Support remote run of Shell tests #95986

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

Merged
merged 11 commits into from
Oct 7, 2024

Conversation

dzhidzhoev
Copy link
Member

@dzhidzhoev dzhidzhoev commented Jun 18, 2024

  1. This commit adds LLDB_TEST_PLATFORM_URL, LLDB_TEST_SYSROOT,
    LLDB_TEST_PLATFORM_WORKING_DIR, LLDB_SHELL_TESTS_DISABLE_REMOTE cmake flags
    to pass arguments for cross-compilation and remote running of both Shell&API
    tests.
  2. To run Shell tests remotely, it adds 'platform select' and 'platform connect' commands to %lldb
    substitution.
  3. 'remote-linux' feature added to lit to disable tests failing with remote execution.
  4. A separate working directory is assigned to each test to avoid
    conflicts during parallel test execution.
  5. Remote Shell testing is run only when LLDB_TEST_SYSROOT is set for
    building test sources. The recommended compiler for that is Clang.

@llvmbot
Copy link
Member

llvmbot commented Jun 18, 2024

@llvm/pr-subscribers-lldb

Author: Vladislav Dzhidzhoev (dzhidzhoev)

Changes
  1. This commit adds LLDB_PLATFORM_URL, LLDB_TEST_SYSROOT,
    LLDB_PLATFORM_WORKING_DIR cmake flags to pass arguments for
    cross-compilation and remote running of both Shell&API tests.
  2. To run Shell tests remotely, It adds 'platform select' and 'platform connect' commands to %lldb
    substitution.
  3. 'remote-linux' feature added to lit to disable tests failing with remote execution.
  4. A separate working directory is assigned to each test to avoid
    conflicts during parallel test execution.

It has been tested on Ubuntu AArch64 with libcxx enabled for tests.


Full diff: https://github.com/llvm/llvm-project/pull/95986.diff

7 Files Affected:

  • (modified) lldb/test/API/lit.cfg.py (+7)
  • (modified) lldb/test/API/lit.site.cfg.py.in (+3)
  • (modified) lldb/test/Shell/Settings/TestEchoCommands.test (+2)
  • (modified) lldb/test/Shell/Target/target-label.test (+10-10)
  • (modified) lldb/test/Shell/helper/toolchain.py (+64-3)
  • (modified) lldb/test/Shell/lit.cfg.py (+5-1)
  • (modified) lldb/test/Shell/lit.site.cfg.py.in (+5-1)
diff --git a/lldb/test/API/lit.cfg.py b/lldb/test/API/lit.cfg.py
index 96520c7c82624..6a0a1b0a76675 100644
--- a/lldb/test/API/lit.cfg.py
+++ b/lldb/test/API/lit.cfg.py
@@ -303,6 +303,13 @@ def delete_module_cache(path):
 # In particular, (1) is visited at the top of the file, since the script
 # derives other information from it.
 
+if is_configured("lldb_platform_url"):
+    dotest_cmd += ["--platform-url", config.lldb_platform_url]
+if is_configured("lldb_platform_working_dir"):
+    dotest_cmd += ["--platform-working-dir", config.lldb_platform_working_dir]
+if is_configured("cmake_sysroot"):
+    dotest_cmd += ["--sysroot", config.cmake_sysroot]
+
 if is_configured("dotest_user_args_str"):
     dotest_cmd.extend(config.dotest_user_args_str.split(";"))
 
diff --git a/lldb/test/API/lit.site.cfg.py.in b/lldb/test/API/lit.site.cfg.py.in
index 8b2d09ae41cd2..ec388297e91eb 100644
--- a/lldb/test/API/lit.site.cfg.py.in
+++ b/lldb/test/API/lit.site.cfg.py.in
@@ -24,6 +24,9 @@ config.lua_executable = "@Lua_EXECUTABLE@"
 config.lua_test_entry = "TestLuaAPI.py"
 config.dotest_common_args_str = lit_config.substitute("@LLDB_TEST_COMMON_ARGS@")
 config.dotest_user_args_str = lit_config.substitute("@LLDB_TEST_USER_ARGS@")
+config.lldb_platform_url = lit_config.substitute("@LLDB_PLATFORM_URL@")
+config.lldb_platform_working_dir = lit_config.substitute("@LLDB_PLATFORM_WORKING_DIR@")
+config.cmake_sysroot = lit_config.substitute("@LLDB_TEST_SYSROOT@" or "@DEFAULT_SYSROOT@")
 config.lldb_enable_python = @LLDB_ENABLE_PYTHON@
 config.dotest_lit_args_str = None
 config.enabled_plugins = []
diff --git a/lldb/test/Shell/Settings/TestEchoCommands.test b/lldb/test/Shell/Settings/TestEchoCommands.test
index 234b9742bfa2a..ce78f91e1cbd4 100644
--- a/lldb/test/Shell/Settings/TestEchoCommands.test
+++ b/lldb/test/Shell/Settings/TestEchoCommands.test
@@ -2,6 +2,8 @@
 # RUN: %lldb -x -b -o 'settings set interpreter.echo-comment-commands false' -s %S/Inputs/EchoCommandsTest.in | FileCheck %S/Inputs/EchoCommandsNoComments.out
 # RUN: %lldb -x -b -o 'settings set interpreter.echo-commands false'         -s %S/Inputs/EchoCommandsTest.in | FileCheck %S/Inputs/EchoCommandsNone.out
 
+XFAIL: remote{{.*}}
+
 RUN: echo start >%t.file
 RUN: %lldb -x -b --source-quietly -s %S/Inputs/EchoCommandsTest.in >>%t.file
 RUN: echo done >>%t.file
diff --git a/lldb/test/Shell/Target/target-label.test b/lldb/test/Shell/Target/target-label.test
index 5ac430601e29a..7f4f31e09fa16 100644
--- a/lldb/test/Shell/Target/target-label.test
+++ b/lldb/test/Shell/Target/target-label.test
@@ -4,16 +4,16 @@
 
 target create -l "ls" /bin/ls
 target list
-# CHECK: * target #0 (ls): /bin/ls
+# CHECK: * target #0 (ls): [[LS_PATH:.*]]
 
 script lldb.target.SetLabel("")
 target list
-# CHECK: * target #0: /bin/ls
+# CHECK: * target #0: [[LS_PATH]]
 
 target create -l "cat" /bin/cat
 target list
-# CHECK: target #0: /bin/ls
-# CHECK-NEXT: * target #1 (cat): /bin/cat
+# CHECK: target #0: [[LS_PATH]]
+# CHECK-NEXT: * target #1 (cat): [[CAT_PATH:.*]]
 
 target create -l "cat" /bin/cat
 # CHECK: Cannot use label 'cat' since it's set in target #1.
@@ -22,12 +22,12 @@ target create -l 42 /bin/cat
 # CHECK: error: Cannot use integer as target label.
 
 target select 0
-# CHECK: * target #0: /bin/ls
-# CHECK-NEXT: target #1 (cat): /bin/cat
+# CHECK: * target #0: [[LS_PATH]]
+# CHECK-NEXT: target #1 (cat): [[CAT_PATH]]
 
 target select cat
-# CHECK: target #0: /bin/ls
-# CHECK-NEXT: * target #1 (cat): /bin/cat
+# CHECK: target #0: [[LS_PATH]]
+# CHECK-NEXT: * target #1 (cat): [[CAT_PATH]]
 
 script lldb.target.GetLabel()
 # CHECK: 'cat'
@@ -36,5 +36,5 @@ script lldb.debugger.GetTargetAtIndex(0).SetLabel('Not cat')
 # CHECK: success
 
 target list
-# CHECK: target #0 (Not cat): /bin/ls
-# CHECK-NEXT: * target #1 (cat): /bin/cat
+# CHECK: target #0 (Not cat): [[LS_PATH]]
+# CHECK-NEXT: * target #1 (cat): [[CAT_PATH]]
diff --git a/lldb/test/Shell/helper/toolchain.py b/lldb/test/Shell/helper/toolchain.py
index 255955fc70d8c..32c37536ec8bd 100644
--- a/lldb/test/Shell/helper/toolchain.py
+++ b/lldb/test/Shell/helper/toolchain.py
@@ -1,10 +1,12 @@
 import os
 import itertools
 import platform
+import re
 import subprocess
 import sys
 
 import lit.util
+from lit.formats import ShTest
 from lit.llvm import llvm_config
 from lit.llvm.subst import FindTool
 from lit.llvm.subst import ToolSubst
@@ -22,6 +24,55 @@ def _disallow(config, execName):
     config.substitutions.append((" {0} ".format(execName), warning.format(execName)))
 
 
+def get_lldb_args(config, suffix=None):
+    lldb_args = []
+    if "remote-linux" in config.available_features:
+        lldb_args += [
+            "-O",
+            '"platform select remote-linux"',
+            "-O",
+            f'"platform connect {config.lldb_platform_url}"',
+        ]
+        if config.lldb_platform_working_dir:
+            dir = f"{config.lldb_platform_working_dir}/shell"
+            if suffix:
+                dir += f"/{suffix}"
+            lldb_args += [
+                "-O",
+                f'"platform shell mkdir -p {dir}"',
+                "-O",
+                f'"platform settings -w {dir}"',
+            ]
+    lldb_args += ["--no-lldbinit", "-S", _get_lldb_init_path(config)]
+    return lldb_args
+
+
+class ShTestLldb(ShTest):
+    def __init__(
+        self, execute_external=False, extra_substitutions=[], preamble_commands=[]
+    ):
+        super().__init__(execute_external, extra_substitutions, preamble_commands)
+
+    def execute(self, test, litConfig):
+        for i, t in enumerate(test.config.substitutions):
+            try:
+                if re.match(t[0], "%lldb"):
+                    cmd = t[1]
+                    if '-O "platform settings -w ' in cmd:
+                        args_def = " ".join(get_lldb_args(test.config))
+                        args_unique = " ".join(
+                            get_lldb_args(test.config, "/".join(test.path_in_suite))
+                        )
+                        test.config.substitutions[i] = (
+                            t[0],
+                            cmd.replace(args_def, args_unique),
+                        )
+                    break
+            except:
+                pass
+        return super().execute(test, litConfig)
+
+
 def use_lldb_substitutions(config):
     # Set up substitutions for primary tools.  These tools must come from config.lldb_tools_dir
     # which is basically the build output directory.  We do not want to find these in path or
@@ -34,7 +85,9 @@ def use_lldb_substitutions(config):
     build_script = os.path.join(build_script, "build.py")
     build_script_args = [
         build_script,
-        "--compiler=any",  # Default to best compiler
+        (
+            "--compiler=clang" if config.lldb_platform_url else "--compiler=any"
+        ),  # Default to best compiler
         "--arch=" + str(config.lldb_bitness),
     ]
     if config.lldb_lit_tools_dir:
@@ -56,7 +109,7 @@ def use_lldb_substitutions(config):
         ToolSubst(
             "%lldb",
             command=FindTool("lldb"),
-            extra_args=["--no-lldbinit", "-S", lldb_init],
+            extra_args=get_lldb_args(config),
             unresolved="fatal",
         ),
         ToolSubst(
@@ -138,7 +191,7 @@ def use_support_substitutions(config):
     # Set up substitutions for support tools.  These tools can be overridden at the CMake
     # level (by specifying -DLLDB_LIT_TOOLS_DIR), installed, or as a last resort, we can use
     # the just-built version.
-    host_flags = ["--target=" + config.host_triple]
+    host_flags = ["--target=" + config.target_triple]
     if platform.system() in ["Darwin"]:
         try:
             out = subprocess.check_output(["xcrun", "--show-sdk-path"]).strip()
@@ -165,6 +218,14 @@ def use_support_substitutions(config):
     if config.cmake_sysroot:
         host_flags += ["--sysroot={}".format(config.cmake_sysroot)]
 
+    if config.lldb_platform_url and config.has_libcxx:
+        host_flags += [
+            "-L{}".format(config.libcxx_libs_dir),
+            "-Wl,-rpath,{}".format(config.libcxx_libs_dir),
+            "-lc++",
+            "-lc++abi",
+        ]
+
     host_flags = " ".join(host_flags)
     config.substitutions.append(("%clang_host", "%clang " + host_flags))
     config.substitutions.append(("%clangxx_host", "%clangxx " + host_flags))
diff --git a/lldb/test/Shell/lit.cfg.py b/lldb/test/Shell/lit.cfg.py
index e24f3fbb4d931..7f832eb3bff4c 100644
--- a/lldb/test/Shell/lit.cfg.py
+++ b/lldb/test/Shell/lit.cfg.py
@@ -21,7 +21,7 @@
 config.name = "lldb-shell"
 
 # testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
+config.test_format = toolchain.ShTestLldb(not llvm_config.use_lit_shell)
 
 # suffixes: A list of file extensions to treat as test files. This is overriden
 # by individual lit.local.cfg files in the test subdirectories.
@@ -68,6 +68,10 @@
     lit_config.note("Running Shell tests in {} mode.".format(lldb_repro_mode))
     toolchain.use_lldb_repro_substitutions(config, lldb_repro_mode)
 
+if config.lldb_platform_url:
+    if re.match(r".*-linux.*", config.target_triple):
+        config.available_features.add("remote-linux")
+
 llvm_config.use_default_substitutions()
 toolchain.use_lldb_substitutions(config)
 toolchain.use_support_substitutions(config)
diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in
index b69e7bce1bc0b..dde705f1918cb 100644
--- a/lldb/test/Shell/lit.site.cfg.py.in
+++ b/lldb/test/Shell/lit.site.cfg.py.in
@@ -10,10 +10,14 @@ config.lldb_src_root = "@LLDB_SOURCE_DIR@"
 config.lldb_obj_root = "@LLDB_BINARY_DIR@"
 config.lldb_libs_dir = lit_config.substitute("@LLDB_LIBS_DIR@")
 config.lldb_tools_dir = lit_config.substitute("@LLDB_TOOLS_DIR@")
+config.lldb_platform_url = lit_config.substitute("@LLDB_PLATFORM_URL@")
+config.lldb_platform_working_dir = lit_config.substitute("@LLDB_PLATFORM_WORKING_DIR@")
 # Since it comes from the command line, it may have backslashes which
 # should not need to be escaped.
 config.lldb_lit_tools_dir = lit_config.substitute(r"@LLDB_LIT_TOOLS_DIR@")
-config.cmake_sysroot = lit_config.substitute("@CMAKE_SYSROOT@")
+config.cmake_sysroot = lit_config.substitute("@LLDB_TEST_SYSROOT@" or "@DEFAULT_SYSROOT@")
+config.has_libcxx = @LLDB_HAS_LIBCXX@
+config.libcxx_libs_dir = "@LIBCXX_LIBRARY_DIR@"
 config.target_triple = "@LLVM_TARGET_TRIPLE@"
 config.python_executable = "@Python3_EXECUTABLE@"
 config.have_zlib = @LLVM_ENABLE_ZLIB@

@labath
Copy link
Collaborator

labath commented Jun 19, 2024

Can't say I'm excited to see this feature (although I admit it is looking less daunting than I originally feared). Can you explain why you need this feature? Is there some particular aspect of lldb's remote operation that you think isn't well covered by the existing tests? Is there a particular category of tests that you'd like to have more than other? How many of the existing tests would actually exercise the remote platform capability in a meaningful way (a lot of these tests don't even build runnable binaries)?

@dzhidzhoev
Copy link
Member Author

Can't say I'm excited to see this feature (although I admit it is looking less daunting than I originally feared). Can you explain why you need this feature? Is there some particular aspect of lldb's remote operation that you think isn't well covered by the existing tests? Is there a particular category of tests that you'd like to have more than others? How many of the existing tests would exercise the remote platform capability in a meaningful way (a lot of these tests don't even build runnable binaries)?

I'm sorry, it took a bit longer time to answer than I expected, my apologies.

In general, our goal is to maximize the functionality of the testing toolkit in case of cross-compilation+remote launch setup.

I agree that not every Shell test launches binaries. According to my grep-based statistics, it's roughly one-fifth of the tests currently (117/533 test files that contain "r", "run", or "process launch" commands). Though it's still a number.

Also, launching the "platform select" and "platform connect ..." commands before executing the rest of a Shell test script may be useful. Here is an example case of a potentially unexpected behavior #94165. So it's not always necessary to have a Shell test build and run a binary to reveal some nuances.
And it seems to me, that it won't cause excessive maintenance overhead since we essentially add just two extra commands to %lldb invocation.

I haven't opened an RFC since I thought it would be clearer to discuss that idea with the showcase of implementation. I'm open to moving a discussion there if it's considered as a better approach in this case (please let me know😅).

@labath
Copy link
Collaborator

labath commented Jun 21, 2024

Can't say I'm excited to see this feature (although I admit it is looking less daunting than I originally feared). Can you explain why you need this feature? Is there some particular aspect of lldb's remote operation that you think isn't well covered by the existing tests? Is there a particular category of tests that you'd like to have more than others? How many of the existing tests would exercise the remote platform capability in a meaningful way (a lot of these tests don't even build runnable binaries)?

I'm sorry, it took a bit longer time to answer than I expected, my apologies.

In general, our goal is to maximize the functionality of the testing toolkit in case of cross-compilation+remote launch setup.

I agree that not every Shell test launches binaries. According to my grep-based statistics, it's roughly one-fifth of the tests currently (117/533 test files that contain "r", "run", or "process launch" commands). Though it's still a number.

Thank you for finding that number.

Also, launching the "platform select" and "platform connect ..." commands before executing the rest of a Shell test script may be useful. Here is an example case of a potentially unexpected behavior #94165. So it's not always necessary to have a Shell test build and run a binary to reveal some nuances.

That's true, but this still seems like a pretty big hammer for that.

And it seems to me, that it won't cause excessive maintenance overhead since we essentially add just two extra commands to %lldb invocation.

Maybe. Like I said, it's cleaner than I though, but I'm still somewhat worried about where this will lead. If you can support running these tests on a different machine, then I think the next question becomes "why not run them with a different compiler as well". And then you need to XFAIL the tests for a particular compiler, so you end up replicating all of the @skipIfClang71ExceptOnTuesdays logic.

I don't know if this is a slippery slope fallacy or an actual slippery slope, but this extra bit of test coverage does not seem worth it to me, and I sort of liked the separation how API tests can run in a multitude of configurations while a Shell test runs in one. I know that isn't really a good separation since "the way I write the tests" is in principle independent of "where I want to run it", but since the two tests use completely separate infrastructures, I think it would make sense to keep this functionality in just one of them.

That said I don't want to be only person blocking this, so I'd like to hear what others think as well. @JDevlieghere ?

I haven't opened an RFC since I thought it would be clearer to discuss that idea with the showcase of implementation. I'm open to moving a discussion there if it's considered as a better approach in this case (please let me know😅).

Maybe the best would be an RFC with a link to a POC, but now that we're here, I think we can stick with it and see how it goes.

@dzhidzhoev
Copy link
Member Author

Could you please give your opinion @JDevlieghere ?

@dzhidzhoev
Copy link
Member Author

Created RFC https://discourse.llvm.org/t/rfc-lldb-support-remote-run-of-shell-tests/80072, hope it fosters the discussion.

@dzhidzhoev
Copy link
Member Author

Updated:
Added documentation lines.
Added TEST_ prefix to cmake variables to indicate they doesn't affect lldb build (as proposed here https://discourse.llvm.org/t/rfc-lldb-support-remote-run-of-shell-tests/80072/5)
Shell tests remote execution can now be disabled with -DLLDB_SHELL_TESTS_DISABLE_REMOTE=On (they should attempt to execute locally this way).
To trigger remote execution, LLDB_TEST_PLATFORM_URL as well as LLDB_TEST_SYSROOT must be set.

@dzhidzhoev dzhidzhoev force-pushed the lldb/remote-shell branch 2 times, most recently from d21c76b to b747d2c Compare July 30, 2024 16:40
@dzhidzhoev
Copy link
Member Author

Update: fixed condition for remote execution.
Now this PR is ready for review.

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

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

I'm not sure whether we need LLDB_SHELL_TESTS_DISABLE_REMOTE, can you explain how that would be used?

Would I set up a build with all the other flags, do my remote testing, then set LLDB_SHELL_TESTS_DISABLE_REMOTE=OFF and run the shell tests locally, using that same build?

I guess I'm asking whether a given build should be all remote or all local or a mix.

@dzhidzhoev
Copy link
Member Author

I'm not sure whether we need LLDB_SHELL_TESTS_DISABLE_REMOTE, can you explain how that would be used?

Would I set up a build with all the other flags, do my remote testing, then set LLDB_SHELL_TESTS_DISABLE_REMOTE=OFF and run the shell tests locally, using that same build?

I guess I'm asking whether a given build should be all remote or all local or a mix.

I've added this flag to address the question raised about the support for different compilers.
We've discussed that we're going to support Shell tests execution only with Clang compiler to avoid the burden of maintaining too many build flag combinations.
However, for tests that use %build substitution, compiler detection is postponed to the test execution time (it happens in lldb/test/Shell/helper/build.py script itself), but it's necessary to know whether remote execution is on in advance (to disable local-only tests with UNSUPPORTED: remote-linux line).

Thus, I've added this flag to disable remote Shell tests execution if tests fail due to unsupported compiler usage. The idea is that if this flag is turned on, tests are run locally as it happens right now. So no "mixed" executions are desired. It should be either "remote execution against the remote target" or "best-effort local execution against the localhost target" (best-effort since if cross toolchain for cross-compilation/remote execution of API tests is built that doesn't support host target and Shell tests can't find another compiler, they fail on current mainline).

Also, I think --target= argument appended to %clang_host substitution should be changed to reflect that logic.

Copy link

github-actions bot commented Jul 31, 2024

✅ With the latest revision this PR passed the Python code formatter.

@DavidSpickett
Copy link
Collaborator

Ok I see what LLDB_SHELL_TESTS_DISABLE_REMOTE does but I don't get why. Perhaps you can show how a developer would:

  • Hit the problem that this option addresses
  • Apply the option
  • What problems it would solve and what that final build looks like
  • What the value of the results of that build are to the developer

I'm thinking that final build has unit and shell tests run locally, API tests run on the remote? I suppose we already support unit tests locally and API run remote, so this carries on that idea, but I've just never tried to do that because I'm generally x86 -> AArch64 where the cross compiler is never compatible.

@dzhidzhoev
Copy link
Member Author

Ok I see what LLDB_SHELL_TESTS_DISABLE_REMOTE does but I don't get why. Perhaps you can show how a developer would:

  • Hit the problem that this option addresses
  • Apply the option
  • What problems it would solve and what that final build looks like
  • What the value of the results of that build are to the developer

For example:

  1. A developer uses gcc to cross-compile lldb and run remote testing.
  2. API tests pass because Makefile.rules provides the ability to use different compilers/adjusts all necessary flags.
  3. Shell tests fail for some reason (--sysroot is not enough or not provided/some tests use clang-specific flags/etc). The developer thinks that it's sufficient for them to get away with Shell tests running only for the host platform.
  4. LLDB_SHELL_TESTS_DISABLE_REMOTE is set to on.
  5. Shell tests are compiled and run locally => tests are green.

@DavidSpickett
Copy link
Collaborator

DavidSpickett commented Aug 1, 2024

Ok, that seems reasonable. I'm still in a mode of thinking where a given build is all remote or all native. LLDB_SHELL_TESTS_DISABLE_REMOTE allows you to reuse all the settings you went to the trouble to set up, but on the host not the remote.

Though another way of thinking about it might be, I have a custom compiler setup but only intend to do host testing. This variable lets me tell the test runner not to assume I'm going to do any remote testing?

And if this compiler were the one from the toolchain you were going to ship, and include lldb with it, this lets you test host and remote then ship what you've tested, right? Instead of testing host with the system compiler and hoping nothing changes when you use the newly built cross compiler.

@dzhidzhoev
Copy link
Member Author

Though another way of thinking about it might be, I have a custom compiler setup but only intend to do host testing. This variable lets me tell the test runner not to assume I'm going to do any remote testing?

Yes, considering only Shell tests. By default, host testing is assumed. LLDB_TEST_PLATFORM_NAME/LLDB_TEST_PLATFORM_URL must be set to execute remote API&Shell testing. LLDB_SHELL_TESTS_DISABLE_REMOTE may be used to disable it for Shell tests.

And if this compiler were the one from the toolchain you were going to ship, and include lldb with it, this lets you test host and remote then ship what you've tested, right? Instead of testing host with the system compiler and hoping nothing changes when you use the newly built cross compiler.

Technically, yes. But I think Shell tests don't aim to test a cross-compiler. It's more like "if the cross-compiler is used, that is not compatible with Shell tests, we can run them only on the host to check at least the part of the functionality". It may make sense since only one-fifth of Shell tests run something remotely.

@DavidSpickett
Copy link
Collaborator

Looks good to me. @labath should give this another look as the biggest skeptic here :)

And @JDevlieghere who was also tagged earlier (start with the RFC though https://discourse.llvm.org/t/rfc-lldb-support-remote-run-of-shell-tests/80072).

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

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

Looks good to me. @labath should give this another look as the biggest skeptic here :)

My position remains unchanged. I don't think we should have this functionality. I'm not going to block you adding it either..

Comment on lines 240 to 243
"-L{}".format(config.libcxx_libs_dir),
"-Wl,-rpath,{}".format(config.libcxx_libs_dir),
"-lc++",
"-lc++abi",
Copy link
Collaborator

Choose a reason for hiding this comment

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

These flags don't seem very consistent. -rpath is only useful for dynamic links but I think you're using static links now. And since we removed -lc++abi (which is only needed for some static links) from the makefile, I don't think it should be used here as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

@labath
Copy link
Collaborator

labath commented Aug 5, 2024

Looks good to me. @labath should give this another look as the biggest skeptic here :)

My position remains unchanged. I don't think we should have this functionality. I'm not going to block you adding it either..

I was going to leave it at that, but seeing #101710, I have to add this as it illustrates my point brilliantly.

Overall, I am more worried about the reproducibility of lldb tests, then their universality. That bug shows we're not able to create a test for a very simple thing (an unaligned stack pointer) that works reliably for everyone. What makes us think we'll be able to do that for tests that execute remotely?

This is important as it slows down the velocity of all developers (old and new). In the end, that also reduces test coverage, because people will start to (even proactively) add REQUIRES: my-system to their tests to avoid breaking other people's CI. I believe that the loss of test coverage due to these proactive annotations is much bigger than anything that can be gained by running these tests remotely, and we'd be better off focusing on making Shell tests as hermetic/reproducible/etc. as possible rather making them generic so they can run remotely. For me, this just sends the wrong message/sets the wrong incentive.

@dzhidzhoev
Copy link
Member Author

dzhidzhoev commented Aug 22, 2024

That bug shows we're not able to create a test for a very simple thing (an unaligned stack pointer) that works reliably for everyone.

Honestly, based on #101710 (comment), I'd say that the mentioned test has a problem of too many redundant dependencies, rather than that it shows the backside of tests universality.

In the end, that also reduces test coverage, because people will start to (even proactively) add REQUIRES: my-system to their tests to avoid breaking other people's CI.

LLDB tests will still somehow depend on at least three targets in the foreseeable future (Linux/Windows/Darwin). If a test fails or is not supported on Linux target, it's unlikely that it will work on Linux target with remote debugging. So I don't see a perspective of having test coverage reduced because of UNSUPPORTED: remote- annotations if they appear.

This is important as it slows down the velocity of all developers (old and new).

I see a situation of a development velocity slowdown if a test the developer wrote is not supposed to work for remote debugging, but is missing a proper annotation for that. For other cases, remote debugging support is claimed as an LLDB feature. If tests are written/executed using the LLDB command line, remote execution shouldn't hinder their execution.

BTW, most of the cases where tests should've been disabled for remote debugging were the cases where platform mismatch happened. Tests were already disabled for "system-windows", but they were attempted to be run against Linux target. Probably, "system-X" semantics should be redefined to indicate a target platform instead of a host platform, or a feature like "target-system-xxx" should be introduced to show that a test should/shouldn't be run on a Windows/Darwin target regardless of the host. I think this will eliminate the need for UNSUPPORTED: remote- annotations for most of the cases.

Considering the complexity of setting up a remote debugging environment, public buildbots with it will be available https://discourse.llvm.org/t/rfc-lldb-support-remote-run-of-shell-tests/80072/4, https://lab.llvm.org/staging/#/builders/195.

Also, the case when no new features are added, but existing ones are changed, shouldn't be neglected. In such cases, it is hard to justify disabling tests without finding out the reason.

For me, this just sends the wrong message/sets the wrong incentive.

From my point of view, the current incentive given is that remote debugging compatibility may be ignored when new commits are made since it's something rare enough/hard to test properly (because testing with it requires writing an API test).
The ability to run Shell tests remotely (and regular testing) may reduce the barrier for those who want to take remote debugging into account in their patches.

@labath
Copy link
Collaborator

labath commented Sep 6, 2024

That bug shows we're not able to create a test for a very simple thing (an unaligned stack pointer) that works reliably for everyone.

Honestly, based on #101710 (comment), I'd say that the mentioned test has a problem of too many redundant dependencies, rather than that it shows the backside of tests universality.

I'm afraid I don't know what you mean by that. How would you go about removing those dependencies?

In the end, that also reduces test coverage, because people will start to (even proactively) add REQUIRES: my-system to their tests to avoid breaking other people's CI.

LLDB tests will still somehow depend on at least three targets in the foreseeable future (Linux/Windows/Darwin). If a test fails or is not supported on Linux target, it's unlikely that it will work on Linux target with remote debugging. So I don't see a perspective of having test coverage reduced because of UNSUPPORTED: remote- annotations if they appear.

This is important as it slows down the velocity of all developers (old and new).

I see a situation of a development velocity slowdown if a test the developer wrote is not supposed to work for remote debugging, but is missing a proper annotation for that. For other cases, remote debugging support is claimed as an LLDB feature. If tests are written/executed using the LLDB command line, remote execution shouldn't hinder their execution.

BTW, most of the cases where tests should've been disabled for remote debugging were the cases where platform mismatch happened. Tests were already disabled for "system-windows", but they were attempted to be run against Linux target. Probably, "system-X" semantics should be redefined to indicate a target platform instead of a host platform, or a feature like "target-system-xxx" should be introduced to show that a test should/shouldn't be run on a Windows/Darwin target regardless of the host. I think this will eliminate the need for UNSUPPORTED: remote- annotations for most of the cases.

Considering the complexity of setting up a remote debugging environment, public buildbots with it will be available https://discourse.llvm.org/t/rfc-lldb-support-remote-run-of-shell-tests/80072/4, https://lab.llvm.org/staging/#/builders/195.

Also, the case when no new features are added, but existing ones are changed, shouldn't be neglected. In such cases, it is hard to justify disabling tests without finding out the reason.

For me, this just sends the wrong message/sets the wrong incentive.

From my point of view, the current incentive given is that remote debugging compatibility may be ignored when new commits are made since it's something rare enough/hard to test properly (because testing with it requires writing an API test). The ability to run Shell tests remotely (and regular testing) may reduce the barrier for those who want to take remote debugging into account in their patches.

I think the main difference here is that you think of the Shell tests as kind of an end to end test which verifies that a certain (user-facing) debugger feature is works the way its supposed to. I don't. I think that's what the API tests are for. I think the Shell tests should verify that a specific piece of debugger code (which is most likely not directly accessible by the user) does what it is supposed to do. I.e., they're more akin to a unit test (which happens to be driven by shell commands).

If that sounds too abstract, let me give you an example. And ideal "end to end" test would be "this source code, compiled with the same compiler that the end user will use, running on a machine most similar to the one the user would use produces this debugger output". An ideal unit test would be "feeding these bytes (e.g. DWARF opcodes) into this function produces this result". The difference is that in the second case you want to make the test as specific as possible, whereas in the first one you want to make it as variable as possible (so that people can use the environment they care about).

This creates an inherent conflict. If you want the test to be runnable or useful remotely, it needs to be written in the first way. This means compiling for the target of the day, and doing while making sure you don't bake in any assumptions that are only true about the target you work on is very hard. That is what ends up creating REQUIRES clauses I was talking about. It's not that someone will write a test that doesn't run remotely (although that can happen too). It's that someone will write a test that only works on (e.g.) a mac (maybe local, maybe also remote), and then that test will get a REQUIRES: mac clause. Now, when I'm touching the related (or even unrelated code), I may break this test, but I'll have no way of knowing because I'm testing on linux. In the worst case I'll find out only after I submit the patch, in the best case, I'll after I copy my changes to a mac machine to test them out. In either case, it will slow my work down. That is the velocity I'm talking about and I think this is also the "wrong direction" that Jonas is talking about as well.

OTOH, if someone writes a test that verifies the operation of some feature on a mac even if the test runs on linux, then we can be all sure that the feature will stay working. Yes, this creates a risk that the feature will not work on linux (or maybe just remote linux?), but that's why we have API tests, which can verify that the most important features work in all configurations. And there's nothing stopping downstream for adding additional end-to-end tests (ones which might not even fit into the API test suite) for additional validation for the use cases they are supporting.

@dzhidzhoev
Copy link
Member Author

That bug shows we're not able to create a test for a very simple thing (an unaligned stack pointer) that works reliably for everyone.

Honestly, based on #101710 (comment), I'd say that the mentioned test has a problem of too many redundant dependencies, rather than that it shows the backside of tests universality.

I'm afraid I don't know what you mean by that. How would you go about removing those dependencies?

I think the dependency on clang/clang's default pipeline was excessive, considering that the biggest part of that test was written directly in x86 assembly. Probably, rewriting that test with yaml2obj would have been better #101710 (comment).

I think the main difference here is that you think of the Shell tests as kind of an end to end test which verifies that a certain (user-facing) debugger feature is works the way its supposed to. I don't. I think that's what the API tests are for. I think the Shell tests should verify that a specific piece of debugger code (which is most likely not directly accessible by the user) does what it is supposed to do. I.e., they're more akin to a unit test (which happens to be driven by shell commands).

I think of them as a simplified way of writing the same tests that could have been written with Python API. They are described as integration tests in the documentation https://lldb.llvm.org/resources/test.html#test-suite-structure. From my perspective, the difference between API and Shell tests lies in the tests' scenario complexity, not in test type (if we take aside command line-specific tests).

As far as I can see, both lldb/API and lldb/Shell directories have pretty generic/platform-dependent and specific/platform-independent tests.

dzhidzhoev and others added 8 commits September 25, 2024 16:34
1. This commit adds LLDB_TEST_PLATFORM_URL, LLDB_TEST_SYSROOT,
   LLDB_TEST_PLATFORM_WORKING_DIR, LLDB_SHELL_TESTS_DISABLE_REMOTE cmake flags
   to pass arguments for cross-compilation and remote running of both Shell&API
   tests.
2. To run Shell tests remotely, it adds 'platform select' and 'platform connect' commands to %lldb
   substitution.
3. 'remote-linux' feature added to lit to disable tests failing with remote execution.
4. A separate working directory is assigned to each test to avoid
   conflicts during parallel test execution.
5. Remote Shell testing is run only when LLDB_TEST_SYSROOT is set for
   building test sources. Recommended compiler for that is Clang.
@dzhidzhoev
Copy link
Member Author

Rebased & added a line to documentation about the usage of API tests for remote testing.

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

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

LGTM.

Maybe @labath would like to take a last look at it before it lands.

@dzhidzhoev
Copy link
Member Author

LGTM.

Maybe @labath would like to take a last look at it before it lands.

I assume there are no more comments, so I'll merge it. I'm open for further corrections.

@dzhidzhoev dzhidzhoev merged commit 32e90bb into llvm:main Oct 7, 2024
8 checks passed
dzhidzhoev added a commit to dzhidzhoev/llvm-zorg that referenced this pull request Oct 8, 2024
…buntu" builder

dotest.py flags replaced with CMake flags introduced in
llvm/llvm-project#95986 to run Shell tests remotely.

Also, USE_LLVM_TOOLS is removed since it's implied by default that LLVM
tools will be used for API tests since llvm/llvm-project#109961.
dzhidzhoev added a commit to llvm/llvm-zorg that referenced this pull request Oct 9, 2024
…buntu" builder (#270)

dotest.py flags are replaced with CMake flags introduced in
llvm/llvm-project#95986 to run Shell tests
remotely.

Also, USE_LLVM_TOOLS is removed since it's implied by default that LLVM
tools will be used for API tests since
llvm/llvm-project#109961.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants