Issue #14235 has been updated by vmakarov (Vladimir Makarov).


k0kubun (Takashi Kokubun) wrote:
> > The short form should be there for convenience IMHO
> 
> TBH I don't have strong preference on having the short versions or not. But I'm expecting that the only option normal user uses would be only "--jit" and others are basically for Vladimir and me. And I believe "--jit" would be short enough compared to "--disable-gems" and very straight-forward.
> 
> Anyway, I share the interface which was considered as reasonable at today's Ruby developers meeting at Tokyo:
> 
> ~~~
>   --jit       use MJIT with default options
> 
> MJIT options:
>   --jit-cc=cc      C compiler to generate native code (gcc, clang)
>   --jit-save-temps Save MJIT temporary files in $TMP or /tmp
>   --jit-warnings   Enable printing MJIT warnings
>   --jit-debug      Enable MJIT debugging (very slow)
>   --jit-verbose=num
>                    Print MJIT logs of level num or less to stderr
>   --jit-max-cache-size=num
>                    Maximum number of methods to be JIT-ed in a cache (default: 1000)
>   --jit-wait       Synchronously wait for ISeq to be compiled (for testing)
>   --jit-threshold=num
>                    Number of calls to trigger JIT compilation (default: 5)
> ~~~
> 

They look ok to me.  I believe people at the developers meeting have the best experience with designing options for C-Ruby.  I created original options mostly for my convenience to work on MJIT.  I did not think about them as a final variant.  Nevertheless I am glad that they are very close to mine.

I also think that in the future setting JIT features and params through environment variable(s) might improve JIT usage experience too.


> As "--jit-wait" and "--jit-threshold" are only for testing JIT implementation, they might be hidden in help.
> 
> I would like to make initial merge as simple as possible. You can separately file a request to have short options after we try the above interface.

--jit-wait/--jit-threshold are very useful options for testers. They should be used to test JIT on ruby tests (e.g. make check) because without them JIT practically has no time to compile methods and run them.  With these options all running methods can be compiled by JIT and executed.  And this considerably improves MJIT test coverage although it makes ruby much slower.


----------------------------------------
Feature #14235: Merge MJIT infrastructure with conservative JIT compiler
https://bugs.ruby-lang.org/issues/14235#change-69782

* Author: k0kubun (Takashi Kokubun)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 2.6
----------------------------------------
## Background

In [Feature#12589](https://bugs.ruby-lang.org/issues/12589), Vladimir Makarov proposed to improve VM performance by replacing VM instructions
to RTL and introduce method JIT compiler based on those instructions.

While his approach for JIT (write C code to local file system, let C compiler executable
to compile it to shared object file and load it dynamically) was great and proven to work,
replacing all VM instructions may change the behavior of all Ruby programs and we can't turn off
such changes once it's released, even if we find a problem. So it's a little risky unlike optional JIT enablement.

Then I developed a JIT compiler called YARV-MJIT, which does not require any VM instruction changes.
After it, I heard Vladimir started to work on another approach to compile from current YARV instructions and
use RTL as IR for JIT compilation, but it's not published yet as far as I know.

## Problems

* We're developing the same JIT infrastructure independently, which can be shared for both implementations
  * it's definitely a waste of time, unlike seeking different optimization approaches
* If we continue to develop JIT in a big feature branch,
  * affected places will be big too, and thus it'll be a dangerous release
  * all of us will continue to waste our time by day-to-day conflict resolution against trunk
  * many valuable commit logs will be lost when we maintain the branch for rebase or squash commits on merge

## Solution

* **Proposal:** Merge MJIT infrastructure from Vladimir's patch with a conservative JIT compiler in early 2.6 development.
  * MJIT infrastructure means: JIT worker thread, profiler, gcc/clang compiler support, loading function from shared object file, some hooks to ensure JIT does not cause SEGV, etc...


Patch: https://github.com/ruby/ruby/pull/1782

### What's the "conservative JIT compiler"?

* Based on my YARV-MJIT, but this drops some problematic optimizations and is slower
* Pass `make test`, `make test-all`, `make test-spec` with and without JIT https://travis-ci.org/ruby/ruby/builds/321589821
* Unlike MJIT on RTL, we can play optcarrot (not just for benchmark, but on GUI) and run Rails application stably (not tested on production yet though)

### Notes

* As YARV-MJIT implementation improved MJIT infrastructure too, pthread was already ported to Windows native threads and it can be compiled with Visual Studio.
  * That's exactly why we should develop this in cooperation
* Visual Sudio is not supported as C compiler for JIT compilation. I did some experiments and had some ideas to support cl.exe, but I didn't want to add extra complexity to initial merge.
  * But it's perfectly working on MinGW and this will be available on Windows if a user uses RubyInstaller2.

### Optcarrot

Benchmarked with: Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores, gcc 5.4.0

|              |2.0.0      |2.5.0      |JIT off    |JIT on     |
|:-------------|:----------|:----------|:----------|:----------|
|optcarrot fps |35.05      |46.75      |46.05      |63.06      |
|vs 2.0.0      |1.00x      |1.33x      |1.31x      |1.80x      |

* 2.0.0: Ruby 2.0.0-p0
* 2.5.0: Ruby 2.5.0 (r61468)
* JIT off: Patched Ruby (based on r61475), JIT disabled
* JIT on: Patched Ruby (based on r61475), JIT enabled

Disclaimer: This JIT compiler performs better with gcc compared to clang for now, so it may be slow on macOS (clang). 

### Micro benchmarks

I used Vladimir's benchmark set which I modified for my convenience https://github.com/benchmark-driver/mjit-benchmarks.

|           |2.0.0-p0   |2.5.0      |JIT off     |JIT on      |
|:----------|:----------|:----------|:----------|:----------|
|aread      |1.00       |1.01       |0.97       |2.33       |
|aref       |1.00       |0.96       |0.96       |3.01       |
|aset       |1.00       |1.39       |1.37       |3.70       |
|awrite     |1.00       |1.07       |1.03       |2.54       |
|call       |1.00       |1.25       |1.22       |3.39       |
|const      |1.00       |0.96       |0.96       |4.00       |
|const2     |1.00       |0.96       |0.96       |3.97       |
|fannk      |1.00       |0.98       |1.02       |1.00       |
|fib        |1.00       |1.16       |1.24       |3.19       |
|ivread     |1.00       |0.94       |0.93       |4.96       |
|ivwrite    |1.00       |1.09       |1.09       |3.32       |
|mandelbrot |1.00       |0.98       |0.98       |1.27       |
|meteor     |1.00       |3.02       |2.85       |3.16       |
|nbody      |1.00       |1.02       |0.99       |1.47       |
|nest-ntimes|1.00       |1.05       |1.01       |1.31       |
|nest-while |1.00       |0.96       |0.96       |1.63       |
|norm       |1.00       |1.06       |1.07       |1.26       |
|nsvb       |1.00       |0.98       |0.88       |0.88       |
|red-black  |1.00       |1.03       |1.02       |1.54       |
|sieve      |1.00       |1.22       |1.22       |1.75       |
|trees      |1.00       |1.07       |1.08       |1.32       |
|while      |1.00       |0.96       |0.96       |5.13       |

## Interface details

If the proposal is accepted, I'm going to add following CLI options:

```
  -j, --jit       use MJIT with default options
  -j:option, --jit:option
                  use MJIT with an option

MJIT options:
  c, cc           C compiler to generate native code (gcc, clang)
  s, save-temps   Save MJIT temporary files in $TMP or /tmp
  w, warnings     Enable printing MJIT warnings
  d, debug        Enable MJIT debugging (very slow)
  v=num, verbose=num
                  Print MJIT logs of level num or less to stderr
  n=num, num-cache=num
                  Maximum number of JIT codes in a cache
```

Note that `-j:l`/`--jit:llvm` are changed to `-j:c`/`--jit:cc` so that we can support cl.exe (Visual Studio) in the future.

Also, for testing, I would like to have following module and method.

```
MJIT.enabled? #=> true / false
```

See the commit log for details.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>