-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Process tests sometimes cause timeout on Linux #1
Comments
This comment was originally written by [email protected] Hanging stack trace: #0 0xf77c0430 in __kernel_vsyscall () We're calling unsafe functions (delete/free) in the SIGCHLD handler, deadlocking glibc's allocator. |
This was fixed in https://code.google.com/p/dart/source/detail?r=325. Added Fixed label. |
During my work on dart-lang/language#3648, I ran into some trybot failures with an exception that looked like this: RangeError (index): Invalid value: Valid value range is empty: -1 #0 List.[] (dart:core-patch/growable_array.dart:264:36) #1 List.removeLast (dart:core-patch/growable_array.dart:336:20) #2 InferenceContext.popFunctionBodyContext (package:analyzer/src/generated/resolver.dart:124:33) #3 ResolverVisitor.visitBlockFunctionBody (package:analyzer/src/generated/resolver.dart:1890:38) Some quick reading of the code revealed that `popFunctionBodyContext` always removed a single entry from a list, and `pushFunctionBodyContext` always added a single entry to it. The two calls were always paired up using a straightforward try/finally pattern that seemed like it should guarantee proper nesting, making this exception impossible: try { inferenceContext.pushFunctionBodyContext(...); ... } finally { ... inferenceContext.popFunctionBodyContext(node); } After a lot of headscratching and experimenting, I eventually figured out what was happening: an exception was being thrown during `pushFunctionBodyContext`, _before_ it had a chance to add an entry to the list. But since the exception happened inside the `try` block, the call to `popFunctionBodyContext` would happen anyway. As a result, the pop would fail, causing its own exception, and the exception that was the original source of the problem would be lost. This seemed like a code smell to me: where possible, the clean-up logic in `finally` clauses should be simple enough that it can always succeed, without causing an exception, even if a previous exception has put data structures in an unexpected state. And I had gained enough familiarity with the code over the course of my debugging to see that what we were doing in those `finally` clauses was more complex than necessary: - In the ResolverVisitor, we were pushing and popping a stack of `BodyInferenceContext` objects using the try/finally pattern described above. But we were only ever accessing the top entry on the stack, which meant that the same state could be maintained with a single BodyInferenceContext pointer, and some logic that can't possibly lead to an exception in the `finally` clause: var oldBodyContext = _bodyContext; try { _bodyContext = ...; ... } finally { _bodyContext = oldBodyContext; } - In the ResolverVisitor and the ErrorVerifier, we were also pushing and popping a stack of booleans tracking whether the currently enclosing function (or initializer) has access to `this`. In the ResolverVisitor, this information wasn't being used at all, so it could be safely removed. In the ErrorVerifier, it was being used, but it was possible to simplify it in a similar way, so that it was tracked with a single boolean (`_hasAccessToThis`), rather than a stack. Simplifying this logic brings several advantages: - As noted above, since it's now impossible for an exception to occur in the `finally` clause, exceptions occurring in the `try` clause won't get lost, making debugging easier. - The code should be more performant, since it no longer requires auxiliary heap-allocated stacks. - The code is (IMHO) easier to understand, since the try/catch pattern for maintaining the new `_bodyContext` and `_hasAccessToThis` fields just involves saving a field in a local variable (and restoring it later), rather than calling out to separate classes. Change-Id: I61ae80fb28a69760ea0b2856a6954b4a68cfcbe1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/358200 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Paul Berry <[email protected]>
…ecks The (utf8) scanner currently has this thing where you give it a 0-terminated byte-array (i.e. you read the file, then allocate something that's 1 bigger, copy the data, then give it to the scanner) to 'avoid bounds checks'. Dart still has bounds checks though - they're just implicit. As for the string scanner ut gets a string, then creates a new string like `string + '\x00'` - so basically the same thing. This CL uses the 'vm:unsafe:no-bounds-checks' pragma, removing the implicit bounds checks, adding explicit bounds checks, saving ~73.6 mio instructions when compiling the CFE in the process: ``` Comparing snapshot #1 with snapshot #2 cycles:u: -0.9983% +/- 0.6563% (-174026333.30 +/- 114410028.98) instructions:u: -0.3416% +/- 0.0005% (-73659267.00 +/- 108567.20) branch-misses:u: -4.8952% +/- 2.2612% (-3172939.50 +/- 1465641.18) ``` With the scanner-benchmark with `--bytes` I get this: ``` msec task-clock:u: -1.2251% +/- 0.6355% (-50.64 +/- 26.27) cycles:u: -1.2376% +/- 0.6385% (-223642830.80 +/- 115393789.68) instructions:u: -2.8155% +/- 0.0000% (-1153243856.00 +/- 428.11) seconds time elapsed: -1.2165% +/- 0.6408% (-0.05 +/- 0.03) seconds user: -1.1539% +/- 0.6495% (-0.05 +/- 0.03) ``` With the scanner-benchmark with `--string` I get this: ``` msec task-clock:u: -7.6439% +/- 0.6628% (-366.08 +/- 31.74) page-faults:u: -95.0034% +/- 0.0014% (-228023.50 +/- 3.41) instructions:u: 2.1041% +/- 0.0000% (897941907.60 +/- 2082.79) branch-misses:u: 3.2994% +/- 1.4675% (3239735.30 +/- 1440940.88) seconds time elapsed: -7.6595% +/- 0.6610% (-0.37 +/- 0.03) seconds user: -0.8801% +/- 0.7676% (-0.04 +/- 0.03) seconds sys: -92.0140% +/- 2.8075% (-0.33 +/- 0.01) MarkSweep( old space) goes from 6 to 0 Notice combined GC time goes from 112 ms to 41 ms (notice only 1 run each). ``` Where I'll note that the 'vm:unsafe:no-bounds-checks' pragma doesn't (yet?) work for `String.codeUnitAt`. See https://dart-review.googlesource.com/c/sdk/+/384540 (and https://dart-review.googlesource.com/c/sdk/+/385201) for details. I assume the relatively big change here is caused by not allocating a new string with a 0-byte in the end each time. Note that the read-allocate-copy dance is still performed for the utf8 scanner in this CL as it requires changing all call-sites instead. It will be done in a follow-up CL where the "end-of-file" int will likely also be changed to `-1` to (I assume) allow for having the 0-byte in the middle of a file (see also the 10+ year old bug at #18090) Note: The pragma (currently?) only has effect in AOT and this change will (for the utf8 scanner) make the JIT version slower (probably by the same ~73.6 mio instructions as - at least in AOT - the implicit check is 6 instructions and the explicit one is 3 instructions). As the pragma doesn't work in the StringScanner anyway I expect the change to be somewhat equivalent there. Once the read-allocate-copy dance is also removed from the utf8 scanner I expect the combined result to be positive all around. Update: With https://dart-review.googlesource.com/c/sdk/+/385201 landed I get these changes: Compiling the CFE: ``` instructions:u: -0.4520% +/- 0.0002% (-98470955.29 +/- 42253.40) ``` Scanner benchmark with `--bytes`: ``` msec task-clock:u: -2.1758% +/- 0.2316% (-92.07 +/- 9.80) cycles:u: -2.1941% +/- 0.2283% (-405224983.11 +/- 42160655.88) instructions:u: -3.1049% +/- 0.0000% (-1272360052.95 +/- 706.54) branch-misses:u: 2.4718% +/- 0.5142% (2371345.23 +/- 493257.76) seconds time elapsed: -2.1761% +/- 0.2317% (-0.09 +/- 0.01) seconds user: -2.2071% +/- 0.2308% (-0.09 +/- 0.01) ``` Scanner benchmark with `--string`: ``` msec task-clock:u: -15.0073% +/- 0.2175% (-745.93 +/- 10.81) page-faults:u: -95.0035% +/- 0.0003% (-228024.25 +/- 0.81) cycles:u: -7.7986% +/- 0.2329% (-1558985588.99 +/- 46560962.79) instructions:u: -3.7054% +/- 0.0000% (-1581977447.66 +/- 481.68) branch-misses:u: -0.6880% +/- 0.5818% (-689453.22 +/- 583101.50) seconds time elapsed: -15.0198% +/- 0.2170% (-0.75 +/- 0.01) seconds user: -8.8149% +/- 0.2648% (-0.41 +/- 0.01) seconds sys: -94.1247% +/- 1.6444% (-0.34 +/- 0.01) MarkSweep( old space) goes from 6 to 0 ``` Change-Id: I524a21f488da7df5dc9d2cdf40112b84896ad3e0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/383324 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
See: b/374689139. https://dart-review.googlesource.com/c/sdk/+/390941 is blocking an SDK roll. Root cause: ``` Action threw an exception: type 'ConstructorMember' is not a subtype of type 'ConstructorFragment' in type cast #0 InterfaceTypeImpl.constructors2.<anonymous closure> (package:analyzer/src/dart/element/type.dart:569) #1 MappedListIterable.elementAt (dart:_internal/iterable.dart:435) #2 ListIterator.moveNext (dart:_internal/iterable.dart:364) #3 new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:189) #4 new _GrowableList.of (dart:core-patch/growable_array.dart:150) #5 new List.of (dart:core-patch/array_patch.dart:39) #6 ListIterable.toList (dart:_internal/iterable.dart:224) #7 InterfaceTypeImpl.constructors2 (package:analyzer/src/dart/element/type.dart:570) #8 _Visitor._hasConstConstructorInvocation (package:linter/src/rules/prefer_const_constructors_in_immutables.dart:110) #9 _Visitor.visitConstructorDeclaration (package:linter/src/rules/prefer_const_constructors_in_immutables.dart:58) ``` To verify the fix locally: ``` solo_test_X() async { await assertNoErrorsInCode(r''' class A<T> {} '''); var A = findElement.class_('A').instantiate( typeArguments: [intType], nullabilitySuffix: NullabilitySuffix.none, ); A.constructors2; } ``` Bug: b/374689139 Change-Id: I70034d938d840dc0c3939db27e7116164e4617e9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391483 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Phil Quitslund <[email protected]>
Either of the process tests
ProcessExitTest.dart
ProcessSegfaultTest.dart
ProcessStartExceptionTest.dart
ProcessStderrTest.dart
ProcessStdoutTest.dart
can hang on Linux. It happens once every ~25 runs.
The text was updated successfully, but these errors were encountered: