LoginSignup
1
1

More than 5 years have passed since last update.

X10ファイルIOのベンチマーク

Last updated at Posted at 2016-01-07

今回はIBM社の並列分散言語であるX10 (http://x10-lang.org/) を使って各種ファイルIO方法を比較して見た。X10を知っている人に対しては当たり前の結果が出ていると思うが、一応地味にやって見たことをポスティングする。

X10は今2.5.4まで出ているらしいが、今回はScaleGraphプロジェクト(http://scalegraph.sourceforge.net/web/) のSX10 2.3.1を使ってやって見た。

今回このバージョンを選んだ理由としては、恥ずかしながらSX10 2.3.1が出た時からやっていた研究がまだあまり進んでいなく、まだSX10 2.3.1を使って研究をしているから。

ベンチマークのやり方

SNAPから拾って来た論文参照関係ネットワークデータ(#Nodes=317,080 / #Edges=85,702,474)において、ファイルIOをテストする。

Read: FileReader VS BufferedReader VS C++ fstream called from x10
Write: Printer VS FileWriter VS C++ ofstream called from x10

C++関数の呼び出しは、以下のブログ文章を参照に作成

x10からC++の関数を呼ぶ
ただ、この記事にはC++関数へ渡す引数として、構造体や配列が扱えるのか、まだX10側でC++関数の結果が参照できるのかは不明だと言っていたが、SX10のソースコードを見ると可能であることがわかった。具体的なやり方は私の他の文章で共有する。

ソースコード

Graph.hpp
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <map>

using namespace x10::lang;
using namespace x10::io;
using namespace x10aux;
using namespace std;

void writeFile(int size, int* data1);
void readGraphCPP1(const char* file, int maxNode);

Graph.cpp
#include "mycpp.hpp"

void writeFile(int size, int* data1) {
  char * filename = "test.bin";  
  ofstream foutput;
  foutput.open(filename, fstream::out | fstream::binary);
  for (int i = 0; i < size; ++i) {
    foutput.write((char *)(&data1[i]),4);
  }
  foutput.close();
}

void readGraphCPP1(const char* file, int maxNode) {
    ifstream finput;
    finput.open(file, fstream::in);
    vector<vector<pair<int, double> > > links(maxNode+1);

    int nb_links = 0;
    double weight = 1.0;
    while (!finput.eof()) {
        unsigned int src, dst;
        finput >> src >> dst;
        links[src].push_back(make_pair(dst, weight));
        nb_links++;
    }
}
BenchInputMain.x10

import x10.io.*;
import x10.compiler.*;
import x10.util.*;
import x10.array.Array;

@NativeCPPInclude("mycpp.hpp")
@NativeCPPCompilationUnit("mycpp.cpp")
public class Test {
    private var infile:String     = null;
    private var maxNode:int   = 0;

    public def parse_args(args:Array[String]) {
        for (var i:int=0; i<args.size; i++) {   
            if (args(i).equals("-n")) {
                maxNode = Int.parse(args(i+1));
            }
            if (args(i).equals("-i")) {
                infile = args(i+1);
            }
            if (args(i).equals("-o")) {
                outfile = args(i+1);    
            }
        }
    }

    @Native("c++", "readGraphCPP1((#1)->c_str(), #2);")
    native static def readGraphCPP1(infile: String, maxNode: int): void;

    public def readGraphCPP(){
        readGraphCPP1(infile, maxNode);
    }

    public def readGraphX10() {
        val finput = new File(infile);
        val links_r = new Array[ArrayList[Pair[int, double]]](maxNode+1);
        for (var startIndex :int=0; startIndex<=maxNode; startIndex++) {
            links_r(startIndex) = new ArrayList[Pair[int, double]]();
        }

        var nb_links: int = 0;
        val weight = 1.0;
        for (line in finput.lines()) {
            val src  = Int.parse(line.split(" ")(0));
            val dest = Int.parse(line.split(" ")(1));

            links_r(src).add(new Pair(dest as int, weight as double));
            nb_links++;
        }
    }

    public def readGraphBuffX10() {
        val finput = new File(infile);
        val reader = new BufferedReader(new FileReader(finput));

        val links_r = new Array[ArrayList[Pair[int, double]]](maxNode+1);
        for (var startIndex :int=0; startIndex<=maxNode; startIndex++) {
            links_r(startIndex) = new ArrayList[Pair[int, double]]();
        }

        var nb_links: int = 0;
        val weight = 1.0;
        for (line in reader.lines()) {
            val src  = Int.parse(line.split(" ")(0));
            val dest = Int.parse(line.split(" ")(1));

            links_r(src).add(new Pair(dest as int, weight as double));
            nb_links++;
        }
    }

    public static def main(args: Array[String]) {
        val test = new Test();
        test.parse_args(args);

        Console.OUT.println("Test read file");
        for (i in 0..4) {
            val t0 = Timer.milliTime();
            test.readGraphX10();
            Console.OUT.println("Read Graph Time (x10, FileReader): " + (Timer.milliTime()-t0) + "ms");

            val t1 = Timer.milliTime();
            test.readGraphBuffX10();
            Console.OUT.println("Read Graph Time (x10, BufferedReader): " + (Timer.milliTime()-t1) + "ms");

            val t2 = Timer.milliTime();
            test.readGraphCPP();
            Console.OUT.println("Read Graph Time (C++): " + (Timer.milliTime()-t2) + "ms");
        }
    }
}

BenchOutputMain.x10
import x10.io.*;
import x10.compiler.*;
import x10.util.*;
import x10.array.Array;

@NativeCPPInclude("mycpp.hpp")
@NativeCPPCompilationUnit("mycpp.cpp")
public class Test {
    @Native("c++", "writeFile(#1, (#2)->raw()->raw());")
    native static def writeFile(size: int, data: Array[int]): void;

    public def writeFileWriter(data: Array[int]) {
        val filename = "FileWriter.bin";
        val w = new x10.io.FileWriter(new File(filename));
        for (i in data) {
            w.writeInt(data(i));
        }
        w.close();
    }

    public def writePrinter(data: Array[int]) {
        val filename = "Printer.bin";
        val f = new File(filename);
        val printer = f.printer();
        for (i in data) {
            printer.writeInt(data(i));
        }
        printer.flush();
        printer.close();   
    }

    public static def main(args: Array[String]) {
        Console.OUT.println("Test write file!!");
        val test = new Test();
        val size = 100000000;        
        val data = new Array[int](size, (i: int)=>Random.nextInt());

        for (i in 0..4) {
            val t0 = Timer.milliTime();
            test.writeFileWriter(data);
            Console.OUT.println("Write (X10, FileWriter): " + (Timer.milliTime()-t0) + "ms");

            val t1 = Timer.milliTime();
            test.writePrinter(data);
            Console.OUT.println("Write (x10), Printer: " + (Timer.milliTime()-t1) + "ms");

            val t2 = Timer.milliTime();
            test.writeFile(size, data);
            Console.OUT.println("Write (C++): " + (Timer.milliTime()-t2) + "ms");
        }
    }
}

結果

Test read file!!
Read Graph Time (x10, FileReader): 13854ms
Read Graph Time (x10, BufferedReader): 13620ms
Read Graph Time (C++): 576ms

Read Graph Time (x10, FileReader): 13872ms
Read Graph Time (x10, BufferedReader): 13157ms
Read Graph Time (C++): 465ms

Read Graph Time (x10, FileReader): 13891ms
Read Graph Time (x10, BufferedReader): 13133ms
Read Graph Time (C++): 461ms

Read Graph Time (x10, FileReader): 13930ms
Read Graph Time (x10, BufferedReader): 12974ms
Read Graph Time (C++): 448ms

Read Graph Time (x10, FileReader): 13854ms
Read Graph Time (x10, BufferedReader): 13254ms
Read Graph Time (C++): 508ms
Test write file!!
Write (X10, FileWriter): 25057ms
Write (x10), Printer: 27068ms
Write (C++): 3914ms

Write (X10, FileWriter): 24732ms
Write (x10), Printer: 27039ms
Write (C++): 3818ms

Write (X10, FileWriter): 24905ms
Write (x10), Printer: 27558ms
Write (C++): 3816ms

Write (X10, FileWriter): 24817ms
Write (x10), Printer: 27008ms
Write (C++): 3625ms

Write (X10, FileWriter): 24616ms
Write (x10), Printer: 27984ms
Write (C++): 3533ms

ファイル読み込みにおいて、C++より20倍以上に遅く、ファイル書き込みでは、C++より7倍ぐらい遅くなっている。


1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1