hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

RubyのワンライナーをCで書き直すと10倍くらい速くなった

昨日,command_not_found_handlerというシェルスクリプトの関数を書いた*1のだけど,どうも実行が遅いような気がした.
試しに時間を計ってみると,確かに遅かった.再帰的に13回呼ぶのに,1秒くらい待たされている.

% time XXXXXXXXXXXXX
=>  xXXXXXXXXXXXX
=> x xXXXXXXXXXXX
=> x x xXXXXXXXXXX
=> x x x xXXXXXXXXX
=> x x x x xXXXXXXXX
=> x x x x x xXXXXXXX
=> x x x x x x xXXXXXX
=> x x x x x x x xXXXXX
=> x x x x x x x x xXXXX
=> x x x x x x x x x xXXX
=> x x x x x x x x x x xXX
=> x x x x x x x x x x x xX
=> x x x x x x x x x x x x x
(eval):1: command not found: x
XXXXXXXXXXXXX  0.62s user 0.29s system 94% cpu 0.957 total


もとの関数はこれ.大文字をスペース+小文字に展開する処理を,Rubyのワンライナーで書いている.

function command_not_found_handler() {
    new=`echo $* | ruby -pe 'sub(/[A-Z]/){" "+$&.downcase}'`
    if [ "$*" != "$new" ]; then
        echo "=> $new"
        eval $new
        return 0
    fi
    return 127
}


Rubyワンライナーが遅いと思ったので,Cで書き直してみた.

#include <stdio.h>
#include <ctype.h>

int main(int argc, char *argv[]) {
    int i, j, found = 0;
    char* s;
    for (i = 1; i < argc; i++) {
        s = argv[i];
        if (found) {
            printf("%s", s);
        } else {
            for(j = 0; s[j] != '\0'; j++) {
                if (isupper(s[j]) == 0) {
                    putc(s[j], stdout);
                } else {
                    printf(" %c%s", tolower(s[j]), (s[j+1] != '\0') ? &s[j+1] : "");
                    found = 1;
                    break;
                }
            }
        }
        if (i < argc-1) printf(" ");
    }
    return found;
}


これを使って,さっきの関数を書き直した.

function command_not_found_handler() {
    new=`~/bin/expand $*`
    if [ $? -ne 0 ]; then
        echo "=> $new"
        eval $new
        return 0
    fi
    return 127
}


実行時間を計測するために,それぞれの関数で,

time XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 

してみる.

Rubyのワンライナーで書いたとき,

  4.54s user 2.25s system 93% cpu 7.278 total

7秒くらい待たされる.


Cで書いたとき,

  0.14s user 0.52s system 76% cpu 0.861 total

0.8秒で終わる.


RubyのワンライナーをCで書き直すと10倍くらい速くなった.Cすごい.

*1:[http://d.hatena.ne.jp/hitode909/20091215/1260856588:title]