OutOfMemoryError on my BF interpreter
Cristian Esquivias
cristian.esquivias at gmail.com
Thu May 3 06:57:15 UTC 2018
@Boris
Thanks for the tip. I saw that in the code but wasn't sure why it was
in there. Adding a comment to explain why @TruffleBoundary is used
could be helpful for the next person.
Sadly, the change didn't make a difference. I made the changes to the
print [1] and read [2] nodes, but I still get the same OOME at the
same spot.
[1] https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/PrintDataNode.java
[2] https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/ReadDataNode.java
@Thomas
I only have two variables stored in my function's VirtualFrame: an int
and a large (1,000-10,000 length) array of bytes
The README [3] explains how to build and run the interpreter. I copied
simplelanguage's build process so it's basically `mvn package &&
JAVA_HOME=/path/to/graalvm ./bf ./examples/mandelbrot.bf` in the root
directory
[3] https://github.com/cesquivias/bf-graal/blob/master/README.md
@Josef
I'm still trying to run my interpreter off of the latest source code.
I think it built fine, but I'm not sure how to connect the compiler to
my Java 9 JDK. I'm using mx vm but I get an error:
> mx vm -XX:+UseJVMCICompiler -Dtruffle.class.path.append=./bf-graal/lang/target/bf-1.0-SNAPSHOT.jar -cp ./bf-graal/main/target/main-1.0-SNAPSHOT.jar cesquivias.bf.Main ./bf-graal/examples/mandelbrot.bf
Exception in thread "main" java.lang.IllegalStateException: A language
with id 'bf' is not installed. Installed languages are: [].
The compiler README [4] is a little out of date. It references the old
graalvm repo though that repo says it's deprecated and to use the one
under oracle org. I'm not sure if I'm calling graal right or
referencing truffle properly. There wouldn't be maven repo that builds
a snapshot of the graalvm that I could use instead? ;-)
[4] https://github.com/oracle/graal/blob/master/compiler/README.md
Thanks,
Cristian
On Wed, May 2, 2018 at 2:18 AM, Boris Spasojevic
<boris.spasojevic at oracle.com> wrote:
> Hey Christian,
>
> This could very well be caused by the calls to System.out.print and
> System.in.read.
>
> Could you please try wrapping calls to such external methods and adding a
> @TruffleBoundary annotation? The end goal would be something like:
>
> public class PrintDataNode extends BFNode {
> private final FrameSlot ptr;
> private final FrameSlot data;
>
> public PrintDataNode(FrameSlot ptr, FrameSlot data) {
> this.ptr = ptr;
> this.data = data;
> }
>
> @TruffleBoundary
> void print(char c) {
> System.out.print(c);
> }
>
> @Override
> public void execute(VirtualFrame frame) {
> try {
> print((char) ((byte[])
> frame.getObject(data))[frame.getInt(ptr)]);
> } catch (FrameSlotTypeException e) {
> e.printStackTrace();
> }
> }
> }
>
> You can see a similar pattern being used in Simple language
> (https://github.com/graalvm/simplelanguage/blob/master/language/src/main/java/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java)
>
> Hope that helps!
> BoriS
>
>
> On 05/02/2018 10:46 AM, Cristian Esquivias wrote:
>>
>> Hi Josef,
>>
>> Thanks for the context. I'll try to build the GraalVM and see if it
>> solves the issue.
>>
>> After reading the bug report, here's a little bit more info that I hope
>> helps:
>>
>> * The report says the SSA register allocator could be the problem on
>> "large inputs". I'm not sure what constitutes a large input, but my
>> mandelbrot script creates around 11,000 nodes in total. That's
>> probably not a huge amount, but they're all within one function since
>> BF doesn't have the concept of functions. That's probably a little
>> more unusual.
>> * My interpreter doesn't put pressure on the heap. After an initial
>> allocation of a 1,000-10,000 size int array no more allocations are
>> done for the rest of a script's life. This is proven out by jvisualvm.
>> The heap stays flat throughout most of the run and only spikes right
>> before the OOME occurs.
>> * There are very few (essentially no) opportunities for adding
>> TruffleBoundary annotations since nearly all my nodes' execute methods
>> are one line that do little more than fetch an item out of my array
>> and inc/dec the value. The only calls out to external methods are
>> calls to VirtualFrame.get [1]/set [2] some variable values, calls to
>> stdout's print method [3] and stdin's read method [4]. A truffle
>> expert's help would definitely be appreciated here since I'm just
>> making an educated guess.
>> * The OOME occurs inside a loop node. Could this OOME be caused by
>> loop unrolling [5]?
>>
>> Thanks,
>> Cristian
>>
>> [1]:
>> https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/DecDataNode.java
>> [2]:
>> https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/DecPointerNode.java
>> [3]:
>> https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/PrintDataNode.java
>> [4]:
>> https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/ReadDataNode.java
>> [5]:
>> https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/BFRepeatingNode.java
>>
>> On Wed, May 2, 2018 at 12:37 AM, Josef Eisl <josef.eisl at jku.at> wrote:
>>>
>>> Hi Cristian!
>>>
>>> Thanks for your report. We have very recently merged a change to
>>> mitigate the OOME in this part of linear scan [1]. Unfortunately this
>>> was after the release so it is not included in 1.0.0 RC1. You would need
>>> to build your own GraalVM from source to see if the change helps.
>>>
>>> That said, the root cause of the OOME is usually a huge compilation unit
>>> thrown into the compiler. For more details, see also the discussion on
>>> the OpenJDK bug tracker [2].
>>> The reasons for big compilation units can me manifold. In case of
>>> Truffle, the issues can often be solved by adding TruffleBoundaries [3],
>>> i.e., instructing the compiler not to inline specified methods into the
>>> truffle graph. Maybe a Truffle expert can give you more hints on that.
>>>
>>> Hope that helps,
>>>
>>> Josef
>>>
>>> [1]:
>>>
>>> https://github.com/oracle/graal/commit/c0a15c562daa0338f61a6e7c22476cf145af5a66
>>> [2]: https://bugs.openjdk.java.net/browse/JDK-8199890
>>> [3]:
>>>
>>> http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.TruffleBoundary.html
>>>
>>> On 01/05/18 08:24, Cristian Esquivias wrote:
>>>>
>>>> With the release of 1.0.0-RC1 I thought I'd come back and see how
>>>> Graal is doing. Great job; Graal is really starting to look like the
>>>> platform everyone should pay attention to.
>>>>
>>>> To get back into it, I built a Brainf*ck interpreter with Truffle
>>>> (https://github.com/cesquivias/bf-graal). I modeled it after
>>>> simplelanguage so it should be easy to build and run.
>>>>
>>>> While running the mandelbrot program, about halfway through the
>>>> program, the VM starts throwing OutOfMemoryError exceptions (one
>>>> pasted below). It created a zip file under dumps/ but it contains a
>>>> .bgv file I don't what to do with and a log file that just contains
>>>> the stacktrace.
>>>>
>>>> I ran jvisualvm and took a heap dump. There are ~200k long[] objects
>>>> alone created by graal taking up ~50% of the memory. Digging through
>>>> the references it seems to be created/retained in
>>>>
>>>>
>>>> org.graalvm.compiler.lir.alloc.lsra.LinearScanLifetimeAnalysisPhase$$Lambda$48#1
>>>> [GC root - Java frame]
>>>>
>>>> I'd provide some file from jvisualvm but the save button is grayed
>>>> out. I hope this is enough info. My interpreter is up on GitHub so
>>>> feel free to test it out.
>>>>
>>>> I tested this both on the community & enterprise edition on Ubuntu
>>>> 18.04 in VirtualBox.
>>>>
>>>> - Cristian
>>>>
>>>>
>>>> Thread[TruffleCompilerThread-12,10,main]: Compilation of
>>>> BFRepeatingNode at 222b298d<OSR> failed: java.lang.OutOfMemoryError: Java
>>>> heap space
>>>> at
>>>> org.graalvm.compiler.lir.util.IndexedValueMap.<init>(IndexedValueMap.java:55)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.RegStackValueSet.<init>(RegStackValueSet.java:62)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.RegStackValueSet.copy(RegStackValueSet.java:70)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.RegStackValueSet.copy(RegStackValueSet.java:46)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.LocationMarker.processBlock(LocationMarker.java:107)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.LocationMarker.build(LocationMarker.java:81)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.LocationMarkerPhase.run(LocationMarkerPhase.java:51)
>>>> at
>>>> org.graalvm.compiler.lir.dfa.LocationMarkerPhase.run(LocationMarkerPhase.java:47)
>>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:115)
>>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:107)
>>>> at
>>>> org.graalvm.compiler.lir.phases.LIRPhaseSuite.run(LIRPhaseSuite.java:96)
>>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:115)
>>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:107)
>>>> at
>>>> org.graalvm.compiler.core.GraalCompiler.emitLowLevel(GraalCompiler.java:367)
>>>> at
>>>> org.graalvm.compiler.core.GraalCompiler.emitLIR0(GraalCompiler.java:336)
>>>> at
>>>> org.graalvm.compiler.core.GraalCompiler.emitLIR(GraalCompiler.java:295)
>>>> at
>>>> org.graalvm.compiler.core.GraalCompiler.emitBackEnd(GraalCompiler.java:275)
>>>> at
>>>> org.graalvm.compiler.core.GraalCompiler.compile(GraalCompiler.java:175)
>>>> at
>>>> org.graalvm.compiler.core.GraalCompiler.compileGraph(GraalCompiler.java:160)
>>>> at
>>>> org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compilePEGraph(TruffleCompilerImpl.java:445)
>>>> at
>>>> org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compileAST(TruffleCompilerImpl.java:391)
>>>> at
>>>> org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl$TruffleCompilationWrapper.performCompilation(TruffleCompilerImpl.java:544)
>>>> at
>>>> org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl$TruffleCompilationWrapper.performCompilation(TruffleCompilerImpl.java:493)
>>>> at
>>>> org.graalvm.compiler.core.CompilationWrapper.run(CompilationWrapper.java:167)
>>>> at
>>>> org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.doCompile(TruffleCompilerImpl.java:222)
>>>> at
>>>> org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime.doCompile(GraalTruffleRuntime.java:679)
>>>> at
>>>> org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime$1.run(GraalTruffleRuntime.java:745)
>>>> at
>>>> java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
>>>> at java.util.concurrent.FutureTask.run(FutureTask.java:266)
>>>> at
>>>> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
>>>> at
>>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
>>>> at java.lang.Thread.run(Thread.java:748)
>>>> To disable compilation failure notifications, set
>>>> CompilationFailureAction to Silent (e.g.,
>>>> -Dgraal.CompilationFailureAction=Silent).
>>>> To print a message for a compilation failure without retrying the
>>>> compilation, set CompilationFailureAction to Print (e.g.,
>>>> -Dgraal.CompilationFailureAction=Print).
>>>> Retrying compilation of BFRepeatingNode at 222b298d<OSR>
>>>>
>
More information about the graal-dev
mailing list