Open JaroslavTulach opened 1 week ago
Apply the following patch:
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/ClosureRootNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/ClosureRootNode.java
index f2ac6c965..bcac8eeab 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/node/ClosureRootNode.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/node/ClosureRootNode.java
@@ -1,10 +1,13 @@
package org.enso.interpreter.node;
import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
+import java.util.ArrayList;
+import java.util.List;
import org.enso.compiler.context.LocalScope;
import org.enso.interpreter.EnsoLanguage;
import org.enso.interpreter.runtime.scope.ModuleScope;
@@ -71,6 +74,10 @@ public class ClosureRootNode extends EnsoRootNode {
usedInBinding);
}
+ private static List<String> biggestTruffleStackTrace = List.of();
+ private static int jStackSize;
+ private static boolean shutdownHookRegistered;
+
/**
* Executes the node.
*
@@ -82,9 +89,51 @@ public class ClosureRootNode extends EnsoRootNode {
if (CompilerDirectives.inCompilationRoot() || CompilerDirectives.inInterpreter()) {
com.oracle.truffle.api.TruffleSafepoint.poll(this);
}
+ if (!shutdownHookRegistered) {
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ System.out.printf("[mylog] biggestStackTrace [java stack size = %d][truffle stack size = %d]:%n",
+ jStackSize,
+ biggestTruffleStackTrace.size());
+ biggestTruffleStackTrace.forEach(stackFrame -> System.out.println(" " + stackFrame));
+ }));
+ shutdownHookRegistered = true;
+ }
+
+ var truffleStack = collectTruffleStackTrace();
+ if (truffleStack.size() > biggestTruffleStackTrace.size()) {
+ biggestTruffleStackTrace = truffleStack;
+ jStackSize = Thread.currentThread().getStackTrace().length;
+ }
return body.executeGeneric(frame);
}
+ private List<String> collectTruffleStackTrace() {
+ List<String> stackTrace = new ArrayList<>();
+ Truffle.getRuntime().iterateFrames((frameInstance) -> {
+ var callNode = frameInstance.getCallNode();
+ if (callNode != null) {
+ var rootNode = callNode.getRootNode();
+ if (rootNode != null) {
+ var nodeName = rootNode.getName();
+ if (rootNode.getSourceSection() != null) {
+ nodeName += " (" +
+ rootNode.getSourceSection().getSource().getName() +
+ "[" +
+ rootNode.getSourceSection().getStartLine() +
+ ":" +
+ rootNode.getSourceSection().getStartColumn() +
+ "])";
+ }
+ stackTrace.add(nodeName);
+ return null;
+ }
+ }
+ stackTrace.add("<unknown>");
+ return null;
+ });
+ return stackTrace;
+ }
+
final ExpressionNode getBody() {
return body;
}
And run enso --run test/Base_Tests
(Warning: will take a long time to run the whole test suite)
Output:
[mylog] biggestStackTrace [java stack size = 1024][truffle stack size = 120]:
<unknown>
Array_Like_Helpers.vector_from_function<arg-1> (Array_Like_Helpers.enso[106:26])
Array_Like_Helpers.vector_from_function<arg-0> (Array_Like_Helpers.enso[106:8])
Array_Like_Helpers.vector_from_function (Array_Like_Helpers.enso[87:1])
Array_Like_Helpers.map (Array_Like_Helpers.enso[260:1])
Vector.map (Vector.enso[702:5])
Builder.add_warnings (Vector.enso[1421:5])
Builder.append<arg-1> (Vector.enso[1366:48])
Builder.append<arg-1> (Vector.enso[1364:33])
Any.if_not_error (Any.enso[434:5])
Builder.append<arg-1> (Vector.enso[1363:42])
Builder.append (Vector.enso[1362:5])
Array_Like_Helpers.filter.predicate.case predicate<arg-1> (Array_Like_Helpers.enso[347:36])
Array_Like_Helpers.filter.predicate.case predicate (Array_Like_Helpers.enso[346:20])
Array_Like_Helpers.map.Array_Like_Helpers.map (Array_Like_Helpers.enso[261:41])
Array_Like_Helpers.vector_from_function.wrapped_function (Array_Like_Helpers.enso[89:5])
Array_Like_Helpers.vector_from_function
Array_Like_Helpers.vector_from_function (Array_Like_Helpers.enso[87:1])
Array_Like_Helpers.map (Array_Like_Helpers.enso[260:1])
Vector.map (Vector.enso[702:5])
Array_Like_Helpers.filter.predicate (Array_Like_Helpers.enso[345:18])
Vector.type.build.results_multiple (Vector.enso[194:53])
Vector.type.build_multiple<arg-0> (Vector.enso[249:17])
Vector.type.build_multiple<arg-1> (Vector.enso[248:51])
Panic.catch
Panic.type.handle_wrapped_dataflow_error (Panic.enso[255:5])
Vector.type.build_multiple<arg-2> (Vector.enso[246:113])
Vector.type.build_multiple (Vector.enso[245:5])
Vector.type.build (Vector.enso[192:5])
Array_Like_Helpers.filter (Array_Like_Helpers.enso[343:1])
Vector.filter (Vector.enso[557:5])
File.with_output_stream<arg-2> (File.enso[200:112])
File.with_output_stream<arg-1> (File.enso[198:167])
Context.if_enabled (Runtime.enso[187:5])
File.with_output_stream (File.enso[185:5])
Local_File_Write_Strategy.write_file_backing_up_old_one.go<arg-1> (Local_File_Write_Strategy.enso[79:38])
Local_File_Write_Strategy.write_file_backing_up_old_one.go<arg-1> (Local_File_Write_Strategy.enso[75:91])
Panic.catch
Local_File_Write_Strategy.write_file_backing_up_old_one.go<arg-1> (Local_File_Write_Strategy.enso[75:67])
Panic.catch
Local_File_Write_Strategy.write_file_backing_up_old_one.go<arg-1> (Local_File_Write_Strategy.enso[75:39])
Panic.catch
Local_File_Write_Strategy.write_file_backing_up_old_one.go (Local_File_Write_Strategy.enso[58:5])
Local_File_Write_Strategy.write_file_backing_up_old_one.go.handle_existing_file (Local_File_Write_Strategy.enso[61:9])
case_branch (Local_File_Write_Strategy.enso[134:40])
Local_File_Write_Strategy.catch_already_exists.panic_handler (Local_File_Write_Strategy.enso[133:5])
Panic.catch
Local_File_Write_Strategy.write_file_backing_up_old_one.go (Local_File_Write_Strategy.enso[58:5])
Local_File_Write_Strategy.write_file_backing_up_old_one.go.handle_existing_file (Local_File_Write_Strategy.enso[61:9])
case_branch (Local_File_Write_Strategy.enso[134:40])
Local_File_Write_Strategy.catch_already_exists.panic_handler (Local_File_Write_Strategy.enso[133:5])
Panic.catch
Local_File_Write_Strategy.write_file_backing_up_old_one.go (Local_File_Write_Strategy.enso[58:5])
Local_File_Write_Strategy.write_file_backing_up_old_one.go.handle_existing_file (Local_File_Write_Strategy.enso[61:9])
case_branch (Local_File_Write_Strategy.enso[134:40])
Local_File_Write_Strategy.catch_already_exists.panic_handler (Local_File_Write_Strategy.enso[133:5])
Panic.catch
Local_File_Write_Strategy.write_file_backing_up_old_one.go (Local_File_Write_Strategy.enso[58:5])
Local_File_Write_Strategy.write_file_backing_up_old_one<arg-2> (Local_File_Write_Strategy.enso[115:72])
Local_File_Write_Strategy.write_file_backing_up_old_one<arg-2> (Local_File_Write_Strategy.enso[114:82])
Local_File_Write_Strategy.write_file_backing_up_old_one<arg-1> (Local_File_Write_Strategy.enso[54:72])
Local_File_Write_Strategy.recover_io_and_not_found<arg-1> (Local_File_Write_Strategy.enso[145:80])
Panic.catch
Local_File_Write_Strategy.recover_io_and_not_found<arg-1> (Local_File_Write_Strategy.enso[144:52])
Panic.catch
Local_File_Write_Strategy.recover_io_and_not_found (Local_File_Write_Strategy.enso[139:1])
Local_File_Write_Strategy.write_file_backing_up_old_one (Local_File_Write_Strategy.enso[54:1])
Local_File_Write_Strategy.moving_backup.handle_existing_file (Local_File_Write_Strategy.enso[37:5])
case_branch (Local_File_Write_Strategy.enso[134:40])
Local_File_Write_Strategy.catch_already_exists.panic_handler (Local_File_Write_Strategy.enso[133:5])
Panic.catch
Local_File_Write_Strategy.moving_backup<arg-1> (Local_File_Write_Strategy.enso[36:56])
Local_File_Write_Strategy.recover_io_and_not_found<arg-1> (Local_File_Write_Strategy.enso[145:80])
Panic.catch
Local_File_Write_Strategy.recover_io_and_not_found<arg-1> (Local_File_Write_Strategy.enso[144:52])
Panic.catch
Local_File_Write_Strategy.recover_io_and_not_found (Local_File_Write_Strategy.enso[139:1])
Local_File_Write_Strategy.moving_backup (Local_File_Write_Strategy.enso[36:1])
case_branch (File_Write_Strategy.enso[58:46])
File_Write_Strategy.write (File_Write_Strategy.enso[55:5])
File_Write_Strategy.write_handling_dry_run<arg-1> (File_Write_Strategy.enso[75:43])
File_Write_Strategy.write_handling_dry_run (File_Write_Strategy.enso[74:5])
Writable_File.write_handling_dry_run<arg-0> (Writable_File.enso[55:9])
Writable_File.write_handling_dry_run (Writable_File.enso[54:5])
Text.write<arg-1> (Write_Extensions.enso[61:26])
Any.if_not_error (Any.enso[434:5])
Text.write (Write_Extensions.enso[59:1])
File_Spec.add_specs.<internal-574><arg-0> (File_Spec.enso[713:13])
File_Spec.add_specs.<internal-574><arg-0> (File_Spec.enso[713:13])
File_Spec.add_specs.<internal-574><arg-1> (File_Spec.enso[691:78])
case_branch.case <internal-559> (Group.enso[30:56])
Helpers.execute_spec_code<arg-1> (Helpers.enso[56:36])
Panic.catch
Panic.type.recover (Panic.enso[185:5])
Helpers.execute_spec_code (Helpers.enso[55:1])
case_branch<arg-3> (Helpers.enso[48:37])
case_branch<arg-1> (Helpers.enso[47:46])
Runtime.no_inline
Duration.type.time_execution (Duration.enso[129:5])
case_branch (Helpers.enso[47:20])
Helpers.run_spec (Helpers.enso[45:1])
case_branch.test_results (Helpers.enso[24:38])
Array_Like_Helpers.map.Array_Like_Helpers.map (Array_Like_Helpers.enso[261:41])
Array_Like_Helpers.vector_from_function.wrapped_function (Array_Like_Helpers.enso[89:5])
Array_Like_Helpers.vector_from_function
Array_Like_Helpers.vector_from_function (Array_Like_Helpers.enso[87:1])
Array_Like_Helpers.map (Array_Like_Helpers.enso[260:1])
Vector.map (Vector.enso[702:5])
case_branch (Helpers.enso[23:17])
Helpers.run_specs_from_group (Helpers.enso[19:1])
case_branch (Suite.enso[96:29])
Suite.run_with_filter.junit_sb_builder (Suite.enso[92:33])
Array_Like_Helpers.each.Array_Like_Helpers.each (Array_Like_Helpers.enso[300:34])
Range.each.go<arg-1> (Range.enso[262:36])
Range.each.go<arg-2> (Range.enso[261:68])
Range.each.go (Range.enso[260:13])
Test_Reporter.wrap_junit_testsuites (Test_Reporter.enso[24:1])
Suite.run_with_filter (Suite.enso[63:5])
Main.main (Main.enso[95:1])
org.graalvm.polyglot.Value<Function>.execute
We can see that there are a lot of frames related to Vector.map
. I will do the same experiment at the end to see how the biggest stack trace was affected.
I was just profiling one of the "sieve benchmarks" (as introduced by #11351):
sbt:std-benchmarks> withDebug --dumpGraphs benchOnly -- Sieve_Lazy
and this is the beginning of the compilation:
Array_Like_Helpers
& Vector
functionality occupies a lot of time. The hope of having a builtin is that we can remove most of the initial compilation overhead as processing builtin code will be easier for the compiler.
Pavel Marek reports a new STANDUP for today (2024-10-18):
Progress: - Experimenting with a regression test for stack trace sizes - https://github.com/enso-org/enso/pull/11363#issuecomment-2422862956
@ScalaSignature
annotation. It should be finished by 2024-10-24.There is an option to
- no way to provide default arguments to Java methods from Scala
use overloaded methods:
public int minus(int a, int b) {
return a-b;
}
public int minus(int a) {
return minus(a, 5);
}
when compiled with -parameters
argument, then the methods can be called as:
minus(b=7, a=3)
minus(a=7)
that provides (limited) support for default arguments. Things will get trickier with the increased number of arguments, but when one doesn't need all combination, but only few - as is the case with IR.copy
most of the time, then overloaded methods might be a decent solution.
PS: You are allowed to modify Scala source to keep the number of needed overloads up to three. If the Scala code continues to compile against Scala IR
and keeps number of needed Java IR
methods overloads up to three, then it is worth the change even right now.
PPS: Probably better to explicitly spell the default values and work with overloads than generate Scala code...
Pavel Marek reports a new STANDUP for today (2024-10-21):
Progress: - Started converting Array_Like_Helpers.vector_from_function
to a builtin.
n
nested map calls with 256k
stack.Pavel Marek reports a new STANDUP for today (2024-10-22):
Progress: - Managed to reduce the stack size for every Vector.map
call by 1:
Vector.map
occupies 6 frames, on my PR it occupies 5 frames.Please more @Tail_Calls
to almost all methods that invoke the builtin.
@jdunkerley complained about strange stacktraces when invoking
.map
:The stacktraces were much simpler prior to https://github.com/enso-org/enso/pull/8307/files#diff-c5e24473d47930ce7b6fd3f7f643967fcb54fcb01df1e6803438203749988f70R39 when all the logic was just a simple builtin. Now, when there is bunch of wrapper functions in Enso, we see them in the stack. The following program yields an exception:
and the stacktrace is quite deep:
Goal: rewrite the logic into a builtin and make the call appear as a single element on the stack - e.g. the above stack should compose of only three lines:
Btw. such a stack compression should also help with @AdRiley problem of too deep stacktraces as one
.map
invocation is more than hundred Java stack frames in the interpreter right now:11327
By having
.map
as a builtin we lower the stack requirements a lot given how frequently we are using.map
& co.