Rのデータ構造とメモリ管理

  • 5,176 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
5,176
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
23
Comments
0
Likes
10

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Rのデータ構造とメモリ管理 一人 R 勉強会 #1 (2012/11/25) @a_bicky 2012/12/15 改訂版
  • 2. 自己紹介• Takeshi Arabiki ‣ Web 業界の底辺エンジニア ‣ Twitter & はてな: @a_bicky & id:a_bicky• 興味など 機械学習、自然言語処理、R• ブログ あらびき日記 http://d.hatena.ne.jp/a_bicky/
  • 3. R関係の主な発表 Tokyo.R #16 Tsukuba.R #9 Rユーザ会 2011http://www.slideshare.net/abicky/r-9034336 http://www.slideshare.net/abicky/r-10128090 http://www.slideshare.net/abicky/rtwitter
  • 4. 注意事項 C 言語書けません&読めませんそんな エンジニアのメモ書きです 間違いは @a_bicky 宛に連絡していただけると喜びます
  • 5. Rのデータ構造
  • 6. 2つのデータ構造 SEXPRECたぶん Symbolic EXPression RECord (S-EXPression RECord) の略*SEXP = SEXPRECVECTOR_SEXPREC 以外のノード(オブジェクト)VECTOR_SEXPRECSEXPREC の Vector 版(メモリを少し節約)*VECSEXP = VECTOR_SEXPRECデータ部分は直後のアドレスに格納raw, logical, integer, numeric, complex, character, list, expression 等
  • 7. SEXPREC// cf. src/include/Rinternals.htypedef struct SEXPREC { struct sxpinfo_struct sxpinfo; // 詳細は後述 struct SEXPREC *attrib; // 属性情報 struct SEXPREC *gengc_next_node; // GC で使用 struct SEXPREC *gengc_prev_node; // GC で使用 // データ部分 union { struct primsxp_struct primsxp; struct symsxp_struct symsxp; struct listsxp_struct listsxp; struct envsxp_struct envsxp; struct closxp_struct closxp; struct promsxp_struct promsxp; } u;} SEXPREC, *SEXP;
  • 8. VECTOR_SEXPREC// cf. src/include/Rinternals.htypedef struct VECTOR_SEXPREC { struct sxpinfo_struct sxpinfo; // 詳細は後述 struct SEXPREC *attrib; // 属性情報 struct SEXPREC *gengc_next_node; // GC で使用 struct SEXPREC *gengc_prev_node; // GC で使用 struct vecsxp_struct vecsxp; // length, truelength} VECTOR_SEXPREC, *VECSEXP;// データ部分のアライメントをするための変数?typedef union { VECTOR_SEXPREC s; double align; } SEXPREC_ALIGN;// データ部分の先頭アドレスの定義#define DATAPTR(x) (((SEXPREC_ALIGN *) (x)) + 1)
  • 9. VECTOR_SEXPREC VECTOR_SEXPREC のイメージ VECTOR_SEXPRECノードsxpinfo attrib gengc_next_nodegengc_prev_node vecsxp_struct データ部分 sizeof(VECREC) * length
  • 10. sxpinfo_struct// cf. src/include/Rinternals.hstruct sxpinfo_struct { SEXPTYPE type : 5; // ノードのタイプ unsigned int obj : 1; unsigned int named : 2; // コピーの際の挙動を制御 unsigned int gp : 16; unsigned int mark : 1; // Mark-and-Sweap の mark unsigned int debug : 1; unsigned int trace : 1; // tracemem 等で使用 unsigned int spare : 1; // もう使われていないらしい unsigned int gcgen : 1; // GC の世代情報 unsigned int gccls : 3; // サイズに応じたクラス番号};
  • 11. Rのメモリ管理
  • 12. 基礎知識• メモリ管理の上でノードは3種類に分かれる ‣ non-vector (gccls = 0) ‣ small vector(gccls = 1, 2, 3, 4, 5, 6) ‣ large vector (gccls = 7)• GC は世代別 GC ‣ old 世代は gcgen = 0, 1 の2つ存在 ‣ old 世代からより若い世代への参照は参照が発生する度 にリストに追加する形で管理(デフォルトオプション)
  • 13. R の世代別 GC 各世代は双方向リストとなっている → 挿入・削除を定数時間で行える R_GenHeap[gccls].New R_GenHeap[gccls].Old[gen]= &R_GenHeap[gccls].NewPeg = &R_GenHeap[gccls].OldPeg[gen] gengc_prev_node gengc_next_node node3 node1 node2 node1 node2 gen th New generation Old generation
  • 14. R の世代別 GC の手順1. old 世代のうち何番目の世代までを GC 対象とするか決定2. GC 対象の old 世代から参照されているノードを参照元世代に移す3. GC 対象の old 世代の世代 (gcgen) をインクリメントして unmark した上で new 世代に移す4. GC 対象外の old 世代から参照されているノードを mark し old 世 代に移す5. root からたどって参照のあるノードを mark し old 世代に移す6. large vector の new 世代に存在するノードを解放7. 場合によっては non-vector, small vector のうち unmarked な ノードを解放cf. RunGenCollect (src/main/memory.c)
  • 15. gc 関数の結果の意味> gc() # 全世代を対象とした GC (full GC) used (Mb) gc trigger (Mb) max used (Mb)Ncells 180515 9.7 407500 21.8 350000 18.7Vcells 287939 2.2 905753 7.0 877008 6.7 used Mb 使用中のノードの数。 sizeof(SEXPREC) x non-vector, small ノードの数 / 1024 /Ncells vector, large vecotor 全 1024 てを含む。 全 vector ノードのデータ ← を個数ではなく Mb で 部分(ヘッダ部分を除 表した値。Vcells く)が VECREC 何個分の つまり sizeof(VECREC) サイズに相当するか x 個数 / 1024 / 1024
  • 16. メモリ確保の仕組み• small vector 1. データ部分のサイズが VECREC 何個分相当かを算出 2. 1 の結果が1以下であれば gccls = 1、2以下は2、4以下は3、6 以下は4、8以下は5、16以下は6という具合に gccls をセット 3. 対応する gccls の使用されていないノードを割り当てる 4. 使用されていないノードが存在しない場合は一定量のノードを新 しく生成 (GetNewPage)• non-vector ‣ ↑の手順のうち gccls を 0 とする
  • 17. メモリ確保の仕組み• large vector 1. データ部分のサイズが VECREC 何個分相当かを算出 2. 1 の結果が16より大きければ gccls を 7 にセット 3. 必要なサイズをその都度 malloc で確保いずれの場合もメモリが足りない場合は GC を実行したりヒープサイズを調整する
  • 18. tracemem の仕組み// cf. src/main/duplicate.cSEXP duplicate(SEXP s){ SEXP t; duplicate_counter++; t = duplicate1(s); // (s)->sxpinfo.trace フラグが立っていればレポートを出力 if (RTRACE(s) && !(TYPEOF(s) == CLOSXP || TYPEOF(s) == BUILTINSXP || TYPEOF(s) == SPECIALSXP || TYPEOF(s) == PROMSXP || TYPEOF(s) == ENVSXP)){ memtrace_report(s,t); // コピーしたノードにもフラグを立てる SET_RTRACE(t,1); } return t;}
  • 19. tracemem の挙動duplicate が呼ばれないコピーはトレースできない> tracemem(a <- 1:5)[1] "<0x103011a48>"> b <- a> b[1] <- 1 # そのまま代入した場合はトレースされるtracemem[0x103011a48 -> 0x101b41760]:tracemem[0x101b41760 -> 0x103063188]:> c <- a[1:5]> c[1] <- 1 # インデックスを指定した場合はトレースされない> tracemem(a <- list(a = 1:5))[1] "<0x1064c0958>"> b <- a> a$a <- 1 # そのまま代入した場合はトレースされるtracemem[0x1064c0958 -> 0x1067e9598]:> c <- a$a> c[1] <- 1 # 一部の要素の代入はトレースされない
  • 20.
  • 21. 参考文献• R Internals - 1.1 SEXPs http://cran.r-project.org/doc/manuals/R-ints.html#SEXPs• RObjectModel - r-optimization-engine - Optimizing the performance of R - Google Project Hosting http://code.google.com/p/r-optimization-engine/wiki/ RObjectModel• R 2.15.2 のソースコード 主に src/include/Rinternals.h, src/main/include/Defn.h, src/main/memory.c
  • 22. 変更履歴• 2012/12/15 世代別 GC の旧世代の世代数が2なのに3になっていたのを訂正