2016-05-07 2 views
4

J'ai le même script Python exécuté sur deux machines, sur la même entrée et donnant la même sortie. Il faut environ 7 minutes pour fonctionner sur mon ordinateur portable et 56 minutes pour fonctionner sur un serveur sur lequel je l'ai téléchargé.Comment diagnostiquer une différence flagrante dans l'exécution du script Python (agrégats pandas) entre deux machines?

Évidemment, l'environnement est différent, mais la différence de vitesse (8x!) était un peu trop flagrante pour moi de l'écrire comme différents environnements. Les deux machines ont beaucoup de mémoire, et le serveur a plus de cœurs que mon ordinateur portable, mais aussi plus de choses qui tournent dessus (et je ne pense pas que les cœurs sont importants pour cette opération). C'est normal pour moi de faire fonctionner mon ordinateur portable et le serveur. Je n'ai jamais eu une différence de vitesse de 2x, sans parler de celle de 10x.

Le script est un exemple, la plupart du travail est un pandas.DataFrame.groupby().aggregate(lambda), mais sur une grande table (~ 400 Mo). Comment puis-je diagnostiquer ce qui cause la différence de vitesse?


Voici ce que j'ai essayé jusqu'à présent, mais je sais que très peu à ce sujet, il peut ou ne peut pas être intéressant.

cprofile

J'ai essayé de courir python -m cProfile dans les deux environnements pour voir si l'appel de fonction particulière prenait beaucoup de temps, mais il semblait être dans tous les domaines:

ordinateur portable:

ncalls tottime percall cumtime percall filename:lineno(function) 
     93 56.976 0.613 372.694 4.007 {method 'get_result' of 'pandas.lib.SeriesGrouper' objects} 
16338970 46.629 0.000 250.104 0.000 aggregate_sv_calls_by_sv_id.py:42(<lambda>) 
18442616 33.808 0.000 56.950 0.000 {sorted} 
18442645 25.395 0.000 172.113 0.000 series.py:1033(__iter__) 
78056747/78056745 15.405 0.000 15.420 0.000 {isinstance} 
18446903 14.235 0.000 34.129 0.000 dtypes.py:68(is_dtype) 
18443264 13.515 0.000 21.058 0.000 internals.py:3806(dtype) 
18442666 13.447 0.000 30.854 0.000 common.py:2192(is_datetime_or_timedelta_dtype) 
18449428 13.250 0.000 13.250 0.000 {hasattr} 
18442793 13.001 0.000 19.134 0.000 internals.py:3833(internal_values) 
... 

serveur:

ncalls tottime percall cumtime percall filename:lineno(function) 
312253983 175.564 0.000 275.203 0.000 {isinstance} 
     93 153.294 1.648 3323.806 35.740 groupby.py:1885(_aggregate_series_pure_python) 
16338970 151.336 0.000 749.431 0.000 aggregate_sv_calls_by_sv_id.py:42(<lambda>) 
18443129 146.950 0.000 607.143 0.000 internals.py:2482(make_block) 
18442874 136.363 0.000 529.415 0.000 series.py:120(__init__) 
18443241 125.725 0.000 248.772 0.000 generic.py:2674(__setattr__) 
18442596 106.353 0.000 1336.629 0.000 internals.py:3868(get_slice) 
18442617 106.296 0.000 172.363 0.000 {sorted} 
18442596 89.203 0.000 2105.284 0.000 series.py:689(_get_values) 
18443048 84.777 0.000 91.065 0.000 base.py:506(_get_attributes_dict) 
... 

Comme il semblait être sur toute la ligne plutôt que d'une seule fonction que je pouvais isoler, j'ai essayé de voir si je pouvais réduire le problème à une minimum, complete, verifiable example ... Ce fut le meilleur que je suis:

% timeit

ordinateur portable:

In [5]: df = pd.DataFrame(np.random.randint(10, size=(10000, 50))) 

In [6]: %timeit df.groupby(0).sum() 
100 loops, best of 3: 5.54 ms per loop 

In [7]: %timeit df.groupby(0).agg(lambda x: sum(x)) 
1 loops, best of 3: 124 ms per loop 

In [8]: %timeit df.groupby(0, 1).agg(lambda x: sum(x)) 
1 loops, best of 3: 155 ms per loop 

serveur:

In [5]: df = pd.DataFrame(np.random.randint(10, size=(10000, 50))) 

In [6]: %timeit df.groupby(0).sum() 
100 loops, best of 3: 6.08 ms per loop 

In [7]: %timeit df.groupby(0).agg(lambda x: sum(x)) 
1 loops, best of 3: 215 ms per loop 

In [8]: %timeit df.groupby(0, 1).agg(lambda x: sum(x)) 
1 loops, best of 3: 327 ms per loop 

Alors cela ne capture pas tout à fait la différence de vitesse 8x. Il montre seulement une différence de vitesse de 2x.

Mais cette différence de taille (2x) me donne l'impression d'être habitué à certains facteurs environnementaux que je ne pourrai peut-être pas comprendre, comme d'autres charges sur le serveur ou quelque chose comme ça, ou différents processeurs. Si je veux effacer une différence de 2x en tant que machines différentes, cela signifie-t-il que je dois aussi accepter une différence de 8x en tant que machines différentes? Ou y a-t-il des choses plus intéressantes à creuser ici?


Conclusion:

Ma version pandas était 0.17.1 sur mon ordinateur portable et 0,18.1 sur le serveur. J'ai comparé le même code fonctionnant sur mon ordinateur portable entre 0.17.1 et 0.18.1, et 0.17.1 a couru environ 4x aussi vite. So ~ 4x peut être attribué à cela, et ~ 2x peut être attribué aux différences de plate-forme entre l'ordinateur portable et le serveur.

+0

Il y a beaucoup de choses qui pourraient se passer ici ... mais je vais demander l'évidence: utilisent-ils tous les deux le même interpréteur Python * (c'est-à-dire qu'il n'y a pas Python 2.11.7 et l'autre a Python 3.5.1)? – mwm314

+0

Vérifiez une liste pip de modules pour les différences de version? – dartdog

+0

Je commencerais par vérifier la version du serveur de Pandas. 'gel de pip | grep pandas' – Alexander

Répondre

2

Je suppose que vous regardez deux, peut-être même trois causes différentes.

En comparant les deux profils, je vois:

  • la même routine (tri), une partie de la distribution standard, exécutée dans le même nombre de fois, montre une différence de temps 3X. Cette routine est liée à la CPU et à la mémoire, elle n'a aucun autre besoin, ce qui peut indiquer une différence de plate-forme (processeur plus rapide, mémoire plus lente, erreur de page massive et éventuellement swash thrashing). La même chose peut être vu dans les appels à aggregate_sv_calls_by_sv_id.py. Ledit sous-programme exécute une fois moins sur le serveur, ce qui indique une différence entre l'exécution du même algorithme. Cela pourrait être le même que l'élément suivant, ou indiquer une sorte d'indétermination. Ce qui semble être la même routine, et est exécuté le même nombre non trivial de fois (93) sur l'ordinateur portable et le serveur, est appelé {method 'get_result' of 'pandas.lib.SeriesGrouper' objects} ici, et groupby.py:1885(_aggregate_series_pure_python) là. Cela signifie qu'il y a une différence dans la base logicielle.

Dans l'ensemble, je sors sur une branche et dire que votre version du logiciel est, en soi , environ 2,5 fois plus rapide que le serveur de. Ensuite, le serveur exécute le script 3 fois plus lentement. Et 2.5 * 3 donne autour de ce facteur 8X que vous observez, si cela est reproductible. Sinon, soit les causes sont vraiment trois et non deux, et l'indétermination ci-dessus joue un rôle, ou le ralentissement 3X sur le serveur est dû à des circonstances aléatoires (par exemple, la charge du système, très probable).

+0

J'ai été frappé par les différences dans la colonne 'filename: lineno (function)' du profil, mais j'ai l'impression que OP ne nous a donné qu'un petit extrait du haut des listes. Je suppose que si nous avions des listes complètes, nous serions en mesure de mieux faire correspondre les choses dans cette colonne. –

+0

Merci. Vous avez fait remarquer qu'il y avait une preuve de différence dans la base de logiciel, j'ai vérifié plus attentivement, et j'ai découvert que mon ordinateur portable fonctionnait avec les pandas 0.17.1 lors de la génération de ces statistiques (j'avais mis à jour 0.18.1, mais seulement après) . Si j'exécute mon code spécifique sur l'ordinateur portable en comparant 0.17.1 et 0.18.1, 0.17.1 est plus rapide de 4x, avec le reste 2x étant la différence de plate-forme. – leekaiinthesky