Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RC15 TypeScript compile memory/cpu usage #149

Closed
hashtag-smashtag opened this issue Apr 13, 2019 · 11 comments
Closed

RC15 TypeScript compile memory/cpu usage #149

hashtag-smashtag opened this issue Apr 13, 2019 · 11 comments
Assignees
Labels
memory Memory footprint, memory leaks performance Performance of the engine (peak or warmup)

Comments

@hashtag-smashtag
Copy link

Here's our setup:

  • Using the TypeScript Compiler API and language services to compile TypeScript
  • The TypeScript compiler is in Javascript and lives in a Graal JS Context which involves warmup and caching for fast subsequent compiling
  • There's a small pool of these Contexts for compiling

This was working well for us, but with RC15 we're seeing:

  1. Heavy CPU usage
  2. Memory growth until heap is depleted

We see issues with both -XX:-UseJVMCINativeLibrary and -XX:+UseJVMCINativeLibrary

@wirthi
Copy link
Member

wirthi commented Apr 15, 2019

Hi @hashtag-smashtag

thanks for your report.

We are not using Typescript as you do, but run the octane-typescript benchmark. I don't see any peculiarity there. I will have to investigate on a setup more similar to yours. It would be helpful if you could share more details on how or what you run exactly.

Are you explicitly using the code-sharing features of GraalVM (i.e., you start from Java, and create Source objects that you share between the Contexts)?

Thanks,
Christian

@wirthi wirthi added memory Memory footprint, memory leaks performance Performance of the engine (peak or warmup) labels Apr 15, 2019
@hashtag-smashtag
Copy link
Author

@wirthi Thanks for the response.

Our actual setup is more complicated than this, but here is a good place to start, a test in Groovy (note the invocationCount):

@Test
class TypescriptTest {

    private static Context context
    private static Value transpileModuleFunction

    @BeforeClass
    static setup() {
        context = Context.create("js")
        def url = new URL("https://cdnjs.cloudflare.com/ajax/libs/typescript/3.4.3/typescript.js")
        def source = Source.newBuilder("js", url).buildLiteral()
        context.eval(source)
        transpileModuleFunction = context.eval("js", "ts.transpileModule")
    }

    @Test(invocationCount = 1000)
    void "transpiling"() {
        String json2Js = new URL("https://raw.githubusercontent.com/douglascrockford/JSON-js/master/json2.js").text
        def result = transpileModuleFunction.execute(json2Js, ProxyObject.fromMap([lib:["es2018"]]))
        assert !result.getMember("outputText").asString().isEmpty()
        assert result.getMember("diagnostics").getArraySize() == 0

        String utilTs = new URL("https://raw.githubusercontent.com/GoogleChromeLabs/squoosh/master/src/lib/util.ts").text
        def result2 = transpileModuleFunction.execute(utilTs, ProxyObject.fromMap([lib:["es2018"]]))
        assert !result2.getMember("outputText").asString().isEmpty()
        assert result2.getMember("diagnostics").getArraySize() == 0
    }

}

Results of profiling with various vm args and using rc15:

  • -XX:+UseG1GC and libgraal :
    -- blows up in native code on OSX, see RC15 G1GC OSX crashes graal#1159

  • -XX:+UseG1GC and -XX:-UseJVMCINativeLibrary (no libgraal) :
    -- slowly grows to use about 3.2 GB of memory and then around 4 minutes heavy GC/CPU activity starts and memory greatly grows, sometimes reaching over 11 GB
    -- also experiences this exception (which may be a G1 code caching bug?):

[truffle] opt fail         createPrinter                                               |Reason jdk.vm.ci.code.BailoutException: Code installation failed: code is too large 
jdk.vm.ci.code.BailoutException: Code installation failed: code is too large
	at jdk.vm.ci.hotspot.HotSpotCodeCacheProvider.installCode(HotSpotCodeCacheProvider.java:150)
	at org.graalvm.compiler.core.target.Backend.createInstalledCode(Backend.java:194)
	at org.graalvm.compiler.core.target.Backend.createInstalledCode(Backend.java:147)
	at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compilePEGraph(TruffleCompilerImpl.java:531)
	at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compileAST(TruffleCompilerImpl.java:452)
	at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl$TruffleCompilationWrapper.performCompilation(TruffleCompilerImpl.java:621)
	at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl$TruffleCompilationWrapper.performCompilation(TruffleCompilerImpl.java:568)
	at org.graalvm.compiler.core.CompilationWrapper.run(CompilationWrapper.java:177)
	at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.doCompile(TruffleCompilerImpl.java:280)
	at org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime.doCompile(GraalTruffleRuntime.java:687)
	at org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime.doCompile(GraalTruffleRuntime.java:711)
	at org.graalvm.compiler.truffle.runtime.BackgroundCompileQueue$Request.run(BackgroundCompileQueue.java:83)
	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)
	at org.graalvm.compiler.truffle.runtime.BackgroundCompileQueue$TruffleCompilerThreadFactory$1.run(BackgroundCompileQueue.java:163)
  • no additional vm args (default garbage collector, libgraal) :
    -- slowly grows to use about 0.8 GB of memory, and then shrinks to a steady state of around max 0.3 GB memory used

@hashtag-smashtag
Copy link
Author

  • jprofiler screenshot of -XX:+UseG1GC and -XX:-UseJVMCINativeLibrary (no libgraal) :
    test - g1gc - no libgraal

  • jprofiler screenshot of no additional vm args (default garbage collector, libgraal) :
    test - no g1gc - libgraal

@hashtag-smashtag
Copy link
Author

Just writing back to share that due to such issues we've externalized our TypeScript compilation to avoid doing it within Graal.

@nchoumitsky
Copy link

I'm running in to the same issue with a similar setup attempting to use the TypeScript compiler in GraalJS through Java code rather than groovy, it appears to be allocating a large amount of memory very quickly. Could you provide the details of how you run the octane typecript benchmark and configure Graal?

@wirthi
Copy link
Member

wirthi commented Mar 10, 2021

Hi @nchoumitsky

what behavior do you see exactly? Excessive memory usage that might leak, and/or slows down the execution; or do you just see the GraalVM process is using its maximum memory? In a system with a garbage collector you expect to see memory usage to fluctuate and even max out, until the Garbage Collector kicks in. See the blue line (actual objects allocated by the user application) vs green line (memory allocated by the process) in the memory rows of the jprofiler screenshot above.

I suspect it is the later - which would be totally fine, that's how Java is designed to work. You can specify the max memory for the java process by the Xmx flag, e.g. js --vm.Xmx100m. Be sure not too set it too low, 100 MB will be to little for TypeScript I suppose. Setting it too low will also cause peak performance to go down, as the GC needs to work more frequently (although on smaller chuncks, which could also be an advantage). It might also impact how effectively the compiler can do its work - worst case, every bit of memory is used by the user application, leaving no resources for the compiler to optimize anything.

We have not published our exact harness for Octane for legal reasons, but the main thing we tweaked was to increase the number of iterations and separate warmup from measure iterations. Other than that, it's basically js run.js (for native mode) or js --jvm run.js (for JVM mode) of https://github.com/chromium/octane

Best,
Christian

@woess
Copy link
Member

woess commented Mar 10, 2021

@hashtag-smashtag you might want to try again with the latest release or nightly. I cannot reproduce the issues that you described. I ran similar code (though not using groovy) and the memory usage seems stable. If there was a bug, it might already be fixed.

@nchoumitsky if you could provide some code that demonstrates the issue, we could take a closer look.

@hashtag-smashtag
Copy link
Author

Glad to hear it might be fixed, but we changed our architecture to not compile TS within the Graal JVM, as mentioned above, almost 2 years ago :)

@nchoumitsky
Copy link

I believe I had around 2GB in my heap when I was running it, I didn't see any GC issues just a large amount of memory allocation. One of the differences between my setup and your Octane harness might be that I'm running on the stock JDK and not GraalVM? I can attempt to pull my test case out of my current project and come up with a smaller repro that includes all of the exact flags & versions of things I'm using.

@woess
Copy link
Member

woess commented Mar 10, 2021

@hashtag-smashtag ok, I guess this issue can be closed then. :)

@woess
Copy link
Member

woess commented Mar 10, 2021

@nchoumitsky The Octane Typescript benchmark is using a rather old version of the typescript compiler, so it's not really comparable. The amount of memory used may actually be normal (IIUC it does not leak); I can't really say without knowing more about your case and how you measured. If you think there's an issue, please create a new github issue with a test case. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
memory Memory footprint, memory leaks performance Performance of the engine (peak or warmup)
Projects
None yet
Development

No branches or pull requests

4 participants