Ruby の tarball の中身のサイズの変化を可視化してみる。

ruby-tarsize.R:
library(ggplot2)
d <- read.csv("2012-02/ruby-tarsize.csv")
print(qplot(version, size, data=d, fill=path, geom="bar") + opts(axis.text.x=theme_text(angle=30)))
うぅむ。ggplot2 でお気楽に作ったグラフはあまり見やすくないな。
まず、デフォルトではバージョン名が重なってしまう。まぁ、これは 30度傾けて対処したが。
また、積み上げ棒グラフと凡例の順番が反対だし、隣り合った色が似すぎていて凡例との対応を取るのが不可能に近い。
ext 以下はさらに分割して表示したいのだが、そうやって種類を増やしてもこのままでは区別不可能だろう。
なお、データは以下のような感じ。
% head 2012-02/ruby-tarsize.csv version,path,size 1.4.0,(root),1822254 1.4.0,beos,0 1.4.0,cygwin,382 1.4.0,ext,540248 1.4.0,lib,185938 1.4.0,misc,41707 1.4.0,missing,99246 1.4.0,sample,89417 1.4.0,win32,77416
このデータは以下のようにして作った。
% cat Makefile
z2.csv: z1.csv
tb gsub -f path '\A[^/]+/' '' $^ | \
tb gsub -f path '(\A|/)[^/]*\z' '' | \
tb gsub -f path '\A([^/]+).*' '\1' | \
tb gsub -f path '\A\z' '(root)' | \
tb group version,path -a 'sum(size),size' -o $@
z1.csv: z0.csv
tb cut version,size,path $^ -o $@
z0.csv: tarballs
rm -f $@.tmp0; \
touch $@.tmp0; \
for f in tarballs/*.tar.gz tarballs/*.tar.bz2; do \
tb tar-tvf $$f -l -o $@.tmp; \
tb newfield version "\"$$f\""'.sub(/tarballs\/ruby-/, "").sub(/\.tar.*/, "")' $@.tmp -o $@.tmp; \
tb cat $@.tmp0 $@.tmp -o $@.tmp0; \
done; \
rm $@.tmp; \
mv $@.tmp0 $@
tarballs ディレクトリ以下に ruby の tarball を置いておけば動く。tb tar-tvf により、展開せずにサイズを抽出している。
最近、Ruby の dbm 拡張で、ヘッダとライブラリのミスマッチの検出をがんばってみた。
場合分けが多くて、頭の中で把握するのは無理だったので、整理してみた。
library:
libc libc の中にあるものを使う
ndbm 4.3BSD ndbm を libndbm として外部に出したもの
db1 Berkeley DB 1
db2 Berkeley DB 2以降
gdbm17 GDBM 1.8.0以前 : libgdbm に ndbm 関数が同梱 : -lgdbm でリンク
gdbm18 GDBM 1.8.1以降 1.8.3以前 : libgdbm_compat が分離 : -lgdbm でリンク
gdbm19 GDBM 1.9以降 : dbm_clearerr が提供される : -lgdbm でリンク
gdbm18c GDBM 1.8.1以降 1.8.3以前 : libgdbm_compat が分離 : -lgdbm_compat -lgdbm でリンク
gdbm19c GDBM 1.9以降 : dbm_clearerr が提供される : -lgdbm_compat -lgdbm でリンク
libc-type:
ndbm-libc libc に 4.3BSD ndbm が入っている (4.3BSD および、Solaris などの商用 Unix)
db1-libc libc に Berkeley DB 1 が入っている (NetBSD など、4.4BSD から派生したもの)
glibc libc に ndbm 関数が入っていない (glibc 2.2以降、uClibc など)
header:
ndbmh 4.3BSD ndbm : _DBM_IOERR を定義する
db1h Berkeley DB 1 : _DB_H_ を定義する
db2h Berkeley DB 2以降 : _DB_H_ を定義する
gdbm18h GDBM 1.8.3以前 : dbm_clearerr が空 (1.8.0 と 1.8.1 の間でヘッダは変化なし)
gdbm19h GDBM 1.9以降 : _GDBM_H_ を定義する
library libc-type ndbmh db1h db2h gdbm18h gdbm19h
libc ndbm-libc O B AB D DB
libc db1-libc O AB D D
libc glibc A AB AB AD ABD
ndbm ndbm-libc O B AB D BD
ndbm db1-libc O AB D D
ndbm glibc O B AB D BD
db1 ndbm-libc E O AB DE DE
db1 db1-libc E O AB DE DE
db1 glibc E O AB DE DE
db2 ndbm-libc E B O DE BDE
db2 db1-libc E O DE DE
db2 glibc AE AB O ADE ABDE
gdbm17 ndbm-libc E BE ABE O BC
gdbm17 db1-libc E E ABE O C
gdbm17 glibc E BE ABE O BC
gdbm18 ndbm-libc E BE ABE BC
gdbm18 db1-libc E E ABE C
gdbm18 glibc AE ABE ABE A ABC
gdbm19 ndbm-libc E BE ABE BC
gdbm19 db1-libc E E ABE C
gdbm19 glibc AE ABE ABE A ABC
gdbm18c ndbm-libc E BE ABE O B
gdbm18c db1-libc E E ABE O
gdbm18c glibc E BE ABE O B
gdbm19c ndbm-libc E E ABE O
gdbm19c db1-libc E E ABE O
gdbm19c glibc E E ABE O
O. 正しいヘッダとライブラリの組み合わせ
A. dbm_open がリンクできる。
4.3BSD ndbm: DBM *dbm_open();
Berkeley DB 1.85: DBM *dbm_open(const char *, int, int);
Berkeley DB 2.7.7: #define dbm_open(a, b, c) __db_ndbm_open(a, b, c)
DBM *__db_ndbm_open(const char *, int, int);
GDBM 1.7: DBM *dbm_open ()
GDBM 1.8.3: DBM *dbm_open ();
GDBM 1.9: DBM *dbm_open (char *file, int flags, int mode);
db2h は db2 以外のすべての組み合わせで失敗する (db2 以外は __db_ndbm_open を提供していないから)
また、gdbm1[89] は libgdbm だけで、そこには dbm_open はないので、glibc の場合は失敗する
もちろん、dbm_open の実体が存在しない libc+glibc の場合も失敗する
db2+glibc も、dbm_open の実体が存在しないので、db2h 以外は失敗する
B. dbm_clearerr がリンクできる。
4.3BSD ndbm: #define dbm_clearerr(db) ((db)->dbm_flags &= ~_DBM_IOERR)
Berkeley DB 1.85: 宣言なし。ライブラリ内に int dbm_clearerr(DBM *db) が存在。
FreeBSD 8.2: int dbm_clearerr(DBM *);
Berkeley DB 2.7.7: #define dbm_clearerr(a) __db_ndbm_clearerr(a)
int __db_ndbm_clearerr(DBM *);
GDBM 1.7: #define dbm_clearerr(dbf)
GDBM 1.8.3: #define dbm_clearerr(dbf)
GDBM 1.9: extern void dbm_clearerr (DBM *dbf); 実体は libndbm_compat に入っている。
ndbm, db2, gdbm1[789], gdbm18c はライブラリ内に dbm_clearerr がないので、
関数として宣言するヘッダとの組み合わせで失敗する。
C. _GDBM_H_ が定義されているなら、gdbm_compat なので、gdbm は禁止
GDBM 1.8.0 までは libgdbm に ndbm 関数が同梱されている
GDBM 1.8.1 以降は libgdbm_compat に分かれている
GDBM 1.9 以降は ndbm.h に #include <gdbm.h> とされていて、_GDBM_H_ が定義される
D. GDBM のヘッダなら、gdbm_version があるはず
gdbm_version は少なくとも GDBM 1.5 からあるので、GDBM のヘッダを使うときはかならずある。
ただし、libgdbm_compat でなく、libgdbm に入っている点は注意。
E. ヘッダの種類とリンクするライブラリがマッチしない
ndbmh * {db[12], gdbm1[789], gdbm[89]c}
db[12]h * {gdbm1[789], gdbm[89]c}
gdbm1[89]h * db[12]
うぅむ。まだ表に穴があるな。埋められるのかどうか良く分からないが。
まぁ、最終的に動かしてしまえば、生成したデータベースの形式を調べて確認できるので、間違いを見逃すことはない、と思われるけれど。
「無限なめこ」なるものを知って、ふと
#!/usr/bin/ruby
xmin = 610
ymin = 140
xmax = 760
ymax = 300
10.times {
ymin.step(ymax, (ymax-ymin)/5.0) {|y|
xmin.step(xmax, (xmax-xmin)/5.0) {|x|
system("xwit -warp #{x} #{y}")
sleep 0.1
}
}
}
というものを書いてみた。
[latest]