From 533930e57db4b9741130735b6849c338f0adfbfd Mon Sep 17 00:00:00 2001 From: Paran Lee Date: Sun, 29 Oct 2023 12:16:14 +0900 Subject: [PATCH] [PATCH] tests: Add Rust basic testcase Add Rust-lang abc test for rust supports. Signed-off-by: Michelle Jin Co-authored-by: Paran Lee --- README.md | 2 +- tests/r001_basic.py | 56 ++++++++++++++++++++++++++++++++++ tests/runtest.py | 74 +++++++++++++++++++++++++++++++++++++++++++++ tests/s-abc.rs | 18 +++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 tests/r001_basic.py create mode 100644 tests/s-abc.rs diff --git a/README.md b/README.md index 86833c662..cbd11b7ba 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Features uftrace traces each function in the executable and shows time durations. Usually, for this to be possible, the program needs to be compiled with -`-pg` or `-fpatchable-function-entry=5` (`=2` is enough on aarch64). +`-pg` or `-fpatchable-function-entry=5` (`=2` is enough on aarch64 and riscv64). With full dynamic tracing (`-P.`|`--patch=.`), uftrace works on all executables (as long they are not stripped, or symbol information is available from a separate file). diff --git a/tests/r001_basic.py b/tests/r001_basic.py new file mode 100644 index 000000000..4287bb9e9 --- /dev/null +++ b/tests/r001_basic.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +from runtest import RustTestBase + +class TestCase(RustTestBase): + def __init__(self): + RustTestBase.__init__(self, 'abc', """ +# DURATION TID FUNCTION + 1.852 us [1008471] | getauxval(); + 0.204 us [1008471] | getauxval(); + 0.203 us [1008471] | getauxval(); + [1008471] | std::rt::lang_start() { + 14.260 us [1008471] | poll(); + 5.056 us [1008471] | signal(); + 2.759 us [1008471] | sigaction(); + 2.426 us [1008471] | sigaction(); + 2.537 us [1008471] | sigaction(); + 2.722 us [1008471] | sigaltstack(); + 0.408 us [1008471] | sysconf(); + 13.907 us [1008471] | mmap64(); + 0.260 us [1008471] | sysconf(); + 26.444 us [1008471] | mprotect(); + 0.296 us [1008471] | sysconf(); + 2.019 us [1008471] | sigaltstack(); + 0.185 us [1008471] | sysconf(); + 0.278 us [1008471] | pthread_self(); + 618.405 us [1008471] | pthread_getattr_np(); + 0.389 us [1008471] | pthread_attr_getstack(); + 0.371 us [1008471] | pthread_attr_destroy(); + 0.166 us [1008471] | malloc(); + 0.389 us [1008471] | malloc(); + 4.241 us [1008471] | __cxa_thread_atexit_impl(); + [1008471] | std::rt::lang_start::_{{closure}}() { + [1008471] | std::sys_common::backtrace::__rust_begin_short_backtrace() { + [1008471] | core::ops::function::FnOnce::call_once() { + [1008471] | s_abc::main() { + [1008471] | s_abc::a() { + [1008471] | s_abc::b() { + [1008471] | s_abc::c() { + 2.389 us [1008471] | getpid(); + 4.630 us [1008471] | } /* s_abc::c */ + 5.148 us [1008471] | } /* s_abc::b */ + 5.500 us [1008471] | } /* s_abc::a */ + 5.889 us [1008471] | } /* s_abc::main */ + 6.426 us [1008471] | } /* core::ops::function::FnOnce::call_once */ + 6.908 us [1008471] | } /* std::sys_common::backtrace::__rust_begin_short_backtrace */ + 0.111 us [1008471] | _<()>::report(); + 8.037 us [1008471] | } /* std::rt::lang_start::_{{closure}} */ + 2.408 us [1008471] | sigaltstack(); + 0.259 us [1008471] | sysconf(); + 0.167 us [1008471] | sysconf(); + 41.648 us [1008471] | munmap(); + 780.960 us [1008471] | } /* std::rt::lang_start */ + 0.259 us [1008471] | free(); + 0.166 us [1008471] | free(); +""") \ No newline at end of file diff --git a/tests/runtest.py b/tests/runtest.py index 6460fc9df..b687d622d 100755 --- a/tests/runtest.py +++ b/tests/runtest.py @@ -69,6 +69,8 @@ class TestBase: supported_lang = { 'C': { 'cc': 'gcc', 'flags': 'CFLAGS', 'ext': '.c' }, 'C++': { 'cc': 'g++', 'flags': 'CXXFLAGS', 'ext': '.cpp' }, + # https://github.com/emosenkis/esp-rs/issues/10 + 'Rust': { 'cc': 'rustc', 'flags': "+nightly -Z instrument-mcount", 'ext': '.rs' }, } TEST_SUCCESS = 0 @@ -573,6 +575,8 @@ def prerun(self, timeout): self.exearg = 't-' + self.name if self.lang == 'Python': self.exearg = TestBase.srcdir + '/tests/' + 's-' + self.name + '.py' + elif self.lang == 'Rust': + self.exearg = TestBase.srcdir + '/tests/' + 's-' + self.name cmd = self.prepare() if cmd == '': @@ -714,6 +718,22 @@ def __init__(self, name, result, lang='Python', cflags='', ldflags='', sort='sim if orig_path != "": os.environ["PYTHONPATH"] += ':' + orig_path +class RustTestBase(TestBase): + def __init__(self, name, result, lang='Rust', cflags='', ldflags='', sort='simple', serial=False): + TestBase.__init__(self, name, result, lang, cflags, ldflags, sort, serial) + + def build(self, name, rflags='', ldflags=''): + + prog = 's-' + name + src = 's-' + name + ".rs" + rflags = self.supported_lang['Rust']['flags'] + + build_cmd = '%s %s %s' % \ + ('rustc', rflags, src) + + self.pr_debug("build command: %s" % build_cmd) + return self.build_it(build_cmd) + RED = '\033[1;31m' GREEN = '\033[1;32m' YELLOW = '\033[1;33m' @@ -780,6 +800,19 @@ def run_python_case(T, case, timeout): ret = tc.postrun(ret) return (ret, dif) +def run_rust_case(T, case, timeout): + tc = T.TestCase() + tc.set_debug(arg.debug) + tc.set_keep(arg.keep) + + ret = tc.build(tc.name, "") + ret = tc.prerun(timeout) + dif = '' + if ret == TestBase.TEST_SUCCESS: + ret, dif = tc.run(case, "", arg.diff, timeout) + ret = tc.postrun(ret) + return (ret, dif) + def run_single_case(case, flags, opts, arg, compilers): result = [] timeout = int(arg.timeout) @@ -795,6 +828,11 @@ def run_single_case(case, flags, opts, arg, compilers): result.append((ret, dif)) continue + if compiler == 'rustc': + ret, dif = run_rust_case(T, case, timeout) + result.append((ret, dif)) + continue + for flag in flags: for opt in opts: tc = T.TestCase() @@ -910,6 +948,30 @@ def print_python_test_header(ftests): ftests.write(header2 + '\n') ftests.flush() +def print_rust_test_header(flags, ftests, compilers): + header1 = '%-24s ' % 'Compiler' + header2 = '%-24s ' % 'Runtime test case' + header3 = '-' * 24 + ':' + empty = ' ' * 100 + + for i, compiler in enumerate(compilers): + if i != 0: + header1 += ' ' + header2 += ' ' + header3 += ' ' + for flag in flags: + # align with optimization flags + header2 += ' ' + flag + header1 += ' ' + compiler + + print("") + print(header1) + print(header2) + print(header3) + ftests.write(header1 + '\n') + ftests.write(header2 + '\n') + ftests.write(header3 + '\n') + ftests.flush() def print_test_report(color, shared): success = shared.stats[TestBase.TEST_SUCCESS] + shared.stats[TestBase.TEST_SUCCESS_FIXED] @@ -962,6 +1024,8 @@ def parse_argument(): help="Hide normal results and print only abnormal results.") parser.add_argument("-P", "--python", dest='python', action='store_true', help="Run python test cases instead") + parser.add_argument("-R", "--rust", dest='rust', action='store_true', + help="Run rust test cases instead") return parser.parse_args() @@ -976,6 +1040,8 @@ def parse_argument(): if arg.cases == 'all': if arg.python: testcases = glob.glob('p???_*.py') + elif arg.rust: + testcases = glob.glob('r???_*.py') else: testcases = glob.glob('t???_*.py') else: @@ -984,6 +1050,8 @@ def parse_argument(): for case in cases: if arg.python: testcases.extend(glob.glob('p*' + case + '*.py')) + elif arg.rust: + testcases.extend(glob.glob('r*' + case + '*.py')) else: testcases.extend(glob.glob('t*' + case + '*.py')) arg.worker = min(arg.worker, len(testcases)) @@ -1000,6 +1068,7 @@ def parse_argument(): patch_size = { 'x86_64' : 5, 'aarch64' : 2, + 'riscv' : 2, } m = os.uname()[-1] # machine @@ -1029,6 +1098,9 @@ def has_compiler(compiler): compilers = [] if arg.python: compilers.append('python') + elif arg.rust: + if has_compiler('rustc') and os.system('rustup default nightly > /dev/null') == 0: + compilers.append('rustc') elif arg.compiler == 'all': for compiler in ['gcc', 'clang']: if has_compiler(compiler): @@ -1083,6 +1155,8 @@ class dotdict(dict): if arg.python: print_python_test_header(ftests) + elif arg.rust: + print_rust_test_header(flags, ftests, ['rustc']) else: print_test_header(opts, flags, ftests, compilers) diff --git a/tests/s-abc.rs b/tests/s-abc.rs new file mode 100644 index 000000000..6df71d7bd --- /dev/null +++ b/tests/s-abc.rs @@ -0,0 +1,18 @@ +use std::process; + +fn a() -> u32 { + return b(); +} + +fn b() -> u32 { + return c(); +} + +fn c() -> u32 { + return process::id(); +} + +fn main() { + // println!("Result: {}", a()); + a(); +} \ No newline at end of file