OutOfMemoryError on my BF interpreter

Christian Humer christian.humer at gmail.com
Sat May 5 10:53:25 UTC 2018


Hey Cristian (it's so weird without that H ;),

Glad it helped.

We recommed migrating one Truffle version at a time. That makes it easier
to pick up the changes.
I wrote a paragraph about that in the readme that is easy to miss:
https://github.com/oracle/graal/tree/master/truffle#compatibility

Thanks for your feedback.

- Christian Humer




On Sat, May 5, 2018 at 8:50 AM Cristian Esquivias <
cristian.esquivias at gmail.com> wrote:

> 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