title: CbCによるMoarVMの改良 author: Takahiro Shimizu profile: lang: Japanese # 研究目的 - Perl5の後継言語として開発されているPerl6はMoarVMと呼ばれるVMを搭載している. - Perl6はMoarVM,JVM,JavaScript上で動くRakudoと呼ばれる実装と,コンパイラ開発者用のサブセットであるNQPが主な実装となっている. - 現在Perl6及びMoarVMは全体的な速度がPerl5と比較し低下しており,実務として利用できるレベルに達していない. - さらにPerl6の実装自体巨大なcase-switch文など見通しが悪くなっている. - この問題を解決するために現在当研究室で開発している継続を中心にしたContinuation based Cを用いて改良を行う - CbCの設計理念からVMの実装と親和性が高い事も推測できる為,実際にCbCを用いてどのようにVMが実装できるかを検証する # 今週の進捗 * JVM版Perl6をBuildしました * logアナライザーを作成して時間計測を行いました * 院試出願しました * 趣味でPerl2をbuildしてます # ログアナライザー(Perl5) ```perl5 #!/usr/bin/env perl use strict; use warnings; use Time::HiRes qw/gettimeofday tv_interval/; my $t0 = [gettimeofday]; my $file = "/var/log/system.log"; if(@ARGV == 2){ if ( $ARGV[0] eq "-f"){ $file = $ARGV[1]; } } my $user_name = qr/anatofuzMBP|anatofuz-15/; open my $fh, "<",$file; my $count = {}; while (my $line = <$fh>) { if ( $line =~ /\w \d{0,2} (?:\d{2}:?){3} $user_name ([\w.]+)\[\d+\]/){ $count->{$1}++; } } my $sum = 0; for my $key (keys %$count){ $sum += $count->{$key}; } print "$sum\n"; my $t1 = [gettimeofday]; my $evec_time = tv_interval($t0,$t1); print "$evec_time\n"; ``` # ログアナライザー(Ruby) ```ruby #!/usr/bin/env ruby require 'benchmark' result = Benchmark.realtime do file = "/var/log/system.log" user_name = Regexp.new("anatofuzMBP|anatofuz-15") count = Hash.new(0) File.open(file,'r') do |f| f.each_line do |line| if line =~ /\w+ \d{0,2} (?:\d{2}:?){3} #{user_name} ([\w.]+)\[\d+\]/ count[$1] += 1 end end end sum = 0 for key in count.keys sum += count[key] end p sum end #p "#{Time.now - start_time}" puts "#{result}" ``` # ログアナライザー(Perl6) ```perl6 #!/usr/bin/env perl use v6; my $start = DateTime.now; unit sub MAIN(:f($file) where { .IO.f } = '/var/log/system.log'); my $user_name = /'anatofuzMBP'|'anatofuz-15'/; my $fh = open $file,:r; my %count =(); for $fh.lines -> $line { if ( $line ~~ /\w+ \s \d**0..3 \s [\d**2\:?]**3 \s $user_name \s (<[\w.]>+)\[\d+\]/) { %count{$0}++; } } $fh.close; my $sum = 0; for %count.keys -> $key { $sum += %count{$key}; } $sum.say; my $end = DateTime.now; my $time = $end - $start; say $time; ``` # ログアナライザー(Python) ```python #!/usr/bin/env python import re import sys from collections import defaultdict import time start_time = time.time() file_path = "/var/log/system.log" args = sys.argv if args == 3: if args[1] == "-f": file_path = args[2] count = defaultdict(int) with open(file_path) as f: for line in f: match = re.search(r'\w+ \d{0,2} (?:\d{2}:?){3} (?:anatofuzMBP|anatofuz-15) ([\w.]+)\[\d+\]',line) if match: count[match.group(1)]+=1 total = 0 for key in count.keys(): total +=count[key] print(total) end_time = time.time() print(end_time - start_time) ``` # ログアナライザー(java) ```java package com.google.anatofuz; import java.io.File; import java.io.FileReader; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; import java.util.regex.Pattern; import java.util.regex.Matcher; public class LogAnalyzer { public static void main(String args[]) { long start = System.currentTimeMillis(); File file = new File("/var/log/system.log"); if (args.length != 0) { if (args[0].equals("-f")) { file = new File(args[1]); } } try { FileReader filereader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(filereader); String line; Map map = new HashMap(0); Pattern p = Pattern.compile("\\w+ \\d{0,2} (?:\\d{2}:?){3} (?:anatofuzMBP|anatofuz-15) ([\\w.]+)\\[\\d+\\]"); while ((line = bufferedReader.readLine()) != null) { Matcher matcher = p.matcher(line); if (matcher.find()) { map.merge(matcher.group(1),1,Integer::sum); } } int sum = 0; for (String key :map.keySet()){ sum += map.get(key); } System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("0.0" + (end - start)); } catch (FileNotFoundException ex){ System.out.println(ex); } catch (IOException ex){ System.out.println(ex); } } } ``` # 計測結果 * 結果をブログに載せたら起動時間の比較と突っ込まれる ``` perl6(moar) 950 /Users/anatofuz/workspace/cr/Basic/build_perl6/bin/perl6 log_analyze.p6 0.94s user 0.05s system 128% cpu 0.769 total perl6(jvm) ./perl6 ~/workspace/cr/Basic/perl6/sandbox/log/log_analyze.p6 17.51s user 0.61s system 439% cpu 4.118 total perl5 950 perl log_analyze.pl 0.04s user 0.04s system 86% cpu 0.098 total ruby 950 ruby log_analyze.rb 0.16s user 0.06s system 92% cpu 0.243 total java java -jar java/build/libs/anatofuz-1.0-SNAPSHOT.jar 0.27s user 0.05s system 149% cpu 0.212 total time python log_analyze.py python log_analyze.py 0.07s user 0.05s system 77% cpu 0.153 total ``` # 内部処理 * 内部処理時間のみ計測 * perl5 * 0.003434s * Ruby * 0.046458s * Python * 0.0097 * Java * 0.047 * Perl6(Moar) * 0.2649 * Perl6(JVM) * 0.687 ``` perl5 0.003434 perl log_analyze.pl 0.04s user 0.04s system 76% cpu 0.105 total ===== ruby 0.04645899997558445 ruby log_analyze.rb 0.15s user 0.05s system 85% cpu 0.239 total ===== python log_analyze.py 0.009788036346435547 ===== java 0.047 java -jar java/build/libs/anatofuz-1.0-SNAPSHOT.jar 0.27s user 0.05s system 151% cpu 0.209 total ===== perl6 0.2649038 /Users/anatofuz/workspace/cr/Basic/build_perl6/bin/perl6 log_analyze.p6 0.86s user 0.08s system 109% cpu 0.856 total ===== perl6(jvm) WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.perl6.nqp.runtime.Ops (file:/Users/anatofuz/workspace/cr/Basic/jvm/nqp/install/share/nqp/runtime/nqp-runtime.jar) to field sun.management.RuntimeImpl.jvm WARNING: Please consider reporting this to the maintainers of org.perl6.nqp.runtime.Ops WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release 0.687 /Users/anatofuz/workspace/cr/Basic/jvm/rakudo/perl6 21.48s user 0.72s system 436% cpu 5.087 total ``` # 院試 * 出願しました * 過去問やってます # Perl2 * Perl5のgitリポジトリにtagとして残っていました * gcc/cc1でbuild出来るようにパッチを書いてます * gccを参照するように変更 * ``というヘッダーファイルを削除 * `sprintf`などの関数の返り値を修正 * yaccのシンタックスエラーを解消