未来のいつか/hyoshiokの日記

hyoshiokの日々思うことをあれやこれや

Cache Aware Ruby Patch

quick and dirty hackだ。

# diff -u gc.c~ gc.c
--- gc.c~       2006-08-25 17:12:46.000000000 +0900
+++ gc.c        2006-10-03 10:47:08.000000000 +0900
@@ -1594,10 +1594,15 @@
     int n = 0;

     for (i = 0; i < heaps_used; i++) {
-       RVALUE *p, *pend;
+       RVALUE *p, *pend;

        p = heaps[i].slot; pend = p + heaps[i].limit;
        for (;p < pend; p++) {
+         if ( (p+1) < pend) {
+               __asm__ __volatile__ (
+                  " prefetch (%0)\n"
+                  : : "r" ((p+1)->as.basic.flags) );
+           }
            if (p->as.basic.flags) {
                switch (TYPE(p)) {
                  case T_ICLASS:

as.basic.flags) を"m" ((p+1)->as.basic.flags)にしていたらなぜかコンパイルエラーがでた。インラインアセンブリ言語のシンタックスに詳しい人教えてください。なぜエラーなのか?">*1

test/runner.rbを2回実行した時のL1キャッシュミス。

オリジナル

CPU: Core Solo / Duo, speed 2666.77 MHz (estimated)
Counted DCACHE_PEND_MISS events (Weighted cycles of L1 miss outstanding) with a unit mask of 0x00 (Weighted cycles) count 100000
samples  %        app name                 symbol name
245481   33.9674  ruby                     os_each_obj
35576     4.9227  ruby                     gc_mark
35297     4.8841  ruby                     rb_clear_cache_by_id
34610     4.7890  ruby                     gc_mark_children
24372     3.3724  ruby                     st_foreach

Cache Aware Ruby Patch

CPU: Core Solo / Duo, speed 2666.77 MHz (estimated)
Counted DCACHE_PEND_MISS events (Weighted cycles of L1 miss outstanding) with a unit mask of 0x00 (Weighted cycles) count 100000
samples  %        app name                 symbol name
102616   17.4094  ruby                     os_each_obj
33412     5.6685  ruby                     gc_mark
32908     5.5830  ruby                     gc_mark_children
26125     4.4322  vmlinux                  copy_page_range
25514     4.3286  ruby                     rb_clear_cache_by_id

L1キャッシュミスが2回runner.rbを実行した時245481回から102616回(約41.8%)へ減少している。
まあ、だからどーだつー話ではないが、そーゆー感じである。

アルゴリズムを一切変更しないでprefetchするだけのpeephole最適化でもこのくらいはいくということが分かったからよしとしたい。Ruby歴3時間のわたしでもツールがあればここまではいける。

*1:"r" ((p+1)->as.basic.flags) を"m" ((p+1)->as.basic.flags)にしていたらなぜかコンパイルエラーがでた。インラインアセンブリ言語のシンタックスに詳しい人教えてください。なぜエラーなのか?