Project

General

Profile

Actions

Feature #1623

closed

rb_objspace_each_objects

Added by ko1 (Koichi Sasada) almost 16 years ago. Updated about 14 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-dev:38602]

Description

=begin
 ささだです.

 C レベルで ObjectSpace.each_object 相当の処理をするための C API を作る
のはどうでしょうか.動機は,[ruby-dev:38584] で提案した機能を,gc.c に手
を入れずに作るためです.

 インターフェス案です.

void rb_objspace_each_objects(
int (*func)(VALUE *start, VALUE *end, void *data),
void *data)

 ObjectSpace.each_object と違い,1つずつコールバック関数に渡すのではな
く,あるまとまった単位ごとに何度かコールバック関数に渡されます.範囲は
start から end まで.渡されるオブジェクトは,free された cell を含んでい
る可能性があります.この場合,flags をチェックする必要があります.

*まとめて渡すのは,性能上の理由です.
 1つ1つ渡すと,結構性能低下が見られました.

 実装を一応つけておきます.ついでに,os_obj_of() をこれで書き換えてみま
した.

*ST_CONTINUE みたいなのを使ってしまったんですが,
 これは行儀が悪い気がする.どうするべき?

 いかがでしょうか.

Index: gc.c

--- gc.c (リビジョン 23682)
+++ gc.c (作業コピー)
@@ -2383,13 +2523,13 @@ Init_heap(void)
init_heap(&rb_objspace);
}

-static VALUE
-os_obj_of(rb_objspace_t *objspace, VALUE of)
+void
+rb_objspace_each_objects(int (*func)(VALUE *start, VALUE *end, void *),
void *data)
{
size_t i;

  • size_t n = 0;
    RVALUE *membase = 0;
  • RVALUE *p, *pend;
  • RVALUE *pstart, *pend;

  • rb_objspace_t *objspace = &rb_objspace;
    volatile VALUE v;

    i = 0;
    @@ -2402,30 +2542,70 @@ os_obj_of(rb_objspace_t *objspace, VALUE
    break;
    membase = heaps[i].membase;

  • p = heaps[i].slot; pend = p + heaps[i].limit;
  • for (;p < pend; p++) {
  • pstart = heaps[i].slot;
  • pend = pstart + heaps[i].limit;
  • for (; pstart != pend; pstart++) {
  •  if (pstart->as.basic.flags) {
    
  •  v = (VALUE *)pstart; /* acquire to save this object */
    
  •  break;
    
  •  }
    
  • }
  • if (pstart != pend) {
  •  if ((*func)((VALUE *)pstart, (VALUE *)pend, data) != ST_CONTINUE) {
    
  •  return;
    
  •  }
    
  • }
  • }
  • return;
    +}

+struct os_each_struct {

  • size_t num;
  • VALUE of;
    +};

+static int
+os_obj_of_i(VALUE *vstart, VALUE *vend, void *data)
+{

  • struct os_each_struct *oes = (struct os_each_struct *)data;
  • RVALUE *p, *pend;
  • VALUE v;
  • for (p = (RVALUE *)vstart, pend = (RVALUE *)vend; p != pend; p++) {
    if (p->as.basic.flags) {
    switch (BUILTIN_TYPE(p)) {
    case T_NONE:
    case T_ICLASS:
    case T_NODE:
    case T_ZOMBIE:
  •      continue;
    
  •  break;
       case T_CLASS:
    
  •      if (FL_TEST(p, FL_SINGLETON)) continue;
    
  •  if (FL_TEST(p, FL_SINGLETON))
    
  •    break;
       default:
    
  •      if (!p->as.basic.klass) continue;
    
  •  if (!p->as.basic.klass) break;
                   v = (VALUE)p;
    
  •      if (!of || rb_obj_is_kind_of(v, of)) {
    
  •  if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
     	rb_yield(v);
    
  •  	n++;
    
  •      oes->num++;
         }
     }
     }
    
    }
  • return ST_CONTINUE;
    }
  • return SIZET2NUM(n);
    +static VALUE
    +os_obj_of(VALUE of)
    +{
  • struct os_each_struct oes;
  • oes.num = 0;
  • oes.of = of;
  • rb_objspace_each_objects(os_obj_of_i, &oes);
  • return SIZET2NUM(oes.num);
    }

/*
@@ -2474,7 +2654,7 @@ os_each_obj(int argc, VALUE *argv, VALUE
rb_scan_args(argc, argv, "01", &of);
}
RETURN_ENUMERATOR(os, 1, &of);

  • return os_obj_of(&rb_objspace, of);
  • return os_obj_of(of);
    }

/*

--
// SASADA Koichi at atdot dot net
=end

Actions #1

Updated by matz (Yukihiro Matsumoto) almost 16 years ago

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:38602] [Feature: trunk] rb_objspace_each_objects"
on Sun, 14 Jun 2009 01:53:21 +0900, SASADA Koichi writes:

| C レベルで ObjectSpace.each_object 相当の処理をするための C API を作る
|のはどうでしょうか.動機は,[ruby-dev:38584] で提案した機能を,gc.c に手
|を入れずに作るためです.
|
| インターフェス案です.
|
|void rb_objspace_each_objects(
| int (*func)(VALUE *start, VALUE *end, void *data),
| void *data)
|
| ObjectSpace.each_object と違い,1つずつコールバック関数に渡すのではな
|く,あるまとまった単位ごとに何度かコールバック関数に渡されます.範囲は
|start から end まで.渡されるオブジェクトは,free された cell を含んでい
|る可能性があります.この場合,flags をチェックする必要があります.

  • each_objectと単数形ではないだろうか
  • VALUE*ではなくVALUEではないだろうか

という懸念がありますが、原則的には賛成です。

|*ST_CONTINUE みたいなのを使ってしまったんですが,
| これは行儀が悪い気がする.どうするべき?

ST_CONTINUEはst_table用ですから、本来はobject_each用の定数を
用意すべきでしょうね。

=end

Actions #2

Updated by ko1 (Koichi Sasada) almost 16 years ago

=begin
 ささだです.

Yukihiro Matsumoto wrote::

  • each_objectと単数形ではないだろうか

 なんて名前がいいでしょうかね.

  • VALUE*ではなくVALUEではないだろうか

 そうでした.で,VALUE だと足しても次の領域には行かないから,拡張ライブ
ラリ向けには struct RObject * にでもするといいのかなぁ.RVALUE を gc.c
から ruby.h に持って行くのも一案ですが....

|*ST_CONTINUE みたいなのを使ってしまったんですが,
| これは行儀が悪い気がする.どうするべき?

ST_CONTINUEはst_table用ですから、本来はobject_each用の定数を
用意すべきでしょうね。

 わかりました.

--
// SASADA Koichi at atdot dot net

=end

Actions #3

Updated by ko1 (Koichi Sasada) almost 16 years ago

=begin
 ささだです.

SASADA Koichi wrote::

  • each_objectと単数形ではないだろうか

 なんて名前がいいでしょうかね.

 ちょっと考えたのですが,こんなのはどうでしょうか.

void rb_objspace_walk_heaps(
enum objspace_walk_retval (*callback)(VALUE start, VALUE end,
size_t stride, void *data),
void *data);

 例えば,callback 内では

for (v = start; v != end; v+= stride) {
if (RBASIC(v)->flags) {
// なんかする
}
}

 こんな感じで 生きているオブジェクトを全部回ることができる,というイン
ターフェースです.なお,free cell は渡されない可能性があります.
walk_heaps だと,free cell 含めて渡らないとまずいかなぁ.

--
// SASADA Koichi at atdot dot net

=end

Actions #4

Updated by matz (Yukihiro Matsumoto) almost 16 years ago

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:38605] Re: [Feature: trunk] rb_objspace_each_objects"
on Sun, 14 Jun 2009 12:30:55 +0900, SASADA Koichi writes:

|>  なんて名前がいいでしょうかね.
|
| ちょっと考えたのですが,こんなのはどうでしょうか.
|
|void rb_objspace_walk_heaps(
| enum objspace_walk_retval (*callback)(VALUE start, VALUE end,
| size_t stride, void *data),
| void *data);

このcallbackですが

(*callback)(VALUE values, size_t run, void data)

でよいんでないですかね。「VALUEにstrideを足す」という操作が
不安です。

| こんな感じで 生きているオブジェクトを全部回ることができる,というイン
|ターフェースです.なお,free cell は渡されない可能性があります.
|walk_heaps だと,free cell 含めて渡らないとまずいかなぁ.

free cellは要らないんじゃないですかね。あと、heapというのは
Ruby GCの外では違う意味であるというakrさんの指摘もありますね。
objspace_walk_objectsで良いような気もします。

=end

Actions #5

Updated by ko1 (Koichi Sasada) almost 16 years ago

=begin
 ささだです.

Yukihiro Matsumoto wrote::

|>  なんて名前がいいでしょうかね.
|
| ちょっと考えたのですが,こんなのはどうでしょうか.
|
|void rb_objspace_walk_heaps(
| enum objspace_walk_retval (*callback)(VALUE start, VALUE end,
| size_t stride, void *data),
| void *data);

このcallbackですが

(*callback)(VALUE values, size_t run, void data)

でよいんでないですかね。「VALUEにstrideを足す」という操作が
不安です。

 これは,RVALUE の配列である heaps_slot を直接渡すんじゃなくて,一回
VALUE の配列に live object をコピーして渡す,というインターフェースで
しょうか.今のところ,RVALUE のサイズは,gc.c 以外からは見れないように
なっています.それを隠蔽するための stride という引数になっています.

 で,これはコピーのオーバヘッドを考えると,嫌だなぁ,と思います.この
API は,速いけど難しいインターフェースで取り扱い注意,というのだと弱いで
しょうか.

| こんな感じで 生きているオブジェクトを全部回ることができる,というイン
|ターフェースです.なお,free cell は渡されない可能性があります.
|walk_heaps だと,free cell 含めて渡らないとまずいかなぁ.

free cellは要らないんじゃないですかね。あと、heapというのは
Ruby GCの外では違う意味であるというakrさんの指摘もありますね。
objspace_walk_objectsで良いような気もします。

 こちらはそれで.ちなみに,RVALUE の配列を直接渡すことを考えていたの
で,free cell が入る,ということだったんですが.

--
// SASADA Koichi at atdot dot net

=end

Actions #6

Updated by ko1 (Koichi Sasada) almost 16 years ago

=begin
 ささだです.

SASADA Koichi wrote::

このcallbackですが

(*callback)(VALUE values, size_t run, void data)

でよいんでないですかね。「VALUEにstrideを足す」という操作が
不安です。

 これは,RVALUE の配列である heaps_slot を直接渡すんじゃなくて,一回
VALUE の配列に live object をコピーして渡す,というインターフェースで
しょうか.今のところ,RVALUE のサイズは,gc.c 以外からは見れないように
なっています.それを隠蔽するための stride という引数になっています.

 で,これはコピーのオーバヘッドを考えると,嫌だなぁ,と思います.この
API は,速いけど難しいインターフェースで取り扱い注意,というのだと弱いで
しょうか.

 本件,まつもとさんとチャットで議論させてもらったんですが,

・速度的な問題があるのは認めるので stride でもよい
・start, end の型は VALUE よりは VALUE * に

という話になりました.

void
rb_objspace_each_objects(
enum objspace_walk_retval (*callback)(VALUE *start, VALUE *end,
size_t stride, void *data),
void *data0

 こんな感じ.

 とりあえず,難しいのは難しいので,コメントに,使うな,と書いておきます
(詳しい説明と).

--
// SASADA Koichi at atdot dot net

=end

Actions #7

Updated by nobu (Nobuyoshi Nakada) almost 16 years ago

=begin
なかだです。

At Tue, 16 Jun 2009 11:05:58 +0900,
SASADA Koichi wrote in [ruby-dev:38650]:

void
rb_objspace_each_objects(
enum objspace_walk_retval (*callback)(VALUE *start, VALUE *end,
size_t stride, void *data),
void *data0

 こんな感じ.

VALUE*を渡すということは一度VALUEの配列を作るわけですから、
strideは不要でしょう。もっとも、end-startが大きくなると、一時配
列を作るコストと一つずつcallbackするコストとどちらが大きいかは微
妙な気もしますが。

--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦

=end

Actions #8

Updated by ko1 (Koichi Sasada) almost 16 years ago

=begin
 ささだです.

Nobuyoshi Nakada wrote::

VALUE*を渡すということは一度VALUEの配列を作るわけですから、
strideは不要でしょう。もっとも、end-startが大きくなると、一時配
列を作るコストと一つずつcallbackするコストとどちらが大きいかは微
妙な気もしますが。

 間違えた,VALUE * じゃなくて void * でした.VALUE を void * に変えただ
け.コピーは発生しません.

--
// SASADA Koichi at atdot dot net

=end

Actions #9

Updated by yugui (Yuki Sonoda) almost 16 years ago

  • Status changed from Open to Closed

=begin
applied in r23708.
=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0