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

Add relative file support to emduk using NODEFS #355

Merged
merged 2 commits into from
Sep 17, 2015
Merged

Conversation

svaarala
Copy link
Owner

Relative file support allows command line running e.g.:

$ make emduk
$ ./emduk tests/ecmascript/test-dev-mandel2-func.js

without resorting to stdin tricks. This is enough to get a performance/testcase baseline for Duktape-on-Emscripten (executed using Node.js).

Tasks:

  • Finalize emduk NODEFS usage, try to get absolute paths working
  • Hack for emduk trailing line (0x20 0x0a) to runtests to allow testcase runs
  • Run a performance test set to get a baseline from master
  • Run qecmatest baseline from master

@svaarala svaarala added this to the v1.4.0 milestone Sep 15, 2015
@svaarala
Copy link
Owner Author

Relative paths only are not sufficient to get runtests.js runs working so supporting at least /tmp paths would be nice.

@svaarala
Copy link
Owner Author

Mapping virtual / to host / seems not to be supported at the moment:

@svaarala
Copy link
Owner Author

Relative paths and /tmp/xxx paths now work by:

  • Mounting virtual /working as host ., and prepending /working/ to relative paths in duk_cmdline.c
  • Mounting virtual /tmp as host /tmp

These two are enough for performance testing and using runtests.js which relies on /tmp now.

@svaarala svaarala force-pushed the add-emduk-nodefs branch 2 times, most recently from e9e7666 to 32ac5e0 Compare September 16, 2015 20:09
@fatcerberus
Copy link
Contributor

I wonder if this would allow the tests to work on Cygwin now. Last time I couldn't get it to run under Cygwin, presumably because the Windows version of Node doesn't like absolute Unix paths such as /tmp.

@svaarala
Copy link
Owner Author

I think the better fix for that would be for runtests.js to use a platform aware temporary file mechanism, that should be quite easy.

But I have to say I'm not very excited about extending/maintaining runtests.js - it's not very good and will be replaced anyway by a client-server runner which will support multiple test target platforms (which is something quite important missing right now).

@svaarala
Copy link
Owner Author

Results from a make qecmatest using emduk:

                          test-bi-array-proto-push: fail; 30 diff lines; known issue: array length above 2^32-1 not supported
                         test-bi-array-push-maxlen: fail; 17 diff lines; known issue: array length above 2^32-1 not supported
                   test-bi-arraybuffer-constructor: fail; 12 diff lines
                    test-bi-date-tzoffset-brute-fi: fail; 394 diff lines; known issue: year 1970 deviates from expected, Duktape uses equiv. year for 1970 on purpose at the moment; requires special feature options: test case has been written for Finnish locale
               test-bi-function-nonstd-caller-prop: fail; 178 diff lines; requires special feature options: DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY
                       test-bi-global-parseint-oct: fail; 20 diff lines; known issue: non-standard octal behavior does not match V8/Rhino
                           test-bi-global-parseint: fail; 89 diff lines; known issue: rounding differences for parsing integers larger than 2^53
                                test-bi-global-uri: fail; 46 diff lines
                          test-bi-json-dec-clipped: fail; 24 diff lines
                            test-bi-json-dec-types: fail; 21 diff lines; known issue: '\x' should be allowed by eval() but not by JSON.parse(), Duktape rejects '\x' in both
                    test-bi-json-enc-proplist-dups: fail; 8 diff lines; known issue: JSON.stringify() can be given a property list to serialize; duplicates should be eliminated but Duktape (and other engines) will happily serialize a property multiple times
                         test-bi-json-enc-reclimit: fail; 16 diff lines
                 test-bi-nodejs-buffer-constructor: fail; 95 diff lines
                test-bi-number-proto-toexponential: fail; 75 diff lines; known issue: corner case rounding errors in toExponential()
                     test-bi-number-proto-tostring: fail; 46 diff lines; known issue: expect strings to be checked, but probably Duktape rounding issues
                test-bi-object-defineproperty-comb: fail; 11997 diff lines
                               test-bi-regexp-gh39: fail; 5 diff lines; known issue: requires leniency for non-standard regexps
             test-bi-typedarray-proto-set-overflow: fail; 7 diff lines
                     test-bug-dataview-buffer-prop: fail; 20 diff lines; known issue: DataView .buffer property misleading when DataView argument is not an ArrayBuffer (custom behavior)
                test-bug-enum-shadow-nonenumerable: fail; 12 diff lines; known issue: corner case enumeration semantics, not sure what correct behavior is (test262 ch12/12.6/12.6.4/12.6.4-2)
                       test-bug-invalid-oct-as-dec: fail; 14 diff lines; known issue: V8/Rhino parse invalid octal constants as decimal values, Duktape doesn't at the moment
                     test-bug-json-parse-__proto__: fail; 18 diff lines; known issue: when ES6 __proto__ enabled, JSON.parse() parses '__proto__' property incorrectly when a specially crafted reviver is used
                             test-bug-numconv-1e23: fail; 10 diff lines; known issue: corner case in floating point parse rounding
                    test-bug-numconv-denorm-toprec: fail; 7 diff lines; known issue: in a denormal corner case toPrecision() can output a zero leading digit
                           test-bug-tonumber-u0000: fail; 7 diff lines; known issue: '\u0000' should ToNumber() coerce to NaN, but now coerces to zero like an empty string
       test-commonjs-require-resolution-randomized: fail; 16 diff lines
                  test-dev-bound-thread-start-func: fail; 13 diff lines; known issue: initial function of a new coroutine cannot be bound
                       test-dev-compiler-reclimit1: fail; 10 diff lines
                       test-dev-compiler-reclimit2: fail; 12 diff lines
                     test-dev-cont-native-reclimit: fail; 6 diff lines
                        test-dev-deep-func-nesting: fail; 5 diff lines
                            test-dev-fastint-basic: fail; 955 diff lines; requires special feature options: requires DUK_OPT_FASTINT
                           test-dev-func-cons-args: fail; 18 diff lines; known issue: corner cases for 'new Function()' when arguments and code are given as strings
                       test-dev-lightfunc-accessor: fail; 50 diff lines; requires special feature options: DUK_OPT_LIGHTFUNC_BUILTINS
                      test-dev-lightfunc-finalizer: fail; 8 diff lines; requires special feature options: DUK_OPT_LIGHTFUNC_BUILTINS
                                test-dev-lightfunc: fail; 462 diff lines; requires special feature options: DUK_OPT_LIGHTFUNC_BUILTINS
                        test-dev-propaccess-random: fail; 11 diff lines
                           test-dev-tail-recursion: fail; 8 diff lines; comment: breaks with DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY
                    test-dev-yield-after-callapply: fail; 8 diff lines; known issue: yield() not allowed when function called via Function.prototype.(call|apply)()
              test-lex-unterminated-hex-uni-escape: fail; 29 diff lines; known issue: unterminated hex escapes should be parsed leniently, e.g. '\uX' -> 'uX' but Duktape now refuses to parse them
                       test-misc-large-expressions: fail; 24 diff lines
                      test-misc-many-temporaries-1: fail; 5 diff lines
                      test-misc-many-temporaries-2: fail; 5 diff lines
                           test-numconv-parse-misc: fail; 12 diff lines; known issue: rounding corner case for 1e+23 (parses/prints as 1.0000000000000001e+23)
                         test-numconv-tostring-gen: fail; 257 diff lines; known issue: rounding corner cases in number-to-string coercion
                        test-numconv-tostring-misc: fail; 6 diff lines; known issue: rounding corner case, 1e+23 string coerces to 1.0000000000000001e+23
                     test-regexp-compiler-reclimit: fail; 9 diff lines
                      test-regexp-empty-quantified: fail; 15 diff lines; known issue: a suitable empty quantified (e.g. '(x*)*') causes regexp parsing to terminate due to step limit
                     test-regexp-executor-reclimit: fail; 9 diff lines
                    test-regexp-executor-steplimit: fail; 8 diff lines
                     test-regexp-invalid-charclass: fail; 7 diff lines; known issue: some invalid character classes are accepted (e.g. '[\d-z]' and '[z-x]')
               test-regexp-nonstandard-patternchar: fail; 6 diff lines; known issue: other engines allow an unescaped brace to appear literally (e.g. /{/), Duktape does not (which seems correct but is against real world behavior)
                              test-stmt-for-in-lhs: fail; 29 diff lines; known issue: for-in allows some invalid left-hand-side expressions which cause a runtime ReferenceError instead of a compile-time SyntaxError (e.g. 'for (a+b in [0,1]) {...}')

SUMMARY: 706 pass, 53 fail

@svaarala
Copy link
Owner Author

Need to sort through the failed cases; looking quickly some of them are at least just V8 recursion limits, e.g.:

exception thrown: RangeError: Maximum call stack size exceeded,RangeError: Maximum call stack size exceeded
    at Kh (/home/duktape/duktape/emduk.js:11:45755)
    at ni (/home/duktape/duktape/emduk.js:11:109896)
    at Ai (/home/duktape/duktape/emduk.js:9:69784)
    at Ai (/home/duktape/duktape/emduk.js:9:83402)
    at Ai (/home/duktape/duktape/emduk.js:9:73998)
    at Ai (/home/duktape/duktape/emduk.js:9:83402)
    at Ai (/home/duktape/duktape/emduk.js:9:73998)
    at Ai (/home/duktape/duktape/emduk.js:9:83402)
    at Ai (/home/duktape/duktape/emduk.js:9:73998)
    at Ai (/home/duktape/duktape/emduk.js:9:83402)
/home/duktape/duktape/emduk.js:1
aughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Mod

@svaarala
Copy link
Owner Author

Here's the performance test from master before merging in longjmp-free RETURN support:

test-array-read.js            : duk.O2  4.93 emduk.O2 138.74
test-array-write.js           : duk.O2  5.23 emduk.O2 134.94
test-bitwise-ops.js           : duk.O2  0.98 emduk.O2 132.71
test-buffer-nodejs-read.js    : duk.O2  5.29 emduk.O2 135.19
test-buffer-nodejs-write.js   : duk.O2  6.55 emduk.O2 150.88
test-buffer-object-read.js    : duk.O2  5.23 emduk.O2 132.34
test-buffer-object-write.js   : duk.O2  6.35 emduk.O2 146.44
test-buffer-plain-read.js     : duk.O2  4.64 emduk.O2 123.93
test-buffer-plain-write.js    : duk.O2  4.42 emduk.O2 140.27
test-call-basic.js            : duk.O2 13.19 emduk.O2 250.96
test-compile-mandel-nofrac.js : duk.O2 14.31 emduk.O2 60.00
test-compile-mandel.js        : duk.O2 17.14 emduk.O2 76.82
test-compile-short.js         : duk.O2 10.38 emduk.O2 66.68
test-const-load.js            : duk.O2  8.15 emduk.O2 260.40
test-empty-loop.js            : duk.O2  3.20 emduk.O2 110.07
test-fib.js                   : duk.O2 11.08 emduk.O2 128.39
test-global-lookup.js         : duk.O2 16.13 emduk.O2 100.96
test-hello-world.js           : duk.O2  0.00 emduk.O2  0.55
test-hex-decode.js            : duk.O2  6.32 emduk.O2 16.48
test-hex-encode.js            : duk.O2 36.98 emduk.O2 68.71
test-json-integer-parse.js    : duk.O2  0.42 emduk.O2  3.46
test-json-number-parse.js     : duk.O2  5.28 emduk.O2 34.02
test-json-serialize.js        : duk.O2  1.62 emduk.O2 22.60
test-json-string-bench.js     : duk.O2  5.81 emduk.O2 46.89
test-json-string-parse.js     : duk.O2  0.52 emduk.O2  2.98
test-json-string-stringify.js : duk.O2  1.38 emduk.O2  3.56
test-prop-read.js             : duk.O2  8.82 emduk.O2 162.58
test-prop-write.js            : duk.O2  7.89 emduk.O2 147.66
test-reg-load.js              : duk.O2  3.58 emduk.O2 120.10
test-reg-readwrite-object.js  : duk.O2  4.03 emduk.O2 145.52
test-reg-readwrite-plain.js   : duk.O2  3.25 emduk.O2 109.96
test-regexp-string-parse.js   : duk.O2 11.11 emduk.O2 42.66
test-string-array-concat.js   : duk.O2  7.27 emduk.O2 93.89
test-string-compare.js        : duk.O2  4.30 emduk.O2 110.76
test-string-decodeuri.js      : duk.O2  3.65 emduk.O2 12.29
test-string-encodeuri.js      : duk.O2  4.50 emduk.O2 13.29
test-string-intern-match.js   : duk.O2  2.47 emduk.O2 10.30
test-string-intern-miss.js    : duk.O2  2.63 emduk.O2 15.67
test-string-plain-concat.js   : duk.O2  4.22 emduk.O2 12.00
test-string-uppercase.js      : duk.O2  2.54 emduk.O2 10.32

@svaarala
Copy link
Owner Author

A few notes on the performance:

  • Operations which are mostly native in Duktape run with a slowdown of around 3-5x. For example, uppercasing a string is 2.54s normally, and 10.32s with Emscripten+Node.js. As far as I know this is a quite typical slowdown.
  • Operations which are bytecode dispatch heavy have a slowdown of roughly 30x.

So, the relative slowdown (compared to equivalent native) for bytecode dispatch is larger than for other native code. Not sure yet what causes that, but two possible issues are:

  • Tagged value union handling might translate to awkward code during Emscripten compilation. To test this theory, I used a hack branch where the union inside duk_tval was changed into a struct instead (with all compatible pointers stored as void *). This didn't improve Emscripten performance so this doesn't look likely.
  • Bytecode executor dispatch uses two large switch statements (one for main opcode and another for extra opcode). These may either (a) compile poorly in Emscripten, e.g. into an if-else ladder, or (b) compile into a JS switch but then execute poorly in e.g. V8.

Regarding the switch:

Trailing line contains a space and a newline (0x20 0x0a), add a hack
runtests option to strip that.
svaarala added a commit that referenced this pull request Sep 17, 2015
Add relative file support to emduk using NODEFS
@svaarala svaarala merged commit e19dec5 into master Sep 17, 2015
@svaarala svaarala deleted the add-emduk-nodefs branch September 17, 2015 09:39
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.

2 participants