OutOfMemoryError on my BF interpreter
Cristian Esquivias
cristian.esquivias at gmail.com
Sat May 5 06:50:36 UTC 2018
Hey Christian (it's so weird typing that H ;),
That command worked like a charm. Your modifications were really
helpful in making my interpreter a lot faster. I can confirm that I
don't get the OOME error when I build against HEAD.
Yeah, I think I'm done with my BF interpreter. My original intent was
to go back and work on my lisp interpreter and make it less dumb, but
the API between the version of Truffle I used and 1.0.0-RC1 had
changed so drastically I didn't know how to migrate. I figured writing
another--even simpler--interpreter would help me understand the
changes. I think I've found my bearings so now I can go update and
improve my lisp interpreter.
I actually read through your BF interpreter, but yours also used an
old version of truffle. Since my main goal was to understand the
latest APIs, I had to roll up my sleeves and implement my own while
(poorly) mimicking SimpleLanguage. I'll take it as a positive sign
that your interpreter and mine were similar.
Thanks, everyone, for the help,
Cristian
On Fri, May 4, 2018 at 3:50 AM, Christian Humer
<christian.humer at gmail.com> wrote:
> Hi Cristian,
>
> This command line should pick up the latest compiler:
> mx -v --jdk=jvmci vm -cp
> ../../bf-graal/main/target/main-1.0-SNAPSHOT.jar:../../bf-graal/lang/target/bf-1.0-SNAPSHOT.jar
> cesquivias.bf.Main ../../bf-graal/examples/mandelbrot.bf
>
> I ran this command out of the graal compiler suite in graal/compiler folder
> of the Graal repository. I checked out the bf repo at the root, hence the
> ../../.
> Note that the -Dtruffle.class.path.append is only a thing in GraalVM so you
> need to use -cp when running with the Graal repository.
> The -v command gives you some info what command it produces. Feel free to
> remove it.
> We are working on deploying nightly snapshots of GraalVM. That should help
> you picking up the latest version in the future.
>
> I took the liberty to have a look at a more reasonable BF application here:
> https://github.com/chumer/bf/blob/master/src/main/resources/test/primes.bf
>
> I was dumping this to IGV (mx igv in compiler project) and then running
> using -Dgraal.Dump=. This showed me a few problems with the graph. You
> should have a look at the "nodeSourcePosition" property that shows you the
> origin of Graal nodes.
>
> I created a PR with the changes that should fix those problems:
> https://github.com/cesquivias/bf-graal/pull/1
>
> When I look at the IGV graph now I can see only loads and stores on your
> memory int[]. Unfortunately Graal needs to materialize all the changes in
> the memory as it cannot see its allocation in the OSR compilations. You
> could try to materialize every memory slot into a frame slot. But I'd rather
> recommend spending your time on a more interesting language like a simple
> Lisp.
>
> BTW.: I did my own BF interpreter two years ago:
> https://github.com/chumer/bf/. Looks very similar to yours :-).
>
> Hope this helps,
>
> - Christian Humer
>
>
>
> On Thu, May 3, 2018 at 8:58 AM Cristian Esquivias
> <cristian.esquivias at gmail.com> wrote:
>>
>> @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