Valhalla 楽しい? その3

今日も Valhalla を少しだけゴニョゴニョします。

Valhalla はプロジェクトがそんなに進んでなく、試せることがほとんどありません。

そんな中で Generic Specialization を使った GenericMethods を試してみます。

これもネット上で見かけるコードを試してみたりしたのですが動かないものが多いですね。

あまり良いサンプルではないけどブログ更新のお遊びとしていちおう動いたコードで未来の技術のパフォーマンスを少しでも感じ取ってみます。

それでは下記のプログラムをご覧ください。

package genericMethods;

import java.util.function.Supplier;

public class GenericMethods {

    public static  T hoge(Supplier supplier) {
        return supplier.get();
    }

    public static  T piyo(T i) {
        return i;
    }

    public static void main(String[] args) {
        int n = 7;
        System.out.println(hoge(() -> n) + " : " + hoge(() -> n).getClass());
        System.out.println(piyo(n) + " : " + piyo(n).getClass());

    }

}

これは int 型の引数 7 を渡してそのまま返してもらうだけのプログラムです。

java.util.function.Supplier を使ったものと普通のコード二つを実行しています。

プログラムの実行結果は次のようになります。

2

Integer 型になって返ってきました。

コストの高い Autoboxing が働いてしまいました。

これを Valhalla の Generic Specialization を使えば Autoboxing によるパフォーマンスの低下を回避できるかもしれません。

さっそく試してみました。

しかし、java.util.function.Supplier に Generic Specialization を使おうとしたけど駄目でした。(>_<。)

欲張らずに普通ので我慢することに・・・(^_^;)

そういうことで下記のようなプログラムを組んで Valhalla の Generic Specialization の実力とやらを見せてもらいました。

public class GenericMethods2 {

    private static long start;
    private static long time;

    // 古いジェネリクス
    public static  T hoge(T i) {
        return i;
    }

    // ジェネリクス スペシャライゼーション
    public static  T piyo(T i) {
        return i;
    }

    public static void main(String[] args) {

        int a = 7;

        System.out.println(hoge(a).getClass() + " : " + hoge(a)); // class java.lang.Integer : 7
        // System.out.println(piyo(a).getClass() + " : " + piyo(a)); エラー: intは間接参照できません
        System.out.println(piyo(a)); // 7

        // ウォーミングアップ	
        for (int i = 0; i < 20; i++) {
            calcInteger();
        }
        for (int i = 0; i < 20; i++) {
            calcInt();
        }

        // 処理速度計測 古いジェネリク
        start = System.nanoTime();
        calcInteger();
        time = System.nanoTime() - start;
        System.out.println(System.lineSeparator() + "(○・ω・)ノ-------------  古いジェネリクス "
                + (int) (time * 1e-9) / 3_600 + "時間"
                + (int) ((time * 1e-9) / 60) % 60 + "分"
                + (int) (time * 1e-9 % 60) + "秒"
                + Double.toString((time * 1e-9 % 60) % 1).substring(2) + "  ------------ )" + System.lineSeparator());

        // 処理速度計測 ジェネリクス スペシャライゼーション
        start = System.nanoTime();
        calcInt();
        time = System.nanoTime() - start;
        System.out.println(System.lineSeparator() + "(○・ω・)ノ-------------  ジェネリクス スペシャライゼーション "
                + (int) (time * 1e-9) / 3_600 + "時間"
                + (int) ((time * 1e-9) / 60) % 60 + "分"
                + (int) (time * 1e-9 % 60) + "秒"
                + Double.toString((time * 1e-9 % 60) % 1).substring(2) + "  ------------ )" + System.lineSeparator());
        System.out.println();
        System.out.println("お終い!");

    }

    private static void calcInteger() {
        for (int i = 0; i < 7; i++) {
            int n = 0;
            for (int j = 0; j < 2100_000_000; j++) {
                n = hoge(j);
                // System.out.println(n);
            }
        }
    }

    private static void calcInt() {
        for (int i = 0; i < 7; i++) {
            int n = 0;
            for (int j = 0; j < 2100_000_000; j++) {
                n = piyo(j);
                // System.out.println(n);
            }
        }
    }
}

このプログラムを動かすと Generic Specialization を利用したメソッドの返り値は int 型となってます。

これで Autoboxing の呪いから解放されるぜ!

処理速度がどれだけ違うかプログラムの実行結果をご覧ください。

1

笑っちゃうくらい大きな差がありますね。

Java にジェネリクスを導入するときにプリミティブ型の対応をしなかったツケが浮き彫りになってます。

Autoboxing は便利だけど私は知らず知らずのうちに働かせてしまうので早く Valhalla が使える日がくるように祈ってます。

Hatena タグ:

Valhalla 楽しい? その2

前回のエントリーで Valhalla をビルドしました。

Valhalla 楽しい?

今回は更新されたソースを取得して最新の Valhalla を楽しむための手順です。

と言っても簡単です。

Babun shell を起動します。

Valhalla ディレクトリに移動します。

cd /cygdrive/c/openjdk/valhalla

変更されたソースを取得します。

./get_source.sh

1

configure を実行します。

./configure –disable-warnings-as-errors –with-freetype-src=/cygdrive/c/openjdk/freetype-2.6.2

2

最後に make を実行します。

make clean images

3

4

これで終わりです。

ビルドに時間がかかるのはしかたないですがソースの取得が追加更新されたものだけをダウンロードするので通信環境の弱い人にはありがたいですね。

さて、これだけではちょっとアレなので JDK8 の Stream API と Lambda 式を使ったシステムプロパティの取得プログラムを走らせてみます。

あれれ、画像ではクラスの宣言部分が切れてます。気にしないでください。(;´Д`)

5

実行結果は次のようになります。

6

Stream API と Lambda 式のおかげでソースコードが美しく表現できて解りやすくて良いですね。

Valhalla が動く JDK だと Integer, Long などが必要なくなってうっかりオートボクシングが働いていて知らず知らずのうちにパフォーマンスの悪いプログラムになってしまっているなんてことが無くなるのかな?

しかも、ValueType で CPU キャッシュメモリにデータを載せやすく?なり、プログラムの高速化も期待できるかもしれない。

早く使ってみたいな。 Valhalla

Hatena タグ: ,