diff options
author | Christopher Haster <chaster@utexas.edu> | 2020-01-03 03:36:53 +0300 |
---|---|---|
committer | Christopher Haster <chaster@utexas.edu> | 2020-01-03 03:36:53 +0300 |
commit | eeaf536ecabbc9a3813d068e367dbe7897e60bcf (patch) | |
tree | d856ea9ba7b0cae5b0601462a225e961a77e466f /scripts | |
parent | 53d2b02f2a113326611b24c069d6098e9cdf53c4 (diff) |
Replaced emubd with rambd and filebd
The idea behind emubd (file per block), was neat, but doesn't add much
value over a block device that just operates on a single linear file
(other than adding a significant amount of overhead). Initially it
helped with debugging, but when the metadata format became more complex
in v2, most debugging ends up going through the debug.py script anyways.
Aside from being simpler, moving to filebd means it is also possible to
mount disk images directly.
Also introduced rambd, which keeps the disk contents in RAM. This is
very useful for testing where it increases the speed _significantly_.
- test_dirs w/ filebd - 0m7.170s
- test_dirs w/ rambd - 0m0.966s
These follow the emubd model of using the lfs_config for geometry. I'm
not convinced this is the best approach, but it gets the job done.
I've also added lfs_ramdb_createcfg to add additional config similar to
lfs_file_opencfg. This is useful for specifying erase_value, which tells
the block device to simulate erases similar to flash devices. Note that
the default (-1) meets the minimum block device requirements and is the
most performant.
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/test_.py | 101 |
1 files changed, 67 insertions, 34 deletions
diff --git a/scripts/test_.py b/scripts/test_.py index 5a481e4..27002d9 100755 --- a/scripts/test_.py +++ b/scripts/test_.py @@ -15,7 +15,6 @@ import subprocess as sp import base64 import sys import copy -import shutil import shlex TESTDIR = 'tests_' @@ -40,8 +39,10 @@ $(foreach target,$(SRC),$(eval $(FLATTEN))) GLOBALS = """ //////////////// AUTOGENERATED TEST //////////////// #include "lfs.h" -#include "emubd/lfs_emubd.h" +#include "filebd/lfs_filebd.h" +#include "rambd/lfs_rambd.h" #include <stdio.h> +const char *LFS_DISK = NULL; """ DEFINES = { "LFS_READ_SIZE": 16, @@ -51,23 +52,25 @@ DEFINES = { "LFS_BLOCK_CYCLES": 1024, "LFS_CACHE_SIZE": "(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)", "LFS_LOOKAHEAD_SIZE": 16, + "LFS_ERASE_VALUE": 0xff, } PROLOGUE = """ // prologue __attribute__((unused)) lfs_t lfs; - __attribute__((unused)) lfs_emubd_t bd; + __attribute__((unused)) lfs_filebd_t filebd; + __attribute__((unused)) lfs_rambd_t rambd; __attribute__((unused)) lfs_file_t file; __attribute__((unused)) lfs_dir_t dir; __attribute__((unused)) struct lfs_info info; __attribute__((unused)) uint8_t buffer[1024]; __attribute__((unused)) char path[1024]; - + __attribute__((unused)) const struct lfs_config cfg = { - .context = &bd, - .read = &lfs_emubd_read, - .prog = &lfs_emubd_prog, - .erase = &lfs_emubd_erase, - .sync = &lfs_emubd_sync, + .context = LFS_DISK ? (void*)&filebd : (void*)&rambd, + .read = LFS_DISK ? &lfs_filebd_read : &lfs_rambd_read, + .prog = LFS_DISK ? &lfs_filebd_prog : &lfs_rambd_prog, + .erase = LFS_DISK ? &lfs_filebd_erase : &lfs_rambd_erase, + .sync = LFS_DISK ? &lfs_filebd_sync : &lfs_rambd_sync, .read_size = LFS_READ_SIZE, .prog_size = LFS_PROG_SIZE, @@ -78,11 +81,26 @@ PROLOGUE = """ .lookahead_size = LFS_LOOKAHEAD_SIZE, }; - lfs_emubd_create(&cfg, "blocks"); + __attribute__((unused)) const struct lfs_filebd_config filecfg = { + .erase_value = LFS_ERASE_VALUE, + }; + __attribute__((unused)) const struct lfs_rambd_config ramcfg = { + .erase_value = LFS_ERASE_VALUE, + }; + + if (LFS_DISK) { + lfs_filebd_createcfg(&cfg, LFS_DISK, &filecfg); + } else { + lfs_rambd_createcfg(&cfg, &ramcfg); + } """ EPILOGUE = """ // epilogue - lfs_emubd_destroy(&cfg); + if (LFS_DISK) { + lfs_filebd_destroy(&cfg); + } else { + lfs_rambd_destroy(&cfg); + } """ PASS = '\033[32m✓\033[0m' FAIL = '\033[31m✗\033[0m' @@ -133,7 +151,8 @@ class TestCase: f.write(') {\n') for k, v in sorted(self.defines.items()): - f.write(4*' '+'#define %s %s\n' % (k, v)) + if k not in self.suite.defines: + f.write(4*' '+'#define %s %s\n' % (k, v)) f.write(PROLOGUE) f.write('\n') @@ -148,27 +167,34 @@ class TestCase: f.write('\n') for k, v in sorted(self.defines.items()): - f.write(4*' '+'#undef %s\n' % k) + if k not in self.suite.defines: + f.write(4*' '+'#undef %s\n' % k) f.write('}\n') def test(self, exec=[], persist=False, gdb=False, failure=None, **args): - # clear disk first - if not persist: - shutil.rmtree('blocks', True) - # build command cmd = exec + ['./%s.test' % self.suite.path, repr(self.caseno), repr(self.permno)] + if persist: + cmd.append(self.suite.path + '.test.disk') # failed? drop into debugger? if gdb and failure: - cmd = (['gdb', '-ex', 'r' - ] + (['-ex', 'up'] if failure.assert_ else []) + [ - '--args'] + cmd) + ncmd = ['gdb'] + if gdb == 'assert': + ncmd.extend(['-ex', 'r']) + if failure.assert_: + ncmd.extend(['-ex', 'up']) + elif gdb == 'start': + ncmd.extend([ + '-ex', 'b %s:%d' % (self.suite.path, self.lineno), + '-ex', 'r']) + ncmd.extend(['--args'] + cmd) + if args.get('verbose', False): - print(' '.join(shlex.quote(c) for c in cmd)) - sys.exit(sp.call(cmd)) + print(' '.join(shlex.quote(c) for c in ncmd)) + sys.exit(sp.call(ncmd)) # run test case! stdout = [] @@ -231,22 +257,27 @@ class ReentrantTestCase(TestCase): if not self.reentrant: return - for cycles in it.count(1): - npersist = persist or cycles > 1 + # clear disk first? + if not persist: + try: + os.remove(self.suite.path + '.test.disk') + except FileNotFoundError: + pass + for cycles in it.count(1): # exact cycle we should drop into debugger? if gdb and failure and failure.cycleno == cycles: - return super().test(exec=exec, persist=npersist, + return super().test(exec=exec, persist=True, gdb=gdb, failure=failure, **args) - # run tests, but kill the program after lfs_emubd_prog/erase has + # run tests, but kill the program after prog/erase has # been hit n cycles. We exit with a special return code if the # program has not finished, since this isn't a test failure. nexec = exec + [ 'gdb', '-batch-silent', '-ex', 'handle all nostop', - '-ex', 'b lfs_emubd_prog', - '-ex', 'b lfs_emubd_erase', + '-ex', 'b lfs_filebd_prog', + '-ex', 'b lfs_filebd_erase', '-ex', 'r', ] + cycles*['-ex', 'c'] + [ '-ex', 'q ' @@ -255,7 +286,7 @@ class ReentrantTestCase(TestCase): '33', '--args'] try: - return super().test(exec=nexec, persist=npersist, **args) + return super().test(exec=nexec, persist=True, **args) except TestFailure as nfailure: if nfailure.returncode == 33: continue @@ -370,10 +401,11 @@ class TestSuite: f.write('\n') f.write('int main(int argc, char **argv) {\n') - f.write(4*' '+'int case_ = (argc == 3) ? atoi(argv[1]) : 0;\n') - f.write(4*' '+'int perm = (argc == 3) ? atoi(argv[2]) : 0;\n') + f.write(4*' '+'int case_ = (argc >= 3) ? atoi(argv[1]) : 0;\n') + f.write(4*' '+'int perm = (argc >= 3) ? atoi(argv[2]) : 0;\n') + f.write(4*' '+'LFS_DISK = (argc >= 4) ? argv[3] : NULL;\n') for perm in self.perms: - f.write(4*' '+'if (argc != 3 || ' + f.write(4*' '+'if (argc < 3 || ' '(case_ == %d && perm == %d)) { ' % ( perm.caseno, perm.permno)) f.write('test_case%d(' % perm.caseno) @@ -590,8 +622,9 @@ if __name__ == "__main__": help="Run all tests instead of stopping on first error. Useful for CI.") parser.add_argument('-p', '--persist', action='store_true', help="Don't reset the tests disk before each test.") - parser.add_argument('-g', '--gdb', action='store_true', - help="Drop into gdb on failure.") + parser.add_argument('-g', '--gdb', choices=['init', 'start', 'assert'], + nargs='?', const='assert', + help="Drop into gdb on test failure.") parser.add_argument('--valgrind', action='store_true', help="Run non-leaky tests under valgrind to check for memory leaks.") parser.add_argument('--reentrant', action='store_true', |