-
Notifications
You must be signed in to change notification settings - Fork 2
/
05-profiling.Rmd
158 lines (128 loc) · 5.44 KB
/
05-profiling.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# *Profiler* son code
```{r, echo=FALSE}
library(mypkgr)
library(microbenchmark)
library(ggplot2)
```
On parle de *profiling* en anglais. Il s'agit de déterminer ce qui prend
du temps dans un code. Le but étant, une fois trouvé le bloc de code qui prend
le plus de temps dans l'exécution, d'optimiser uniquement cette brique.
Pour obtenir un *profiling* du code ci-dessous, sélectionner les lignes de code
d’intérêt et aller dans le menu "*Profile*" puis "*Profile Selected Lines*". Cela utilise en fait la fonction `profvis()` du package `profvis`.
```{r, eval=FALSE}
n <- 10e4
pdfval <- mvnpdf(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE)
```
```{r, echo=FALSE}
n <- 10e4
profvis::profvis(mvnpdf(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE))
```
*OK, we get it !* Concaténer un vecteur au fur et à mesure dans une boucle
n'est vraiment pas une bonne idée.
## Comparaison avec une version plus habile de `mnvpdf()`
Considérons une nouvelle version de `mvnpdf()`, appelée `mvnpdfsmart()`. Télécharger le [fichier](https://r-dev-perf.borishejblum.science/FormationRavancee_dev_perf_files/mvnpdfsmart.R) puis l'inclure dans votre package.
Profiler la commande suivante :
```{r, eval=FALSE}
n <- 10e4
pdfval <- mvnpdfsmart(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE)
```
```{r, echo=FALSE}
n <- 10e4
profvis::profvis(mvnpdfsmart(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE))
```
On a effectivement résolu le problème et on apprend maintenant de manière plus
fine ce qui prend du temps dans notre fonction.
Pour confirmer que `mvnpdfsmart()` est effectivement bien plus rapide que
`mvnpdf()` on peut re-faire une comparaison avec `microbenchmark()` :
```{r}
n <- 1000
mb <- microbenchmark(mvnpdf(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
mvnpdfsmart(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
times=100L)
mb
```
```{r, echo=FALSE}
data2plot <- cbind.data.frame("Time" = mb$time/10^6, "Expression" = mb$expr)
rangeTime <- c(floor(log10(min(data2plot$Time))):ceiling(log10(max(data2plot$Time))))
brk <- NULL
for(i in rangeTime){
brk <- c(brk, seq(from = 10^i, to = 10^(i+1), by=10^i))
}
levels(data2plot$Expression) <- gsub("mvtnorm::", "", sapply(strsplit(levels(data2plot$Expression), "(", fixed=T), "[", 1))
ggplot(data2plot) + geom_violin(aes(x=Expression, y=Time, fill=Expression), alpha=0.8) +
scale_fill_manual(guide="none", values=viridis::viridis(6)[2:3]) +
scale_y_log10(minor_breaks=brk) +
ylab("Log-temps de calcul (milli-sec)") +
xlab("Expression évaluée") +
theme_bw() +
annotation_logticks(sides="l")
```
Et on peut également voir si on devient compétitif avec `dmvnorm()` :
```{r}
n <- 1000
mb <- microbenchmark(mvtnorm::dmvnorm(matrix(1.96, nrow = n, ncol = 2)),
mvnpdf(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
mvnpdfsmart(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
times=100L)
mb
```
```{r, echo=FALSE}
library(ggplot2)
data2plot <- cbind.data.frame("Time" = mb$time/10^6, "Expression" = mb$expr)
levels(data2plot$Expression) <- gsub("mvtnorm::", "", sapply(strsplit(levels(data2plot$Expression), "(", fixed=T), "[", 1))
rangeTime <- c(floor(log10(min(data2plot$Time))):ceiling(log10(max(data2plot$Time))))
brk <- NULL
for(i in rangeTime){
brk <- c(brk, seq(from = 10^i, to = 10^(i+1), by=10^i))
}
ggplot(data2plot) + geom_violin(aes(x=Expression, y=Time, fill=Expression), alpha=0.8) +
scale_fill_manual(guide="none", values=viridis::viridis(6)[1:3]) +
scale_y_log10(minor_breaks=brk) +
ylab("Log-temps de calcul (milli-sec)") +
xlab("Expression évaluée") +
theme_bw() +
annotation_logticks(sides="l")
```
Il y a encore du travail...
## Comparaison avec une version optimisée dans `r fontawesome::fa("r-project")`
Boris est arrivé, après de longues recherches et plusieurs tests, à une
[version optimisée](https://r-dev-perf.borishejblum.science/FormationRavancee_dev_perf_files/mvnpdfoptim.R) avec les outils de `r fontawesome::fa("r-project")`.
Inclure la fonction `mvnpdfoptim()` dans le package, puis profiler cette
fonction :
```{r}
n <- 10e4
profvis::profvis(mvnpdfoptim(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE))
```
Et un petit `microbenchmark()` :
```{r}
n <- 1000
mb <- microbenchmark(mvtnorm::dmvnorm(matrix(1.96, nrow = n, ncol = 2)),
mvnpdf(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
mvnpdfsmart(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
mvnpdfoptim(x=matrix(1.96, nrow = 2, ncol = n), Log=FALSE),
times=100L)
mb
```
```{r, echo=FALSE}
library(ggplot2)
data2plot <- cbind.data.frame("Time" = mb$time/10^6, "Expression" = mb$expr)
levels(data2plot$Expression) <- gsub("mvtnorm::", "", sapply(strsplit(levels(data2plot$Expression), "(", fixed=T), "[", 1))
rangeTime <- c(floor(log10(min(data2plot$Time))):ceiling(log10(max(data2plot$Time))))
brk <- NULL
for(i in rangeTime){
brk <- c(brk, seq(from = 10^i, to = 10^(i+1), by=10^i))
}
ggplot(data2plot) + geom_violin(aes(x=Expression, y=Time, fill=Expression), alpha=0.8) +
scale_fill_manual(guide="none", values=viridis::viridis(6)[1:4]) +
scale_y_log10(minor_breaks=brk) +
ylab("Log-temps de calcul (milli-sec)") +
xlab("Expression évaluée") +
theme_bw() +
annotation_logticks(sides="l")
```
Pour finir on peut profiler la fonction `dmvnorm()` :
```{r}
n <- 10e5
library(mvtnorm)
profvis::profvis(dmvnorm(matrix(1.96, nrow = n, ncol = 2)))
```