Skip to content

Instantly share code, notes, and snippets.

View chrisseaton's full-sized avatar

Chris Seaton chrisseaton

View GitHub Profile
string = 'hello'
enumerators = []
loop do
1000.times do
e = string.each_byte
e.next # Has to create a fiber to run `each_byte` in
# so it can pause in the method waiting for
# you to call #next again.

Here's an example of using C code from Java, via GraalVM.

I want to run the xxHash algorithm for some reason (I don't know anything about this algorithm, I just know I found a single-file C implementation of it). There's a Java port, but let's say there isn't for the sake of argument, so I want to run the original C version rather than doing the port myself.

I clone it from https://github.com/Cyan4973/xxHash.

I can then compile the native version.

One Approach to Easy and High Performance VMs

This is a lab that walks you through one approach to the challenge of how we can have easy and high performance language virtual machines.

It's designed to come after Mario Wolczko's lecture on a Concise and Opinionated History of Virtual Machines, and illustrates practically some of the concepts and techniques introduced there.

This lab is about just one approach to easy and high performance VMs, and that

0x00000001088d9f40: mov DWORD PTR [rsp-0x14000],eax
0x00000001088d9f47: push rbp
0x00000001088d9f48: sub rsp,0x1f0
0x00000001088d9f4f: mov QWORD PTR [rsp+0x190],rsi
0x00000001088d9f57: mov QWORD PTR [rsp+0x1a8],rcx
0x00000001088d9f5f: movabs rbx,0x119fe1928
0x00000001088d9f69: mov eax,DWORD PTR [rbx+0x8]
0x00000001088d9f6c: add eax,0x8
0x00000001088d9f6f: mov DWORD PTR [rbx+0x8],eax
0x00000001088d9f72: movabs rbx,0x119fe1008 ; {metadata({method} {0x0000000119fe1008} 'RUBY$method$core_min$2' '(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/parser/StaticScope;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;Lorg/jruby/RubyModule;Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;' in 'test')}
public long readLong(VirtualFrame vframe) {
return readLongHelper(vframe.materialize());
}
@TruffleBoundary
public long readLongHelper(MaterializedFrame vframe) {
try {
return vframe.getLong(getSlot());
} catch (FrameSlotTypeException e) { }
MaterializedFrame frame = getLexicalScope(vframe);
org.truffleruby.language.CallStackManager.getBacktrace(CallStackManager.java:272)
org.truffleruby.language.CallStackManager.getBacktraceForException(CallStackManager.java:253)
org.truffleruby.language.CallStackManager.getBacktraceForException(CallStackManager.java:234)
org.truffleruby.core.exception.ExceptionNodes$CaptureBacktraceNode.captureBacktrace(ExceptionNodes.java:117)
org.truffleruby.core.exception.ExceptionNodesFactory$CaptureBacktraceNodeFactory$CaptureBacktraceNodeGen.executeAndSpecialize(ExceptionNodesFactory.java:461)
org.truffleruby.core.exception.ExceptionNodesFactory$CaptureBacktraceNodeFactory$CaptureBacktraceNodeGen.execute(ExceptionNodesFactory.java:435)
org.truffleruby.language.control.SequenceNode.execute(SequenceNode.java:34)
org.truffleruby.language.methods.ExceptionTranslatingNode.execute(ExceptionTranslatingNode.java:51)
org.truffleruby.language.LazyRubyNode.execute(LazyRubyNode.java:42)
org.truffleruby.language.RubyRootNode.execute(RubyRootNode.java:50)

In Vladimir's blog post it's said that GCC can remove a loop that the JVM cannot. This isn't true - the JVM and our Graal JIT compiler can remove the loop in the example.

The loop is this method, which we're then running within another loop to trigger compilation of the method foo.

def foo
 i = 0; while i < 100_000; i += 1; end;

There's a better way to run that benchmark - using the benchmark-ips tool which is designed carefully to allow for optimising implementations of Ruby to do their work and will allow for the JIT to warm up.

require 'benchmark/ips'

def calculate(a, b, n = 40_000_000)
  i = 0
  c = 0
  while i < n
    a = a * 16807 % 2147483647
@Specialisation(guards = "f.arity < args.length")
curry(Function f, Object[] args,
@Cached("createCallNode()") CallNode callNode) {
callNode.curry(f, args);
}
@Specialisation(guards = "f.arity == args.length")
exact(Function f, Object[] args,
@Cached("createCallNode()") CallNode callNode) {
callNode.call(f, args);
main # Rubinius::Loader at core/loader.rb:861
script # Rubinius::Loader at core/loader.rb:679
load_script . Rubinius::CodeLoader at core/code_loader.rb:590
load_script # Rubinius::CodeLoader at core/code_loader.rb:505
__script__ # Object at ../test.rb:7
to_s (inspect) # Array at core/array.rb:1032
detect_recursion . Thread at core/thread.rb:405
{ } in inspect # Array at core/array.rb:1033
each_with_index # Enumerable(Array) at core/enumerable.rb:289
each # Array at core/array.rb:72