 Thanks, everyone. Given the sparsity of the room, I'm guessing that this question is relevant. So what is Ruby plus OMR? So we'll start by talking about OMR a little bit. OMR is an open source toolkit for language runtimes. It consists of a bunch of components that you can then glue together to your existing language runtime, things like garbage collection, a monitoring system, a JIT compiler. The goal of OMR is one of compatibility. So in contrast to other projects like Truffle and Grawl, we don't want to rewrite a new runtime. We want to step in and help your existing runtime get better, faster, and stronger. The goal here is really it's about integration rather than replacement. So the Ruby plus OMR preview is a vehicle by which we've been experimenting with OMR technology in the Ruby language. Now at RubyKaigi 2015, I talked about this project and as did some of my colleagues talking about the garbage collector. And despite the fact that that was RubyKaigi 2015, that was only 13 months ago. It sounds longer because it's 2017 now. So what have we been doing for the last 13 months? The answer is a lot of things. So at RubyKaigi, we had tried really hard to get our code open-sourced before RubyKaigi and we super didn't make it. There's still more things to do. And in fact, our initial contribution got merged finally, March 7th, by Charlie. Right there. Shortly afterwards, we released the code that we modified in Ruby. However, this didn't have the JIT compiler technology because when we did the first drop of OMR, we didn't put up the JIT compiler because it still was going to take some time. In fact, that's what I spent most of last year on, was trying to get to September where we finally actually did release the JIT compiler technology. So after the JIT compiler technology went open-source, we released the JIT technology for Ruby. And then I've spent a little bit of time taking the JIT technology and moving it up to Ruby 2.4. So I've been working on getting up to date so that we can actually build against Ruby 2.4. So today, if you visit our GitHub project, you'll see that Ruby 2.4 OMR is the current default branch and this is based right off of the Ruby 2.4 tag. The JIT compiler is hooked up and running Travis CI tests. We only run a small set of the MRI tests because we fail make test all right now, working on that. I've spent a bunch of time populating our issue tracker, trying to make sure that it's clear the state of the project, what we're working on, what needs to be worked on. Just a heads up for any of you who go and benchmark this right now. We're slower than we were in our preview. This is because I've actually turned off some of the optimizations that were hard to justify because they were a little too specific to math and math type things that show up in benchmarks, which isn't a real workload. We're aiming for something that's actually going to be much better in the software engineering layer. So for the JIT, the goal has really been functional correctness right now. We want to pass the whole test suite at all of the optimization levels we're exploring. And as I said, the goal here is integration, not replacement. So we don't put any restrictions on native code. Since the preview, we've added some optimizations and reworked a couple of others. So I have reworked the way that our inliner works a little bit, taking advantage of the new call caches that got added for Ruby 2.4. It's got a very simple compilation control today. It just counts how many times the method's invoked before it compiles the method. And so really what I've built is a foundation. This is the state of the project today is we are, we've laid the foundation and now we have to build the house on top. So what's our goal with the Ruby plus OMR preview? Well, our goal is to make Matt change his slides. Specifically, the slide where he called out IBM J9, at the time we hadn't named the project, as a potential contributor to Ruby 3x3. So we want to turn this from a maybe into a yes. Indeed, we actually did help contribute. Ruby 3x3 is really going to be about trying to take the performance forward in big steps. And that's going to probably involve JET. We have a lot of pre-built technology from OMR and we think that MRI will be able to exploit that. And what's in it for us is a validation of the OMR approach. We believe that we can take these pre-existing components and turn them into a recyclable toolkit for building language runtimes. And if Ruby's using it, that's proof that we did it. The other thing, and this is the other half of the OMR theory, is that community improvement will be shared by everyone. So today, we already build our IBM JDK on top of OMR. Our build process internally consists of cloning OMR and then building the JDK on top of it. So benefits and improvements that happen in OMR are already being shared by Ruby, and that can continue. Now, December, Chris Seton posted a tweet. I know of two people working on secret Ruby JITs for MRI. I don't find this scary. I think that this is actually an opportunity here. So as I go through my talk, what you're going to notice is that I'm not actually talking that much about just in time compiler stuff. Because the compiler technology, we've already got it. It's already there. What really has to happen are changes in MRI to enable the JIT compiler to get better and do a better job. And so this is the area where multiple JITs can collaborate on providing an interface to information to make things better. But having some competitions makes too, because it means that we can actually push each other. And the end result of this is a better result for Ruby as a community, not just for us at OMR. So one of the things that Chris mentioned, though, is that, in order to get anything when you're compiling Ruby, it takes a lot of sophistication. And I really agree with that. Because in my mental model of where I am in doing Ruby JIT work, it kind of looks like this. We've got a curve that we can start pushing up pretty heavily. But we've spent a lot of time just laying the foundation again. All right, so the title of this talk was Challenges, highly surmountable challenges. So the first set of challenges that I want to talk about are challenges that we have in the community. So Aaron Patterson has this great tweet that I have now used in two talks and will probably use in many more because I really like it. And there is no best of anything. And so for us, there is no best Ruby JIT. There is no best Ruby interpreter. There's just what works for your use case. So for your use case, that might be Truffle Ruby, that might be JRuby, that might be Rubinius, that might be Ruby plus OMR, that might be MRuby. But as we try to mutate and work in the VM, we need to make the right trade-offs. JIT compilation is by definition a trade-off. You are trading off some of the computation that could be used for your user's tasks and spending it to create native code that will hopefully make things better. But this costs memory and this is gonna cost time before your VM hits peak performance. And we need to prioritize because we can focus extensively on peak performance at the cost of footprint and at the cost of warm-up or we can focus a little bit on both. There's a whole bunch of metrics that we could be talking about and really what needs to happen is that the Ruby community, and this will happen naturally as people just adopt things, but it can be a deliberative effort as well, help provide benchmarks. So Opt-Carrot, by the way, is a great first start. Opt-Carrot, though, is kind of weird. It's not what most Ruby looks like. It's very, very CPU-intensive and that's not what Rails looks like. And so it may drive optimization in the wrong direction. Now, I gave a big talk at RubyKaigi about this, so you can go watch that talk. Me, I think we have to have a variety of benchmarks. Opt-Carrot's a great start for a CPU-intensive benchmark, but I also think we need some memory-intensive benchmarks. We probably need a startup benchmark and we're gonna need some web application framework benchmarking. And as I admitted at my RubyKaigi talk, I have no idea how to benchmark a web application framework. That's way outside of my skill set. The good news is, I managed to actually inspire Noah Gibbs to go and start trying to do this. And so for those of you who are interested in Rails performance, go take a look at his repo, leave some comments on his approach. He's made choices with a lot of thought into why he made those choices and it's worth engaging with him to see if you can give him a hand, make it better. Now, the other challenge we're gonna face in doing compilation with RubyPlusOMR is information challenges. And so, when you look at a diagram of what the MRI, what MRI looks like when you've added in the JIT compiler, what's really important here are gonna be these white arrows here, which are the JIT and VM interface because JITs are symbiotic with their host VMs. A JIT provides performance, but the VM has to tell the JIT a bunch of information. And so, this kind of information can then drive even higher performance and you've got the symbiosis. So one of the kinds of information that we really like to see MRI export is the notion of infrequent event notification. So there's a whole bunch of things that in your typical application might never happen, might happen only at the beginning of your application. These are things like redefining basic operations. So if you're gonna redefine Fixnum Plus or Fixnum Add, this is a weird thing to do and probably won't happen very often. But if it does happen, I would like the VM to actually tell us. Similar things about modifying constants, changing the class hierarchy. These unlock new kinds of optimization. We can be more aggressive in our specialization. We can actually start optimizing our calls based on assumptions about what the class hierarchy looks like if the VM tells us when it changes, we can then adapt. Essentially, the goal here is don't create code for things that haven't happened yet. So I don't wanna have to generate code to check whether or not you've redefined Plus unless you've redefined Plus. Another challenge that we face in MRI is the way that it does exceptions. And ideally this would be, change the way it does exceptions, but that would be hard for almost anyone. But in the meantime, what we might be able to do is actually just ask the VM to tell us whenever a stack frame could be modified. And so today, when you throw an exception in Ruby, what happens is your C-stack gets unwound using Long Jump. And then you'll iterate down the call frames to the bottom, executing any final evocs that you encounter. Now, the way that we've implemented the Ruby Plus OMR Jet, on that C-call stack are your jitted frames. And so when an exception fires, we lose any information in there. And so we deal with this today by just actually restoring all of the interpreter state every time we leave jitted code. And this is costly. It costs us time and memory and code cache to do all of this extra work. What would be nice is if we didn't do that and we only wrote the code back to the stack when it was needed. And so this is where we need on-stack replacement, the ability to transition from an existing jitted body back into the interpreter, restoring any state that the JIT has hidden away in things like virtual machine or things like actual physical machine registers. And the same principle applies to things like debuggers that are actually going and iterating through the call stack themselves. Any of those need to tell us. Really, we don't wanna be executing code for things that might happen. We wanna only execute code for things that have happened. And in the case of the JITs typically get their best performance by lying to you about what they're doing. They hide as much as they can until you actually ask for it. We will only actually materialize things when they're needed. So another piece of information that would be nice to get out of the VM is profiling information. So personally, I would love it if I could get the frequencies of basic blocks, which would tell me for a contiguous sequence of Ruby byte codes, how often has that actually been hit? Or maybe how often has that been hit proportionally to how often the method's been invoked? Or maybe we do that in a sampling fashion. So we only update it probabilistically. These kinds of information though are really valuable because they let us direct the optimization inside of the JIT. We don't have to spend time then working on optimizing and compiling code that only gets executed one in a million requests. So another thing that would be nice to get is some type information. So if you have a Ruby method that only ever gets called with fixed num arguments, we can generate better code if we know that that's what's happening. And so we would like to be able to speculate on types, but we can't speculate blindly. We need to have some reasonable expectation we're gonna succeed here. And the way to do that is type profiling. So there's this problem that we face inside of MRI, which is called the horizon problem, or this is what it was called when Evan Phoenix was talking about it at RubyKaigi 2015. The thing is a compiler typically will only look at one method at a time. And so it needs to be able to see a broad horizon in order to bring optimization opportunities. So increasing that horizon will really help things. But much of Ruby's core functionality is actually written in C code, which is a problem for the optimization horizon. So one of the original conceptions of Rubinius was this idea of, well, we'll write as much of the Ruby core library in Ruby. And that has been successful for Rubinius at times, but has never really been adopted by the MRI core. They've not been super interested in the idea. In order to address that, Evan Phoenix came up with this wild and crazy idea of what he called lifting the core. And the notion here was, well, LLVM has JIT framework, has a JIT framework. LLVM also compiles C code. So let's ship the MRI interpreter with all of its MRI intermediate language and let the JIT portion of LLVM look at the actual LLVM compiled portions and do inlining and things across the C boundary. So I have my own skepticisms about this idea, but if any of you try it and I want someone to try it, please tell me how it works out. Okay, so rewriting all of core, not gonna work. Lifting the core, I would love to see it happen, but maybe not gonna work. So what do we have for a solution? So my current thinking on this is that we could try something like this, which is incremental rubyification of the core. So this turns out to be really easy to do in Ruby because we have what's called the prelude, which is a set of Ruby code that's always gonna get injected before the interpreter even starts up. This actually gets compiled right into C code that gets loaded directly. So what we could do is take prelude.rb today and move it, convert it to being a directory so that it's easy to reason about, and then put implementations in Ruby of methods that are actually interesting and causing problems for us that we use maybe only when the JIT's turned on, maybe you only use it when, maybe you only use it from the perspective of the JIT, you don't actually run that code. There's a couple of ideas. This brings start-up concerns, but I think they can be mitigated by using Koichi-san's IC serialization stuff, and longer-term, maybe we can do an ahead-of-time JIT solution. I've had some interest in doing that. So now we talk a little bit about optimizations, and here's where I admit. When it comes to optimizing Ruby, we who work on Ruby and OMR are babies, literal babies. We've got a lot to learn. We've got a lot of things to learn from other projects before we can graduate to doing our own thing. We've got things to learn from Ravinius, JRuby, Truffle Ruby. Other people have done really optimized Ruby's. Let's pay attention and listen to the lessons and wisdom they have. There's some challenges in testing a JIT, and this is the big one. This slide, next slide is dense, because this is a thing I have feelings about, but I'll keep it short. So JIT testing is hard. The thing is, when you are testing your normal Ruby program and you write your tests, there's a lot of value and enjoyment that you get from having a fast-running test suite and having coverage that you get 100% code coverage with almost no repetition. Every single line of your test suite is perfectly nice and valid. You can reason about your test suite very locally. You don't have to do anything special on the command line. You just run rake test or whatever. Compiler tests are not like that, unfortunately. There, often you have to run the code multiple times, because a compiler will not choose to compile things until it's necessary, which means that you have to iterate around to make sure that the compiler will actually try to compile something, or you have to have special funky command lines to get it to do things. Compiler tests often require global reasoning. So once you have this idea of infrequent event notification or you do optimization based on speculation, then you have to be able to reason about when does that speculation fail, what is the impact on that. You're gonna have to run many VM instances under different options. And all of these problems end up being the same when we're gonna test your gem underneath a jet. It's kind of awkward. But there is some good news in this world. I actually recently had my own personal hero moment where Benoit Delos came along and he fixed a bug that I had opened against RubySpec to allow it to do repetition, and he fixed it fast, like way faster than I thought he did, or would. And this is a great win for JIT testing, because it means that we can at least run RubySpec under repetition to stress the JIT better. We've got some engineering challenges too. So, you know, one of the big ones. This 309 commits, gets bigger every day, causes me increasing levels of anxiety. You know, how are we gonna keep up with Ruby Core? You know, so some of this can be addressed by just good software engineering. So, a long time ago I spent the time and I built a system that parses instructions.def in order to generate callback code for the JIT automatically. So, if somebody changes instructions.def, the callbacks get updated automatically, saves a lot of pain and agony. But there's still a lot more that's needed and I don't have great answers to some of these ones because some of this is just gonna be collaboration that's gonna have to happen with the core. There's also just clean up that has to happen. You know, the callback generator code that I wrote in Ruby is not very good. It's not idiomatic. It's strange, weird Ruby written by me who I spend all of my day writing C++. The make files in the project also need some love and I've got links to issues there. There's also some challenges that we have with OMR. So, all of OMR, more specifically the JIT compiler portion, has only been open source for four and a half months. So, we're still working on things like improving our interfaces, our integration story. We're building a community slowly, but surely. So, here's where I say the one thing that, you know, helps bring this to my point, which is mentorship. I want to help you guys help Ruby plus OMR. So, if anybody's interested in trying to tackle some of the issues here, get in touch. You know, I will write documentation for things that are unclear. I'll help you guide the implementation. I'll answer email. I'll be on Slack. I'll schedule a video chat with you. Like I really do want to help try to spread this technology and help get people up and running. And so, I'm willing to spend some time because the thing is at the end of the day, Ruby plus OMR needs community and trust to survive. You know, we haven't really put any, we haven't put really any effort into community building up until now. But, going forward, we're gonna have to. And we're gonna need to get some interest from the community. So, my to-do list for the next little while is to start publicizing my mentorship commitment a lot more. I need to start talking more with the Ruby core. I'm that guy in the corner listening right now, but now it's time for me to start actually talking. And I need to start writing some of these changes down that we need to make in the VM or in experimenting and prototyping, getting feedback from core developers. Your to-do list is to give it a try. And when something breaks and it'll break, believe me, open an issue because that'll help. And ask me how to help. You know, little things are perfectly appreciated. Even if I've got a typo in a make file, that's great. Semi-polar class. So, for hitting Ruby 3 by 3, the work ahead kinda looks like this in my mind. Yeah, we do have some work that has to happen in the JIT compiler. But, a lot of it's gonna be VM work. And to reiterate the point I made earlier, the VM work can be shared among competition. So, any of this work that you do or I do on the Ruby VM, probably can be used again by another JIT implementation for MRI. Thank you very much for having me. So, you have plenty of time for questions. Oh, good. So, maybe you can already help people to use that. So, have you any questions, it's the time for? So, I saw, like, at the beginning you were saying that you can build on Ruby 2.4 or that. So, like, if you're running Ruby 3, you can't just sit out of this out yet, right? Or you have to move to the... Yeah. So, we have a branch for 2.2. Oh, sorry, to repeat the question, for those who are interested in trying this out, but are currently running 2.3 or a lower version. Yeah, you'll have to start using Ruby 2.4 for the newest work. We do have a branch that has an earlier version of this stuff all built for Ruby 2.2. So, that can be a start. And things that break in Ruby 2.2 may be fixable, you know, for Ruby 2.4. We kind of don't have the resources to maintain multiple version branches and backport, especially given the amount of change that happened between 2.2 and 2.4. So, all development's happening on 2.4 because my goal at the end of this is to upstream it, which means that my goal ultimately is to chase head or trunk. You had a question? In terms of performance, not really, as you were saying, not really micro benchmarks, but if I tested it right now, would it be any faster or about the same as MRI or even slower, what's the... It depends a lot on what you run and how you run it. So, fairly simple benchmarks. We definitely beat MRI sometimes by an appreciable fraction, you know, 50%. In other cases, you will see degradations. This gets into the wibbly bits about how to benchmark, which was my Ruby Kiggy talk. So, if you wanna watch that, I talk a lot about this, but there's a lot of rough edges here. So, I can tell you Opt-Caret, it's pretty much a wash today. We're working on it, but it's not there yet. I had a follow-up question, which is not really related, but one thing that would make it very easier for the community to test would be if support was added to our VM or some of the Ruby version managers, which would go up in the drivers and things like that. So, the question or comment here is, you know, to make it easier to test, we should add this to RVM or RBN for Ruby install and Ruby build. So, if I don't have a public issue about this already, I definitely have an issue here about getting that done, but I've kind of mentally been holding off on doing that until I at least pass make test all. That's kind of my barb in for before, before I do too much in the way of like, hey, RBN, can you add me as a buildable formula? I wanted to at least pass all the tests. Which occurs to me now, that actually that's probably too high a bar because I do pass all the tests in interpreter mode and the JIT's not turned on until you ask for it. So, I need to think about this a little bit. I saw a question over there. No, okay, I'm hallucinating. Have you thought about maybe making it a Docker, I could say, a Docker image? So, we have a Docker container for the Tutu branch. I haven't pushed anything from the Tutu for a branch. It is something we've tried before. People have sort of mixed opinions on doing testing in Docker containers. I believe we did have someone try it out and build a Docker container for us. Or, no, sorry, he built a build container. So, I can point to you at that. It just has all the prereqs installed. So, why is IBM working on this? So, this is all based on the, you know, IBM's sort of plan for the next little while in runtimes is OMR. It's about how we are gonna invest in language runtime technologies. And so, OMR needs proof points. And Ruby was a great proof point. We have many others actually. So, we have proof points in Lua, proof points in a research small talk interpreter called ZonPlusPlus. There are more, I mean, I'm just totally blanking. There's one on, called. Okay, open source ones. No, but the JIT's not done yet. Open. Is it? Oh, okay, never mind. So, this tells you how much I know about all of these various other ports because I missed them. Because they're happening. Okay. We have two JavaScripts, and they don't seem like them. Yes. Another question. I have played a bit with OMR, and one of the things that really interested me was the tooling that you can get. You can get some of IBM's tooling with it. Are there any plans to make it a bit more available because I think you need a license of something like that for the tooling or... Yeah, this is like Health Center? Yeah, for instance. So, most people are getting Health Center through whatever tooling and the way we used to get it, but Health Center is actually just an Eclipse project. You get it from Eclipse Marketplace now. So, most of those tools are all there just on Eclipse to download. Yes, we've got a memory analyst who will read the GC box for a little more. Oh. And some of the other stuff. Because I think that's also a very good selling point that can be... That is what also makes it a little bit different, is that you have, you can stick it easier to debug memory issues, and look at it, and because on MRI it's just bad. Thank you. Any other questions? I have one. You were mentioning about profiling that you need capabilities in MRI to have that. Is it a TracePoint API that you could candidate for that? Maybe. So, this is where it gets into the questions of implementation. So, we could add sort of a private TracePoint and use that. One of the flaws of the TracePoint... Or not flaws, let's turn. TracePoints can be fairly high overhead. That's really the big thing here. And it is possible if you're asking very, very precise questions to hand roll something that's gonna be much more efficient. But there's, it's gonna take more time to do that, so maybe it's better to just go through TracePoints, which is a long way of saying maybe. Any other questions? Matthew, thank you very much for that point. Thank you very much. So, we'll do the next one.