Java 8 Stream API 性能測定 - IntStream.sum()

# はじめに
Java SE 8のIntStream.sum()の性能を測定してみました。
IntStream.sum()は、並列処理のコストが低く、並列化すれば性能が向上するだろうという期待がありました。

# 性能測定

1～100,000の総和($\sum_{i=1}^n i$)を求めます。
次の3通りの処理方法における処理時間を出力します。

1. 単純なfor文で総和を計算
2. IntStream.sum()で計算
3. IntStream.sum()を並列で計算

##プログラム

```java:Sum.java
public class Sum {
    private static final int SIZE = 100_000;

    public static void main(String[] args){
        System.out.println("os.arch="+System.getProperty("os.arch"));
        System.out.println("os.name="+System.getProperty("os.name"));
        System.out.println("os.version="+System.getProperty("os.version"));
        System.out.println("java.version="+System.getProperty("java.version"));
        System.out.println("java.vm.info="+System.getProperty("java.vm.info"));
        System.out.println("java.vm.name="+System.getProperty("java.vm.name"));
        System.out.println("sun.management.compiler="+System.getProperty("sun.management.compiler"));
        System.out.println("poolParallelism="+java.util.concurrent.ForkJoinPool.getCommonPoolParallelism());
        //warming up
        for(int i=0; i<10_000; i++){
            createIntStream().sum();
            createIntStream().parallel().sum();
        }
        //process
        System.out.println();
        sum000();
        sum001();
        sum002();
    }
    
    private static java.util.stream.IntStream createIntStream(){
        return java.util.stream.IntStream.rangeClosed(1, SIZE);
    }
    
    static void sum000(){
        final long start = System.nanoTime();
        int sum = 0;
        for(int i=0; i<=SIZE; i++){
            sum += i;
        }
        result("sum000", sum, start);
    }

    static void sum001(){
        final long start = System.nanoTime();
        result("sum001", createIntStream().sum(), start);
    }

    static void sum002(){
        final long start = System.nanoTime();
        result("sum002", createIntStream().parallel().sum(), start);
    }

    static void result(String prefix, int sum, long start){
        final long elapsed = System.nanoTime()-start;
        System.out.println(prefix+": sum="+sum+", elapsed="+elapsed);
    }
}
```

## 測定環境

| Key  | Value                                |
|:-----|:-------------------------------------|
| CPU  | Intel Core i7-2670QM CPU @ 2.20GHz コア数4 スレッド数8   |
| RAM  | 8GB                                  |
| OS   | Windows 7 Home Premium SP1 64ビット版|
| Java | Java SE 8 Update 20                  |

## 測定結果

os.arch=amd64
os.name=Windows 7
os.version=6.1
java.version=1.8.0_20
java.vm.info=mixed mode
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
poolParallelism=7
<dl>
<dt>1回目
    <dd>sum000: sum=705082704, elapsed=3846275
    <dd>sum001: sum=705082704, elapsed=113359
    <dd>sum002: sum=705082704, elapsed=429644
<dt>2回目
    <dd>sum000: sum=705082704, elapsed=1785288
    <dd>sum001: sum=705082704, elapsed=50848
    <dd>sum002: sum=705082704, elapsed=229050
<dt>3回目
    <dd>sum000: sum=705082704, elapsed=2575069
    <dd>sum001: sum=705082704, elapsed=74173
    <dd>sum002: sum=705082704, elapsed=332147
</dl>

##まとめ
1. あらかじめウォーミングアップしておけば、単純なfor文よりもStreamを使った方が性能が良くなりました。
2. ただし、sum()をパラレルで実行すると、シーケンスよりも性能が悪化しました。（原因はこれから検証する）
3. 要素数を10万→1000万に増やしても（**10万でも1000万でも**総和がオーバーフローするが）、パラレル処理の性能が悪かったです。

#お願い
別の性能測定方法（別のプログラム）や、別の環境（CPU、コア数、OS）では、性能測定の結果が違うよという事例がありましたら、コメントをいただけると嬉しいです。