Project

General

Profile

Actions

Feature #21695

open

Optimizing Ruby performance with Ruby itself instead of Rust

Feature #21695: Optimizing Ruby performance with Ruby itself instead of Rust

Added by fredlinhares (Frederico Linhares) 5 months ago. Updated 7 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:123836]

Description

I am using ERB on top of C for a game I am making now. We can use the tool to improve the productivity, memory safety, and runtime speed for Ruby. It can also replace a Rust JIT compiler for better results. The only problem is that it requires some level of manual memory management, while Rust does it all for you. If I demonstrate that it is better than Rust in practice, would you be willing to incorporate it into the Ruby language? I want to know because making it more generic will require more effort from me; if you are not interested, I won’t make the tool public.

Updated by matz (Yukihiro Matsumoto) 5 months ago Actions #1 [ruby-core:123839]

I am interested. What kind of API do you need? Since bare memory allocation could break the whole app (leads to DoS), it's not that easy to disclose general purpose memory allocation (that's the reason YJIT, RJIT etc. has their own allocators), but there might be the way to satisfy your version of performance improvement.

Matz.

Updated by Eregon (Benoit Daloze) 5 months ago Actions #2 [ruby-core:123850]

What are you proposing exactly? A "tool" is very vague.
Do you mean a JIT compiler for Ruby written in Ruby? Something else?
Are you interested in speeding up ERB specifically, or Ruby in general?
Why do you think it would achieve better results than a JIT compiler for Ruby written in Rust?
(I think the language in which a JIT is written has little impact on the performance of emitted code, but it matters a lot more for startup/warmup)

Regarding manual memory management, can't you use Fiddle or FFI which already provides that?

Updated by fredlinhares (Frederico Linhares) 5 months ago Actions #3 [ruby-core:123868]

Currently, my goal is to rewrite the C++ code I have into C. To achieve this, I am creating a set of macros in Ruby on top of C that run at compile time, and the output of these macros is C code. Here is an example of what I am doing, code goes from this:

<%= scope do %>
  <%= var :my_texture, Game::Texture("img/some_texture.qoi") %>

  render(my_texture)
<% end %>

to this:

{
	Texture my_texture;
	Texture_constructor(&my_texture, "img/some_texture.qoi");

	render(my_texture);

	Texture_destructor(&my_texture);
}

When I create a Ruby variable, it tracks everything; this way, the tool (I have no name for it yet) can, for example, automatically add a destructor when needed.

Since you are interested, I will move my code to a gem and post the link here.

Updated by tekknolagi (Maxwell Bernstein) 10 days ago Actions #4 [ruby-core:125206]

I am curious about this gem and will give it a read over if you post the link here.

Updated by fredlinhares (Frederico Linhares) 9 days ago Actions #5 [ruby-core:125214]

Sorry for the delay. I was busy until very recently, but I will be more active from now on. Here is the repository: https://gitlab.com/fredlinhares/pre_c

Updated by ufuk (Ufuk Kayserilioglu) 9 days ago Actions #6 [ruby-core:125216]

fredlinhares (Frederico Linhares) wrote in #note-5:

Sorry for the delay. I was busy until very recently, but I will be more active from now on. Here is the repository: https://gitlab.com/fredlinhares/pre_c

There is hardly any code here and no tests, so I don't understand what this gem is supposed to do. Can you elaborate a little bit on what it is and how it should be used?

Updated by fredlinhares (Frederico Linhares) 8 days ago Actions #7 [ruby-core:125222]

Let me try to elaborate as much as I can.

Rust is not as fast as C; it is as fast as the equivalent C. However, C allows us to use some valid memory management techniques that are impossible in Rust unless you use considerable amounts of ‘unsafe’ code, eliminating the purpose of using Rust. Proper C can be tremendously faster than Rust.

I am using C++ in my game, but I realized that C++ has so many flaws that it is not worth it. So, I came up with a solution: I can use ERB to pre-process my C code, just as we usually do with many languages, such as SQL (for example, ActiveRecord), HTML (for example, ActiveView), CSS, and even Ruby itself. This is what we call meta-programming. The interesting thing is that with this process, I make my C code safer, just like when we use an ORM to prevent SQL injections.

This code inside the gem is not much, but it allows me to implement template functionalities in C similar to those in the C++ STL. Unfortunately, I will not add to the gem the templates I made so far because they are specific to my game. But now I am currently working on a vector similar to STL vector, that instead of requesting memory from the heap, it requests from an arena. After I finish it, I make it public. This will make it easier to see what I am working on.

#include <cstddef>
#include <cstdint>
#include <cstdlib>

typedef struct
{
	size_t num_elements;
	size_t capacity;
	<%= @struct_type %> *elements;
} <%= @struct_name.capitalize %>Vector;

uint32_t
<%= @struct_name.capitalize %>Vector_constructor(
	<%= @struct_name.capitalize %>Vector *vector, size_t size);

uint32_t
<%= @struct_name.capitalize %>Vector_push(
	<%= @struct_name.capitalize %>Vector *vector, <%= @struct_type %> obj);

void
<%= @struct_name.capitalize %>Vector_destructor(
	<%= @struct_name.capitalize %>Vector *vector);

After finishing this layer of code, I can make a DSL on top of it and use it to write a JIT compiler. I will be using Ruby as a language to modify my game anyway, so making Ruby faster will also benefit me. And once the Ruby community likes the concept of a faster JIT, I will share everything.

Updated by ufuk (Ufuk Kayserilioglu) 8 days ago Actions #8 [ruby-core:125223]

So, what you are doing is code-generation at compile time using ERB templates, which is cool! But, I find it a stretch to call it meta-programming, since the C code isn't writing C code at runtime, everything is happening at compile time.

I am also not able to follow the chain of thought where you go from the ERB preprocessing to JIT compilers. How are you making that jump? JIT compilers are a whole different class of tool that generate specialized compiled code at runtime based on the instructions (and their arguments) that have been seen at runtime. How do get from compile time code generation to runtime compilation?

Updated by Hanmac (Hans Mackowiak) 7 days ago Actions #9 [ruby-core:125228]

@fredlinhares (Frederico Linhares)

A really long time ago, while i was working with ruby and wxWidgets (C++ lib), i worked on this:
https://github.com/Hanmac/rwx/blob/master/ext/main.hpp#L538

Where I was writing C macros to help me with writing getter and setter methods for all these different C++ classes.

For example in my wxRect class

#define _self unwrap<wxRect*>(self)
macro_attr(X,int)

macro_attr together with other macros, turned this into that:

DLL_LOCAL VALUE _getX(VALUE self)
{ 
	return RB_INT2NUM(_self->GetX());
}

DLL_LOCAL VALUE _setX(VALUE self,VALUE other)
{
	rb_check_frozen(self);
	_self->SetX(RB_NUM2INT(other));
	return other;
}

nicely defined C functions that can be used for defining the attributes like this:

	rb_define_attr_method(rb_cWXRect,"x",_getX,_setX);

which is just a fancy define method, but hidden so that rdoc doesn't read it: (i wanted to treat them as attributes, not methods)

	rb_define_method(rb_cWXRect, "x", RUBY_METHOD_FUNC(_getX), 0);
	rb_define_method(rb_cWXRect, "x=", RUBY_METHOD_FUNC(_setX), 1);

Updated by fredlinhares (Frederico Linhares) 7 days ago Actions #10 [ruby-core:125233]

ufuk (Ufuk Kayserilioglu) wrote in #note-8:
How do get from compile time code generation to runtime compilation?

I am using these hacks I mentioned and many other related hacks to make a JIT compiler. My point is that using Ruby to generate low-level code is far more efficient than any feature in languages that attempt to succeed C or C++.

Actions

Also available in: PDF Atom