Submit Search
Rubyで実はwritev(2) が使われているはなし
•
5 likes
•
7,839 views
Masaki Matsushita
Follow
大江戸Ruby会議05で発表した内容です
Read less
Read more
1 of 9
Download now
Download to read offline
More Related Content
Rubyで実はwritev(2) が使われているはなし
1.
Rubyで実はwritev(2) が使われているはなし 2015年11月7日 松下 正樹
2.
自己紹介 ● 松下 正樹 ○ svn:
glass, twitter: @_mmasaki, github: mmasaki ● NTTコミュニケーションズ ● 136 commits for Ruby ○ 高速化: String#include?, Hash#flatten. Marshal.load ● 16 commits for OpenStack (Liberty) ○ “I like Python too.”と書いたらCFP通ったので OpenStack Summit Tokyoで発表
3.
知らない間に使われているwritev(2) # 書き込みバッファのサイズは8192バイト str =
"a" * 5000 File.open("foo", "w") do |f| f.write(str) # 書き込みバッファに収まる f.write(str) # 収まらない! end ● 下記のコードではwrite(2)が2回呼ばれ…ない ● writev(2)が1回だけ呼ばれる
4.
writev(2)とは? ● 複数のバッファの内容をアトミックに 書き込めるかもしれないシステムコール ○ write(2)同様バッファを全て書き込めるとは限らない struct
iovec { void *iov_base; size_t iov_len; }; struct iovec vector[2]; /* 2つのバッファを書き出す例 */ vector[0].iov_base = buf1; vector[0].iov_len = strlen(buf1); vector[1].iov_base = buf2; vector[1].iov_len = strlen(buf2); writev(1, vector, 2);
5.
RubyのIO typedef struct rb_io_t
{ FILE *stdio_file; int fd; /* file descriptor */ int mode; /* mode */ (中略) rb_io_buffer_t wbuf, rbuf; (後略) } struct rb_io_buffer_t { char *ptr; int off; int len; int capa; } ● stdioを使わず直接システムコールを使っている ● ruby自身が読み書きのバッファを持つ
6.
IO#writeの大まかな流れ (io.c) IO#writeの呼び出し ↓ io_write(): レシーバがIOかどうか、IOが書き込み可能かのチェック io_fwrite():
文字コード変換とStringのfreeze ↓ io_binwrite(): 書き込みバッファに溜め込む ↓ io_binwrite_string(): 書き込みバッファが溢れると呼ばれる ↓ write(2) or writev(2)
7.
io_binwrite_string()の実装: writev(2)導入前 if (書き込みバッファの中身がある)
{ if (渡されたバイト列がバッファに収まる) { if (バッファを詰めれば収まる) { 頑張って詰める; } バイト列を書き込みバッファに収める; } io_fflush(fptr); /* 中でwrite(2)が呼ばれる */ } rb_write_internal(p->fptr->fd, p->ptr, p->length);
8.
io_binwrite_string()の実装: writev(2)導入後 struct iovec
iov[2]; /* iov[0]: 書き込みバッファ */ iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off; iov[0].iov_len = fptr->wbuf.len; /* iov[1]: 書き込みバッファに収まらなかったバイト列 */ iov[1].iov_base = (char *)p->ptr; iov[1].iov_len = p->length; r = rb_writev_internal(fptr->fd, iov, 2);
9.
まとめ ● RubyのIOはstdioを使わず自前でシステムコールを叩く ● RubyのIOではwritev(2)が使われている ●
writev(2)は、複数のバッファをアトミックに書き込む ○ write(2)同様成功するとは限らない ● writev(2)の導入によって ○ システムコール呼び出し回数を減らすことができる ○ バッファの中身と渡されたStringをアトミックに 書き出せる(かもしれない)
Download