 Good morning everybody. As you can see, the title of my talk is M-Ruby on small devices. By now, you are all introduced to M-Ruby. There were two talks on M-Ruby, one by Eric and one by Koshoban. I'm sure I'm butchering the name. So, I did not tell you what M-Ruby stands for. So, M-Ruby is the minimalistic Ruby, which is considered as a lightweight sibling of Ruby. It complies with part of the Ruby ISO standard. It's sponsored by this institute in Japan and I'm going to be following a convention of using the name with a capital R M-Ruby as the language and M-Ruby as the interpreter with a smaller R. Just as we do Ruby with a capital R to indicate the language and Ruby with a small R to indicate that it is an interpreter that I'm talking. So, for the rest of the talk, that's the convention I'm going to follow. Okay. All right. So, M-Ruby the language is derived out of this ISO standard. There is an ISO standard for Ruby, believe it or not. But M-Ruby is not Ruby. It is a little less than Ruby. From my last count on the documentation of M-Ruby and Ruby, I found out that M-Ruby has about 36 classes and seven modules and not all classes that are there have the same list of methods to the classes. So, it's a smaller subset of the larger language that we know as Ruby. And I'm comparing that with Ruby 2.3, which has about 105 classes and 19 modules. Okay. The syntax is compatible with 1.9 version of Ruby not 2.0 because it was conceived before Ruby 2.0 came. So, M-Ruby, the work started in around 2010 is what Matt told me the other day. It has the more liberal license, the MIT license, so you can use it for fun and profit. So, why do we think we should use something like M-Ruby? Well, the stated purpose of M-Ruby is that it is used for embedding and linking. And as we all know, we are in the age of small devices, right? We have Fitbit talking to my phone, talking to something out in the cloud, controlling my Philips Hue, all these devices around us. And these are small devices that we would like to control. And for those small devices to be controlled using smaller languages is one of the purpose of M-Ruby. So, we want to embed it and link it. And also, because Matt is interested. So, just as there is a rich one, there is a rich one. M-Ruby is nice, and so we are nice. Okay, so let's talk a little bit about it being lightweight. What I mean, what I understand as it being lightweight is that it uses less memory during runtime, that the size of the executable that it generates is small because it has to fit on the small devices, that it consumes less CPU cycles. That means that it is a little fast or fast enough to drive that device. And it has minimal dependencies on external libraries. And we'll see what each of these mean in my demo part of this. So, this talk is in two parts. I'll go through the slides and then we'll go through some demos. Okay. All right. So, small devices, what do we mean by small devices? Well, in this context, I'm talking of something like Raspberry Pi. I'm sure you must have heard of Raspberry Pi, a single-board computer. There is a version of Raspberry Pi, which is called Raspberry Pi Zero, costs about $5. And has a CPU that has a 32-bit single-core CPU and 512 MB of RAM. Okay. So obviously, everything that we do on this single-board computer has to fit in that kind of small device. It has storage as microSD. I have a bunch of those over here. And we will have a birds of feather session soon where we will be able to hack these Raspberry Pi's. So, that's the spec of Raspberry Pi. And I play with these Raspberry Pi's for fun. However, the one that I'm using today is a slightly beefier version because I have to do more things. I have to do demos and I have to run this presentation of Raspberry Pi. So, believe it or not, this is the first time I'm doing this on a Raspberry Pi that is running here at the podium. Thank you. This is not given by my laptop. I'm driving this on the small device. I mean, I'm talking of M-Ruby on small devices. It behaves upon me to run it on a small device, right? So, a huge shout out to the organizers over here. I had made this special request. I was pleasantly surprised that they have heeded to my request. I thanked the AV team for helping me out last night in figuring all this out. So, Raspberry Pi for fun, you know, and we will see all that fun just here shortly. I also do it for profit. I work for a company that it's a credit card company which is a close look credit card system. Not many people here may use it unless you have trucks, a fleet of trucks or a fleet of jets or yachts or something like that. We have fuel cards and these FBOs are the places where you tank up your jet or truck or whatever it is that you use our card for has these point of sale devices that are small devices, okay? Now, they compare to this Raspberry Pi. They are kind of bulky, you know, and heavier. But look at the specs. We are talking of 200 megahertz of arm 9, 32-bit risk, which has 6 MB of RAM, of which only 2 MB of SRAM is available for my program. So, my program, if I have to run anything that I do on that device, it better fit into MB. We are talking of 2 MB here, okay? And these are still out there in production. More beefier versions of these devices are out there. But, you know, we have to support the lowest common denominator. And so, these are the kind of devices that I have to program on. And I thought, well, maybe it would be nice to have these devices or run Mrooby on those devices. I tried very hard. It's an up here task. I haven't gotten that there yet. But that's my ultimate dream, is to be able to drive one of these devices using Mrooby. How is that possible? Well, let's see. So, this is the company that I work for, Shameless Plug. We are hiring. We have Pearl, Ruby, Rails, Ember, Oracle, C as our stack. Go to our website. There is a now hiring link, too, on the homepage. And you'll see what we are interested in. So, hit me up after the talk if you're interested in doing something like this as a career. Okay. So, let's talk about embedding and linking. We saw in the talk yesterday that we have embedding. What we mean by embedding is you take a Ruby script and embed it inside of C. Most of the Ruby code that I will be showing today will have some C component to it. We will, of course, run the Mrooby interpreter. But what I'm doing here is I am creating that string, as you can see, put as hello world. And I'm loading that string into the Mrooby evaluator. And it loads the string and executes that string. And then it closes the evaluator. So, that's the minimalistic kind of approach to embedding a Ruby script inside of C. And then linking, right? We are talking of embedding and linking. So, how do we link this? On my system over here, we have GCC as the compiler. I have invoked the compiler flags on the first line. I give the path to include the Mrooby headers that are required by the secret. How many over here do C? Okay. All right. So, I'm not talking to an audience that does not know what this is all about. All right. At least some of them understand what I'm doing here. And I'm linking. That's where that linking comes in. The Ruby library, LibMrooby.a is where it gets linked into my C code. And then, of course, it creates an executable. And I execute that hello, just like any executable on that device, or in this case, on the Raspberry Pi. And it would execute and run the Ruby code that was embedded inside of C. Okay. So, how do we get that? Mrooby. Well, to install Mrooby, you have to have some prerequisites you need to have get, because I'm going to install it from the source. You need GCC to build. Mrooby itself is written in C. So, you need GCC. You need a parser generator called Bison on a Linux platform. I don't know what is the equivalent of this on Windows. But you would need something like this. And then you do need Ruby. Now, that's one of the difficulties that I'm having in having Mrooby compiled on the device. Okay. If I have to compile Mrooby on the device, I need Ruby on that device, which, you know, is a challenge for certain class of small devices. But for Raspberry Pi, that's not a problem, especially the one that I have up here. That's not a problem. I first installed Ruby, got all these things done, and then I compiled it using, from the source, I cloned the git repo and just .mini rake, and it compiled Mrooby for me. So, that's how I got Mrooby on the device, running on my Raspberry Pi. All right, what it does then, it generates a bunch of binaries, and some of them are obvious, like the interpreter gets generated after compilation. You get an interactive shell just as Ruby has IRB. Mrooby has MIRB. You get the compiler that will compile the bytecode into a symbol table or the actual executable, and then we have the debugger to debug your code, and then we, I just learned yesterday that there is a way to remove the debugging information from the code that it generates, and that's where you use RubyStrip. Thank you, Matt, for helping me on that one. All right, so that's what it generates when you run minirake on the source. Okay, so let's see what I mean by embedding the bytecode in C. Here, I have a simple one-liner Ruby program called hello.rb. All it does is put s hello world. If I compile that hello.rb, it would generate a bytecode, and it would generate it in a file called hello.mrb. So, it's a bytecode that the Mrooby compiler would understand how to interpret that bytecode. It's a binary file, so if you want to see open and see what is in there, you would need something like hex dump to see the contents of this file. All right, and then to run this bytecode on or using Mrooby, you will have to give that flag the minus b for bytecode, and sure enough, it will interpret the bytecode and do what you asked it to do, which is to put s hello world on the std out. Okay. You can also generate the bytecode as a C array. Okay. So, in the second example here, the same file, however, you see that I am passing another command line argument here called hw under code symbol. It's just a name I made up with a flag of minus capital B this time for the same program. It produces a symbol table, which is nothing but an array. So, you have to include that generated file into the file that you want to embed it in, which is on the right-hand side, and then instead of loading the string, you can see that the load function is now using iRap, which is the intermediate representation of that bytecode. Okay. So, it is reading that symbol table that you have created using the previous command, and then, of course, when you compile this code just as we did in the earlier case as we saw it, I compile it using a magic shell script, which we'll see here very soon. Compile it, and when you run the executable, it does what you wanted to do. The compiler, again, it's no surprise, except here I have given the path that I used, and I have given the path that I used, and it compiles the code. Okay. So, mruby itself, as you may have known if you have listened to the earlier talks on mruby, the way you generate gems, there is a gem generator in mruby called mrbGems. You can configure, one of the nice things about mruby is it's very modular. You can pick and choose which part of mruby you want in the compile version of your mruby, so you can make your own version of mruby with gems included or compiled into it, baked into it, and that is by virtue of this library manager, and the way you do that is you open up the build config.rb that comes with the source code when you clone the git repo, and modify the config.rb to include or exclude the gems that you want to have in your binary. There is no require in mruby, okay? So, everything that you do, you have to kind of build it into the configuration file, and it generates one single executable, which we will see here very soon how to do that, and there are multiple options of doing that. You can pull it straight away from git, or git hub, or bit bucket, it has interfaces to these reapers, and then when you compile this again using the .mini rake, you get your own version of mruby, which is slightly fatter or thinner depending on what you have included or excluded from the out of the box or the default set of mruby. And then most of the embedded world actually is driven by another embedding language called Lua, which has been around for a long time, so it's not really fair to compare, but we should try to aim to come to that level. Lua is a prototype based language, has no classes, it's much simpler than mruby, has only those data types available in it, it also compiles into bytecode, has a stack based CAPI, I don't know if it is true that mruby also has stacked based CAPI, okay. And then the VM, however in Lua is register based, which is a slightly more complex version of VM, but it also makes it faster. And so because the language itself is smaller than mruby, it's going to be faster. It came out in 1993, whereas mruby came out in 2014, so there is that difference of timing in how much work has gone into Lua that makes it faster. And Lua has LuaJet, which is just in time compiler, I don't know if we have mrubyJet, but I have seen on the internet that some people are working towards it, I don't know that it is considered as production worthy yet. Okay, so Lua example also looks very similar to mruby example in C. This is an example of embedding Lua script inside of the C code, just like we saw earlier, except in this case I am loading up a file that has the Lua script in it. So this line on the right hand side which says Lua underscore do file, hello dot Lua, expects that there is a Lua file existing in the directory that it reads, which has the Lua script in it. You compile that Lua, the C code. I haven't been able to figure out how to do that on my Raspberry Pi. I was able to do it on my Ubuntu laptop, but not on Raspberry Pi because it requires some installations that I couldn't quite figure out. But yes, when you compile this, apparently it will run the code that is in hello dot Lua. And you can see that it is just about as simple as it is in mruby. So that was the intent from the get go that was what Lua was designed for. And it was surprising to me that mruby comes so close to making it as simple as this. So again, it's testament to this design genius. So this is part of the demo. This is where we will switch over to demo. However, if you are interested in learning a little bit, sorry, mruby is so recent that we don't have books yet on it. You have Stack Overflow and the Git repo itself serves as your way to communicate with the authors of mruby or the contributors of mruby. I believe there is an IRC channel where you can jump in and ask questions or you can ask maths when he's around. These two guys are, I have seen a lot of videos of people using mruby, but these are probably one of the best videos that I have seen. They have written mruby on an RTOS. Absolutely fabulous work done by these two people. Okay, so before I switch over to my demo, I also have some announcements. So I'm going to keep this pie running for you guys. So you can SSH into my Raspberry Pi and hack it to your heart's content. I will give you the IP address soon here right after when I go into my demo session. You can SSH into it. That's the password. It does not have pseudo access right now, this account, but if you need to do access, let me know. After I finish my presentation, I will open it up for you guys for doing whatever you want to do. The hard disk on this is a little microSD card. So you can do whatever you want to do on the Raspberry Pi because it's going to get formatted right after the conference is over. So, okay, so now let's go to the demo session which is, again, I'm doing this for the first time. I believe this is still the address. Can somebody confirm that they can SSH with mruby at 10.35.5.141. And then give rubycon 201. I think Prathamesh there was trying it a few minutes ago. I just want to make sure that we're still on. It depends on Wi-Fi being available. You're on? All right. Okay. So feel free to play around on my Raspberry Pi while I'm doing it. I will open it up for you to try out certain things. Okay. So the few things that I wanted to do in the demo today, how much time do I have? It comes down, right? Okay. Okay. Oh, sorry. I want to show you what I mean by binary file being small. And remember I said it's lightweight means the binary has to be small and it has to have less dependencies on the operating system. The devices that I use to program it on the POS devices, by the way, are a bit of an operating system. So I'm coding right to the metal. Okay. There is no operating system. Everything that I need on that device, I have to compile it in my code, cross compile it, sorry, in my code. And effectively my code is the operating system on those POS devices. However, over here, we have a much richer environment. And so, okay. So you see here, this is where I have compiled the mruby. Myrb is a little over 1.5 megabytes. So it will fit or mruby is a little over 1.5 megabytes. So my limitations on that POS were that the program should be less than 2 megabytes. This will run. Ruby may or may not run. And the dependencies, you can see those dependencies by doing LDD on Raspberry Pi. The operating system that I'm using here is called Raspbian. The Raspbian is the operating system that the company that produces Raspberry Pi has come up with. It's a variant of Debian. So these commands are pretty much available, I think, on all Linux platforms. So if I do LDD on mruby, you will see that it depends on these many runtime libraries, .so files. However, if I had done this on Ruby on the same device, you would see it has slightly more dependencies. So that's what I meant by it has to have less dependencies on it. And also, if you saw the size of a Ruby, it would be definitely larger. I don't know how to see the size because when I try to do size, I think there is a command called size on mruby. Yeah, see all that. And I try to do the same thing on the version of Ruby that I have. Oh, yeah, there you go. Okay, so here is the thing. So when you look at the size of the compiled version, sometimes it is deceptive because it might have a small size but it depends on a whole bunch of other things. And so when we consider the size of the entire application, you have to take into consideration those things. So this can be confusing. So be careful about how you measure size of a binary. Okay, so that was, you know, in terms of the size and memory. So also, we want to see how much memory it consumes when it is running in RAM. So that's the other requirement that I have. I have only so much of RAM. Does it, will it work or will it run out of RAM? Okay, the device is like I said that I have, I want this to work on, don't have page faults and any sophisticated paging mechanism. So everything that you want to run has to fit into the RAM. Okay, so for that purpose, what I have done is let me, what I have done is I have written a little, I have found this. So here, I am going to run Ruby. Okay? And here, I am going to say, let's name Ruby. Okay, and it shows that it is using about 6.14 megabytes of RAM. Okay, obviously this will not run on that small device that I was intending to run it on. All right? So how does it compare with Ruby? So let's look at that. I run Ruby in this panel and then run the same command for, yeah, this would work, this would work on that small device. So that's how I look at, so every program that you're running, you would want to use this tool and I will make these tools available on the Internet, those that I have either written myself or have got copied from somebody else, and they will all be available by the end of this conference on GitHub. So that's how I look at the size of the memory that it consumes at runtime, not just the size while it is on the hardest compiled version, but also when it is running, actually in the memory. Okay? And then the other thing that we want to see is the speed. How fast is Ruby compared to Ruby or Lua or whatever it is that you're trying to use as an alternate to embed your code in. All right, so to do that, I'm going to try to go to my code. So what I have done here is I have written Fibo.rb, which calculates the Fibonacci of a number, and I've used, this is not the most accurate version of Fibonacci because it might do wrong things depending on smaller values of n such as 0 and minus 1 and 2 and minus 2 negative numbers. But for the purpose of this particular demo, I think this would suffice. Okay, so I'm going to time this with mruby. So time mrubyfibo.rb. And mruby took about, took about 8 seconds. The last time I measured this, it was taking around 8 seconds to run Fibonacci of 32. All right. Oh, it took 10 seconds today. Benchmarking in this way is, you have to be very careful about benchmarking stuff like this. I mean, just a couple of runs is not going to give you. There's a whole study that shows you how to properly benchmark programs against each other. But this is just a rough estimate of how it would look like when you ran. So mruby took 10 seconds, mruby took around 4 seconds because mruby is probably using a lot of resources and therefore making proper use of them. So the idea here is, okay, so let me see if I have something else to compare it with. The other thing that I have to look at when I do these things is see how fast it takes to load the environment. Okay, because, again, my devices have no operating system, so everything that I put on it has to load, and these are POS devices. They have to be constantly on, not crash, be fast, everything, you know, because people are actually swiping their card and has to happen in real time. So the other factor that comes to my mind is how do you load these devices? Let me just, I don't need this session here. So I have a little shell script that shows how long, not in the right directory, CD2, okay, how long it will take to load. I think it is, yeah, okay, so boot times. So that's the time it takes to boot your application. So this shell script runs for different versions of the compiler. All it does is, so for example, let me show you what I'm trying to do. If you run Ruby on the command line like this, which does nothing, okay, it just runs and does nothing. How long does it take? And that's the time it takes for Ruby the interpreter to run. Okay, so if I time this guy, all right, it took about one-tenth of a second to load up and do nothing. If I did the same thing with Ruby, see the difference there? Okay, if I did the same thing with Lua, see the difference there? Okay, and I have on this, I believe there is Perl, so I was comparing with a bunch of these. So this gives you an idea of how long it would take to boot things up when you first load the program. Okay, so as you can see, we have, we have, okay, so let me get this for you. So I had Ruby, Perl, Python, Node, and Ruby and Lua in this boot program, and so when I do this, okay, so let's see, let me scroll. Why is it not scrolling up? That's what's happening. Okay, so let's do this. Oh, so that's why. Okay, so it's the output of time is not going on standard out. It is going to standard error. I believe that's why I was not able to see it. But let's do this at the command line then. Time, that's how long it takes to Python, Lua. So you get the idea. So what I have seen is, is when I play around with Ruby, the biggest challenge that I have is to compile, cross compile it for the devices that I'm interested in running it on. And so one of the hurdles that I'm coming up with in getting this running on the POS device that I was talking about is not all the libraries that Ruby needs for it to run properly are on that device. So it's a challenging task for me to get that Ruby working on the small device. But with support from the community, I might be able to do it. That is all I have for as far as demo is concerned. I have about eight minutes for question answers. So shoot away. Okay, so the question is, since I'm running it on a small device that is so constrained, is there anything in the language itself that will monitor whether it is going out or running out of cache? I don't think so. Is there anything, Matt, that would tell me from within the program that... So the answer there is that it is not there by default. If you want that kind of monitoring, you'll have to write your own code. For most of these answers, like these questions, it is, you probably have to write it on your own. If it is not there given... So these compilers, the cross compilers that are available for those devices are very, very pricey. The compilers themselves have a very stringent restrictions on what you can and cannot compile onto the devices because, obviously, we are playing with credit cards here. So they do a lot of checking of your code before they allow you. And it has to be signed by two authorities before it can be loaded onto the device. So one of the key things that I have learned in playing with these is that you need to know the operating environment in which you want to embed in before you can successfully embed and get it to work the way you want it to work. Any other question? Counting to three. One, two, three. No questions. Okay. Thank you.