最適化オプションを知った。

言語の処理速度に興味があったので、C言語Javaphpで同じ処理を行った場合の速度比較をやってみた。

処理内容は、以下サイトのコードとほぼ同じ。

TAKENAKA's Web Page: meshcode

C言語

#include <stdio.h>

int main(int argc, char *argv[]) {

    int rep = 1000000; // 足し算の回数
    int n   = 10000;   // 変数の数(配列の要素数)

    int x[10000] = {};

    for (int j = 0; j < rep; ++j) {    
        for (int i = 0; i < n; ++i) {   
            x[i] += 1; 
        }
    }

}

Java

package com.company;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {


        int rep = 1000000;
        int n   = 10000;

        int[] x = new int[n];
        Arrays.fill(x, 0);

        for (int j = 0; j < rep;) {

            for (int i = 0; i < n;) {
                x[i] += 1;
                i++;
            }

            j++;
        }


    }
}

PHP

<?php

$rep = 1000000;
$n   = 10000;

$x = range(0,$n);

for($j = 1; $j < $rep; $j++){

  for($i = 0; $i < $n-1; $i++){
    $x[$i] += $i;
  }

}

?>

結果

ざっくりと知りたかったので、 今回はtimeコマンドでやってみました。

C言語 Java PHP
real 0m26.795s 0m1.698s 9m54.769s
user 0m26.754s 0m2.134s 9m53.398s
sys 0m0.028s 0m0.217s 0m0.789s

様子がおかしい?

PHPは、そうなんだろうなという印象だったのだけど、 CとJavaが思ってたのと違う!!

CとJavaについては、まったくいじったこと無かったので、 よくわからないので、質問してみました。

c言語、javaの実行速度について、解決できない疑問があります。 … - 人力検索はてな

ご回答頂いた方によると、コンパイラの最適化が関連しているのでは?ということ。調べてみる。

最適化実行

C言語コンパイルするときは、自分のMac環境では以下の様に行っていました。

gcc main.c -o main.out

これを以下の様にオプションをつけると、 どうなるか。

gcc -O2 main.c -o main.out

再度計測!

C言語 (最適化前) C言語 (最適化後) Java PHP
real 0m26.795s 0m1.484s 0m1.698s 9m54.769s
user 0m26.754s 0m1.474s 0m2.134s 9m53.398s
sys 0m0.028s 0m0.006s 0m0.217s 0m0.789s

これだよ、求めていたのは!

最適化オプションをつけたとき、コンパイラは何をしているんだろう。

最適化については、コンパイラによって様々な最適化を行うらしいのだけど、 共通しているのは、コンパイルにコストをかけて、プログラム実行時のコストを減らすということみたい。

Using and Porting the GNU Compiler Collection (GCC) - GCCコマンド・オプション

今回のコードにおいては、最適化オプション指定時に変数へのアクセスが、メモリじゃなくて、CPUにあるレジスタにおきかわって、forとかでアクセスしまくっている変数がregister宣言に置き換わって、爆速になったのでは?と考えている。

最適化結果を知りたいと思って、逆アセンブラとかしてみたんだけど、 アセンブラが読めないことを忘れていて、撃沈。。

結論

自分のような、WEBのフロント側から、バックにきた人間にとっては、 C言語コンパイルの裏、レジスタのことなど、 当たり前だけど、知らないことが多いので、こうやって調べていくのは大変勉強になる。

普段phpのWEBアプリを作っていて、 たまに複雑な計算処理などが入るときも 力業でphpで書いて、夜間にバッチで処理なんてやってたけど、 ある部分、処理にあった言語で実装をしなおして 高速化や効率化を今後考えていきたい。

追い切れていないところ

※Goもやってみたので追加

package main

func main() {

    rep := 1000000
    n := 10000

    var x [10000]int

    for j := 0; j < rep; j++ { // rep 回の繰り返し
        for i := 0; i < n; i++ { // 一万個の変数それぞれに値を加える
            x[i]++
        }
    }

}
go build main.go
C言語 (最適化前) C言語 (最適化後) Java PHP Go
real 0m26.795s 0m1.484s 0m1.698s 9m54.769s 0m9.053s
user 0m26.754s 0m1.474s 0m2.134s 9m53.398s 0m9.049s
sys 0m0.028s 0m0.006s 0m0.217s 0m0.789s 0m0.008s