【質問】ALLOC_NとALLOCA_N

View: New views
5 Messages — Rating Filter:   Alert me  

【質問】ALLOC_NとALLOCA_N

by mi.ml :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

いしもと といいます。

 かなり長い(数百万単位)要素数の数値配列といくつかの
係数を受け取り、それを計算して二次元配列を返す拡張ライ
ブラリを作っています。
 拡張ライブラリ内で配列の領域を確保する際、ALLOCA_N
で確保した場合は(スタック領域の範囲内であれば)問題なく
動作しているようなのですが、同じ領域をALLOC_Nで(ヒー
プ領域に?)確保するとかなり短い配列(私の環境では要素数
6266)しか扱えず、それを超えるとsegmentation faultが発
生してしまいます。私は一体何を間違ってしまっているのでし
ょうか?
 rubyは2年ほど使っていますが、c言語を扱うのは初めてで、
ruby本やc言語関連のwebを参考にしながら見よう見まねで書
いているレベルです。アドバイス頂ければ幸いです。
使用環境:
MacOSX 10.4(PowerPC)
メモリ 1GB
Ruby 1.8.6

SI.c --------------------------------------------------
#include "ruby.h"

static VALUE
si_calc6( self, ary1d, x0, y0, a )
        VALUE self ;
        VALUE ary1d ;
        VALUE x0 ;
        VALUE y0 ;
        VALUE a ;
{
        unsigned int i ;
        unsigned int len = 2 ;
       /* 引数をc言語の型に変換 */
        int x0c = NUM2INT( x0 ) ;
        int y0c = NUM2INT( y0 ) ;
        double ac = NUM2DBL( a ) ;
        long length = RARRAY( ary1d )->len ;
        VALUE *items = ALLOC_N( VALUE, length ) ; /* <- これ */
        /* VALUE *items = ( VALUE *)malloc( length * sizeof( VALUE ) ) ;*/

        VALUE item ;
        VALUE t ;
        VALUE xt ;
        double y ;

        for ( i = 0 ; i < length ; i++){
                t = INT2FIX( i + x0c );
                y = NUM2DBL( rb_ary_entry( ary1d, i ) ) ;
                xt = rb_float_new( y0c - ( y * ac ) ) ;
                item = rb_ary_new3( len, t, xt ) ;
                items[i] = item ;
        }
       
        VALUE result = rb_ary_new4( length, items ) ;
        free( items ) ;
        return result ;
}

void Init_SI(){
        VALUE msi = rb_define_module( "SI" ) ;
        rb_define_module_function( msi, "calc6", si_calc6, 4) ;
}

test.rb -----------------------------------------------
require 'SI'
include SI

ary=[]
6267.times{ ary.push 14238.45331 }

x0=40
y0=100
a=0.01213

ext=calc6(ary,x0,y0,a)  # => segmentation fault
                               # (ary.length<=6266ならOK)
___________________
いしもと まさと(石本 将人)



[ruby-ext:02319] Re: 【質問】ALLOC_NとALLOCA_N

by ysk-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

和田と言います。

From: mi.ml@...
Subject: [ruby-ext:02318] 【質問】ALLOC_NとALLOCA_N
Date: Sat, 07 Apr 2007 14:07:47 -0700

VALUE型をヒープに確保した場合は
rb_gc_markという関数でそのことをRuby側に
伝えてやる必要があるようです。
ですので、以下のようにすればいいのでは
ないでしょうか?

        for ( i = 0 ; i < length ; i++){
                t = INT2FIX( i + x0c );
                y = NUM2DBL( rb_ary_entry( ary1d, i ) ) ;
                xt = rb_float_new( y0c - ( y * ac ) ) ;
                item = rb_ary_new3( len, t, xt ) ;
                items[i] = item ;
                rb_gc_mark(items[i]); /* <--- これを追加 */
        }

青木さんの
http://i.loveruby.net/w/RubyExtensionProgrammingGuide.html
を参考にしました。


[ruby-ext:02320] Re: 【質問】ALLOC_NとALLOCA_N

by Nobuyoshi Nakada-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

なかだです。

At Sun, 08 Apr 2007 13:35:28 +0900 (JST),
ysk wrote in [ruby-ext:02319]:
> VALUE型をヒープに確保した場合は
> rb_gc_markという関数でそのことをRuby側に
> 伝えてやる必要があるようです。

rb_gc_mark()をmark用関数以外から呼んではいけません。

この場合はresultを先に確保しておいて、そのptrを使うということで
いいのではないでしょうか。

static VALUE
si_calc6(self, ary1d, x0, y0, a)
    VALUE self;
    VALUE ary1d;
    VALUE x0;
    VALUE y0;
    VALUE a;
{
    unsigned int i;
    /* 引数をc言語の型に変換 */
    int x0c = NUM2INT(x0);
    int y0c = NUM2INT(y0);
    double ac = NUM2DBL(a);
    long length = RARRAY(ary1d)->len;
    VALUE result = rb_ary_new2(length);
    VALUE *items = RARRAY_PTR(result);
    VALUE klass = RBASIC(result)->klass;

    VALUE item;
    VALUE t;
    VALUE xt;
    double y;

    RBASIC(result)->klass = 0;
    for (i = 0; i < length; i++){
        t = INT2FIX(i + x0c);
        y = NUM2DBL(rb_ary_entry(ary1d, i));
        xt = rb_float_new(y0c - (y * ac));
        item = rb_ary_new3(2, t, xt);
        items[i] = item;
    }
    RBASIC(result)->klass = klass;

    return result;
}

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


[ruby-ext:02321] Re: 【質問】ALLOC_NとALLOCA_N

by ysk-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

和田と言います。

From: Nobuyoshi Nakada <nobu@...>
Subject: [ruby-ext:02320] Re: 【質問】ALLOC_NとALLOCA_N
Date: Sun, 08 Apr 2007 16:23:52 +0900

> rb_gc_mark()をmark用関数以外から呼んではいけません。

そうでしたか。よくわからずに答えるのはよくなかったですね。
失礼しました。


[ruby-ext:02323] Re: __R e:_【質問】ALLOC_NとALLOCA_N

by mi.ml :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

質問者の いしもと です。

和田さん、中田さん、アドバイスありがとうございます。
知らないことばかりで、とても勉強になります。
ただ、お二方のアドバイスを実行しましたが、悲しいこと
に望むような結果は得られませんでした。
以下、現状報告です。
【和田さん案】
かなり長い配列を引数に指定してもseg faultしなくなった。
しかし、returnされた配列をruby program内で扱おうとす
るとseg faultが発生する。(引数配列の長さによっては発生
しないこともあるが、returnされる配列が少しおかしい。)
(例1)
ary.length==3,000,000
result=calc6(ary, etc)
p result[0] => seg fault
(例2)
ary.length==1,000,000
result=calc6(ary, etc)
p result[0] => value             # ?
p result[-1] => [index, value] # ok

【中田さん案】
seg faultはしなくなった。しかし、returnされる配列が
空になっている。
(例)
result=calc6(ary, etc)
p result.length => 0

現在、和田さんが紹介して下さった青木さんのサイトや
rhgなどを見ながら(にわか)猛勉強中です。volatileあた
りも気になっていますが、それ以前に基礎を固める必要も
痛感しています...
引き続きアドバイスなど頂けましたら幸いです。
___________________
いしもと まさと(石本 将人)

 
2007年04月08日 16:23 の "Nobuyoshi Nakada" <nobu@...>のメール:

>なかだです。
>
>At Sun, 08 Apr 2007 13:35:28 +0900 (JST),
>ysk wrote in [ruby-ext:02319]:
>> VALUE型をヒープに確保した場合は
>> rb_gc_markという関数でそのことをRuby側に
>> 伝えてやる必要があるようです。
>
>rb_gc_mark()をmark用関数以外から呼んではいけません。
>
>この場合はresultを先に確保しておいて、そのptrを使うということで
>いいのではないでしょうか。
>
>static VALUE
>si_calc6(self, ary1d, x0, y0, a)
>    VALUE self;
>    VALUE ary1d;
>    VALUE x0;
>    VALUE y0;
>    VALUE a;
>{
>    unsigned int i;
>    /* 引数をc言語の型に変換 */
>    int x0c = NUM2INT(x0);
>    int y0c = NUM2INT(y0);
>    double ac = NUM2DBL(a);
>    long length = RARRAY(ary1d)->len;
>    VALUE result = rb_ary_new2(length);
>    VALUE *items = RARRAY_PTR(result);
>    VALUE klass = RBASIC(result)->klass;
>
>    VALUE item;
>    VALUE t;
>    VALUE xt;
>    double y;
>
>    RBASIC(result)->klass = 0;
>    for (i = 0; i < length; i++){
>        t = INT2FIX(i + x0c);
>        y = NUM2DBL(rb_ary_entry(ary1d, i));
>        xt = rb_float_new(y0c - (y * ac));
>        item = rb_ary_new3(2, t, xt);
>        items[i] = item;
>    }
>    RBASIC(result)->klass = klass;
>
>    return result;
>}
>
>--
>--- 僕の前にBugはない。
>--- 僕の後ろにBugはできる。
>    中田 伸悦
>
>