2009-08-21 7 views
3

Je rencontre un comportement temporel très étrange d'une fonction que j'ai écrite. Si j'enveloppe ma fonction dans une autre fonction de conteneur vide, elle obtient une accélération de 3x.MATLAB Comportement de chronométrage du mystère magique

>> tic; foo (args); toc

temps écoulé: ~ 140 secondes

>> tic; barre (args); toc

temps écoulé: ~ 35 secondes

Voici le kicker - la définition de la barre():

définir bar (args)

foo (args)

fin

Y a-t-il une sorte d'optimisation déclenchée dans MATLAB pour les appels de fonction imbriqués? Dois-je ajouter une fonction fictive à chaque fonction que j'écris?

+1

Quelques questions: Est-ce reproductible (c'est-à-dire que vous l'avez exécuté plusieurs fois)? Quels sont les arguments? Y a-t-il des «collisions de noms» potentielles (une variable et une fonction portant le même nom)? – gnovice

+1

Veuillez publier un ensemble court, mais complet, de fonctions (ou un programme si vous voulez) qui démontre ce comportement. Cela rend plus facile pour les autres de creuser et essayer de comprendre quel est le problème. –

+0

Bien sûr, je vais voir si je peux générer le programme et l'ensemble de données les plus simples sur lesquels ce comportement est observable. Le comportement est répétable. J'ai demandé si peu d'informations pour voir si ce genre de comportement était bien connu du monde Matlab. –

Répondre

3

L'accélérateur JIT ne fonctionne pas sur les expressions de ligne de commande autant que je sache. Ainsi, lorsque vous exécutez "tic; foo (args); toc" le code de foo s'exécute entièrement dans l'interpréteur MATLAB. Cependant, lorsque vous exécutez "tic; bar (args); toc", la barre est évaluée dans l'interpréteur et l'accélérateur JIT essaie de compiler l'appel à foo() en code natif. Je suis vraiment agitant mes mains sur les détails, mais c'est l'essentiel de celui-ci. Les détails concernant les capacités JIT de MATLAB sont difficiles à trouver. La plupart de ce que j'ai trouvé est sur le blog de Loren à The MathWorks. L'affirmation la plus proche que je peux trouver sur la ligne de commande en interprétant seulement est ici: http://blogs.mathworks.com/loren/2006/05/10/memory-management-for-functions-and-variables/#comment-207

+0

J'ai marqué ceci comme la réponse parce que cela semble le plus plausible. –

1

Avez-vous essayé foo une deuxième fois sans effacer les variables? Je suis incapable de reproduire cette augmentation des performances si Je l'exécute à plusieurs reprises. Sinon, cela semble plus rapide mais c'est seulement parce que MATLAB précompile ces fonctions si vous les exécutez une fois.

function barfoo  

    for i = 1:Inf 
    end  

end 

Et,

function foobar   
    barfoo(); 
end 
1

Je ne sais pas si vous avez essayé de courir votre code plusieurs fois, mais une explication possible, je l'ai remarqué est que la première exécution d'un fichier récemment mis à jour est généralement plus lent que les suivants (je suppose en raison de la compilation). Je devine que vous pouvez voir différents calendriers d'exécution de la troisième ligne de ce qui suit (appelé après avoir modifié foo):

tic; foo(args); toc; % First call of foo 
tic; bar(args); toc; % Second call of foo inside bar 
tic; foo(args); toc; % Third call of foo 
+1

Je peux courir foo et la barre autant de fois que je veux, je reçois toujours 100-140 secondes pour foo et 25 - 30 secondes pour la barre. –

1

Ce comportement est surprenant. Un appel de fonction intermédiaire ne devrait pas accélérer les choses comme ça. Essayez le profilage et voyez où il passe son temps. C'est le meilleur premier recours à presque tout "Pourquoi mon code Matlab est lent?" question.

clear all 
profile on -timer real 
foo(args); 
profile report 
%read the report and save a screencap 
clear all 
profile clear 
bar(args); 
profile report 

Termine le conseil. Ici commence la spéculation.

Il y a deux choses qui sont différentes dans les deux appels. Il y a une interaction de l'espace de travail. Appeler foo() à partir de la ligne de commande peut laisser la variable "ans" remplie dans votre espace de travail. Lorsqu'il est appelé à partir de bar(), ans sera défini, mais immédiatement effacé lorsque le retour de bar(). En outre, il est possible que foo() utilise evalin()/assignin() pour rechercher des espaces de travail dans la pile d'appels et qu'il puisse interagir avec des variables affectées dans votre espace de travail de base. La fonction bar() a un espace de travail propre.En fonction de l'emplacement de bar.m, il est possible qu'il invoque un foo() différent ou qu'il le résolve légèrement différemment. Vérifiez la résolution de votre chemin avec "quel truc" dans les deux contextes.

En fonction de la définition des "args", différents noms d'entrée() peuvent être visibles par foo. De plus, foo() peut contenir un code pathologique qui vérifie s'il est appelé depuis l'espace de travail de base, ou même s'il est appelé par une fonction d'un nom particulier, et se comporte différemment en fonction de cela. Ceci dit, il devrait s'agir principalement d'interactions mineures et ne devrait pas provoquer un ralentissement de cet ordre. Je soupçonnais que quelque chose d'autre se passait, peut-être juste exposé par des contextes d'appel légèrement différents. Ajouter un niveau d'indirection avec bar() ne devrait pas être la réponse. Voir ce que le profiler a à dire et partir de là. Le code exact à reproduire aidera beaucoup à obtenir de l'aide de la communauté.

+0

Mes excuses pour ne pas être à venir, ce n'est pas mon choix. En utilisant vos conseils, je pourrais être en mesure d'affiner le problème à quelque chose de suffisamment petit que je peux partager. Merci! –

Questions connexes