Hatena::ブログ(Diary)

hogeなlog

プロフィール

hogelog

hogelog

小室 直(こむろ すなお)。電気通信大学2003年入学。2010年修士卒業。プログラミングとかしてます。

カレンダー
1984 | 01 |
2006 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 |
2010 | 01 | 06 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 05 | 08 | 09 | 10 | 12 |
2012 | 01 | 04 | 06 |

December 26(Fri), 2008

[][] 1.5冊目おすすめしたい本「Rubyで作る奇妙なプログラミング言語」

yharaさんが「Rubyで作る奇妙なプログラミング言語~Esoteric Language~」という本(通称esolang本)を執筆されました。

Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~

Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~

内容はタイトルの通り珍妙なプログラミング言語をRubyで実装するというもので、HQ9+から始まりBrainf*ck、Whitespace、終いにはオリジナル言語の設計と実装に至ります。


このesolang本、ありがたいことに献本で頂いたのです。なんでdankogaiならぬ私が献本などされるのだろうと不思議に思ったのですが、理由を聞くとどうもこの本が以前私が1000speakersカンファレンスでした話に影響を受けているそうなのです。

ええ、ええ、話しました。「プログラミング初心者はHello Worldを書いたら次はプログラミング言語処理系を実装するんだ、まずはbrainf*ck、次にWhitespaceだ!」などと。そう、プログラミング言語処理系というのは、頭の良い人だけのおもちゃじゃなくて、プログラミング初心者にも楽しめるおもちゃなのです。

以下は録画したものをニコニコ動画にアップしたものです。最初の3分ほど録音できてません。

D*1

「yharaさんがbrainf*ckとかについての本を書いたらしい」と聞いたときは、一介のbrainf*ck好きとして嬉しく思っていましたが、まさか自分の話に影響を受けていただなんて。自分の話が誰か他の人にそんな影響を与えることができたと聞いてとても嬉しく思いました。僕自身はこの書籍には全く関わっていないしわけですが、この本が世に出てきてとても嬉しいです。


んで、届いてから読んでいるわけですけど、これは良い本です。

この本は「たのしいプログラミング」とはどういうものか、HQ9+やらbrainf*ckなどの奇妙な言語処理系を題材に解説しています。「たのしいプログラミング」は多くのプログラミング言語書籍で欠けている、表現できていない部分です。帯に"Rubyユーザにとっての「2冊目の本」としてもバッチリ役立ちます"と書いてありますが、私としては1.5冊目としてオススメしたい。つまり「1冊目の本をある程度読んでなんとなく読み書きできるようになったときに取り組む本」です。

動画の中でも少し語ってますけど私はプログラミング書籍を読もうとしても、Hello Worldとか出力できたけど意味わからんし何が嬉しいのかわからんし、とほぼその辺りで挫折する人でした。でなんだか随分長いことHello Worldレベルプログラマの位置でずっと足踏みしていたのですが、ある時出会ったbrainf*ckというプログラムで「なんか実装できたし、これ面白い!」と初めて感じたのです。

そんなわけで私は疑っています。手取り足取り段階を踏んで進んでいく真面目なプログラミング言語の書籍を、ちゃんと読み通すことができる初心者という存在を。プログラミング入門の書籍をちゃんと読み進められない、そんな人には是非このesolang本をオススメしたい。他の書籍を参考書として使いながらesolang本に取り組んでほしい。


esolang本に書かれているプログラムはRubyだが、他の言語で取り組むのも良いでしょう。全国のプログラミング系日記書いてるみなさん、「○○で作る奇妙なプログラミング言語」シリーズをするなら今が旬ですよ!


プログラミングは自分の思ったものを書くことができる便利な技能であるというのは、プログラミングしない人も割と知ってるかもしれません。でもそれだけじゃなくて、便利さとかとは別の次元の「なんかおもしれー」というものがあるのです。その「なんかおもしれー」が存分に詰まっているのがesolang本です。女房を質に入れてでも読むべきとは言いませんが、財布に余裕があるなら一冊買ってみるのも良いのではないでしょうか。

*1:日記に貼るにあたって久しぶりに再見したけど、だいぶ無茶苦茶言ってるなーこの人は。なんだよ妹とか女子高生とかLive少子化対策とか。いねえよ妹なんて

トラックバック - http://d.hatena.ne.jp/hogelog/20081226

December 22(Mon), 2008

[] char-hints-mod2の設定

char-hints-mod2.jsはchar-hintラベルの入力・表示を大文字にするか小文字にするか、ラベルに使う文字の設定を

set charhintinput=uppercase
set charhintshow=uppercase
set hintchars="HJKLASDFGYUIOPQWERTNMZXCVB"

みたいにしてできるようにしてたんですけど、これだとvimperatorrcで設定できませんでした。*1

なので設定方法を変えました。vimperatorrcに

let g:hintsio="iO"
let g:hintchars="HJKLASDFGYUIOPQWERTNMZXCVB"

と書くとヒントラベルの入力を小文字、表示を大文字と設定され、使う文字は"HJKLASDFGYUIOPQWERTNMZXCVB"となります。

http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/char-hints-mod2.js

謝辞

メールにて指摘していただいたキム様ありがとうございました。

*1:vimperatorrcがプラグインより先に読みこまれるからなので、vimperatorrcでloadpluginとかやれば設定できたけど

December 19(Fri), 2008

[] char-hints-mod2.jsで小文字で入力できるように

追記

設定方法変えました

http://d.hatena.ne.jp/hogelog/20081222/p1



charhintの入力、出力を大文字にするか小文字にするかを

:set charhintinput=uppercase|lowercase
:set charhintshow=uppercase|lowercase

で選べるようにしました。デフォルト設定はどちらもuppercaseです。

http://coderepos.org/share/browser/lang/javascript/vimperator-plugins/trunk/char-hints-mod2.js

謝辞

http://d.hatena.ne.jp/joma/20081217/p1

別に逆でもいいんだよなーと気付かされました。jomaさんと同様の、昔のchar-hintsっぽく表示を大文字に、charhintsの入力を小文字にしたいなら

:set charhintinput=lowercase

とだけすれば良いです。

December 17(Wed), 2008

[] tinyurlをvimperatorから

与えられたURLが現在開いているURLをtinyurl化する:tinyurlコマンドと、tinyurl化されたURLを展開する:expandurlコマンドを追加するtinyurl.jsを書いた。

http://coderepos.org/share/browser/lang/javascript/vimperator-plugins/trunk/tinyurl.js


普通のURLからtinyurlはAPIが用意されてて

http://tinyurl.com/api-create.php?url=http://d.hatena.ne.jp/hogelog/

とかにリクエスト送るだけでいいんですけど、残念なことに逆にtinyurl化されたURLはリクエストを送ると元のURLを返すようなAPIは用意していない。困ったなーと思ったんですけど、実はそんな困ることでもなかった。

XMLHttpRequest.channel.nameリダイレクトのURLが格納されるのでそこを読めばいいだけだった。

なのでhttp://tinyurl.com/6dpndfに対してリダイレクト先が知りたいなら

util.httpGet('http://tinyurl.com/6dpndf').channel.name

とかすればいい*1

ソースコードを読むのは楽しいですね。

Thanks

util.copyToClipboard(str, verbose)の第二引数使うように修正してコミット

teramako [vimperator] echopyって関数名が素敵。でも、わざわざechoしなくてもutil.copyToClipboard("hoge",true)で良いんだよなぁ 2008/12/17

http://b.hatena.ne.jp/teramako/20081217#bookmark-11325811


ちなみにechopyというネーミングは

http://coderepos.org/share/browser/lang/javascript/vimperator-plugins/trunk/echopy.js

から

*1:util.httpGetはvimperatorが提供するXMLHttpRequestのラッパ関数

トラックバック - http://d.hatena.ne.jp/hogelog/20081217

December 16(Tue), 2008

[][] スクリプト言語により生活を楽にする

こういう「プロファイラを実行してプログラムを動かし、プロファイラを停止して結果に適当な名前を付けて保存する」みたいな決まりきった形の一連の作業はスクリプト一つにまとめましょう。

「何か一つスクリプト言語を身に付けろ」と言う方が多いですけどそういうことです。

#!/usr/bin/env ruby
def which(exec)
    `which #{exec}`.chomp
end
def exit_on_execerr(*args)
    puts "# #{args.join(' ')}"
    if !system(*args)
        STDERR.puts "fail: #{args.join(' ')}"
        exit 1
    end
end
def execute(*args)
    puts "# #{args.join(' ')}"
    system(*args)
end

SUDO        = which 'sudo'
CONTROL     = which 'opcontrol'
REPORT      = which 'opreport'
ANNOTATE    = which 'opannotate'
EXEC        = which ARGV[0]

opts = {}
ARGS        =
    if ARGV.length > 1
        ARGV[1..-1].reject!{|x|
            if x =~ /^--(\w+)(?:=(.+))?$/
                opts[$1] = $2 || true
                true
            else
                false
            end
        }
    else
        []
    end

if !FileTest.executable?(EXEC)
    STDERR.puts "#{ARGV[0]} is not executable"
    exit 1
end

report = opts['report'] || 'report'
if opts['event']
    exit_on_execerr(SUDO, CONTROL, "--event=#{opts['event']}")
end

exit_on_execerr(SUDO, CONTROL, "--image=#{EXEC}")
exit_on_execerr(SUDO, CONTROL, '--shutdown')
exit_on_execerr(SUDO, CONTROL, '--reset')
exit_on_execerr(SUDO, CONTROL, '--start')
execute(EXEC, *ARGS)
exit_on_execerr(SUDO, CONTROL, '--stop')

[
    ['report', [REPORT, EXEC]],
    ['report.l', [REPORT, '-l', EXEC]],
    ['annotate.as', [ANNOTATE, '-as', EXEC]],
    ['annotate.a', [ANNOTATE, '-a', EXEC]],
    ['annotate.s', [ANNOTATE, '-s', EXEC]],
].each{|array|
    ext, args = array
    puts "# #{args.join(' ')}"
    File.open("#{report}.#{ext}", 'w') do |file|
        file.print `#{args.join(' ')}`
        file.flush
    end
}

# vim: sw=4 ts=4 et:

unlimited tanpopo putting worksで褒められるのは小学生までです。


ほんの少しのスクリプトで生活が激変! て書こうと思ったんだけどなんかあれこれ追加したら意外と長くなってしまった。

トラックバック - http://d.hatena.ne.jp/hogelog/20081216

December 15(Mon), 2008

[][] RakefileでLaTeXファイルを監視自動コンパイル

id:hayamizがなんかOMake つかって LaTeX コンパイルしたら簡単すぎて身長が5cm伸びたとか書いてたのでOMake使おうかと思ったけど

LATEX = platex
DVIPDFM = dvipdfmx

LaTeXDocument(document, document)

.DEFAULT: document.pdf document.dvi

ここでは、 .tex ファイルが "document.tex" というもの1つだけであることを仮定しとります。なので、hoge.tex なら ↑の内容の "document" を "hoge" に書き換えればおk。

とかちょっと面倒過ぎてありえないのでやっぱりrakeでやることにした。前々から使ってるLaTeXファイルコンパイル用のRakefileに継続的に自動コンパイルするcontタスクを追加。

desc "Continuation Watching Build"
task :cont do
    at_exit{
        loop do
            system("rake", "--silent")
            sleep 5
        end
    }
end

手抜き最高!


使い方は

  1. http://coderepos.org/share/browser/lang/ruby/misc/rake_template/Rakefile-latex をダウンロードしてRakefileという名前でtexファイル置いてるディレクトリに置く
  2. 対象のファイルがhoge.texならrake hogeとして一度コンパイル
  3. rake cont&として自動コンパイルをbgで走らせておく

あとはrakeがhoge.texから、hoge.texがinputしてるtexファイルやら画像ファイルやらbibファイルとか色々適当に監視して、更新されたらコンパイルしてくれます! やった!

ujihisaujihisa 2008/12/16 03:51 うちはloop+sleepではなく、vimの保存をフックして、保存時にバックグラウンドで非同期にtexをコンパイルさせて、完了したらgrowlで通知するようにしている。

hogeloghogelog 2009/01/28 21:57 気付いてなかったコメントに亀レスする祭開催中。

なるほどしかし、最近はこの機能も使わず「rakeって打つの気持ち良い!」という猿に退化していますふへへ

December 13(Sat), 2008

[] 逆襲のchar-hints-mod for vimperator 2.0pre

2.0preで動くchar-hints-modを書いてみた。

http://coderepos.org/share/browser/lang/javascript/vimperator-plugins/trunk/char-hints-mod2.js

このchar-hints-mod2.jsは小文字は候補を絞るためのテキスト入力に、大文字をラベルの選択に使います。


書いたばかりなのでたぶんまだちゃんと動かないことがあります。2008/12/12以降あたりで動作します。2008/12/07以前のバージョンはcommandline.commandが無いので確実に動きません。


このプラグインはできるだけvimperator本体を利用して、コード自体は小さくなるように書きました。なのでvimperatorが更新されていっても変更はかなり少なく済むはず。


数字ラベルを隠して文字ラベルを表示し、大文字入力を盗んで数字入力に置き換えてるだけなので、数字入力でも飛べてしまいます。

Thanks

途中どうもうまく書けず「vimperator本体のコード丸ごとコピーしてくるしかないのか」という思いを込めてtwitterで

だめだ、hintsのonInputがいじれねえ http://twitter.com/hogelog/statuses/1053696632

とつぶやいたところid:nokturnalmortumから

@hogelog liberator.eval('onInput', hints.addMode); みたいにしていじるのはだめですか? http://twitter.com/anekos/status/1053710292

@hogelog 怪しい処理を中に突っ込む魔術について書いてみた。http://d.hatena.ne.jp/nokturnalmortum/20081213/1229102458 http://twitter.com/anekos/status/1053766211

と助言をいただきました。これ知らなかったら書けませんでした。多謝!

トラックバック - http://d.hatena.ne.jp/hogelog/20081213

December 08(Mon), 2008

[][] OProfileの使い方備忘録

プログラムのボトルネックがどこにあるのか、なんて調べるときには計測する必要がありますね。プログラム中の特定処理の前後でrdtsc命令使って時間を計測して処理時間を求める、とかそういうこともできるんですけど、まあめんどうじゃないですか。プロファイラを使いましょう。

プロファイラとはなんぞや、Wikipediaの性能解析のページに色々書いてますね

そういうわけでOProfileというLinuxで動くプロファイラを使っているので、未来の自分とか「OProfile動かしてみてーけどさっぱりわからん!」みたいな人のためにまとめておきます。

OProfileの特徴

OProfileは

  • 計測したいプログラムに対して特別な処理をしなくてもいい
  • 低レイヤーの情報も計測できる
  • gprof形式のコールグラフも表示できる
  • オーバーヘッドがとても小さい

これらの特徴があるらしいです。使ってみて特に嬉しいと感じたのは「低レイヤーの情報も計測できる」ですね。CPUの種類にもよる*1のですが処理時間だけではなく、L1キャッシュミスした回数やらDRAMアクセス回数とかがプログラムのどこで発生しているのか一目でわかったりするのは、いやなんともすごいものだなあと感嘆の念を覚えます。

インストール

まず対応しているCPUはだいたい

http://oprofile.sourceforge.net/docs/

の最後の「Event type reference」にまとめられてると思いますが、ソースコード見た感じ、ここに書かれていないものもちょっとは対応とかされてる気もします。無かったら書けばいいんじゃないですか!

今回入れる環境のCPUは

$ cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 15
model           : 43
model name      : AMD Athlon(tm)64 X2 Dual Core Processor  4600+
...

AMD Athlon64ということで幸いにも対応しているのでOProfileをインストールすることにします。OSはUbuntu 8.10。この環境だとこんな硬派なOProfileですら

$ sudo apt-get install oprofile oprofile-gui

こんなに軟派に一行でインストールできる。

# カーネルプログラムのプロファイルまで取りたいならカーネル再構築してvmlinux作らないといけないので、それなりに面倒なことをする必要がある。

使い方

oprofileは基本的にopcontrolコマンドからopcontrol --startのようにoprofileデーモンに命令を与える扱い方をします。とりあえず以下のコマンドがわかればプロファイリングっぽいことができます。

--start-daemon
oprofileデーモンを開始(プロファイルは始まらない)
--start
(デーモンが起動していなければ起動してから)プロファイルをはじめる。
--dump
現在までのプロファイル結果を出力する
--stop
プロファイルを停止し、結果を出力する
--shutdown
oprofileデーモンを停止
--reset
プロファイル結果をリセットする

手元のバージョンのopcontrolだとルート権限が必要。ルート権限無しでも使えるバージョン(設定?)もあるようだけどそれはよくわからない。

とりあえず動かしてみたいなら、まず

$ sudo opcontrol --no-vmlinux

のように「カーネルのプロファイルまでは取らない」と設定。(設定内容は/etc/oprofile/daemonrcに保存されます)opcontrol --startでプロファイリングを開始し、opcontrol --stopで終了し、その間に動いたプログラムについて記録します。


ためしにこんなプログラムのプロファイルを取ってみます。

#include <stdio.h>
#include <stdlib.h>
#define ROWS 1000
#define COLS 1000
#define table_ref(table,row,col) ((table)[(row)*COLS+(col)])
typedef int* Table;
void touch_row_col(Table from, Table to) {
    int i, j;
    for(i=0;i<ROWS;++i) {
        for(j=0;j<COLS;++j) {
            table_ref(from, i, j) = table_ref(to, i, j);
        }
    }
}
void touch_col_row(Table from, Table to) {
    int i, j;
    for(i=0;i<COLS;++i) {
        for(j=0;j<ROWS;++j) {
            table_ref(from, j, i) = table_ref(to, j, i);
        }
    }
}
int main() {
    Table from, to;
    from = malloc(sizeof(int)*ROWS*COLS);
    to = malloc(sizeof(int)*ROWS*COLS);
    touch_row_col(from, to);
    touch_col_row(from, to);
    return 0;
}

gcc -gでコンパイルして(-gオプションを付けると、あとでopannotateでソースと並べて結果を見ることができる)、--startと--stopの間でプログラムを実行します。

$ gcc -g array.c
$ sudo opcontrol --reset
$ sudo opcontrol --start && ./a.out ; sudo opcontrol --stop
Using default event: CPU_CLK_UNHALTED:100000:0:1:1
Using 2.6+ OProfile kernel interface.
Using log file /var/lib/oprofile/samples/oprofiled.log
Daemon started.
Profiler running.
Stopping profiling.

opreportまたはopannotateなどでプロファイルの結果を見ます。

$ opreport
CPU: AMD64 processors, speed 1000 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No u
nit mask) count 100000
CPU_CLK_UNHALT...|
  samples|      %|
------------------
     2711 42.3461 no-vmlinux
     2618 40.8935 a.out
      351  5.4827 ld-2.8.90.so
      343  5.3577 libc-2.8.90.so
      139  2.1712 dash
       53  0.8279 libglib-2.0.so.0.1800.2
       25  0.3905 oprofiled
...

引数を指定しないと、プロファイル中に実行されていたすべてのプロセスについて情報を表示します。特定のプログラムのプロファイル情報のみ見たい場合は引数で指定。

$ opreport a.out /usr/local/bin/zsh /bin/grep
CPU: AMD64 processors, speed 1000 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 100000
CPU_CLK_UNHALT...|
  samples|      %|
------------------
     2618 99.3548 a.out
       15  0.5693 grep
        2  0.0759 zsh

引数-lでシンボル情報、-cでコールグラフとあわせて表示されます。touch_col_rowがtouch_row_colに比べてとても遅いのが見て取れます。

$ opreport -l a.out
CPU: AMD64 processors, speed 1000 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 100000
samples  %        symbol name
2025     77.3491  touch_col_row
593      22.6509  touch_row_col
$ opreport -c a.out
CPU: AMD64 processors, speed 1000 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 100000
samples  %        symbol name
-------------------------------------------------------------------------------
2025     77.3491  touch_col_row
  2025     100.000  touch_col_row [self]
-------------------------------------------------------------------------------
593      22.6509  touch_row_col
  593      100.000  touch_row_col [self]
-------------------------------------------------------------------------------

opannotateでは-sでソースコード、-aでアセンブリコードとあわせた結果を表示することが可能です。

$ opannotate -s a.out
/*
 * Command line: opannotate -s a.out
 *
 * Interpretation of command line:
 * Output annotated source file with samples
 * Output all files
 *
 * CPU: AMD64 processors, speed 1000 MHz (estimated)
 * Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 100000
 */
/*
 * Total samples for file : "/home/komuro/lang/c/etc/array.c"
 *
 *   2618 100.000
 */


               :#include <stdio.h>
               :#include <stdlib.h>
               :#define ROWS 1000
               :#define COLS 1000
               :#define table_ref(table,row,col) ((table)[(row)*COLS+(col)])
               :typedef int* Table;
               :void touch_row_col(Table from, Table to) { /* touch_row_col total:    593 22.6509 */
               :    int i, j;
     3  0.1146 :    for(i=0;i<ROWS;++i) {
   235  8.9763 :        for(j=0;j<COLS;++j) {
   355 13.5600 :            table_ref(from, i, j) = table_ref(to, i, j);
               :        }
               :    }
               :}
               :void touch_col_row(Table from, Table to) { /* touch_col_row total:   2025 77.3491 */
               :    int i, j;
     7  0.2674 :    for(i=0;i<ROWS;++i) {
   471 17.9908 :        for(j=0;j<COLS;++j) {
  1547 59.0909 :            table_ref(from, j, i) = table_ref(to, j, i);
               :        }
               :    }
               :}
               :int main() {
               :    Table from, to;
               :    from = malloc(sizeof(int)*ROWS*COLS);
               :    to = malloc(sizeof(int)*ROWS*COLS);
               :    touch_row_col(from, to);
               :    touch_col_row(from, to);
               :    return 0;
               :}
$ opannotate -a a.out
/*
 * Command line: opannotate -a a.out
 *
 * Interpretation of command line:
 * Output annotated assembly listing with samples
 *
 * CPU: AMD64 processors, speed 1000 MHz (estimated)
 * Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (N
o unit mask) count 100000
 */
               :
               :/home/komuro/lang/c/etc/a.out:     file format elf32-i386
               :
               :
               :Disassembly of section .text:
               :
08048422 <touch_col_row>: /* touch_col_row total:   2025 77.3491 */
               : 8048422:       push   %ebp
               : 8048423:       mov    %esp,%ebp
               : 8048425:       sub    $0x10,%esp
               : 8048428:       movl   $0x0,-0x4(%ebp)
               : 804842f:       jmp    8048475 <touch_col_row+0x53>
               : 8048431:       movl   $0x0,-0x8(%ebp)
               : 8048438:       jmp    8048468 <touch_col_row+0x46>
    80  3.0558 : 804843a:       mov    -0x8(%ebp),%eax
   465 17.7617 : 804843d:       imul   $0x3e8,%eax,%eax
   116  4.4309 : 8048443:       add    -0x4(%ebp),%eax
               : 8048446:       shl    $0x2,%eax
               : 8048449:       mov    %eax,%edx
   454 17.3415 : 804844b:       add    0x8(%ebp),%edx
               : 804844e:       mov    -0x8(%ebp),%eax
               : 8048451:       imul   $0x3e8,%eax,%eax
   239  9.1291 : 8048457:       add    -0x4(%ebp),%eax
               : 804845a:       shl    $0x2,%eax
               : 804845d:       add    0xc(%ebp),%eax
   193  7.3720 : 8048460:       mov    (%eax),%eax
               : 8048462:       mov    %eax,(%edx)
               : 8048464:       addl   $0x1,-0x8(%ebp)
   471 17.9908 : 8048468:       cmpl   $0x3e7,-0x8(%ebp)
               : 804846f:       jle    804843a <touch_col_row+0x18>
               : 8048471:       addl   $0x1,-0x4(%ebp)
     7  0.2674 : 8048475:       cmpl   $0x3e7,-0x4(%ebp)
               : 804847c:       jle    8048431 <touch_col_row+0xf>
               : 804847e:       leave
               : 804847f:       ret
...
$ opannotate -sa a.out
/*
 * Command line: opannotate -sa a.out
 *
 * Interpretation of command line:
 * Output annotated assembly listing with samples
 *
 * CPU: AMD64 processors, speed 1000 MHz (estimated)
 * Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (N
o unit mask) count 100000
 */
               :
               :/home/komuro/lang/c/etc/a.out:     file format elf32-i386
               :
               :
               :Disassembly of section .text:
               :
08048422 <touch_col_row>: /* touch_col_row total:   2025 77.3491 */
               :        for(j=0;j<COLS;++j) {
               :            table_ref(from, i, j) = table_ref(to, i, j);
               :        }
               :    }
               :}
               :void touch_col_row(Table from, Table to) {
               : 8048422:       push   %ebp
               : 8048423:       mov    %esp,%ebp
               : 8048425:       sub    $0x10,%esp
               :    int i, j;
               :    for(i=0;i<ROWS;++i) {
               : 8048428:       movl   $0x0,-0x4(%ebp)
               : 804842f:       jmp    8048475 <touch_col_row+0x53>
               :        for(j=0;j<COLS;++j) {
               : 8048431:       movl   $0x0,-0x8(%ebp)
               : 8048438:       jmp    8048468 <touch_col_row+0x46>
               :            table_ref(from, j, i) = table_ref(to, j, i);
    80  3.0558 : 804843a:       mov    -0x8(%ebp),%eax
   465 17.7617 : 804843d:       imul   $0x3e8,%eax,%eax
   116  4.4309 : 8048443:       add    -0x4(%ebp),%eax
               : 8048446:       shl    $0x2,%eax
               : 8048449:       mov    %eax,%edx
   454 17.3415 : 804844b:       add    0x8(%ebp),%edx
               : 804844e:       mov    -0x8(%ebp),%eax
               : 8048451:       imul   $0x3e8,%eax,%eax
   239  9.1291 : 8048457:       add    -0x4(%ebp),%eax
               : 804845a:       shl    $0x2,%eax
               : 804845d:       add    0xc(%ebp),%eax
   193  7.3720 : 8048460:       mov    (%eax),%eax
               : 8048462:       mov    %eax,(%edx)
               :    }
               :}
...

opcontrol --event=で補足するイベントを指定することができます。イベントの種類はドキュメントかophelpコマンドやopcontrol --list-eventsなどで表示されるものが使用可能です。

touch_col_rowがとても遅いのは、きっとメモリ領域に対するアクセスパターンが飛び飛びになってしまっててキャッシュミスが発生しまくってるんだろうなあとあたりをつけて、キャッシュミスの発生具合を見ることにしましょう。AMD64だとDATA_CACHE_MISSESとかですね。

$ sudo opcontrol --shutdown
Stopping profiling.
Killing daemon.
$ sudo opcontrol --reset
$ sudo opcontrol --event=DATA_CACHE_MISSES:500
$ sudo opcontrol --start && ./a.out ; sudo opcontrol --stop
Using 2.6+ OProfile kernel interface.
Using log file /var/lib/oprofile/samples/oprofiled.log
Daemon started.
Profiler running.
Stopping profiling.
$ opreport -l a.out
CPU: AMD64 processors, speed 1000 MHz (estimated)
Counted DATA_CACHE_MISSES events (Data cache misses) with a unit mask of 0x00 (No unit mask) count 500
samples  %        symbol namet
3965     95.0839  touch_col_row
205       4.9161  touch_row_col

touch_col_rowでキャッシュミスが多発していることがわかりますね。


このように、噂には聞いていて意識して書くことで実際にプログラムが速くなったりすることは確認したのだけれども、どうにも存在が遠くてよくわからないキャッシュさんを身近に感じることのできて嬉しい! それがOProfileのしてくれた大きな仕事なのでした。ありがたいありがたい。

あとGUIから操作することとかも可能らしいんだけど全く試してないのでわからない。

[] vimperator 2.0preだと簡単にXPathを取得できる

.vimperatorに以下の文字列を貼り付けておくだけで、;xでヒントモードに入り、そこで選んだ要素のXPathがvimperatorコマンドラインに出力され、コピーされる。

javascript <<EOM
// ;x use FireBugLibrary(FBL)
hints.addMode("x", "copy xpath",
    function(elem) {
        let xpath = FBL.getElementXPath(elem);
        liberator.echo(xpath);
        util.copyToClipboard(xpath);
    },
    function() "//*");
EOM

ただここで使っているFBL.getElementXpathはFirebugが提供するライブラリなのでFirebugはいってないと使えないですね。

f:id:hogelog:20081208125537p:image

ということを

http://d.hatena.ne.jp/goinger/20081206/1228585045

を読んで思いついたのでした。xpathBlink.jsは入力したXPathが示す要素を表示するので、それとはちょうど逆のことをする。

これもプラグインとして公開すべきだろか。

*1:OProfileが対応していないCPUだったら全く使えない

otsuneotsune 2008/12/18 20:59 http://svn.coderepos.org/share/lang/javascript/bookmarklets/yunogenerator.bookmarklet.js?
こっちのYunoGenerator.getXPathByElementを同梱すればplugin化できそげ。
というか_libly.jsにあっても良いかも。

hogeloghogelog 2009/01/28 21:55 いまさらながらコメントに気付いてなかった。Skypeチャットで聞いたけども。ものすごい遅い反応だけどやろうかなー

December 04(Thu), 2008

[] ハイライトだけされてhintsの数字が表示されなくなるバグ

followでhints絞ったあとfollowの文字を削除したら数字だけ表示されなくなる。

f:id:hogelog:20081204074037p:image

しばらく前にあって、でもちょっと前に無くなったと思ったのだけど。これ書いてる時点の最新版のソースコードだとこうなってしまう。

commit e40b68c7f479489b564793924d43cc9ca2f825b0
Author: Kris Maglione <maglione.k@gmail.com>
Date:   Tue Dec 2 20:35:03 2008 -0500

    Remove mozdev links and external images/css from the help

真面目に原因追ったりしないでとりあえず手元で場当たり的な修正だけしてみた。

--- a/liberator/content/hints.js
+++ b/liberator/content/hints.js
@@ -218,6 +218,12 @@ function Hints() //{{{
                     elem.removeAttributeNS(NS.uri, "highlight");
                     continue inner;
                 }
+                else
+                {
+                    span.style.display = "inline";
+                    if (imgspan)
+                        imgspan.style.display = "inline";
+                }

                 if (text == "" && elem.firstChild && elem.firstChild.tagName == "IMG")
                 {

anekosさんナイスです!

nokturnalmortum 2008/12/05 18:58

パクってコミットしてみました。

おお、ありがたい!

nokturnalmortumnokturnalmortum 2008/12/05 18:58 パクってコミットしてみました。

December 03(Wed), 2008

[] 本日の補完関数 _opcontrol

http://coderepos.org/share/browser/lang/zsh/Completion/_opcontrol

zshの提供する_filesと_commandなどの結果を併せた結果を補完候補としたいときにどうやったらいいんだか非常にあれこれした結果、_alternativeでやるとまあ目的のことができたのでとりあえずこんな程度で一旦コミット。

あとopreport,opannotate,oparchive,opgprofの補完関数も書かにゃ。


oprofileで実験を進めるというのが本来の目的だったはずがまたあさっての方向に進んでるなあ。

トラックバック - http://d.hatena.ne.jp/hogelog/20081203

December 01(Mon), 2008

[] zshでgemの補完関数を書いた

軽い気持ちで始めたけどかなりわけわからなかった。

#compdef gem

# gem 1.2.0

typeset -A opt_args
local context state line ret=1
local -a cmds
cmds=( 'build' 'cert' 'check' 'cleanup' 'contents' 'dependency' 'environment' 'fetch' 'generate_index' 'help' 'install' 'list' 'lock' 'mirror' 'outdated' 'pristine' 'query' 'rdoc' 'search' 'server' 'sources' 'specification' 'stale' 'uninstall' 'unpack' 'update' 'which' )

_arguments \
'(1 * -)'{-h,--help}'[print help message]' \
'(1 * -)'{-v,--version}'[print the version]' \
"(-)1: :->cmds" \
'*: :->args' && ret=0

case $state in
  cmds)
    _describe -t commands 'gem command' cmds && ret=0
  ;;
  args)
    case $line[1] in
      (fetch|install)
        if ( [[ ${+_packages} -eq 0 ]] || _cache_invalid packages ) && ! _retrieve_cache packages; then
          _packages=(${${(f)"$(_call_program packages $words[1] list -r 2>/dev/null |sed '1,3d')"}/(#b)([^ ]##) # (*)/${match[1]}})
          _store_cache packages _packages
        fi

        _wanted packages expl 'gem package' compadd $_packages && ret=0
      ;;
      (clean|uninstall|unpack)
        local -a packages
        packages=(${${(f)"$(_call_program packages $words[1] list -l 2>/dev/null |sed '1,3d')"}/(#b)([^ ]##) # (*)/${match[1]}})
        _wanted packages expl 'gem package' compadd $packages && ret=0
      ;;
    esac
  ;;
esac
return ret
# vim: ft=zsh sw=2 ts=2 et:

$fpathの通ってる所にこの_gemファイルを放り込んでおくと、gemのコマンド(installとか)と、パッケージの補完が可能になる。各コマンドのオプション(gem install -Vとか)は補完できない。

内容は解説しようにも、自分でいまいちよくわかってなくて苦しい。codereposに上げときました。

http://coderepos.org/share/browser/lang/zsh/Completion/_gem


secondlifeさんの書いたgemの補完とかあるのは前から知ってたけど

つーかcompctl用いた旧世代の方法じゃカッコワルイのでだれか新世代のスマートな方法でやってください!

とか書いてるからつい。しかし、これ全然スマートじゃあないように思える。zshめ!

参考ページ

あとほとんどわけわからんけどman zshcompsysとか。

トラックバック - http://d.hatena.ne.jp/hogelog/20081201
最近のコメント