2012-11-05 19 views
19

Interesuje mnie profilowanie kodu Rcpp pod OS X (Mountain Lion 10.8.2), ale profiler ulega awarii podczas uruchamiania.Profilowanie kodu Rcpp na OS X

Przykład z zabawkami, przy użyciu inline, zaprojektowanej po to, aby poświęcić wystarczająco dużo czasu, aby zauważył profiler.

library(Rcpp) 
library(inline) 

src.cpp <- " 
    RNGScope scope; 
    int n = as<int>(n_); 
    double x = 0.0; 
    for (int i = 0; i < n; i++) 
    x += (unif_rand()-.5); 
    return wrap(x);" 

src.c <- " 
    int i, n = INTEGER(n_)[0]; 
    double x = 0.0; 
    GetRNGstate(); 
    for (i = 0; i < n; i++) 
    x += (unif_rand()-.5); 
    PutRNGstate(); 
    return ScalarReal(x);" 

f.cpp <- cxxfunction(signature(n_="integer"), src.cpp, plugin="Rcpp") 
f.c <- cfunction(signature(n_="integer"), src.c) 

Jeśli używam albo instrumentów GUI (w Xcode, wersja 4.5 (4523)) lub wiersz poleceń sample, zarówno katastrofy: Przyrządy awarii od razu, natomiast próba zakończy przetwarzania próbek przed upaść:

# (in R) 
set.seed(1) 
f.cpp(200000000L) 

# (in a separate terminal window) 
~ » sample R # this invokes the profiler 
Sampling process 81337 for 10 seconds with 1 millisecond of run time between samples 
Sampling completed, processing symbols... 
[1] 81654 segmentation fault sample 81337 

Jeśli tak się ten sam proces, ale z wersją C (tj f.c(200000000L)) oba instrumenty i sample działała dobrze wytwarzać moc jak

Call graph: 
1832 Thread_6890779 DispatchQueue_1: com.apple.main-thread (serial) 
    1832 start (in R) + 52 [0x100000e74] 
    1832 main (in R) + 27 [0x100000eeb] 
     1832 run_Rmainloop (in libR.dylib) + 80 [0x1000e4020] 
     1832 R_ReplConsole (in libR.dylib) + 161 [0x1000e3b11] 
      1832 Rf_ReplIteration (in libR.dylib) + 514 [0x1000e3822] 
      1832 Rf_eval (in libR.dylib) + 1010 [0x1000aa402] 
       1832 Rf_applyClosure (in libR.dylib) + 849 [0x1000af5d1] 
       1832 Rf_eval (in libR.dylib) + 1672 [0x1000aa698] 
        1832 do_dotcall (in libR.dylib) + 16315 [0x10007af3b] 
        1382 file1412f6e212474 (in file1412f6e212474.so) + 53 [0x1007fded5] file1412f6e212474.cpp:16 
        + 862 unif_rand (in libR.dylib) + 1127,1099,... [0x10000b057,0x10000b03b,...] 
        + 520 fixup (in libR.dylib) + 39,67,... [0x10000aab7,0x10000aad3,...] 
        356 file1412f6e212474 (in file1412f6e212474.so) + 70,61,... [0x1007fdee6,0x1007fdedd,...] file1412f6e212474.cpp:16 
        56 unif_rand (in libR.dylib) + 1133 [0x10000b05d] 
        38 DYLD-STUB$$unif_rand (in file1412f6e212474.so) + 0 [0x1007fdf1c] 

Byłbym wdzięczny za poradę, jeśli coś jest nie tak, jeśli jest jakiś inny preferowany sposób, lub jeśli to po prostu niemożliwe. Biorąc pod uwagę, że jednym z głównych zastosowań Rcpp wydaje się być przyspieszenie kodu R, jestem zaskoczony, że nie mogę znaleźć więcej informacji na ten temat, ale być może szukam w niewłaściwym miejscu.

To jest na OS X 10.8.2 z R 2.15.1 (x86_64-apple-darwin9.8.0), Rcpp 0.9.15, i g ++ --version raportów "i686-apple-darwin11-llvm-g ++ - 4.2 (GCC) 4.2.1 (na podstawie wersji 5658 firmy Apple Inc.) (kompilacja LLVM 2336.11.00) ".

Rozwiązanie

Dzięki odpowiedź Dirka poniżej i mowie tutaj http://dirk.eddelbuettel.com/papers/ismNov2009introHPCwithR.pdf, mam przynajmniej częściowe rozwiązanie korzystając perftools Google. Najpierw zainstaluj stąd http://code.google.com/p/gperftools/ i dodaj -lprofiler do PKG_LIBS podczas kompilowania kodu C++. Wówczas

(a) Run R jak CPUPROFILE=samples.log R uruchomić cały kod i zamknąć (lub użyć Rscript)

(b) Za pomocą dwóch małych funkcji użytkowych, aby włączyć/wyłączyć profilowanie:

RcppExport SEXP start_profiler(SEXP str) { 
    ProfilerStart(as<const char*>(str)); 
    return R_NilValue; 
} 

RcppExport SEXP stop_profiler() { 
    ProfilerStop(); 
    return R_NilValue; 
} 

następnie, w ramach badania można zrobić

.Call("start_profiler", "samples.log") 
# code that calls C++ code to be profiled 
.Call("stop_profiler") 

Tak czy inaczej, będzie zawierać plik samples.log profilowania informacji. To może być postrzegana z

pprof --text /Library/Frameworks/R.framework/Resources/bin/exec/x86_64/R samples.log 

który wytwarza moc jak

Using local file /Library/Frameworks/R.framework/Resources/bin/exec/x86_64/R. 
Using local file samples.log. 
Removing __sigtramp from all stack traces. 
Total: 112 samples 
    64 57.1% 57.1%  64 57.1% _unif_rand 
    30 26.8% 83.9%  30 26.8% _process_system_Renviron 
    14 12.5% 96.4%  101 90.2% _for_profile 
    3 2.7% 99.1%  3 2.7% Rcpp::internal::expr_eval_methods 
    1 0.9% 100.0%  1 0.9% _Rf_PrintValueRec 
    0 0.0% 100.0%  1 0.9% 0x0000000102bbc1ff 
    0 0.0% 100.0%  15 13.4% 0x00007fff5fbfe06f 
    0 0.0% 100.0%  1 0.9% _Rf_InitFunctionHashing 
    0 0.0% 100.0%  1 0.9% _Rf_PrintValueEnv 
    0 0.0% 100.0%  112 100.0% _Rf_ReplIteration 

który prawdopodobnie byłby bardziej pouczający na rzeczywistym przykładzie.

+1

+1 - perftools, profiler gcc lub valgrind mogą pomóc. Fakt, że R jest interaktywny, rzuca tutaj klucz, ponieważ dodaje więcej warstw kodu. –

+0

Wpadłem na to sam, kiedy uaktualniłem mój XCode, ale myślałem, że to może być po prostu ja. Rzecz w tym, że Shark doskonale pracował nad profilowaniem Rcpp wcześniej, ale teraz jest już nieczynny. Myślę, że możemy nazwać to błędem Apple. –

Odpowiedz

4

Jestem zdezorientowany, Twój przykład jest niekompletna:

  • nie pokazują (trywialne) wywołanie cfunction() i cxxfunction()

  • nie pokazać jak wywołać profilera

  • nie są profilowania kodu C++ lub C (!!)

Czy możesz edytować pytanie i uczynić je bardziej przejrzystym?

Również po uruchomieniu tego dwa przykłady dają identyczne wyniki prędkości, ponieważ są w zasadzie identyczne. [Rcpp pozwoliłoby ci to zrobić w połączeniu z cukrowymi liczbami losowymi. ]

R> library(Rcpp) 
R> library(inline) 
R> 
R> src.cpp <- " 
+ RNGScope scope; 
+ int n = as<int>(n_); 
+ double x = 0.0; 
+ for (int i = 0; i < n; i++) 
+  x += (unif_rand()-.5); 
+ return wrap(x);" 
R> 
R> src.c <- " 
+ int i, n = INTEGER(n_)[0]; 
+ double x = 0.0; 
+ GetRNGstate(); 
+ for (i = 0; i < n; i++) 
+  x += (unif_rand()-.5); 
+ PutRNGstate(); 
+ return Rf_ScalarReal(x);" 
R> 
R> fc <- cfunction(signature(n_="int"), body=src.c) 
R> fcpp <- cxxfunction(signature(n_="int"), body=src.c, plugin="Rcpp") 
R> 
R> library(rbenchmark) 
R> 
R> print(benchmark(fc(10000L), fcpp(10000L))) 
     test replications elapsed relative user.self sys.self user.child sys.child 
1 fc(10000)   100 0.013  1  0.012  0   0   0 
2 fcpp(10000)   100 0.013  1  0.012  0   0   0 
R> 
+0

Cześć Dirk, i dzięki za pomoc! Wydaje mi się, że poprawiłem powyższy przykład dla jasności. Profiler jest wywoływany za pomocą polecenia "sample", a ja dodałem dane wyjściowe z wersji C, aby pokazać, że jest profilowane. Użyłem tego ogólnego podejścia z powodzeniem z kodem R + C wcześniej, ale nie z C++. Przykłady powinny dać identyczne wyniki i nie są reprezentatywne dla problemu, który próbuję profilować. Jeszcze raz dziękuję, Rich – Rich

+1

Widzę teraz - nic nie wiem o aspekcie OS X tego. Dla prostego "gcc" i innych, zamieściłem kilka uwag na temat profilowania w slajdach "Intro to HPC with R" na mojej stronie internetowej/z poprzednich rozmów. Będziesz musiał sprawdzić przy pomocy r-sig-mac, czy 'sample' działa na łańcuchu narzędziowym R. –