Kishima's Hateda log

はてなダイアリー記事の保管庫

iRemoconでエアコンと電灯を自動制御する

寝る前に電灯を消し忘れたり、自宅に帰る前に暖房で部屋を温めておきたかったり、といったことがあったのでiRemoconを使って簡単な遠隔家電制御システムを作ってみた。
iRemocon使わなくてももっと安く実現可能だけど、以前API使ったことあったので、楽をするために採用。
iRemoconのサービスを契約すれば宅外制御もできるのだけど、月額課金もあれなので気分転換も兼ねて自前で作ってみた。↓がシステムの構成です。

https://docs.google.com/presentation/d/e/2PACX-1vRTto2BJ8OTVQi0Qqt6SRSkOmQHVTHpqVTOQEcjXdQDL9vUUHNPKDAaIOukVPeT_P4KOVpQ3HE3jnOX/pub?start=false&loop=false&delayms=3000

iRemoconの外部公開API仕様
http://i-remocon.com/development/

色々ありました

2013の秋から3年間とあるプロジェクトのお仕事を続けて来て、この秋に一区切りつきました。
ずっと忙しかったですが、最近やっと多少余裕がでてきました。

この3年間、世界各国を飛び回って、死ぬほど大変でしたが、色々と面白い体験もできました。
表に出しても差し支えない範囲で体験を整理して、まとめたいなあ、と思っています。

TokyuRubyKaigi07にスタッフとして参加してきた

FBからのほぼ転載ですが、こちらにも残しておきます。
土曜日はおにくの休日、ということで、TokyuRubyKaigi07が開催されました。
そこにスタッフとして参加してきました。今回はしおり作ったり、当日の記録をとったりしてました。

参加頂いたみなさまありがとうございました。
昨日はあみだ係ではなかったので、スタッフしつつも、すべてのLTを聴くことができて楽しかったです。メモも取ったので、あとでちゃんとまとめます。
こういうざっくばらんなイベントとはいえ、技術系のイベントに参加するのはとても久しぶりだったので、心が少しクリアになりました。
それと初LTに挑戦して頂けた方が多かったのも、スタッフとしては、とても嬉しかったです。
参加されたみなさんも、こういう息抜きや交流を上手く利用してもらって、日々のことに邁進して頂ければと思います。
まさに自分も。

http://regional.rubykaigi.org/tokyu07


Kawasaki.rb #3でmrubyの簡単な紹介をしてきた。


ものすごく時間が立ってしまいましたが、8/28のKawasaki.rb*1でmrubyの簡単な紹介と、そのちょっとしたサンプルとして、webrubyを使って作った抽選スクリプトの紹介をしてきました。
その資料を置いておきます。

webruby & enchant.jsを使って作ったスクリプトの実物は下記にあります。

http://silentworlds.info/webruby/

ソースコードはこんな感じ

続きを読む

WebrubyをMacにインストールしてみる


webrubyとは、ブラウザの上でrubyを動かしてしまおうというものです。
http://qiezi.me/talks/rubykaigi2013/index.html#/
https://github.com/xxuejie/webruby
RubyKaigi2013でのお話を聞いて、試してたくなったので、開発環境の準備をしてみた。

↓を参考に。
http://qiezi.me/2013/01/09/webruby-1-2-3-tutorial/

Emscriptenが必要→LLVMが必要→Homebrewあった方がいいな→macports消さないと

という感じで色々準備が必要だった。

ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

Emscriptenのインストール
https://gist.github.com/nathanhammond/1974955

LLVMバージョンが3.2である必要があるらしいが、デフォルトだと3.3がインストールされてしまったので、下記の手順で修正。
なるほど、git checkout で切り替えるのかー。

$ brew versions llvm
3.3      git checkout c4cc4cc /usr/local/Library/Formula/llvm.rb
3.2      git checkout f8f4ca1 /usr/local/Library/Formula/llvm.rb
3.1      git checkout 7d15192 /usr/local/Library/Formula/llvm.rb
$ cd /usr/local/Library/Formula
$ git checkout f8f4ca1 /usr/local/Library/Formula/llvm.rb
$ brew info llvm
llvm: stable 3.2 (bottled), HEAD
http://llvm.org/
Not installed
From: https://github.com/mxcl/homebrew/commits/master/Library/Formula/llvm.rb
==> Options
--all-targets
	Build all target backends
--disable-assertions
	Speeds up LLVM, but provides less debug information
--disable-shared
	Don't build LLVM as a shared library
--rtti
	Build with C++ RTTI
--universal
	Build a universal binary
--with-asan
	Include support for -faddress-sanitizer (from compiler-rt)
--with-clang
	Build Clang C/ObjC/C++ frontend
--without-python
	Build without python support
==> Caveats
For non-homebrew python (2.x), you need to amend your PYTHONPATH like so:
  export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH
Extra tools are installed in /usr/local/Cellar/llvm/3.2/share/llvm and /usr/local/Cellar/llvm/3.2/share/clang.

If you already have LLVM installed, then "brew upgrade llvm" might not work.
Instead, try:
    brew rm llvm && brew install llvm
$ brew install llvm --with-clang

これで準備はできたので、webrubyのビルドへ。

$ git clone git://github.com/xxuejie/webruby.git
$ git submodule init && git submodule update

build_config.rb中の下記の行のコメントを外す。

conf.gem :git => 'git://github.com/xxuejie/mruby-js.git', :branch => 'master' # This is the line to uncomment!

rake mrbtest を実行して、問題なければbuildディレクトリ以下に、webruby.jsが出来上がっている。
mruby、emscriptenはmodulesディレクトリ以下に収まっている。
appディレクトリにある*.rbのソースコードは自動的にコンパイルされて組み込まれるそうだ。
後はこれをHTML上で読み込んで、案内にあるサンプルの通り呼び出せば、mrubyが動いていることが確認できた。

<!DOCTYPE html>
<html>
  <head>
    <title>Webruby tutorial</title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="webruby.js"></script>
  </head>
  <body>
    <h1>This is a skeleton for Webruby tutorial!</h1>
    <div id="container"></div>
    <script>
      $(document).ready(function() {
        var mrb = WEBRUBY();

        /* Runs embedded source code in mruby.js file. */
        mrb.run();

        mrb.close();
      });
    </script>
  </body>
</html>

動的にテキストを読み込んで実行することも可能。
そのときは"mrb.run_source(source)"を実行する。
mruby→JSの呼び出しと、コールバック登録ができることは確認出来た。
ただ、JS→mrubyでコールバックを呼ぶ時にオブジェクトを引数に入れると、繰り返し呼んでいるうちにスタックが溢れてしまうという現象が起きた。setjmpやらlongjmpがからむemscriptenの問題らしいが、詳しくは分からない。

いやしかし、すごいものだ。

mrubyのメモリ使用量

ミニマムでどれくらいか調べるため、下記のようなプログラムでチェックしてみた。
使ったmrubyは今日取得したもの。mrbconf.h の内容は触っていない(デフォルトでオプションは全て外されているようなので)。
mrubyは中間コードをmrbcで生成できるので、VM側にパーサーを乗せなくてもmrbcで生成した.mrbファイルを渡せば実行することができる。

$ mrbc sample.rb
$ mruby sample.mrb

使ったソースコード

sample.rb

while 1 > 0 
end

mruby.c

#include "mruby.h"
#include "mruby/proc.h"
#include "mruby/array.h"
#include "mruby/string.h"
#include "mruby/compile.h"
#include "mruby/dump.h"
#include <stdio.h>
#include <string.h>

int
main(int argc, char **argv)
{
  printf("- mrb_open start -\n");
  mrb_state *mrb = mrb_open();
  printf("- mrb_open end -\n");
  int n = -1;

  if (mrb == NULL) {
    fprintf(stderr, "Invalid mrb_state, exiting mruby");
    return EXIT_FAILURE;
  }

  FILE *fp = fopen(argv[1],"r");

  printf("- mrb_load_irep start - %p\n",fp);
  n = mrb_load_irep(mrb, fp);
  printf("- mrb_load_irep end -\n");
  
  if (n >= 0) {
    printf("- mrb_run start\n");
    mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb));
    printf("- mrb_run end\n");
  }

  return n > 0 ? 0 : 1;
}

ヒープがどれだけ使われているか確認したかったので、allocf にちょっと仕掛けを入れた。
各所のヒープメモリ確保解放はこの関数に集約されている、はず。
アロケータの実装によっては大きく性能に影響しそうなところに見える。
src/state.c

/*
** state.c - RiteVM open/close functions
**
** See Copyright Notice in mruby.h
*1340547113*/

#include "mruby.h"
#include "mruby/irep.h"
#include <string.h>
#include <stdio.h>

void mrb_init_heap(mrb_state*);
void mrb_init_core(mrb_state*);
void mrb_init_ext(mrb_state*);

#define LOCAL_TOTAL_MAX 10000
struct memstack{
    void* p;
    size_t size;
}memstacktest[LOCAL_TOTAL_MAX];


int local_g_count=0;

void local_add_mem(void* p,size_t size){
    int i;
    for(i=0;i<LOCAL_TOTAL_MAX;i++){
        if(memstacktest[i].p==NULL){
            memstacktest[i].p=p;
            memstacktest[i].size=size;
            local_g_count++;
            return;
        }
    }
    printf("no stack mem!\n");
}
void local_del_mem(void* p){
    int i;
    for(i=0;i<LOCAL_TOTAL_MAX;i++){
        if(memstacktest[i].p==p){
            memstacktest[i].p=NULL;
            local_g_count--;
            return;
        }
    }
    printf("not hit!\n");
}
int local_get_total_mem(){
    int i=0;
    int total=0;
    for(i=0;i<LOCAL_TOTAL_MAX;i++){
        if(memstacktest[i].p!=NULL){
            total+=memstacktest[i].size;
        }
    }
    return total;
}


mrb_state*
mrb_open_allocf(mrb_allocf f)
{
  mrb_state *mrb = (f)(NULL, NULL, sizeof(mrb_state));
  if (mrb == NULL) return NULL;

  memset(mrb, 0, sizeof(mrb_state));
  mrb->allocf = f;
  mrb->current_white_part = MRB_GC_WHITE_A;

  mrb_init_heap(mrb);
  mrb_init_core(mrb);
  mrb_init_ext(mrb);
  return mrb;
}

static void*
allocf(mrb_state *mrb, void *p, size_t size)
{
  if (size == 0) {
      local_del_mem(p);
      printf("free[%d] %p\n",local_g_count,p);

    free(p);
    return NULL;
  }
  else {
      void* pointer = realloc(p, size);
      local_add_mem(pointer,size);
      printf("alloc[%d] %p, %d \n",local_g_count,pointer,(int)size);
      printf("alloc[%d] total %d \n",local_g_count,local_get_total_mem());
      return pointer;
  }
}

以下続く…

結果

Mac OSX 上で実行してみて、topと仕込みの出力の内容を確認してみる。

実行時の物理メモリ使用量(RSIZE):848K
mrb_openが終わった時点のヒープメモリ使用量:157816 byte
mrb_load_irepが終わった時点のヒープメモリ使用量:157737 byte

実行時のメモリが結構食ってるけど、これはどう解釈すればよいのだろう。
MacOSXでの実行ファイルの扱いは全然理解してないので、何か暗黙的なものが展開されてこのサイズなのか、mrubyが確保している分がこれだけあるのか、まだ自分には判別付かない。もう少し調べよう。

このmruby.cをビルドした場合のバイナリサイズを見てみる。
パーサー付きだと500KBくらあったが、そこを削った上記のmruby.cでは、

240,360 byte

だった。おお、小さい。

NXTの中に入ったというのも頷ける。ただメモリが全然足りてないので、どうやって64KBに収めたのか気になる。