Perl Advent Calendar 2017 2日目「SPVMという言語について語る」

この記事は、Perl Advent Calender 2日目の記事です。1日目はK君でしたね。

先週は妻の実家に帰っていて、甥っ子ちゃんと遊びました。そのあと、カラオケいって、バッティングセンター行ったら、ちょっと疲れて風邪をひいちゃいました。

さて、本題へ。

SPVMの開発の動機

もともとは、Perlの集合演算を速くしたいなぁとずっと思っていて、RstatsというR言語のライブラリを、Perlに移植するプロジェクトをやっていました。これはC++とXSで書いていたのですけれど、関数を実装するためには、C++とXSで書かなくっちゃいけなくってちょっと辛い。

集合演算というのは、まぁ、簡単にいうと、配列の足し算や引き算や掛け算や割り算のことです。たとえば、10万の長さの二つの配列の要素を足し算して、結果として返すというようなことですね。

Perlの配列の足し算は、かなり遅い。C++とXSで書くと、速くできる。だから、集合演算ライブラリを書いて、Perlから呼び出すというのが、Rstatsの基本的な考えでした。

けれども、これは、柔軟性という点で、さまざまな問題を抱えていることがわかりました。

新しい集合演算の関数を作りにくい

新しく集合演算を定義したいと思ったとき、たとえば三角関数を配列に作用させて結果を受け取りたい、といった場合に、その関数を、XSとC++で書かないといけない。でも、XSはXSレベルでは、モジュール性がないので、他のモジュールから参照できないんです。

モジュールユーザーが、新しく集合演算の関数を作りたい場合に、簡単に対応することができない。これが、一つ目の問題です。

集合演算は、条件分岐に弱い

もうひとつの問題は、集合演算は条件分岐に弱いということです。単純な演算だといいのですが、基本的には、プログラミングというのは、条件分岐のかたまりのようなものです。この条件のときには、こうしたい。この条件のときは、こうしたい。そういうことばかりが書かれるのが、プログラミングです。

集合演算ライブラリは、単純な、条件分岐ができない。集合演算ライブラリを使って、条件分岐を書きたい場合は、論理和論理積、否定も、集合演算を使う必要があるんだけれど、これが、かなりめんどくさい。10万個の配列が二つあれば、さらに、10万個の配列を準備して、論理和の結果を取り出すみたいなことをしないといけない。メモリリソースもかなり使う。

だから、Perlで集合演算を行うインフラフラストラクチャとして、どうしても、集合演算ライブラリではなくって、配列の演算を高速で行える、静的なプログラミング言語が必要だなぁという結論になった。

静的なプログラミング言語を使って、集合演算ライブラリを構築することで、非常に簡潔に、柔軟に、集合演算を行うことができるはず。

メモリリソースを扱いにくい

集合演算のもう一つの問題点は、メモリリソース確保の問題だ。

たとえば、ライブラリの関数で、新しくメモリを確保して返すというものになっている場合、配列の要素10万個のメモリ対して、新しく配列の要素10万個のメモリを確保するということになる。

ライブラリではなくって、静的なプログラミング言語であれば、元の要素に対して、演算するということが簡単にできる。メモリリソースの調節を簡単にできるということだ。

AI(人工知能)が話題になり続けている

今、インターネットやテレビでは、人工知能が話題になり続けている。僕も、本屋で脳・心・人工知能 数理で脳を解き明かすという本を一冊、読んでみた。

プログラミングの観点からいえば、人工知能プログラミングに、何が必須かといえば、GPUを使った、高速な並列処理プログラミングだなと思った。たとえば、次のような数値計算を莫大な量行わないといけない。

output = weight1 * intput1 + weight2 * intput2 + ... + weightn * weightn

もしこれに対して、Perlが適用しようと思うならば「連続した領域のデータ構造」と「GPUのライブラリを簡単にバインディング」できることが必要だ。AI::MXNetという人工知能ライブラリがPerlにある。

AI::MXNetはC++のライブラリをPerlのXSを使って、バインディグしている。これは、一つの解決策なのだけれど、大きな問題としては、ユーザーがライブラリを追加したいという場合と、集合演算は条件分岐が苦手なので、その部分でPerlは遅いように思う。

SPVMという静的言語のプログラミングの層が一つ間に入れば、パフォーマンス面とメモリリソース確保の問題を解決できるように思う。

SPVMの仕組み

SPVMはPerlではないんです。SPVMはPerl風静的プログラミング言語です。静的型を持つということを除いて、Perlに限りなく近い文法で、書くことができるCPANモジュールです。

  # lib/SPVM/MyMath.spvm
  package MyMath {
    
    # Sub Declaration
    sub sum ($nums : int[]) : int {
      
      # Culcurate total
      my $total = 0;
      for (my $i = 0; $i < @$nums; $i++) {
        $total += $nums->[$i];
      }
      
      return $total;
    }
  }
SPVMの目標

SPVMは次の主要な目標を持っています。

  1. 集合演算に適したデータ構造をPerlに追加すること。つまり、連続した領域を持つ配列をPerlから扱えるようにすること。
  2. 配列のループ処理をPerlの30倍の速度にする。理想はC言語で最適化されたパフォーマンスを出せること。
  3. C言語で書かれた、GPUSIMDの並列処理を簡単にバインディングできること

具体的な内容でいうと、SPVMの機能を利用することで、Perl言語を人工知能ビッグデータに対応できるようにすることです。

SPVMの現状

言語仕様は、90%くらいはできていて、実装もできてきて、Perlから実行できるようになっています。インストールも簡単にすぐに終わります。

cpanm SPVM

目標1の集合演算に適したデータ構造を追加するというのは、達成しています。目標3のバインディングについては、仕様が少し変わる可能性がありますが、動かすことができます。

目標2のパフォーマンスは、まだ目標に到達していません。現状は、Javaバイトコードに似た、バイトコードを実行する仕組みになっていて、これをJITの実装に変えることで、目標に近づけようと奮闘しているところです。

JITの実装に加えて、ループ最適化を施すことで、さらに目標に近づけることができそうです。

明日は参加者がまだいないみたいなので、書いてみたい方は、参加をどうぞ!