OutOfMemoryError on my BF interpreter

Boris Spasojevic boris.spasojevic at oracle.com
Thu May 3 08:01:46 UTC 2018


Hey Cristian,

Yeah, placing Truffle boundaries is a bit counterintuitive if one 
doesn't actively think about the partial evaluation.
A simple rule of thumb basically is to have a TruffleBoundary when 
calling any code that's out of your control (calls to library code for 
example, standard library included). This is not guaranteed to be 
sufficient , but it caches a lot of problems caused by a missing 
TruffleBoundary.

With that said, I would also recommend a TruffleBoundary before calling 
printStackTrace as it is basically a System.err.println

Cheers,
BoriS

On 05/03/2018 08:57 AM, Cristian Esquivias 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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_PrintDataNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=XHQ0a5p5oZndQdhC47G43J5sK6yqBL2B6quxhECa9kc&e=
> [2] https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_ReadDataNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=bNMbb0YzOBTpiswbkS4kWPcHndxUBbJ4nfN744tn-_A&e=
>
>
> @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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_README.md&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=-1-AzVo8qqKnlaLPCon2ASMq37E_P3WMnIHmhdR4BsY&e=
>
>
> @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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_oracle_graal_blob_master_compiler_README.md&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=2a3Z0BOiZ3BcnNk7Pf1KvavZFMpll7WlQC2ZOVb21dc&e=
>
>
> 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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_graalvm_simplelanguage_blob_master_language_src_main_java_com_oracle_truffle_sl_builtins_SLPrintlnBuiltin.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=giidu6TjqemIVn_pLYhakLSzU-TkIyYEdixHr2NUm7s&e=)
>>
>> 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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_DecDataNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=IVqgl6m3CiYHQee_fG23LJBm-NVM4n6dXjFd6Kfh9KE&e=
>>> [2]:
>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_DecPointerNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=-TXnuUXPvxuHGrnR3G2_VUat55zVhcISswe2sGtrGJE&e=
>>> [3]:
>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_PrintDataNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=XHQ0a5p5oZndQdhC47G43J5sK6yqBL2B6quxhECa9kc&e=
>>> [4]:
>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_ReadDataNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=bNMbb0YzOBTpiswbkS4kWPcHndxUBbJ4nfN744tn-_A&e=
>>> [5]:
>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal_blob_master_lang_src_main_java_cesquivias_bf_BFRepeatingNode.java&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=3bfEd_51FCE6DFloTP4rkquO0kSaeFtVFwCS658QUak&e=
>>>
>>> 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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_oracle_graal_commit_c0a15c562daa0338f61a6e7c22476cf145af5a66&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=7YLDLYqar4_8tMJzlvNYCt8hFzQNdAH2MgLKpEl-HGo&e=
>>>> [2]: https://bugs.openjdk.java.net/browse/JDK-8199890
>>>> [3]:
>>>>
>>>> https://urldefense.proofpoint.com/v2/url?u=http-3A__www.graalvm.org_truffle_javadoc_com_oracle_truffle_api_CompilerDirectives.TruffleBoundary.html&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=2hdW0qEgkD7u2vIp8yWOQYf3jx6DVSkesQGUEoEfazE&e=
>>>>
>>>> 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://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_cesquivias_bf-2Dgraal&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=NwNmAv3qE59ZjkeHn5Yud4_C4XfMw6Xa7kM8PVY7CGA&m=dXO26nNo7uW2-OUngRCOYOjy8XsDAg1nOz-al_kjiDo&s=tqWPZH7230x0xGzs_O8_vIBObFrb8-1F9iSrUdTZdv4&e=). 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