Skip to content

Instantly share code, notes, and snippets.

@pmbauer
Last active February 2, 2017 21:45

Revisions

  1. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -30,4 +30,4 @@ Okay, so Clojure isn't adding _that_ much overhead. We're still several orders
    **UPDATE: In interest of full disclosure, I previously misinterpreted the strace output. I'm attaching the full strace run. The main takeaway here is that dynamically compiling and executing code in Java and Clojure has intrinsic startup overhead, and Clojure compares favorably with Java for this limited benchmark.**

    Also note that Clojure doesn't cross-compile to Java and doesn't use JavaCompiler; instead it generates JVM bytecodes using ASM.
    This example is just the Java-native semantic equivalent of what Clojure is doing with (-> {:parse {:some :data}} :parse :some) : reading, parsing, compiling, executing code - and it takes 46 lines to do it!
    This example is just the Java-native semantic equivalent of what Clojure is doing with `(-> {:parse {:some :data}} :parse :some)`: reading, parsing, compiling, executing code - and it takes 46 lines to do it!
  2. pmbauer revised this gist Feb 2, 2017. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -29,3 +29,5 @@ Okay, so Clojure isn't adding _that_ much overhead. We're still several orders

    **UPDATE: In interest of full disclosure, I previously misinterpreted the strace output. I'm attaching the full strace run. The main takeaway here is that dynamically compiling and executing code in Java and Clojure has intrinsic startup overhead, and Clojure compares favorably with Java for this limited benchmark.**

    Also note that Clojure doesn't cross-compile to Java and doesn't use JavaCompiler; instead it generates JVM bytecodes using ASM.
    This example is just the Java-native semantic equivalent of what Clojure is doing with (-> {:parse {:some :data}} :parse :some) : reading, parsing, compiling, executing code - and it takes 46 lines to do it!
  3. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -27,5 +27,5 @@ time java pmbauer.JavaIsKindaLight

    Okay, so Clojure isn't adding _that_ much overhead. We're still several orders of magnitutde slower than python.

    *UPDATE: In interest of full disclosure, I previously misinterpreted the strace output. I'm attaching the full strace run. The main takeaway here is that dynamically compiling and executing code in Java and Clojure has intrinsic startup overhead, and Clojure compares favorably with Java for this limited benchmark.*
    **UPDATE: In interest of full disclosure, I previously misinterpreted the strace output. I'm attaching the full strace run. The main takeaway here is that dynamically compiling and executing code in Java and Clojure has intrinsic startup overhead, and Clojure compares favorably with Java for this limited benchmark.**

  4. pmbauer revised this gist Feb 2, 2017. 2 changed files with 154 additions and 17 deletions.
    18 changes: 1 addition & 17 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -27,21 +27,5 @@ time java pmbauer.JavaIsKindaLight

    Okay, so Clojure isn't adding _that_ much overhead. We're still several orders of magnitutde slower than python.

    But why? Is it because the Java and Clojure versions are writing to disk and the python version isn't? Well ...

    ```
    strace -r java pmbauer.JavaIsKindaLight
    0.000000 execve("/usr/bin/java", ["java", "pmbauer.JavaIsKindaLight"], [/* 115 vars */]) = 0
    0.000288 brk(NULL) = 0x10d1000
    0.000034 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    ...
    0.000037 futex(0x7fdc1b2a19d0, FUTEX_WAIT, 7052, NULLdata
    ) = 0
    0.842562 exit_group(0) = ?
    0.002464 +++ exited with 0 +++
    ```

    `futex -> exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup. IO appears to be a non-factor.
    The minimal example and Clojure both exhibit this profile and simple Java applications that don't dynamically compile code do not.

    *UPDATE: In interest of full disclosure, I previously misinterpreted the strace output. I'm attaching the full strace run. The main takeaway here is that dynamically compiling and executing code in Java and Clojure has intrinsic startup overhead, and Clojure compares favorably with Java for this limited benchmark.*

    153 changes: 153 additions & 0 deletions strace.out
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,153 @@
    strace -r java pmbauer.JavaIsKindaLight
    0.000000 execve("/usr/bin/java", ["java", "pmbauer.JavaIsKindaLight"], [/* 115 vars */]) = 0
    0.000300 brk(NULL) = 0x20c7000
    0.000056 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    0.000078 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d1600b000
    0.000043 readlink("/proc/self/exe", "/usr/lib/jvm/java-8-oracle/jre/b"..., 4096) = 39
    0.000042 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
    0.000027 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/tls/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000030 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/tls/x86_64", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000022 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/tls/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000040 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/tls", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000034 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000023 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/x86_64", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000023 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000023 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
    0.000032 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/tls/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000026 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/tls/x86_64", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000024 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/tls/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000022 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/tls", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000022 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000022 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/x86_64", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000021 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000022 stat("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
    0.000025 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/tls/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000023 stat("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/tls/x86_64", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000021 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/tls/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000034 stat("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/tls", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000022 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000022 stat("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/x86_64", 0x7fff4866d440) = -1 ENOENT (No such file or directory)
    0.000021 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000022 stat("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
    0.000024 open("tls/x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000021 open("tls/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000019 open("x86_64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    0.000018 fstat(3, {st_mode=S_IFREG|0644, st_size=157471, ...}) = 0
    0.000016 mmap(NULL, 157471, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d15fe4000
    0.000016 close(3) = 0
    0.000017 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    0.000022 open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
    0.000017 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260`\0\0\0\0\0\0"..., 832) = 832
    0.000017 fstat(3, {st_mode=S_IFREG|0755, st_size=138696, ...}) = 0
    0.000016 mmap(NULL, 2212904, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d15bcb000
    0.000018 mprotect(0x7f7d15be3000, 2093056, PROT_NONE) = 0
    0.000019 mmap(0x7f7d15de2000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7f7d15de2000
    0.000021 mmap(0x7f7d15de4000, 13352, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d15de4000
    0.000022 close(3) = 0
    0.000018 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/libjli.so", O_RDONLY|O_CLOEXEC) = 3
    0.000017 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20#\0\0\0\0\0\0"..., 832) = 832
    0.000067 fstat(3, {st_mode=S_IFREG|0755, st_size=102352, ...}) = 0
    0.000015 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d15fe3000
    0.000018 mmap(NULL, 2184904, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d159b5000
    0.000015 mprotect(0x7f7d159ca000, 2097152, PROT_NONE) = 0
    0.000016 mmap(0x7f7d15bca000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7f7d15bca000
    0.000018 close(3) = 0
    0.000018 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000019 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000017 open("tls/x86_64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("tls/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000015 open("x86_64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000015 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    0.000020 open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
    0.000017 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\r\0\0\0\0\0\0"..., 832) = 832
    0.000020 fstat(3, {st_mode=S_IFREG|0644, st_size=14608, ...}) = 0
    0.000022 mmap(NULL, 2109680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d157b1000
    0.000018 mprotect(0x7f7d157b4000, 2093056, PROT_NONE) = 0
    0.000018 mmap(0x7f7d159b3000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f7d159b3000
    0.000024 close(3) = 0
    0.000018 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000018 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000015 open("tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000015 open("x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000015 open("libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000015 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    0.000016 open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    0.000015 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
    0.000017 fstat(3, {st_mode=S_IFREG|0755, st_size=1864888, ...}) = 0
    0.000015 mmap(NULL, 3967392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d153e8000
    0.000017 mprotect(0x7f7d155a7000, 2097152, PROT_NONE) = 0
    0.000019 mmap(0x7f7d157a7000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bf000) = 0x7f7d157a7000
    0.000030 mmap(0x7f7d157ad000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d157ad000
    0.000019 close(3) = 0
    0.000048 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d15fe2000
    0.000023 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d15fe1000
    0.000016 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d15fe0000
    0.000017 arch_prctl(ARCH_SET_FS, 0x7f7d15fe1700) = 0
    0.000058 mprotect(0x7f7d157a7000, 16384, PROT_READ) = 0
    0.000020 mprotect(0x7f7d159b3000, 4096, PROT_READ) = 0
    0.000021 mprotect(0x7f7d15de2000, 4096, PROT_READ) = 0
    0.000020 mprotect(0x7f7d1600d000, 4096, PROT_READ) = 0
    0.000017 munmap(0x7f7d15fe4000, 157471) = 0
    0.000020 set_tid_address(0x7f7d15fe19d0) = 25696
    0.000015 set_robust_list(0x7f7d15fe19e0, 24) = 0
    0.000017 rt_sigaction(SIGRTMIN, {0x7f7d15bd0b50, [], SA_RESTORER|SA_SIGINFO, 0x7f7d15bdc390}, NULL, 8) = 0
    0.000019 rt_sigaction(SIGRT_1, {0x7f7d15bd0be0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7f7d15bdc390}, NULL, 8) = 0
    0.000016 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
    0.000020 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
    0.000074 brk(NULL) = 0x20c7000
    0.000015 brk(0x20e8000) = 0x20e8000
    0.000023 readlink("/proc/self/exe", "/usr/lib/jvm/java-8-oracle/jre/b"..., 4096) = 39
    0.000038 access("/usr/lib/jvm/java-8-oracle/jre/lib/amd64/libjava.so", F_OK) = 0
    0.000020 open("/usr/lib/jvm/java-8-oracle/jre/lib/amd64/jvm.cfg", O_RDONLY) = 3
    0.000020 fstat(3, {st_mode=S_IFREG|0644, st_size=627, ...}) = 0
    0.000017 read(3, "# Copyright (c) 2003, 2013, Orac"..., 4096) = 627
    0.000023 read(3, "", 4096) = 0
    0.000016 close(3) = 0
    0.000018 stat("/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/libjvm.so", {st_mode=S_IFREG|0755, st_size=16989733, ...}) = 0
    0.000024 getgid() = 1000
    0.000015 getegid() = 1000
    0.000014 getuid() = 1000
    0.000015 geteuid() = 1000
    0.000021 futex(0x7f7d159b40a8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    0.000019 open("/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/libjvm.so", O_RDONLY|O_CLOEXEC) = 3
    0.000018 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\350!\0\0\0\0\0"..., 832) = 832
    0.000016 fstat(3, {st_mode=S_IFREG|0755, st_size=16989733, ...}) = 0
    0.000017 mmap(NULL, 16717288, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d143f6000
    0.000017 mprotect(0x7f7d150c4000, 2097152, PROT_NONE) = 0
    0.000017 mmap(0x7f7d152c4000, 888832, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xcce000) = 0x7f7d152c4000
    0.000021 mmap(0x7f7d1539d000, 304616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d1539d000
    0.000021 close(3) = 0
    0.000018 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/jli/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000019 open("/usr/lib/jvm/java-8-oracle/jre/bin/../lib/amd64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000017 open("/home/pbauer/.gvm/pkgsets/go1.7.4/global/overlay/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000017 open("tls/x86_64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("tls/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("x86_64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000016 open("libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    0.000017 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    0.000016 fstat(3, {st_mode=S_IFREG|0644, st_size=157471, ...}) = 0
    0.000026 mmap(NULL, 157471, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d15fe4000
    0.000018 close(3) = 0
    0.000019 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    0.000021 open("/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
    0.000020 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0V\0\0\0\0\0\0"..., 832) = 832
    0.000018 fstat(3, {st_mode=S_IFREG|0644, st_size=1088952, ...}) = 0
    0.000018 mmap(NULL, 3178744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d140ed000
    0.000020 mprotect(0x7f7d141f5000, 2093056, PROT_NONE) = 0
    0.000020 mmap(0x7f7d143f4000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x107000) = 0x7f7d143f4000
    0.000025 close(3) = 0
    0.000043 mprotect(0x7f7d143f4000, 4096, PROT_READ) = 0
    0.001052 munmap(0x7f7d15fe4000, 157471) = 0
    0.000048 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f7d15edf000
    0.000026 mprotect(0x7f7d15edf000, 4096, PROT_NONE) = 0
    0.000018 clone(child_stack=0x7f7d15fdeff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f7d15fdf9d0, tls=0x7f7d15fdf700, child_tidptr=0x7f7d15fdf9d0) = 25697
    0.000036 futex(0x7f7d15fdf9d0, FUTEX_WAIT, 25697, NULLdata
    ) = 0
    0.829684 exit_group(0) = ?
    0.003112 +++ exited with 0 +++
  5. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,7 @@ strace -r java pmbauer.JavaIsKindaLight
    0.002464 +++ exited with 0 +++
    ```

    `futex->exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup. IO appears to be a non-factor.
    `futex -> exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup. IO appears to be a non-factor.
    The minimal example and Clojure both exhibit this profile and simple Java applications that don't dynamically compile code do not.


  6. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,7 @@ strace -r java pmbauer.JavaIsKindaLight
    0.002464 +++ exited with 0 +++
    ```

    `exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup. IO appears to be a non-factor.
    `futex->exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup. IO appears to be a non-factor.
    The minimal example and Clojure both exhibit this profile and simple Java applications that don't dynamically compile code do not.


  7. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaIsKindaLight.java
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ public static void main(String[] args) throws IOException, ClassNotFoundExceptio
    sb.append("}");

    // Save source in .java file.
    File root = new File("/tmp"); // On Windows running on C:\, this is C:\java.
    File root = new File("/tmp");
    File sourceFile = new File(root, "test/ParseSomeCode.java");
    sourceFile.getParentFile().mkdirs();
    Files.write(sourceFile.toPath(), sb.toString().getBytes(StandardCharsets.UTF_8));
  8. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    This is in response to a series of tweets by Chouser regarding java/clojure/python startup time dynamically parsing some code.
    This is in response to a series of tweets by Chouser regarding java/clojure/python startup time for dynamically parsing a small code snippet.

    https://twitter.com/chrishouser/status/826881223486226432
    https://twitter.com/chrishouser/status/826884726485032960
  9. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ time python -c "print $CODE"
    0m0.016s
    ```

    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC in Java parsing `{"parse": {"some": "data"}}` is roughly 10x faster than the example.
    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC in Java parsing `{"parse": {"some": "data"}}` (JSON) is roughly 10x faster than the example.

    But to be fair to Clojure, this example is parsing and executing _code_ not data. So this gist provides the semantic equivalent of what Clojure, Python, and Node.js are doing in pure Java.

  10. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ time python -c "print $CODE"
    0m0.016s
    ```

    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC in Java parsing some JSON is roughly 10x faster than the example.
    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC in Java parsing `{"parse": {"some": "data"}}` is roughly 10x faster than the example.

    But to be fair to Clojure, this example is parsing and executing _code_ not data. So this gist provides the semantic equivalent of what Clojure, Python, and Node.js are doing in pure Java.

  11. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ time python -c "print $CODE"
    0m0.016s
    ```

    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC parsing some JSON is roughly 10x the example.
    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC in Java parsing some JSON is roughly 10x faster than the example.

    But to be fair to Clojure, this example is parsing and executing _code_ not data. So this gist provides the semantic equivalent of what Clojure, Python, and Node.js are doing in pure Java.

  12. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    This is in response to a series of tweets by Chouser regarding java/clojure/python startup time dynamically parsing some code.

    https://twitter.com/chrishouser/status/826881223486226432
    https://twitter.com/chrishouser/status/826881223486226432
    https://twitter.com/chrishouser/status/826884726485032960

    (bench results are normalized to my dev environment)
  13. pmbauer revised this gist Feb 2, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,7 @@ strace -r java pmbauer.JavaIsKindaLight
    0.002464 +++ exited with 0 +++
    ```

    `exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup.
    `exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup. IO appears to be a non-factor.
    The minimal example and Clojure both exhibit this profile and simple Java applications that don't dynamically compile code do not.


  14. pmbauer revised this gist Feb 2, 2017. 1 changed file with 47 additions and 0 deletions.
    47 changes: 47 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    This is in response to a series of tweets by Chouser regarding java/clojure/python startup time dynamically parsing some code.

    https://twitter.com/chrishouser/status/826881223486226432
    https://twitter.com/chrishouser/status/826884726485032960

    (bench results are normalized to my dev environment)
    ```
    CODE='(-> {:parse {:some :data}} :parse :some)'
    time java -jar clojure-1.8.0.jar -e "$CODE"
    0m1.018s
    CODE='({"parse": {"some": "data"}})["parse"]["some"]'
    time python -c "print $CODE"
    0m0.016s
    ```

    I initially suspected the poor showing for Clojure/JVM could mostly be attributed to `clojure.jar` and not the JVM. A quick POC parsing some JSON is roughly 10x the example.

    But to be fair to Clojure, this example is parsing and executing _code_ not data. So this gist provides the semantic equivalent of what Clojure, Python, and Node.js are doing in pure Java.

    ```
    time java pmbauer.JavaIsKindaLight
    0m0.471s
    ```

    Okay, so Clojure isn't adding _that_ much overhead. We're still several orders of magnitutde slower than python.

    But why? Is it because the Java and Clojure versions are writing to disk and the python version isn't? Well ...

    ```
    strace -r java pmbauer.JavaIsKindaLight
    0.000000 execve("/usr/bin/java", ["java", "pmbauer.JavaIsKindaLight"], [/* 115 vars */]) = 0
    0.000288 brk(NULL) = 0x10d1000
    0.000034 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    ...
    0.000037 futex(0x7fdc1b2a19d0, FUTEX_WAIT, 7052, NULLdata
    ) = 0
    0.842562 exit_group(0) = ?
    0.002464 +++ exited with 0 +++
    ```

    `exit_group` is taking up the vast majority of execution time; all of the real work is already done, java is just blocked exiting on thread cleanup.
    The minimal example and Clojure both exhibit this profile and simple Java applications that don't dynamically compile code do not.


  15. pmbauer created this gist Feb 2, 2017.
    46 changes: 46 additions & 0 deletions JavaIsKindaLight.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    package pmbauer;

    import javax.tools.JavaCompiler;
    import javax.tools.ToolProvider;
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;

    public class JavaIsKindaLight {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    StringBuilder sb = new StringBuilder();
    sb.append("package test;");
    sb.append("import java.util.*;");
    sb.append("public class ParseSomeCode { ");
    sb.append(" public static Object data() {");
    sb.append(" Map m = new HashMap() {{");
    sb.append(" put(\"parse\", new HashMap() {{");
    sb.append(" put(\"some\", \"data\");");
    sb.append(" }});");
    sb.append(" }};");
    sb.append(" return ((Map)((Map)m.get(\"parse\"))).get(\"some\");");
    sb.append(" }");
    sb.append("}");

    // Save source in .java file.
    File root = new File("/tmp"); // On Windows running on C:\, this is C:\java.
    File sourceFile = new File(root, "test/ParseSomeCode.java");
    sourceFile.getParentFile().mkdirs();
    Files.write(sourceFile.toPath(), sb.toString().getBytes(StandardCharsets.UTF_8));

    // compile
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    compiler.run(null, null, null, sourceFile.getPath());

    // load, run
    URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
    Class<?> cls = Class.forName("test.ParseSomeCode", true, classLoader);
    Method method = cls.getMethod("data");
    System.out.println(method.invoke(null));
    }
    }