Rubyで実はwritev(2)
が使われているはなし
2015年11月7日
松下 正樹
自己紹介
● 松下 正樹
○ svn: glass, twitter: @_mmasaki, github: mmasaki
● NTTコミュニケーションズ
● 136 commits for Ruby
○ 高速化: String#includ...
知らない間に使われているwritev(2)
# 書き込みバッファのサイズは8192バイト
str = "a" * 5000
File.open("foo", "w") do |f|
f.write(str) # 書き込みバッファに収まる
f.w...
writev(2)とは?
● 複数のバッファの内容をアトミックに
書き込めるかもしれないシステムコール
○ write(2)同様バッファを全て書き込めるとは限らない
struct iovec {
void *iov_base;
size_t i...
RubyのIO
typedef struct rb_io_t {
FILE *stdio_file;
int fd; /* file descriptor */
int mode; /* mode */
(中略)
rb_io_buffer_t ...
IO#writeの大まかな流れ (io.c)
IO#writeの呼び出し
↓
io_write(): レシーバがIOかどうか、IOが書き込み可能かのチェック
io_fwrite(): 文字コード変換とStringのfreeze
↓
io_bin...
io_binwrite_string()の実装: writev(2)導入前
if (書き込みバッファの中身がある) {
if (渡されたバイト列がバッファに収まる) {
if (バッファを詰めれば収まる) { 頑張って詰める; }
バイト列を書...
io_binwrite_string()の実装: writev(2)導入後
struct iovec iov[2];
/* iov[0]: 書き込みバッファ */
iov[0].iov_base = fptr->wbuf.ptr+fptr->w...
まとめ
● RubyのIOはstdioを使わず自前でシステムコールを叩く
● RubyのIOではwritev(2)が使われている
● writev(2)は、複数のバッファをアトミックに書き込む
○ write(2)同様成功するとは限らない
● ...
Upcoming SlideShare
Loading in...5
×

Rubyで実はwritev(2) が使われているはなし

71

Published on

大江戸Ruby会議05で発表した内容です

Published in: Engineering
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
71
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Rubyで実はwritev(2) が使われているはなし

  1. 1. Rubyで実はwritev(2) が使われているはなし 2015年11月7日 松下 正樹
  2. 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. 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. 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. 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. 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. 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. 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. 9. まとめ ● RubyのIOはstdioを使わず自前でシステムコールを叩く ● RubyのIOではwritev(2)が使われている ● writev(2)は、複数のバッファをアトミックに書き込む ○ write(2)同様成功するとは限らない ● writev(2)の導入によって ○ システムコール呼び出し回数を減らすことができる ○ バッファの中身と渡されたStringをアトミックに 書き出せる(かもしれない)
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×