2009年3月31日火曜日

ハード

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
hpc.co.jpは計算が重いアプリに対応したハードを準備したいときに参考になる。やはり法人と個人の資金力・工数の差を感じる。CentOS 4なのは微笑んじゃいますが。

Core i7-920のオーバークロック性能を試す ~ 動画エンコードでチェック ~ 、Q6600とi7の比較記事。メモリの転送性能がかなり違う(3チャンネルDDR3は大きいようだ)。ワーキングセットがでかいプログラムではかなり有利だろう。エンコードだと律速が転送能力か演算能力かかはわからないが。

で、最近気になるshuttle(この会社は、コンパクトという価値を、ヒートパイプによる冷却という技術的強みで提供していますね。)ですが、「i7のshuttleの箱」が出ています。

SX58H7のスペック

ETHERNET (2)Realtek RTL8111C
IEEE 802.3u 100Base-T specifications compliant
10Mb/s,100Mb/s,1Gb/s operation
Support Wake-ON-LAN function


Realtek 8111Cのページ
wake on LAN

CentOSでwake on LANする方法。

PXEBoot+Wake on Lanは可能なのだろうか?PXEはすでに試したし、やっている人もたくさんいる。(PXEを使ったネットワークブート予想としては初回ブートした後になんか書き換えてあげるとBIOSレベルの何かが書き換わって次回は大丈夫になる、かな。

あったあった。http://homepage.mac.com/nand/netbsd/wakeonlan.html。gnubgを走らせるためのcluster slaveはこれで最小限の構成のマシンにすればよい。

kakaku.comの口コミ

munin

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
192.168.2.65(eth1)を追加。

[nori@housyou]/etc/munin/plugins% ls -ltra if_*
lrwxrwxrwx 1 root root 28 Aug 29 2007 if_eth0 -> /usr/share/munin/plugins/if_
lrwxrwxrwx 1 root root 32 Aug 29 2007 if_err_eth0 -> /usr/share/munin/plugins/if_err_
lrwxrwxrwx 1 root root 28 Mar 31 10:29 if_eth1 -> /usr/share/munin/plugins/if_
lrwxrwxrwx 1 root root 32 Mar 31 10:30 if_err_eth1 -> /usr/share/munin/plugins/if_err_

構成変更DNS編

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
しくじった。やっぱり1日以上blankができてしまった。おかげで、blog.tonic-water.comに書き込めてない。その後修正したけど、blog.tonic-water.comだけ挙動が変だ。

192.168.2.64と192.168.2.65が同じマシン(housyou)に刺さっている。
192.168.2.64上では124.155.113.117で公開するサービスを走らせて、192.168.2.65上ではLAN上に公開したいものを走らせる。

というのも、LAN上で124.155.113.117を返されてもrouterがNATできないらしく、つながらないためだ。したがって、tonic-water.comを192.168.2.65のDNSと192.168.2.64のDNSに問い合わせると結果が異なる。それらを決めているfileも/etc/maradns/{local|pub}とdiffを使って検証しやすい範囲にあり、ありがたい。


[nori@umikaze]~% dig @192.168.2.64 tonic-water.com

; <<>> DiG 9.3.4-P1 <<>> @192.168.2.64 tonic-water.com
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57135
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; QUESTION SECTION:
;tonic-water.com. IN A

;; ANSWER SECTION:
tonic-water.com. 86400 IN A 124.155.113.117

;; AUTHORITY SECTION:
tonic-water.com. 86400 IN NS ns.tonic-water.com.

;; ADDITIONAL SECTION:
ns.tonic-water.com. 86400 IN A 124.155.113.117

;; Query time: 1 msec
;; SERVER: 192.168.2.64#53(192.168.2.64)
;; WHEN: Tue Mar 31 09:39:28 2009
;; MSG SIZE rcvd: 82

[nori@umikaze]~% dig @192.168.2.65 tonic-water.com

; <<>> DiG 9.3.4-P1 <<>> @192.168.2.65 tonic-water.com
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51269
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; QUESTION SECTION:
;tonic-water.com. IN A

;; ANSWER SECTION:
tonic-water.com. 86400 IN A 192.168.2.64

;; AUTHORITY SECTION:
tonic-water.com. 86400 IN NS ns.tonic-water.com.

;; ADDITIONAL SECTION:
ns.tonic-water.com. 86400 IN A 192.168.2.64

;; Query time: 1 msec
;; SERVER: 192.168.2.65#53(192.168.2.65)
;; WHEN: Tue Mar 31 09:39:32 2009
;; MSG SIZE rcvd: 82

[nori@umikaze]~% dig @192.168.2.65 google.com

; <<>> DiG 9.3.4-P1 <<>> @192.168.2.65 google.com
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37585
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;google.com. IN A

;; ANSWER SECTION:
google.com. 300 IN A 74.125.45.100
google.com. 300 IN A 209.85.171.100
google.com. 300 IN A 74.125.67.100

;; Query time: 411 msec
;; SERVER: 192.168.2.65#53(192.168.2.65)
;; WHEN: Tue Mar 31 09:39:51 2009
;; MSG SIZE rcvd: 76


当たり前だが、192.168.2.64はcontent serverなのでrecursiveなresolveを許していない。

[nori@housyou]~% dig @192.168.2.64 google.com

; <<>> DiG 9.3.4-P1 <<>> @192.168.2.64 google.com
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 16782
;; flags: qr rd; QUERY: 0, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; Query time: 0 msec
;; SERVER: 192.168.2.64#53(192.168.2.64)
;; WHEN: Tue Mar 31 10:06:49 2009
;; MSG SIZE rcvd: 12

次はhttpです。

2009年3月30日月曜日

サービス停止

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
しばらくとまります。

2009年3月28日土曜日

JoelもSSDしたらしい

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Solid State Disks 27 Marというエントリが出ていた。


The first experiment was trying to rejuvenate an 18 month old IBM Thinkpad X61s notebook, which I originally got for the FogBugz World Tour. I got the new, 160GB Intel X25-M drives, which are about $760 on NewEgg.com.

NotePCを再生しようとは考えることが同じだ。ブートできるようになるまでになんか変な苦労してますが。ところでHDDのまるまるコピーってサイズが違うとブートしないほうが普通な気がしているのですが、私の勘違い?


But... compile time. Hmm. That wasn’t much better. I got it down from 30 seconds to ... 30 seconds.

Our compiler is single threaded, and, I guess, a lot more CPU-bound than IO bound. Oh well. We’ll still probably upgrade all the developer’s desktops with SSD drives, because making everything else snappy will make their lives better, but we may still be forced to spend some time making the compiler do its work in parallel.

distccがないらしい。かくして廊下でチャンバラの時間はのこったようだ。

2009年3月26日木曜日

gnubg 1.0に向かって

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
しばらく新規機能は追加されない。安定化フェーズにむかっているようだ。

Hi all,

I believe that the current version is what I would like to call 1.0.
Probably the cmark and hint features still need a bit of polishing,
but besides that I'm committed to not adding more features and making
adjustments that aren't totally necessary. That is, unless something
comes up in reply to this mail and I guess that Jon will have a few
things that he would like to do. Otherwise, it is bug fixing,
documentation ?!, and translations until we hit 1.0.

Christian.

CentOS 5.3

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
もうすぐですね。何も考えずにネットワーク構成の変更を4/1に考えていた。まあ、前倒しして、変更してから5.3にupgradeだな。

vncのほうがはやい!??

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
shig wrote:

うん。X over sshはかなりストレスたまる。
vnc over sshの方がストレス少ないかも。いやまじで。試してみた?

nori wrote:

それは主観の問題では?
vncは遅いに決まってるってわかってるからとか。

実際に使ってみたが、主観じゃないかも?!
駒が動くアニメーション(アニメーション中は操作できない)があったんだけど、 見た目で

  1. 何かをdrawするコマンドをremoteが発行する

  2. localがコマンドを受信

  3. localのdrawの完了

  4. drawの完了がremoteに通知される

  5. remote次のdrawをするための計算をする。


が起こっているようにみえる。もし真実ならばVNCより帰りの遅延が乗る分、かならず遅い。vncは差分の画像をサーバからクライアントに送るだけなので帰りの遅延は無い。
帯域が太いが、遅延が大きいときはX over sshよりVNC over sshのほうがよいかもしれない。
owner drawでinteractionするX applicationはX over ssh(WAN)はしないほうがいいかもしれない。

どーやって検証しようかねぇ。

普段LANでVNCつかってるけど、remote loginであることをまったく感じないしねぇ。

おうぷんそうすの経済学?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
無用の恐れを与える害悪のほうが大きい
「GPLはもう要らない」、OSSの伝道師が異説

Open Sourceにするメリットは、企業から見た場合、

  • 開発リソースのシェア

  • エンジニアのコモディテイ化、モジュール化(市場で買える、買いやすい規格化されたパーツ)


だろう。オープンソースにするとフレームワークみたいなものなら、エンジニアの調達コストが下がるのだ。企業にとってクリティカルな部分だけをproprietaryにすればいい。OSまで自前する必要が無いのと同じで、closedにして自分だけでコストを背負い込む部分は本当にコアの価値に結びついている部分だけでいい。

ソフトウェアのどこから価値が生じているかわかっていない会社や、ソフトウェアではなく顧客のlock inによる独占から利益を得ている会社は縁が無いロジックだが。(悲しいことにおそらく日本の99%の会社はこれに該当するだろう)

スキルが明確でポータブルならば、労働市場に参加しているすべての人がハッピーになるはずだ。何もかもproprietaryだったら、「バベルの塔」の伝説のように市場にいる人々は意思疎通できないだろうし、不良品の中古車をつかまされる話や、ほしいものと買ったものがマッチしない(そして解雇できない・・・)といった情報の非対称性が問題になるだろう。

2009年3月25日水曜日

emobile on CentOS

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
CentOSでD02HWを使ってみる【改訂版でほぼ仕上げだ。あとはsshを使って自宅サーバに入ったときにXをforwardできれば終わり。dialupしてpppdが立ち上がった。FireFoxがまだ機能していないが。

軟弱なので、GUIからすべくを試す。emobileを起動中です・・・。ではじまらない。番号を変えるか。

Xで体感速度が出るといいなぁ。

memory

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
1GByte 2000円くらいだったので思わず買ってしまった。512かなんか搭載していたが、VRAMでとられるので実際にはもっと使える量は少ない。いまはとられる前で1.5GByteなのでよゆーである。もっともSSDなのでswapなしですが。swapなしだから追加したかったともいう。パーツ買うところがT-Zoneばっかだなぁ。。。

買ってきてから増設用のスロットが開いてから、スロットが空いていたことに気づいた点は突っ込まないように。NotePC用のメモリ1GByte2000円とはよい世の中になったものだ。産業として熟成して大事なことはハードからソフトやサービスに移ったといっていいだろう。

息抜き

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
「1からスタートして与えられた整数nまで何回の操作でたどり着けるかこたえなさいに手をつけてみた。

16の扱いに問題がある。(1, 4)になったほしいのだが、(1, 2, 2)にしてしまう。まあ、opに4をいれればいいのだが、4乗は2乗の2乗だし・・・。opsからopを選んで作って試すというやり方なのだが、opの選び方が効率よく計算するときの鍵だろうなぁ、ということだけは見当がついた。それから単に目標値と現在の値の差で評価関数を組んでしまうと、243(3の5乗)みたいな数で256から減らしていこうとしてしまうので厄介。

おそらくはステップ数が進んでから調整しようとするほどペナルティがかかる評価関数を組む必要がありそうだ。
ひょっとしてこれは最寄のn乗数を発見する問題かなぁ?

123を計算させると、(1, 2, 1, 3, -1, -1)
121を計算させると、(1, 1, 2, 1, 1, 2)



'''
find count of step to get N from 1 using
a) add 1
b) sub 1
c) i th pow of N

'''
def decode(i):
if i == -1:
def op_dec(x):
return x-1
return op_dec
elif i == 1:
def op_inc(x):
return x+1
return op_inc
elif i > 1:
def op_pow(x):
return pow(x, i)
return op_pow
else:
assert False

def calc(xs, n):
for op in xs:
f = decode(op)
print n
n = f(n)
return n


def gen_ix(n):
'''\
>>> gen_ix(1)
()
>>> gen_ix(2)
(1,)
>>> gen_ix(3)
(1, 1)
>>> gen_ix(4)
(1, 2)
>>> gen_ix(5)
(1, 2, 1)
>>> gen_ix(10)
(1, 1, 2, 1)

'''
ixs = {1:(True, ())}
ops = (-1, 1, 2, 3, 5, 7, 11)
while n not in ixs:# or not ixs[n][0]:
xs = [(key, item) for key, item in ixs.items()]
for i, (done, ix) in xs:
for op in ops:
f = decode(op)
j = f(i)
if j > 0 and j not in ixs:
ixs.update({j: (False, ix + (op,))})

return ixs[n][1]


#print gen_ix(10)
#print calc(gen_ix(10), 1)
#print gen_ix(16)
if __name__ == '__main__':
import doctest
doctest.testmod()

2009年3月24日火曜日

仕方ないのでmod probeを読むことにした

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
kernel/kmod.c



extern int max_threads;

static struct workqueue_struct *khelper_wq;

#ifdef CONFIG_MODULES

/*
modprobe_path is set via /proc/sys.
*/
char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";

pathがhard codeされている。


/**
* request_module - try to load a kernel module
* @fmt: printf style format string for the name of the module
* @...: arguments as specified in the format string
*
* Load a module using the user mode module loader. The function returns
* zero on success or a negative errno code on failure. Note that a
* successful module load does not mean the module did not then unload
* and exit on an error of its own. Callers must check that the service
* they requested is now available not blindly invoke it.
*
* If module auto-loading support is disabled then this function
* becomes a no-operation.
*/

成功時0、失敗時負数。


int request_module(const char *fmt, ...)
{
va_list args;
char module_name[MODULE_NAME_LEN];
unsigned int max_modprobes;
int ret;
char *argv[] = { modprobe_path, "-q", "--", module_name, NULL };
static char *envp[] = { "HOME=/",
"TERM=linux",
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
static atomic_t kmod_concurrent = ATOMIC_INIT(0);
#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg;

va_start(args, fmt);
ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
va_end(args);
if (ret >= MODULE_NAME_LEN)
return -ENAMETOOLONG;
引数のパース


/* If modprobe needs a service that is in a module, we get a recursive
* loop. Limit the number of running kmod threads to max_threads/2 or
* MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method
* would be to run the parents of this process, counting how many times
* kmod was invoked. That would mean accessing the internals of the
* process tables to get the command line, proc_pid_cmdline is static
* and it is not worth changing the proc code just to handle this case.
* KAO.
*
* "trace the ppid" is simple, but will fail if someone's
* parent exits. I think this is as good as it gets. --RR
*/

ここからが肝、というか、call_usermodehelperだけやんけ・・・

max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
atomic_inc(&kmod_concurrent);
if (atomic_read(&kmod_concurrent) > max_modprobes) {
/* We may be blaming an innocent here, but unlikely */
if (kmod_loop_msg++ < 5)
printk(KERN_ERR
"request_module: runaway loop modprobe %s\n",
module_name);
atomic_dec(&kmod_concurrent);
return -ENOMEM;
}

ret = call_usermodehelper(modprobe_path, argv, envp, 1);
atomic_dec(&kmod_concurrent);
return ret;
}
EXPORT_SYMBOL(request_module);
#endif /* CONFIG_MODULES */

man modprobeによると、

modprobe intelligently adds or removes a module from the Linux kernel: note that
for convenience, there is no difference between _ and - in module names. modprobe
looks in the module directory /lib/modules/‘uname -r‘ for all the modules and other
files, except for the optional /etc/modprobe.conf configuration file and /etc/mod-
probe.d directory (see modprobe.conf(5)).

Note that this version of modprobe does not do anything to the module itself: the
work of resolving symbols and understanding parameters is done inside the kernel.
So module failure is sometimes accompanied by a kernel message: see dmesg(8).

modprobe expects an up-to-date modules.dep file, as generated by depmod (see dep-
mod(8)). This file lists what other modules each module needs (if any), and mod-
probe uses this to add or remove these dependencies automatically. See mod-
ules.dep(5)).

だそうな。全然ほしい情報が無い。

request_moduleの引数に渡しているものがわかっているので、それでgrep。

[nori@asama]~/Desktop/work/kernel/linux-2.6-allstable% grep -R 'request_module("binfmt' .
./fs/exec.c: request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));


呼んでいる関数はこいつ。

/*
* cycle the list of binary formats handler, until one recognizes the image
*/
int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
{
unsigned int depth = bprm->recursion_depth;
int try,retval;
struct linux_binfmt *fmt;

retval = security_bprm_check(bprm);

この関数の終わりのほうで、

if (retval != -ENOEXEC || bprm->mm == NULL) {
break;
#ifdef CONFIG_MODULES
} else {
#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
if (printable(bprm->buf[0]) &&
printable(bprm->buf[1]) &&
printable(bprm->buf[2]) &&
printable(bprm->buf[3]))
break; /* -ENOEXEC */
request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
#endif
}
}
return retval;
}

んで、bprmとはなにかというと、これ。

/*
* This structure is used to hold the arguments that are used when loading binaries.
*/
struct linux_binprm{
char buf[BINPRM_BUF_SIZE];
#ifdef CONFIG_MMU
struct vm_area_struct *vma;
#else
# define MAX_ARG_PAGES 32
struct page *page[MAX_ARG_PAGES];
#endif
struct mm_struct *mm;
unsigned long p; /* current top of mem */
unsigned int sh_bang:1,
misc_bang:1,
cred_prepared:1,/* true if creds already prepared (multiple
* preps happen for interpreters) */
cap_effective:1;/* true if has elevated effective capabilities,
* false if not; except for init which inherits
* its parent's caps anyway */
#ifdef __alpha__
unsigned int taso:1;
#endif
unsigned int recursion_depth;
struct file * file;
struct cred *cred; /* new credentials */
int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
unsigned int per_clear; /* bits to clear in current->personality */
int argc, envc;
char * filename; /* Name of binary as seen by procps */
char * interp; /* Name of the binary really executed. Most
of the time same as filename, but could be
different for binfmt_{misc,script} */
unsigned interp_flags;
unsigned interp_data;
unsigned long loader, exec;
};

一方で、binfmt_なファイル名を検索するとこうなる。

[nori@asama]~/Desktop/work/kernel/linux-2.6-allstable% find . | grep -e "binfmt_.*\.c$"
./arch/alpha/kernel/binfmt_loader.c
./arch/parisc/kernel/binfmt_elf32.c
./arch/mips/kernel/binfmt_elfn32.c
./arch/mips/kernel/binfmt_elfo32.c
./arch/ia64/ia32/binfmt_elf32.c
./fs/binfmt_som.c
./fs/binfmt_elf_fdpic.c
./fs/binfmt_elf.c
./fs/binfmt_misc.c
./fs/binfmt_em86.c
./fs/compat_binfmt_elf.c
./fs/binfmt_script.c
./fs/binfmt_flat.c
./fs/binfmt_aout.c

とりあえず、fs/binfmt_aout.cを見ることに。ここでbufが初期化される。

static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct exec ex;
unsigned long error;
unsigned long fd_offset;
unsigned long rlim;
int retval;

ex = *((struct exec *) bprm->buf); /* exec-header */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
i_size_read(bprm->file->f_path.dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}

struc execはこんな感じ。(x86の場合)

struct exec
{
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
unsigned a_text; /* length of text, in bytes */
unsigned a_data; /* length of data, in bytes */
unsigned a_bss; /* length of uninitialized data area for file, in bytes */
unsigned a_syms; /* length of symbol table data in file, in bytes */
unsigned a_entry; /* start address */
unsigned a_trsize; /* length of relocation info for text, in bytes */
unsigned a_drsize; /* length of relocation info for data, in bytes */
};

XXMAGICを解読して、464が何であるかを知る必要がありそうだ。
あー、だめだ。aoutじゃないし。そもそもになんだかわかってない。validじゃないtypeが来ているので、その起源が知りたい可能性大。

で、マクロはinclude/Linux/a.out.hで定義されている。

/* Code indicating object file or impure executable. */
#define OMAGIC 0407
/* Code indicating pure executable. */
#define NMAGIC 0410
/* Code indicating demand-paged executable. */
#define ZMAGIC 0413
/* This indicates a demand-paged executable with the header in the text.
The first page is unmapped to help trap NULL pointer references */
#define QMAGIC 0314

/* Code indicating core file. */
#define CMAGIC 0421

kernel build for nc4200

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
やってしまったことその1。
ARCH=i386を付け忘れた。 x86_64上でbuildするならmake のすべてのステップで必須。

その2request_module: runaway loop modprobe binfmt-464c

oss message pediaによれば

modprobeコマンドなどカーネルモジュール作成処理が、同時実行の最大数を超えて要求された。この要求はエラーとなる。

らしい。

request_module: runaway loop modprobe binfmt-464cとかを見てみる。volumeの名前の問題じゃなさそうだから、ドライバということになる。

2009年3月23日月曜日

end = 1 をするべきでない理由(そうまでしてpythonを使うのか?)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
RubyからPythonに移ってきた人にendをつけたらとか言うエントリがあったが・・・(わかって書いているネタor釣り記事だけど)。

いにしえにPascalからCに移るときの話で、

#define BEGIN {
#define END ;}

をやるなって話。第8章 Pascalが好き Pascal?とか。読み手がこれを知っている人じゃないと笑いはあまり取れないかもしれない。
Pythonはstatement(文)であって、式じゃないからなぁ。起源がmatzが俺lispしたくて作った言語だし。Emacsがendをうまくindentできなかったならばendは無かったかもしれない。
制御構造@オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル

Rubyでは(Cなどとは異なり)制御構造は式であって、何らかの値を返すものが あります(返さないものもあります。値を返さない式を代入式の右辺に置くと parse error になります)。

YARVではこうらしい(このエントリを書いたきっかけ。ああ、そうだったねって思い出した)
YARV Maniacs 【第 5 回】 命令セット (2) リテラル・変数・定数

end は前号でも紹介したとおり、そのスコープの終わり(そして呼び出し元、例えばメソッドコールの返り値としてスタックトップの値を返す)、という意味ですが、これもあわせて次回に。

matzの日記では

なんとなく分かるような気がする。なんでだかPythonって私のあってほしいような言語じゃないんだよな。逆にPythonファンにとってはRubyが「なんか違う」言語なんだろうか。

らしいので。それが式であるか文であるかの差であるかはわからない。LLと分類されるpythonとrubyだが、使い手の脳みそのつくり、癖という観点から見ると、C/Pascalに見られる違いとは比べ物にならないくらい大きいのかもしれない。

2009年3月22日日曜日

毎回再現しないバグ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク



def codeblock(self):
self.write('<pre class="codeblock">')
for line in self.instream: #may be...
if not self.parse(line):
self.write('<code>' + escape(line.strip('\n')) + '</code>\n')
self.write('</pre>')

の結果、出てくるぶっ壊れたhtmlの一部。

<pre class="codeblock"><code>m&ograve;^M</code>

for line in self.instreamが行単位の処理になら無いらしい。原因は何だろう?


原因判明。__file__を使っていたのだが、pycが取れていた。だめじゃん。

2009年3月21日土曜日

windows xpのconnection制限

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
sshで複数マシンに入りながらFireFoxで情報を集め、休憩でIEでgyaoを見ようとするとつながらない。かなり昔から?でしたが、唐突に思いあったって調べたら思ったとおりで、納得いきました。

TCPコネクション最大値

Windows XP/2003のTCP同時接続数制限とその回避


Windows XP SP2とWindows Server 2003 SP1のTCP/IPスタックでは、不完全な外向きのTCP同時接続数を10接続に制限しています。接続数が10に達した場合、接続要求はキューイングされ、ある一定間隔で処理されるようになります。

 この制限は、ホストがワームに感染した際、他のホストへの影響を最小限にするため、Windows XP SP2とServer 2003 SP1で新たに実装されました。しかしこの制限は、不完全な外向きのTCP接続を大量かつ同時に張るアプリケーションにおいては、大きなパフォーマンス低下を招く可能性があります。例えば、P2Pシステムや脆弱性スキャナなどが挙げられます。特に脆弱性スキャナは業務で利用するケースが多いと思いますので、パフォーマンス低下は非常に致命的です。


えーなんで20とかじゃないくて10なのさ。普段使っていて到達してしまう私って変??

distcc

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
distccでpythonでできてるんですね。buildbotとのつくりの差が気になります。
distccのほうがはるかにデザインがよい気がするが・・・。

my環境でのtimeを使った計測結果

@asama, Core2Duo

make -j10 650.69s user 84.98s system 197% cpu 6:12.33 total
make -j10 CC=distcc 351.40s user 76.40s system 192% cpu 3:42.76 total


@umikaze, macmini(Core2Duo)のVMWare上。

make -j10 2079.76s user 802.05s system 60% cpu 1:19:06.52 total
make -j10 CC=distcc 507.79s user 638.87s system 60% cpu 31:25.57 total

VMWare上ではIOも遅い。当然か。

Facebookへのbug reportしたら・・・

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
たわいも無いbugなのだが、Facebookほどの規模でこんなbugがあったのは意外。
どーしょもないreportが山盛りきていて、それを捌く作業を延々やっている人がいるのだろうなぁ。

で、さっき試したら、やっぱり駄目みたいなんですけど・・・。

Hi Noriyuki,

This problem should now be resolved. Sorry for any inconvenience, and enjoy the site! Let me know if you have any further questions.

Thanks for contacting Facebook,

Roy
User Operations
Facebook



-----Original Message to Facebook-----
From: Noriyuki Hosaka (bgnori@gmail.com)
To: info@facebook.com (info@facebook.com)
Subject: POSTED: Links with url encoded

User id: 1154827662
Description of problem: When pasted the url following:

http://image.backgammonbase.com/image?width=400&format=png&height=300&css=kotobuki&gnubgid=4PPgAyDgc%2BQBIg%3AcInqAEAAAAAA

it gets decoded as:

http://image.backgammonbase.com/image?gnubgid=4HPwATDgc/ABMA%3AMAAAAAAAAAAA&height=300&width=400&css=minimal&format=png


Browser: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7 (.NET CLR 3.5.30729)

-----End Original Message to Facebook-----

2009年3月20日金曜日

サーバ再編計画(DNS)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
再編といっても90%がDNSの問題なのです。もっている固定IPにresolveされるようなドメイン名をいくつか持っていて、それらのcontent server(maradns)が自前server上で稼動しているわけです。

Router Ralph 192.168.2.254
Machine Alpha 192.168.2.1
Machine Bravo 192.168.2.2
Machine Charlie 192.168.2.3

現状のmy dmzは上のようなマシンからなるネットワークで、Ralphを通じて外部とやり取りします。固定IPを持っているRalphが外部からくるpacketをあて先portを見て各machineに転送しています。具体的には、TCP80やUDP53はAlphaに、sshdは各machineごとに稼動portが異なり、それによってgate way要らずのssh loginを実現しています。

問題なのは、Alphaの上で外向けのContent ServerとHTTPが動いており、それらの内容を、BravoやCharlieから参照しようとすると、うまくいかないのです。現状はHostsを書き直して対応していますが、さすがにそろそろげんなりです。Bravoの上でdns serverを動かしてもみたのですが、いかんせん開発機なのでこまります(現状は無理やり)。CharlieはAlphaのメンテ時に代替サーバとして転送を処理するサーバでもあるので、内向きのものを置いておくわけには行きません。DNSだけならrequest元のIP見て返す値を変えるとかも可能でしょう。でもあまり複雑な設定も困り者ですし。(動作チェックするのが大変)

また、HTTPに関しても/etc/httpd/conf.d/*.confを好き勝手したがるやつが多くて、困ります。とくに管理系のソフトはvirtual hostで使われる可能性をあまり考えてなくて、/var/wwwのしたとかでやらかしてくれます。

2つIPを持っていれば1つを内向き、もうひとつを外から転送されてきたpacketを処理するために使えるでしょう。同じリソースに結びつくかどうかは設定しだいです。


代替機のCharlieも2つNICがあることが望ましいのですが、とりあえずは外向きだけでいいでしょう。まあ、VMWareがvirtualにNICを二つ作らせてくれれば一番よいですが。

2009年3月19日木曜日

?!!異常

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
プチフリならぬスーパーフリーズ状態。アクセスランプがぜんぜん消えない。大規模なレベリングがおきているのかもしれない。知る術は無いが。リアルタイム性が要求されるジャンルでは使い物にならないね。

でもその間も完全に無音。アクセスランプが壊れているんじゃないかと思えるくらい。ディスクなら猛烈にがりがりかっこんかっこんの世界だ。

yum updateが必ずdisk accessする、そしてlock fileを生成するのでそれでどんどんフラグっていくのだろう。

SSDへの換装、インスト最終局面

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
yum update yumを実行し、yum updateで根こそぎupdate。
ここからはほかのマシンで使っているpackageを使えるようにするとか、suspendとかresumeがちゃんとできるかとか、emobileを使えるようにするとかといった作業になる。

あと日本語入力か。

pxe boot(2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
なんとかたどり着いた。localのdhcp設定に渡すdnsではまったのと、Virtual Hostしているせいか、local networkのrepositoryを見てくれない。せっかくミラーしたというのに。

File Systemのformatが始まった。

2009年3月17日火曜日

pxe boot

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
diskを換装したので、NIC以外にデータを入れる手段が無い状態です。dhcp, tftpの設定がすんで次のdefaultのメニューを表示しているらしいところまではたどり着いた。インストールに使うファイルがtftpにあがってないようでそこから先が進まない。なので5.2を全部syncしてその間休憩。

DEFAULT menu
PROMPT 0
MENU TITLE Cobbler | http://cobbler.et.redhat.com
TIMEOUT 200
TOTALTIMEOUT 6000
ONTIMEOUT local

LABEL local
MENU LABEL (local)
MENU DEFAULT
LOCALBOOT 0



MENU end

このへんとかを参考にがんばるですよ。

SSDへの換装

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
元がぼろっちい中古価格1万円のNotePCだからなぁ~。新品だったけど展示処分品を100Kくらいでかったはずだし。HP Compaq nc4200
enterprise watch @ impress

nc4200は、12.1インチXGA液晶を搭載するB5サイズの1スピンドルノートPC。基本スペックは、インテル915PM Expressチップセット、CPUがPentium M 740(1.73GHz)、メモリが256MB(最大2GB)、HDDが60GB、Gigabit Ethernet、IEEE 802.11a/b/g、Bluetooth(Ver 1.2準拠)を搭載する。グラフィックチップはチップセット内蔵。サイズは285×235×30.2mm(W×D×H)、重量は約1.8kg。標準バッテリー駆動時間は5.4時間。


普通にHDDかってもいい値段するだろうし。ざっくりSSDはHDDにくらべ単位容量あたりの値段が10倍だ。200GB以上あっても使うかどうか不明だ。持ち歩く開発環境としてLinux/BSD系を入れて使うことを考えているのですが、60GBだと現状のdesktop環境がそのくらいだから若干不安が残る。128GBだとまあまず問題ない。

[nori@asama]~% df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol04
145G 27G 111G 20% /
/dev/sda1 965M 192M 724M 21% /boot
tmpfs 942M 0 942M 0% /dev/shm
/dev/mapper/VolGroup00-LogVol01
9.5G 152M 8.9G 2% /tmp
/dev/mapper/VolGroup00-LogVol03
37G 1.1G 34G 3% /var
/dev/mapper/VolGroup00-CentOS5InstallDisk
13G 161M 13G 2% /usr/local/centos
/dev/mapper/VolGroup00-usr--local--repos
2.1G 68M 1.9G 4% /usr/local/repos
/dev/mapper/VolGroup00-LogVol00
60G 35G 23G 61% /home



IFがIDA Ultra-ATA/100なのが残念だね。規格として速度無いだろうからMLCだな。
transcendのページでは

OSのインストールにはSLC搭載製品を推奨しています。

とのこと。どういうことだろう?信頼性?

この辺とかをみるとやる気が出てくる。デフラグは、原理的にまずいだろ。フラッシュは書き込みすると壊れていく、かつランダムアクセスが早く連続にブロックを配置することに意味が無い。

パラレルIDE-SSDで旧式ノートPCはどれだけアップグレードできるか?

 この原因はおそらく、HDD搭載時では必要だったHDDからのコマンドの応答などが不要となり、その分の時間が短縮されたものと思われる。結果として、 5秒でスタンバイに入り、4秒で復帰。さらに復帰直後から操作が可能という、かなり気持ちのよいシステムが実現できている。

 また、意外と馬鹿にできないのが静音性。当然ながらHDDの動作音が一切しないので、非常に静かである。T40に標準搭載されていたHDDは 4,200rpmの製品だったため、あまりうるさくはないと思っていたのだが、SSDと聞き比べるとまるで違うことがわかった。現在はこれにより目立ってしまったCPUクーラーの音が気になってきたところである(笑)。


ssdの寿命テスト

SanDisk、SSD向けファイルシステム「ExtremeFFS」を解説 ~“プチフリ”と無縁な、高速化技術

これにより3つの問題が生じるとBarnetson氏は指摘する。1つは、待ち時間が生じる点。前述の通り、NANDでは1ページのサイズの書き換えであっても、丸々1ブロックを消去し、別ブロックにほとんど同じデータを書き込む手順が必要となる。Barnetson氏によると、この作業には概ね 200ms程度かかるといい、ランダムライトが多発する状況では、SSD/OSのレスポンスが体感できるほど悪くなることがある。これが一部のユーザーの間で話題になっている「プチフリーズ」の正体だ。

vRPMなるものが提案されている。

この式を2007年、2008年、2009年(予定)の世代のSSDに当てはめると、それらのvRPMは順におよそ1,000、10,000、40,000となる。

 vRPMを用いるメリットの1つは、HDDと同じ土台で性能を比較できる点。10,000なら7,200rpmのHDDより、40,000なら 15,000rpmのHDDよりも高速ということだ。もう1つのメリットは、この数値が実際に使っている時の実効性能を示しているという点だ。

あとはPXE bootか。これも課題だったなぁ。PXE bootとYum repositoryを組み合わせれば、組み立てた後はつなぎっぱでserver farmが作れるので、できるようになっておきたい。

2009年3月13日金曜日

weakrefの話

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Modules/weakref.txtを読んでいる。

一般にdeleteしたobjectが持っていた領域にあるpointer呼んではいけない。new/deleteって契約だから。newはこの部分のメモリをobjectとして振舞わせますという通告だし、deleteはobjectではなくなりましたっていう通告だ。問題としては、かなり古典だ。Destructors @ C++ FAQ Liteとか。

1度deleteしてしまったら、一般的には復活させることはできないだろう。該当object持っているメンバを再帰的に復活させる必要があり、それは自明で無い。memoryは運が悪いとsystemのmalloc/freeのfreeが呼ばれてしまい、OSが回収してしまうかもしれない。memory以外のresource(たとえばnetworkとかlockとか)をもっていればなおさらで、同じ質で再獲得できる保障はどこにもない。

これはgcの問題(いつdestructorを呼ぶか?)というよりdestructorへのhookをdestructorを実行した後に呼んではイケマセンという話だと思うのだが。

一方でweakrefは指しているobjectがinvalidになったことを通知してもらわないと、困る。なぜかというとrefの仕様を読めばわかるが、wr = ref(referent)という形で作られ、
wr is not Noneで判定する。この辺。wrはproxyになっていて、

  • referentが存在するならreferent

  • referentが存在しないならNone


を返す。Noneを返すためには、refの実装が状態を持ってreferentが死んだことをgcから通知してもらい、死亡フラグを立てる必要がある。そうしないと死後長くたってから問い合わせがくると、応えることができない。weakrefを使う状況は、この辺とかがわかりやすい。使い手に通知するようなコードがかけない、書きにくいときに、通知をgc機構に代行してもらうといった感じだ。

ではその通知をgc機構がいつするかといことだ。

結論はこうなったらしい。

Jim Fulton gave the best nutshell summary of the new (in 2.4 and 2.3.5)
approach:

Clearing cyclic trash can call Python code. If there are weakrefs to
any of the cyclic trash, then those weakrefs can be used to resurrect
the objects. Therefore, *before* clearing cyclic trash, we need to
remove any weakrefs. If any of the weakrefs being removed have
callbacks, then we need to save the callbacks and call them *after* all
of the weakrefs have been cleared.


deleteしてしまったらobjectでありえないので、当然weakrefを先に解決しなければならない。なので、消そうと思っているobjectにくっついているweakrefに対して通知し、消そうと思っているobjectに対してのweakrefを解決してから、消すということになった。おのおのの__del__を呼ぶ直前ではなく、cyclicな「塊」に属するobjectすべてのweakrefを先に取り除いてからとなる。__del__が処理される瞬間に関して理解が怪しいのでアレだが、多分PyObjectのdestructor相当の関数の中でcallされるのだろう。__del__なしでcyclicなclassというくだりがあるところを見るとね。


An alternative would have been to treat objects with callbacks like objects
with __del__ methods, refusing to collect them, appending them to gc.garbage
instead. That would have been much easier. Jim Fulton gave a strong
argument against that (on Python-Dev):

There's a big difference between __del__ and weakref callbacks.
The __del__ method is "internal" to a design. When you design a
class with a del method, you know you have to avoid including the
class in cycles.

Now, suppose you have a design that makes has no __del__ methods but
that does use cyclic data structures. You reason about the design,
run tests, and convince yourself you don't have a leak.

Now, suppose some external code creates a weakref to one of your
objects. All of a sudden, you start leaking. You can look at your
code all you want and you won't find a reason for the leak.


メモ:

常にNoneを返すwrの実装は実用にはならないが、プログラムをクラッシュさせたりLeakしたりすることは無い。だからgcがまだ__del__を呼んだり、メモリ上からobjectを消す前にwrにNoneを返すことを要請することは間違ってはいない。一方で、その逆はreferentが死んでいると一番最初に書いた契約を破ることになり、プログラムがクラッシュする。

Heapyを試す

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
さきのエントリで名前が出てきたHeapyをへろっと試してみた。
dictを100回ネストと、インスタンスを1100回ネスト、listを1000回ネストしてみた。


In [14]: h.heap()
Out[14]:
Partition of a set of 60943 objects. Total size = 9562944 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 31276 51 2886304 30 2886304 30 str
1 541 1 1295696 14 4182000 44 dict (no owner)
2 13437 22 1254624 13 5436624 57 tuple
3 204 0 809728 8 6246352 65 guppy.sets.setsc.ImmNodeSet
4 186 0 603552 6 6849904 72 dict of module
5 3628 6 435360 5 7285264 76 function
6 3617 6 405104 4 7690368 80 types.CodeType
7 363 1 326168 3 8016536 84 list
8 342 1 284256 3 8300792 87 dict of class
9 196 0 246848 3 8547640 89 dict of type
In [16]: d = {}

In [17]: for i in range(100):
d = dict(hoge=d)
Out[19]:
Partition of a set of 61155 objects. Total size = 9609792 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 31284 51 2886704 30 2886704 30 str
1 645 1 1327824 14 4214528 44 dict (no owner)
2 13445 22 1255192 13 5469720 57 tuple
3 204 0 809728 8 6279448 65 guppy.sets.setsc.ImmNodeSet
4 186 0 603552 6 6883000 72 dict of module
5 3628 6 435360 5 7318360 76 function
6 3617 6 405104 4 7723464 80 types.CodeType
7 365 1 326440 3 8049904 84 list
8 342 1 284256 3 8334160 87 dict of class
9 196 0 246848 3 8581008 89 dict of type
In [20]: len(gc.get_objects())
Out[20]: 27920

In [21]: class Hoge:
....: def __init__(self, v):
....: self._v = v
....:
....:

In [22]: x = Hoge(None)

In [23]: for i in range(100):
....: x = Hoge(x)
....:
....:

In [24]: h.heap()
Out[24]:
Partition of a set of 61438 objects. Total size = 9656504 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 31295 51 2887240 30 2887240 30 str
1 647 1 1330672 14 4217912 44 dict (no owner)
2 13450 22 1255552 13 5473464 57 tuple
3 204 0 809728 8 6283192 65 guppy.sets.setsc.ImmNodeSet
4 186 0 603552 6 6886744 71 dict of module
5 3629 6 435480 5 7322224 76 function
6 3618 6 405216 4 7727440 80 types.CodeType
7 365 1 326440 3 8053880 83 list
8 343 1 284528 3 8338408 86 dict of class
9 196 0 246848 3 8585256 89 dict of type
In [25]: for i in range(1000):
x = Hoge(x)
....:
....:

In [27]: h.heap()
Out[27]:
Partition of a set of 63469 objects. Total size = 10005064 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 31299 49 2887432 29 2887432 29 str
1 648 1 1331712 13 4219144 42 dict (no owner)
2 13451 21 1255624 13 5474768 55 tuple
3 204 0 809728 8 6284496 63 guppy.sets.setsc.ImmNodeSet
4 186 0 603552 6 6888048 69 dict of module
5 3629 6 435480 4 7323528 73 function
6 3618 6 405216 4 7728744 77 types.CodeType
7 365 1 326440 3 8055184 81 list
8 1101 2 299472 3 8354656 84 dict of __main__.Hoge
9 343 1 284528 3 8639184 86 dict of class
n [32]: for i in range(1000):
....: L = [L]
....:
....:

In [33]: h.heap()
Out[33]:
Partition of a set of 64569 objects. Total size = 10159328 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 31306 48 2887792 28 2887792 28 str
1 651 1 1337136 13 4224928 42 dict (no owner)
2 13457 21 1256096 12 5481024 54 tuple
3 204 0 809728 8 6290752 62 guppy.sets.setsc.ImmNodeSet
4 186 0 603552 6 6894304 68 dict of module
5 1366 2 462512 5 7356816 72 list
6 3629 6 435480 4 7792296 77 function
7 3618 6 405216 4 8197512 81 types.CodeType
8 1101 2 299472 3 8496984 84 dict of __main__.Hoge
9 343 1 284528 3 8781512 86 dict of class

python scriptのmemory消費をどうへらすか?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Python Memory Usage: What values are taking up so much memory?なるページがあった。これとHeapyをあわせて使えばなんかできるはず。

pythonがleak freeかというとそうとも言い切れない。うまく寿命が管理できていなければ、参照がacyclicでもreference countは0にならず、リークしてしまう。item数が単調増加するlistやdictが現象として現れる。これを解決する手段のひとつ(設計変更もある)は、weakrefでweakrefの話でとりあげる。

python scriptのメモリ消費の内訳をしらべよう

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
先ほどのネタの続き。

そんなにがんばる必要は無かった。module gcを使えばよさそう。あとはおのおののobjectのサイズをとって集計してあげないとね。

get_objects( )
現在、追跡しているオブジェクトのリストを返します。このリストには、戻り値のリスト自身は含まれていません。 バージョン 2.2 で 新たに追加 された仕様です。


ただipythonを立ち上げてimport gcしただけでもこれだけobjectがある。もちろん環境による違いはあるだろうが。

In [3]: len(gc.get_objects())
Out[3]: 16033

ところで3.0ではget_objectはviewを返すのだろうか?iterateしてる間に変わりそうだからやはりlistだろう。

Heapyなるものがある。お時間の無い方はどうぞ。ものすごく時間の無い方はこちらにrpmがあります。

自力でやるならこの先はsourceを読むことになるのだが、obmalloc.cにはなかなか素敵なAscii Artがある。



#include "Python.h"

#ifdef WITH_PYMALLOC

/* An object allocator for Python.

Here is an introduction to the layers of the Python memory architecture,
showing where the object allocator is actually used (layer +2), It is
called for every object allocation and deallocation (PyObject_New/Del),
unless the object-specific allocators implement a proprietary allocation
scheme (ex.: ints use a simple free list). This is also the place where
the cyclic garbage collector operates selectively on container objects.


意訳:

これが、pythonのメモリアーキテクチャの階層図です。+2レイヤのallocatorがobjectをalloc/deallocするときに呼ばれます。intとかは「マイ」allocatorを持っていてそれでしょりします。(intの場合はlink list。[訳注:効率のためだと思われる。__slot__なやつらは別途読んでみるといいかもしれない。])cyclic garbage collectorが機能しているレイヤでもある。

+2レイヤでobjectのメモリ消費量を調べないといけない。仮にmemuseというmoduleを作って実現するなら、memuse.size(object)でメモリ消費を返す仕組みにする。


Object-specific allocators
_____ ______ ______ ________
[ int ] [ dict ] [ list ] ... [ string ] Python core |
+3 | <----- Object-specific memory -----> | <-- Non-object memory --> |
_______________________________ | |
[ Python's object allocator ] | |
+2 | ####### Object memory ####### | <------ Internal buffers ------> |
______________________________________________________________ |
[ Python's raw memory allocator (PyMem_ API) ] |
+1 | <----- Python memory (under PyMem manager's control) ------> | |
__________________________________________________________________
[ Underlying general-purpose allocator (ex: C library malloc) ]
0 | <------ Virtual memory allocated for the python process -------> |

=========================================================================
_______________________________________________________________________
[ OS-specific Virtual Memory Manager (VMM) ]
-1 | <--- Kernel dynamic storage allocation & management (page-based) ---> |
__________________________________ __________________________________
[ ] [ ]
-2 | <-- Physical memory: ROM/RAM --> | | <-- Secondary storage (swap) --> |

*/

参考文献。見習いたいものです。

/*==========================================================================*/

/* A fast, special-purpose memory allocator for small blocks, to be used
on top of a general-purpose malloc -- heavily based on previous art. */

/* Vladimir Marangozov -- August 2000 */

/*
* "Memory management is where the rubber meets the road -- if we do the wrong
* thing at any level, the results will not be good. And if we don't make the
* levels work well together, we are in serious trouble." (1)
*
* (1) Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles,
* "Dynamic Storage Allocation: A Survey and Critical Review",
* in Proc. 1995 Int'l. Workshop on Memory Management, September 1995.
*/

/* #undef WITH_MEMORY_LIMITS */ /* disable mem limit checks */

/*==========================================================================*/


デジャブ。ちっこいものに対しては、標準のblockを「ちぎって」小さくallocateする戦略。その昔つとめていた会社でこういうことやっていたなぁ。分割の方針が2nだったけど。

/*
* Allocation strategy abstract:
*
* For small requests, the allocator sub-allocates <Big> blocks of memory.
* Requests greater than 256 bytes are routed to the system's allocator.
*

意訳:

allocatorは小さなメモリ要求に対しては、ブロックから切り出してメモリを割り当てます。256byteよりでかい要求はsystemのallocatorを使います。


* Small requests are grouped in size classes spaced 8 bytes apart, due
* to the required valid alignment of the returned address. Requests of
* a particular size are serviced from memory pools of 4K (one VMM page).
* Pools are fragmented on demand and contain free lists of blocks of one
* particular size class. In other words, there is a fixed-size allocator
* for each size class. Free pools are shared by the different allocators
* thus minimizing the space reserved for a particular size class.
*

意訳:

リクエストは、allocatorが返すアドレスのアライメント都合上、8byte刻みでグループ分けされます。仮想メモリマネジャからもらってきた4KByte blockから1つのグループ用にリストを作ります。リストの生成は必要に応じて行われます。


* This allocation strategy is a variant of what is known as "simple
* segregated storage based on array of free lists". The main drawback of
* simple segregated storage is that we might end up with lot of reserved
* memory for the different free lists, which degenerate in time. To avoid
* this, we partition each free list in pools and we share dynamically the
* reserved space between all free lists. This technique is quite efficient
* for memory intensive programs which allocate mainly small-sized blocks.

意訳:

この割り当て戦略はsimple segregated storage based on array of free lists[あえて訳すなら、リストの配列を用いた単純区分法とかか?]と呼ばれている。この手法の主な欠点はたくさん種類のlist(pool)がおのおのフリーのitemを持つためにメモリlisが消費され、それが時間がたつにつれてひどくなることがあげられる。これを避けるために、poolの間でメモリを共有できるようにする仕組みになっている。ちっこいメモリをたくさんとるようなメモリ郷土の高いプログラムにおいては非常に効果のあるトリックである。


*
* For small requests we have the following table:
*
* Request in bytes Size of allocated block Size class idx
* ----------------------------------------------------------------
* 1-8 8 0
* 9-16 16 1
* 17-24 24 2
* 25-32 32 3
* 33-40 40 4
* 41-48 48 5
* 49-56 56 6
* 57-64 64 7
* 65-72 72 8
* ... ... ...
* 241-248 248 30
* 249-256 256 31
*
* 0, 257 and up: routed to the underlying allocator.
*/

/*==========================================================================*/

/*
* -- Main tunable settings section --
*/

/*
* Alignment of addresses returned to the user. 8-bytes alignment works
* on most current architectures (with 32-bit or 64-bit address busses).
* The alignment value is also used for grouping small requests in size
* classes spaced ALIGNMENT bytes apart.
*
* You shouldn't change this unless you know what you are doing.
*/

意訳:

ユーザに返されるアドレスのアライメント。
やっていることの意味がわからないなら触るべからず。

cpythonだとid()して手に入るものはaddressだからアライメントがどうなっているかを試すといいかもしれません。

#define ALIGNMENT 8 /* must be 2^N */
#define ALIGNMENT_SHIFT 3
#define ALIGNMENT_MASK (ALIGNMENT - 1)

Python Code Reading 08 懇親会で見聞き・思いついたネタ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

  • memoryの消費をprofileする機能。速度に関するprofileはあるけど。思いつく実装のidea。
    • gcまわりからたどる。PyObjectのヘッダを覗き見れば、物がなんだかわかりそう。weakrefを読んだついでに読んでしまうか。

      そんなにがんばる必要は無かった。module gcを使えばよさそう。あとはおのおののobjectのサイズをとって集計してあげないとね。

      get_objects( )
      現在、追跡しているオブジェクトのリストを返します。このリストには、戻り値のリスト自身は含まれていません。 バージョン 2.2 で 新たに追加 された仕様です。

      ただipythonを立ち上げてimport gcしただけでもこれだけobjectがある。もちろん環境による違いはあるだろうが。

      In [3]: len(gc.get_objects())
      Out[3]: 16033

      こんなにいろいろしているのに、電卓代わりとか、reference代わりだと富豪どころか大富豪だね。アラブの石油王なみだ。

    • newとdeleteを全部フックして拾う。覚えておくが大変そう。動的に大きさが変わると困るなぁ。


  • packageを作って配布する関係
    • monoを使ったmultiplatform GUIアプリ開発。gnomeではひとつの選択肢らしい

    • py2exe, py2install etcなどsigle binaryの生成、いつ使うのか。使うべきでないときは?受け取り手が開発者なのか、unix userなのか、windows userなのかおばあちゃんなのか?

    • bad know howが多いのでまとめるといいかもしれない。

    • ports + rpmみたいなもの無いかなぁ。

      • 開発者個人で使うならports

      • サーバファームや山盛りの端末を管理するならbinaryでcompileのいらないrpmか?、でもconfigurationを変えたい

      • 自前のpackageが楽に作りたい

      • テストするときにはsource treeからcleanにpackageしたい




2009年3月12日木曜日

マシな名前無いのかな

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
set_shiftableは、後から読んでわからなかった。set_int or setか。intはlongかもしれんし、C的なintじゃないからなぁ。__int__は、intにcastするためのメソッドで、setはその逆操作だ。shiftableでintじゃ無いものも無いし、実装でもdivmodしてるし。反省。



class BitArray(object):
strcut_fmt = '!B'
def __init__(self, size, binary=None, endian=None):
self.size = size
if binary:
if len(binary) > byte_length(size):
raise ValueError('spilling data, %i byte is too long for array size %i bits !'
%(len(binary), size))
self.binary = binary
else:
self.binary = '\x00'*byte_length(self.size)
if endian:
self.endian = endian
else:
self.endian = '<' # little endian

def __len__(self):
return self.size

def __int__(self):
ret = 0
mask = 1
for bit in self:
if bit:
ret |= mask
mask = mask << 1
return ret

def set_shiftable(self, value, begin, end):
d = value
for n in range(begin, end):
d, m = divmod(d, 2)
self[n] = m

def _getbyte(self, pos_of_byte):
return struct.unpack(self.strcut_fmt, self.binary[pos_of_byte])[0]

def _setbyte(self, pos_of_byte, value):
self.binary = (self.binary[:pos_of_byte]
+ struct.pack(self.strcut_fmt, value)
+ self.binary[pos_of_byte+1:]
)[:self.size]

def __iter__(self):
for i in range(self.size):
yield self[i]

Ascii Art Boardをparse/生成する。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク


+24-23-22-21-20-19------18-17-16-15-14-13-+
OO | X O O | | X X X X |
OO | X O O | | X |
OO | O | | |
OO | | | |
OO | | | |
| |BAR| |v
| | | |
| | | |
| | | X |
| X X | | X |
| X X X | | X |
+-1--2--3--4--5--6-------7--8--9-10-11-12-+

をparseして

GNU Backgammon Position ID: bgAAALYOjAoMAA
Match ID : MAHgAEAAIAAA

を吐くmoduleを作ろう。長らく先送りしていたが。

unittestのためにデータを集めていて気づいたが、逆周りにできるようだ。

GNU Backgammon Position ID: 9xoAAJA1gwcDAg
Match ID : cAn6AEAAEAAA
+24-23-22-21-20-19------18-17-16-15-14-13-+ O: HarryDiculus
O | O O O O | | X X | 4 points
O | O O O | | X X |
O | O O | | X |
O | O | | X |
O | | | |
| |BAR| |v 7 point match (Cube: 1)
| | | |
| | | |
| | | |
| X X | | X | Rolled 46
| X X X X | X | X | 2 points
+-1--2--3--4--5--6-------7--8--9-10-11-12-+ X: nori

生成側はあまり問題ないにせよ、鏡像のregexpを書かなければならないparse側がだるい。

mlのアーカイブからなんかを抽出する(2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ここから先は正規表現の時間。position idとmatch idのペアを捕まえて、message idとさらにpairにしてあげればよい。

GNU Backgammon Position ID: bgAAALYOjAoMAA
Match ID : MAHgAEAAIAAA
+24-23-22-21-20-19------18-17-16-15-14-13-+
OO | X O O | | X X X X |
OO | X O O | | X |
OO | O | | |
OO | | | |
OO | | | |
| |BAR| |v
| | | |
| | | |
| | | X |
| X X | | X |
| X X X | | X |
+-1--2--3--4--5--6-------7--8--9-10-11-12-+

1つのメッセージの中には1つしかpositionが出てこないと仮定してsearchしgroupdictしてあげる。



import re
import email
import email.Iterators
import mailbox

r = re.compile((r"(Position +ID *: *(?P<position>[a-zA-Z0-9]{14}))"
r"|(Match +ID *: *(?P<match>[a-zA-Z0-9]{12}))"
r"|(24-23-22-21-20-19------18-17-16-15-14-13-)"))

f= open('all')#2002-06')
mbox = mailbox.UnixMailbox(f, email.message_from_file)
for msg in mbox:
for part in email.Iterators.typed_subpart_iterator(msg):
b = part.get_payload()
enc = part.get_content_charset()
if not enc:
enc = 'us-ascii'
try:
u = b.decode(enc)
except (UnicodeError, LookupError):
continue
found = r.search(u)
if found:
d = found.groupdict()
print msg['message-id'], "%s:%s"%(d['position'], d['match'])


IDをまったく書かないでpositionを投稿なさっている方がいるらしい。勘弁して。

[nori@asama]~/Desktop/work/gnubg/bug-ml% grep 'None:None' positions.txt | wc
17 34 1104

mlのアーカイブからなんかを抽出する(1)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
まずは準備。mboxをローカルにコピー。wgetのオプション考えたくなかった。



import urllib
import re

yearmonth = re.compile(r'\d\d\d\d-\d\d')

base = 'ftp://lists.gnu.org/bug-gnubg/'

for line in urllib.urlopen(base):
xs = yearmonth.findall(line)
if xs:
ym = xs[0]
print ym, '->', base + ym
f = open(ym, 'w')
f.write(urllib.urlopen(base+ym).read())
f.close()


意味が無いが、これをあとから作るものと組み合わせれば、on the flyでnetworkからとってくるようにもかける。いまやるのは単にdebugのrep loopが長くなるだけ。

mutlifileとfileinputがそれっぽく見える。multifileは1→多、fileinputは多→1なので、今回は後者。seekableであることが要求されているのでそこをなんとかしないといけない。seekが無いようだ。で、拡張できないか fileinputのソースを見てみる。



def readline(self):
try:
line = self._buffer[self._bufindex]
except IndexError:
pass
else:
self._bufindex += 1
self._lineno += 1
self._filelineno += 1
return line

なんかコテコテに行志向です。無理がありそうなのでscrachするか、探すかですが、昨日探した感じではうまく見つけられず。まあ、そろそろ作ることを考えたほうがいいかもしれない。方針としては、userから触れるwindow bufferを用意して、必要に応じて実体のfileから読み込むのがいいかな。どの実体のどのoffesetかという情報ともつか。

あとはcatして標準入力からもらう。問題点としてはどのfileだったかわからなくなる、メモリかな。catしてfile作ってみたけど、89,259,554 byteかぁ。。。びみょー。



import email
import mailbox

f= open('all')
mbox = mailbox.UnixMailbox(f, email.message_from_file)
print mbox
for msg in mbox:
print msg['Date']
f.close()

んで、一体いくつメールがあるかというと、

[nori@asama]~/Desktop/work/gnubg/bug-ml% python find_position.py | wc
13865 83325 441602

とりあえずは富豪的に、複数Fileをラップする話は動くようになってから考えよう。

Python Code Reading 08

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
懇親会幹事してきました。

みなさんのご協力、とくにミラクルリナックスの森本さんには大変お世話になりました。pizzaがすぐになくなったので、もう一枚あってもよかったかもしれません。よいpizzaでした。配達を1Fにとりに行ったときに最初に感じた香りでよいものだとすぐわかった。
ビールはハートランドビールを採用しました。アサヒとかじゃつまらないだろうし、本物のビールであるハートランドが好きなので。ノンアルコールbeerも数本入れてみました。合計6本でしたがそこまでいらないようです。5本あれば十分。まあそもそもにアルコールがらみの税金がかかっていないおかげですごく安いので大差ないですが。

ノンアルコールbeerはTexas SelectMalt Squashでした。

Malt Squashは

2009年2月をもって製造を終了させていただきました。

だそうです。最終ロットだったかもしれませんね。

テキサスセレクトはモルトスカッシュ半額だし、十分においしい。あっさりめで、暑い夏の午後に汗かいた後にのむといいかもしれません。酔わずにのめます。

2009年3月11日水曜日

buildbot with nose coverage plugin

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

buildsteps_tonic.addStep(
ShellCommand(command='nosetests --with-coverage --cover-package="tonic" tonic 2>&1',
workdir='tonic')
)

ですた。なんだかねぇもう。|&とか2>&1は、リストで渡すときには許されないらしい。まあ少し考えれば当然ですが。しかし何でcoverageがnose pluginとして出力するときに%の部分だけ標準エラー出力なんだ??coverageが100%の時は何も出さない挙動をしているわけではなさそう。

2009年3月9日月曜日

using coverage via nose in buildbot

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
daily build/testの中でcoverageを出力させたいのだが、うまくいかない。どうなっているのだろう?きっとくだらないことだろうが・・・。

buildsteps_tonic.addStep(
ShellCommand(command=["nosetests", "--with-coverage", '--cover-package="tonic"', "tonic"],
workdir='tonic')
)

こんな出力になってしまう。

Name Stmts Exec Cover Missing
-------------------------------------
----------------------------------------------------------------------
Ran 8294 tests in 52.108s

2009年3月7日土曜日

python committer

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Hirokazu Yamamoto (oceancityってだれ?
blogとかpageないのかな?

MLのポストはこれ。
http://mail.python.org/pipermail/python-committers/2008-August/000024.html

初コミットはこれ

commit 7fde9990754bd0ebcf6d16d3812f0f14071c944f
Author: hirokazu.yamamoto
Date: Thu Aug 14 01:33:44 2008 +0000

Issue #2065: VC6 related fix.

- PC/VC6/_bsddb.dsp:
removed '/nodefaultlib:"msvcrt"' to fix linker error.

- PC/VC6/_msi.dsp, PC/VC6/pcbuild.dsw:
added new module support.

- PC/VC6/_sqlite3.dsp:
/D "MODULE_NAME=\"sqlite3\""
caused extra leading space like
#define MODULE_NAME " sqlite3"
so uses
/D MODULE_NAME=\"sqlite3\"
instead.

- PC/VC6/python.dsp:
changed stack size to 2MB to avoid stack overflow on
some tests.

git-svn-id: http://svn.python.org/projects/python/trunk@65663 6015fed2-1504-0410-9fe1-9d1591cc4771

自動ポスト続き

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
書き直した。datetimeをpickleして古いやつをpostしないようにした。
entryが新しいものから順に並んでいると仮定してます。



#!/usr/bin/env python
# -*- coding: us-ascii -*-
# vim: syntax=python
#
# Copyright 2009 Noriyuki Hosaka bgnori@gmail.com
#

import os.path
import sys
import time
from datetime import datetime as dt
import pickle

import urllib
import feedparser
import smtplib
from email.MIMEText import MIMEText
from email.Utils import formatdate


class Bot(object):
def __init__(self, out=None, **kw):
#feed_url, bot_addr, sender_addr, password, server, grp_addr,
if out is None:
out = sys.stdout
self.out = out
self.depot = kw

def __getattr__(self, name):
assert name in ("feed_url", "bot_addr",
"sender_addr", "password",
"grp_addr", "server",
"mailbody", "mailsubject",
"last",), '%s is not in list'%name
return self.__dict__['depot'][name]

def write(self, s):
self.out.write(s)

def run(self):
feed = self.get(self.feed_url)


self.write('connecting to mail server.\n')

con = smtplib.SMTP(self.server)
c = 0
try:
con.ehlo()
con.starttls()
con.ehlo()
con.login(self.sender_addr, self.password)
self.write('sending with %s to %s\n'
%(self.sender_addr, self.grp_addr))
for entry in reversed(feed.entries):
generated = dt(*entry.updated_parsed[:5])
if generated > self.lastupdate():
msg = self.make_message(entry)
con.sendmail(self.sender_addr, self.grp_addr, msg.as_string())
self.update(generated)
c += 1
self.write('.')
finally:
con.close()
if c > 0:
self.write('sent.\n')
else:
self.write('no item to work with.\n')
self.write('done.\n')
return

def get(self, url):
self.write('getting feed from "%s".\n'%(url))
f = urllib.urlopen(url)
try:
return feedparser.parse(f.read())
finally:
f.close()

def lastupdate(self):
path = os.path.abspath(self.last)
if not os.path.exists(path):
return dt(1900, 1, 1)
else:
f = file(path)
try:
t = pickle.load(f)
finally:
f.close()
assert isinstance(t, dt)
return t

def update(self, t):
assert isinstance(t, dt)
path = os.path.abspath(self.last)
f = file(path, 'w')
try:
pickle.dump(t, f)
finally:
f.close()

def make_message(self, entry):
msg = MIMEText(self.mailbody(entry).encode('utf-8'), 'plain', 'utf-8')
msg['Subject'] = self.mailsubject(entry).encode('utf-8')
msg['From'] = self.bot_addr
msg['To'] = self.grp_addr
msg['Date'] = formatdate()
return msg

buildbot

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
buildbotページを公開した。真っ赤なのが悲しい。

勝手に答えてみた

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
技術者・SE・プログラマ面接時の技術的な質問事項

プログラマ系



malloc したメモリは free すべきか

大事なことは「いつ」やるかだ。freeするかどうかではない。正しいタイミングでなければdouble freeかleakか、違法アクセスかのいずれかだ。


 ・どの言語が好きか。使用している言語のバージョンは(言語共通)★

そんなくだらない質問するなら過去に書いたコードを送ってもらえ。コードの質を見ればいい。見掛けで駄目なコードはいくらでもある。たいして時間から無いと思うけどなぁ。お互いに相手を拘束しなくてすむから低コストだし。

packageを作ったことあるかどうかとかdaily buildのシステムを組んで使っているかとかのほうがよっぽど大事。しかし暗記系の質問が多すぎ。googleがあるのに・・・。

管理者系



メールサーバ管理経験(sendmail/Postfix/qmail/その他)

gmailがあるから運用したら負けだと思う。世の中の95%のメールサーバの管理の質はgmailのそれに遠く及ばないと思う。中身をgoogleに見られるのが嫌だ??なにいってるんですか。

そんなことよりも大事な質問が飛んでいる。sshでremoteから入るアカウントにrootを許すかどうか?とか。portの設定を変えたときにどのようなトレードオフを考えたかとか?


・セキュリティ
 ・外部のセキュリティ診断を受けたことがあるか
 ・SQL インジェクションとは何か。その対策は
 ・XSS 脆弱性とは何か。その対策は
 ・CSRF (クロスサイト・リクエスト・フォージュリ) とは何か。その対策は
 ・暗号化知識
  ・ブロック暗号とは何か
  ・公開鍵暗号とは何か
  ・MD5・SHA とは何か。暗号化と一方向ハッシュの違いは何か
 ・日々のセキュリティ情報をどこから入手しているか★
 ・高木浩光を知っているか★

過去にも書いたが、費用対効果意識が大事。表層的な知識をなぞっていて本質を突いていない。

最後に世の中の面接者の皆さんに:
「調べてわかることに関して質問しない。」

2009年3月6日金曜日

feedの内容をgooglegroupに自動投稿する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

参考にしたサイト




#!/usr/bin/python
BOT_ADDR = "your posting bot <sample@gmail.com>"
SENDER = 'sample@gmail.com'
PASSWORD = 'secret'
GRP_ADDR = "sample@googlegroups.com"

import urllib
import feedparser
import time
import datetime

print 'getting feed'
f = urllib.urlopen("http://sample.com/rss.php")
rss = f.read()
x = feedparser.parse(rss)

tobepost = []

now = datetime.datetime.utcnow()
for entry in x.entries:
generated = datetime.datetime(*entry.updated_parsed[:5])
delta = generated - now
if delta.days == 0 and delta.seconds < 3600:
tobepost.append(entry)

if not tobepost:
import sys
print 'no new post found'
sys.exit()

print len(tobepost), ' new posts found'

from email.MIMEText import MIMEText
from email.Utils import formatdate
tosend = []
for entry in tobepost:
msg = MIMEText(entry.summary.encode('utf-8'), 'plain', 'utf-8')
msg['Subject'] = entry.title.encode('utf-8')
msg['From'] = BOT_ADDR
msg['To'] = GRP_ADDR
msg['Date'] = formatdate()
tosend.append(msg)

import smtplib
print 'connecting to mail server.'
con = smtplib.SMTP('smtp.gmail.com')#, 587)
con.ehlo()
con.starttls()
con.ehlo()
con.login(SENDER, PASSWORD)
print 'sending',
for msg in tosend:
print '.',
con.sendmail(SENDER, GRP_ADDR, msg.as_string())
con.close()
print 'sent'
print 'done.'

2009年3月3日火曜日

似たようなサイトが発見された

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
http://image.backgammonbase.com/mobileを半年前くらいから運用しているが、http://www.backgammonaustralia.org/gabbi.phpが機能的にかなり近い。

2009年3月2日月曜日

なるほど

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
omoさんが行きそびれたのは「キー・バリュー型データストア」開発者が大集合した夜 だったのね。

zope:queryMultiAdapater

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
おそらく/usr/lib64/python/site-packages/zope/interface/adapter.pyのこれなんだろう。



def queryMultiAdapter(self, objects, interface, name='', default=None):
factory = self.lookup(map(providedBy, objects), interface, name)
if factory is not None:
return factory(*objects)

return default

これだけではたいしたことはわからない。なんか検索して戻って来るのはfactoryで、そいつにinterfaceを満たすobjectのインスタンスを生成させている。なのでlookupの実装と、lookupの実装で探しているコンテナを特定し、InterfaceをregisterするAPIを読み解かないといけない。



class AdapterLookup(object):
# Adapter lookup support
# We have a class here because we want to provide very
# fast lookup support in C and making this part of the adapter
# registry itself would provide problems if someone wanted to
# persistent adapter registries, because we want C slots for fast
# lookup that would clash with persistence-suppplied slots.
# so this class acts a little bit like a lookup adapter for the adapter
# registry.

def __init__(self, registry, surrogates, _remove):
self._registry = registry
self._surrogateClass = registry._surrogateClass
self._default = registry._default
self._null = registry._null
self._surrogates = surrogates
self._remove = _remove


問題のlookup.

def lookup(self, required, provided, name='', default=None):
order = len(required)



if order == 1:
# Simple adapter:
s = self.get(required[0])
byname = s.get(provided)
if byname:
value = byname.get(name)
else:
value = None

if value is None:
byname = self._default.get(provided)
if byname:
value = byname.get(name, default)
else:
return default

return value


orderが0ってことはrequieredは[]とか()だ。どういう状況なのだろうか?

elif order == 0:
# null adapter
byname = self._null.get(provided)
if byname:
return byname.get(name, default)
else:
return default



getが取り出す操作を担当。ここにあるのはどれがbest matchかを決める実装

# Multi adapter

with = required[1:]
key = provided, order

for surrogate in self.get(required[0]), self._default:
byname = surrogate.get(key)
if not byname:
continue

bywith = byname.get(name)
if not bywith:
continue

# Selecting multi-adapters is not just a matter of matching the
# required interfaces of the adapter to the ones passed. Several
# adapters might match, but we only want the best one. We use a
# ranking algorithm to determine the best match.

# `best` carries the rank and value of the best found adapter.
best = None
for rwith, value in bywith:
# the `rank` describes how well the found adapter matches.
rank = []
for rspec, spec in zip(rwith, with):
if not spec.isOrExtends(rspec):
break # This one is no good
# Determine the rank of this particular specification.
rank.append(list(spec.__sro__).index(rspec))
else:
# If the new rank is better than the best previously
# recorded one, make the new adapter the best one found.
rank = tuple(rank)
if best is None or rank < best[0]:
best = rank, value
# If any match was found, return the best one.
if best:
return best[1]

return default


method weakrefはweakrefだろう。なぜ使っているのか理解するべし。
なぜsurrogateなのか



def get(self, declaration):
if declaration is None:
return self._default

ref = declaration.weakref(self._remove)
surrogate = self._surrogates.get(ref)
if surrogate is None:
surrogate = self._surrogateClass(declaration, self._registry)
self._surrogates[ref] = surrogate

return surrogate

Zope:getRoles

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク



##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Define Zope's default security policy

$Id$"""

from types import MethodType

# AccessControl.Implementation inserts:
# ZopeSecurityPolicy, getRoles, rolesForPermissionOn

_norolesの実装は[]である。Noneと[]の扱いはちゃんとチェックしたほうがよさそう。roleを要求していない(いかなるroleもOK、allow any)のか、roleがない(allow none, 該当なしの空集合)のかなど。

from AccessControl.SimpleObjectPolicies import _noroles

rolesForPermissionOn = None # XXX: avoid import loop

tuple_or_list = tuple, list


def getRoles(container, name, value, default):

global rolesForPermissionOn # XXX: avoid import loop

if rolesForPermissionOn is None:
from PermissionRole import rolesForPermissionOn

roles = getattr(value, '__roles__', _noroles)

__roles__ attributeをもっていないケース。

if roles is _noroles:
if not name or not isinstance(name, basestring):
return default


im_selfはメソッドを結合されたインスタンスである。ここを参照のこと。つまりvalueがmethodだと、そのmethodがbindされているインスタンスを取り出す。

if type(value) is MethodType:
container = value.im_self


__class__はインスタンスのclassを取り出す。そしてそのclassはnameごとにroleを提供できる。

cls = getattr(container, '__class__', None)
if cls is None:
return default

roles = getattr(cls, name+'__roles__', _noroles)
if roles is _noroles:
return default


valueを保持しているcontainerを基準にrolesを決める。

value = container


rolesはsequenceである可能性が高い。そうでないときはrolesForPermissionOn attributeを持っているとvalueを見て決めているのだろう。

if roles is None or isinstance(roles, tuple_or_list):
return roles

rolesForPermissionOn = getattr(roles, 'rolesForPermissionOn', None)
if rolesForPermissionOn is not None:
roles = rolesForPermissionOn(value)


お疲れ様。

return roles

2009年3月1日日曜日

みんなfileを読み書きしたくない。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
omoさんHowFriendFeedUsesMySqlToStoreSchemaLessData - FriendFeed では MySQL を使いどのようにスキーマレスのデータを保存しているのかを訳出したようだ。性能面を念頭においているようだ。

特にスキーマ変更に伴うインデクスの追加は, 1-2 千万行もあるデータベースだと一度に数時間ものロックがおきてしまう. 古いインデクスを削除するにも同じくらい時間がかかる. かといって消さずに置くのも性能を損ねる. データベースは INSERT のたびに使いもしないブロックを読み書きし, 大事なデータをメモリから追い出してしまうからだ.


あーZopeのZCatalog読まないとな~。

あまり影響なかった。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
記事を書いたのだが、アクセスには影響なし。



トラフィックが増えているのはこいつのせいだろう。どっかの誰かがiso imageをdlしたようだ。

Top 10 of 42401 Total URLs By KBytes
1 1 0.00% 652872 19.17% /mirrors/centos-isos/centos5.1-x86_64/CentOS-5.1-x86_64-bin-2of7.iso
2 1 0.00% 650806 19.11% /mirrors/centos-isos/centos5.1-x86_64/CentOS-5.1-x86_64-bin-5of7.iso
3 1 0.00% 640834 18.82% /mirrors/centos-isos/centos5.1-x86_64/CentOS-5.1-x86_64-bin-1of7.iso
4 1 0.00% 447356 13.13% /mirrors/centos-isos/centos5.1-x86_64/CentOS-5.1-x86_64-bin-7of7.iso