Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Rのデータ構造とメモリ管理    一人 R 勉強会 #1 (2012/11/25)                    @a_bicky             2012/12/15 改訂版
自己紹介• Takeshi Arabiki   ‣   Web 業界の底辺エンジニア   ‣ Twitter & はてな: @a_bicky & id:a_bicky• 興味など  機械学習、自然言語処理、R• ブログ  あらびき日記 http...
R関係の主な発表      Tokyo.R #16                               Tsukuba.R #9                             Rユーザ会 2011http://www.slid...
注意事項 C 言語書けません&読めませんそんな エンジニアのメモ書きです 間違いは @a_bicky 宛に連絡していただけると喜びます
Rのデータ構造
2つのデータ構造    SEXPRECたぶん Symbolic EXPression RECord (S-EXPression RECord) の略*SEXP = SEXPRECVECTOR_SEXPREC 以外のノード(オブジェクト)VECT...
SEXPREC// cf. src/include/Rinternals.htypedef struct SEXPREC {  struct sxpinfo_struct sxpinfo;     //   詳細は後述  struct SEXP...
VECTOR_SEXPREC// cf. src/include/Rinternals.htypedef struct VECTOR_SEXPREC {  struct sxpinfo_struct sxpinfo;   // 詳細は後述  s...
VECTOR_SEXPREC          VECTOR_SEXPREC のイメージ                                     VECTOR_SEXPRECノードsxpinfo               at...
sxpinfo_struct// cf. src/include/Rinternals.hstruct sxpinfo_struct {   SEXPTYPE type      : 5; // ノードのタイプ   unsigned int o...
Rのメモリ管理
基礎知識• メモリ管理の上でノードは3種類に分かれる ‣   non-vector (gccls = 0) ‣   small vector(gccls = 1, 2, 3, 4, 5, 6) ‣   large vector (gccls =...
R の世代別 GC           各世代は双方向リストとなっている           → 挿入・削除を定数時間で行える   R_GenHeap[gccls].New                  R_GenHeap[gccls].O...
R の世代別 GC の手順1. old 世代のうち何番目の世代までを GC 対象とするか決定2. GC 対象の old 世代から参照されているノードを参照元世代に移す3. GC 対象の old 世代の世代 (gcgen) をインクリメントして ...
gc 関数の結果の意味> gc()  # 全世代を対象とした GC (full GC)         used (Mb) gc trigger (Mb) max used (Mb)Ncells 180515 9.7      407500 2...
メモリ確保の仕組み• small vector 1. データ部分のサイズが VECREC 何個分相当かを算出 2. 1 の結果が1以下であれば gccls = 1、2以下は2、4以下は3、6    以下は4、8以下は5、16以下は6という具合に...
メモリ確保の仕組み• large vector 1. データ部分のサイズが VECREC 何個分相当かを算出 2. 1 の結果が16より大きければ gccls を 7 にセット 3. 必要なサイズをその都度 malloc で確保いずれの場合もメ...
tracemem の仕組み// cf. src/main/duplicate.cSEXP duplicate(SEXP s){  SEXP t;    duplicate_counter++;    t = duplicate1(s);    ...
tracemem の挙動duplicate が呼ばれないコピーはトレースできない> tracemem(a <- 1:5)[1] "<0x103011a48>"> b <- a> b[1] <- 1 # そのまま代入した場合はトレースされるtra...
終
参考文献•   R Internals - 1.1 SEXPs    http://cran.r-project.org/doc/manuals/R-ints.html#SEXPs•   RObjectModel - r-optimizatio...
変更履歴•   2012/12/15    世代別 GC の旧世代の世代数が2なのに3になっていたのを訂正
Upcoming SlideShare
Loading in …5
×

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

12,560 views

Published on

  • Be the first to comment

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

  1. 1. Rのデータ構造とメモリ管理 一人 R 勉強会 #1 (2012/11/25) @a_bicky 2012/12/15 改訂版
  2. 2. 自己紹介• Takeshi Arabiki ‣ Web 業界の底辺エンジニア ‣ Twitter & はてな: @a_bicky & id:a_bicky• 興味など 機械学習、自然言語処理、R• ブログ あらびき日記 http://d.hatena.ne.jp/a_bicky/
  3. 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. 4. 注意事項 C 言語書けません&読めませんそんな エンジニアのメモ書きです 間違いは @a_bicky 宛に連絡していただけると喜びます
  5. 5. Rのデータ構造
  6. 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. 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. 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. 9. VECTOR_SEXPREC VECTOR_SEXPREC のイメージ VECTOR_SEXPRECノードsxpinfo attrib gengc_next_nodegengc_prev_node vecsxp_struct データ部分 sizeof(VECREC) * length
  10. 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. 11. Rのメモリ管理
  12. 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. 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. 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. 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. 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. 17. メモリ確保の仕組み• large vector 1. データ部分のサイズが VECREC 何個分相当かを算出 2. 1 の結果が16より大きければ gccls を 7 にセット 3. 必要なサイズをその都度 malloc で確保いずれの場合もメモリが足りない場合は GC を実行したりヒープサイズを調整する
  18. 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. 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. 20.
  21. 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. 22. 変更履歴• 2012/12/15 世代別 GC の旧世代の世代数が2なのに3になっていたのを訂正

×