Lacunes possibles de L'utilisation de JIT avec R?

4 réponses

rpart exemple donné ci-dessus, ne semble plus être un problème:

library("rpart")
fo = function() {
  for(i in 1:500){
    rpart(Kyphosis ~ Age + Number + Start, data=kyphosis)
  }
}    system.time(fo())
#   user  system elapsed 
#  1.212   0.000   1.206 
compiler::enableJIT(3)
# [1] 3
system.time(fo())
#   user  system elapsed 
#  1.212   0.000   1.210 

j'ai aussi essayé un certain nombre d'autres exemples, tels que

  • développement d'un vecteur;
  • Une fonction qui est juste un wrapper autour de mean

bien que je n'accélère pas toujours, je n'ai jamais connu de ralentissement significatif.


R> sessionInfo()
R version 3.3.0 (2016-05-03)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04 LTS
4
répondu csgillespie 2016-05-21 18:34:34

la sortie d'un test simple avec rpart pourrait être un conseil de ne pas utiliser enableJIT dans tous les cas:

library(rpart)
fo <- function() for(i in 1:500){rpart(Kyphosis ~ Age + Number + Start, data=kyphosis)}
system.time(fo())
#User      System verstrichen 
#2.11        0.00        2.11 

require(compiler)
enableJIT(3)
system.time(fo())
#User      System verstrichen 
#35.46        0.00       35.60

Tout explanantion?

11
répondu Robert 2012-04-12 19:16:24

en principe, une fois que le byte-code est compilé et chargé, il doit toujours être interprété au moins aussi rapidement que l'interpréteur AST original. Certains codes bénéficieront de grandes vitesses, il s'agit généralement de code avec beaucoup d'opérations scalaires et de boucles où la plupart du temps est consacré à l'interprétation R (j'ai vu des exemples avec une vitesse 10x mais des micro-benchmarks arbitraires pourraient en effet gonfler cela si nécessaire). Certains codes vont fonctionner à la même vitesse, ce qui est généralement le code bien vectorisé et donc dépenser presque pas de temps dans l'interprétation. Maintenant, la compilation elle-même peut être lent. Par conséquent, le compilateur just in time ne compile plus de fonctions lorsqu'il devine qu'elles ne seront pas payantes (et les heuristiques changent avec le temps, c'est déjà en 3.4.x). Les heuristiques ne le devinent pas toujours correctement, donc il peut y avoir des situations où la compilation ne portera pas ses fruits. Les modèles problématiques typiques sont la génération de code, la modification de code et la manipulation des reliures des environnements capturés dans les fermetures.

Packages peut être byte-compilé au moment de l'installation de sorte que le coût de compilation n'est pas payé (à plusieurs reprises) au moment de l'exécution, au moins pour le code qui est connu à l'avance. C'est maintenant la version de développement par défaut de R. alors que le chargement du code compilé est beaucoup plus rapide que sa compilation, dans certaines situations on peut charger même du code qui ne sera pas exécuté, donc il peut effectivement y avoir un overhead, mais la pré-compilation globale est bénéfique. Récemment, certains paramètres du CA ont été ajustés pour réduire les coût de chargement du code qui ne sera pas exécuté.

ma recommandation pour les rédacteurs de paquets serait d'utiliser les valeurs par défaut (la compilation juste-à-temps est maintenant activée par défaut dans les versions publiées, la compilation byte au moment de l'installation du paquet est maintenant activée dans la version de développement). Si vous trouvez un exemple où le compilateur de byte-code ne fonctionne pas bien, veuillez soumettre un rapport de bogue (j'ai aussi vu un cas impliquant rpart dans les versions précédentes). Je recommande contre la génération de code et manipulation de code et en particulier dans les boucles chaudes. Cela comprend la définition des fermetures, la suppression et l'insertion de reliures dans les environnements saisis par les fermetures. Certainement on ne devrait pas faire eval(parse(text= dans les boucles chaudes (et cela avait déjà été mauvais sans octet-compilation). Il est toujours préférable d'utiliser les branches plutôt que de générer de nouvelles fermetures (sans branches) de manière dynamique. Aussi, il est préférable d'écrire du code avec des boucles que de générer dynamiquement du code avec d'énormes expressions (sans boucle). Maintenant, avec la compilateur de byte-code, il est maintenant souvent correct d'écrire des boucles fonctionnant sur des scalaires en R (la performance ne sera pas aussi mauvaise qu'avant, donc on pourrait plus souvent s'en tirer sans passer à C pour les pièces critiques de performance).

0
répondu Tomas Kalibera 2018-03-06 14:20:20

suite à la réponse précédente, l'expérimentation montre que le problème est pas avec la compilation de la boucle, c'est avec la compilation de fermetures. [enableJIT(0) ou enableJIT(1) laisser le code rapide, enableJIT(2) ralentit considérablement, et enableJIT(3) est légèrement plus rapide que l'option précédente (mais toujours très lent)]. Contrairement aussi au commentaire de Hansi, cmpfun ralentit l'exécution dans une mesure similaire.

-2
répondu Elroch 2013-10-04 19:18:30