Parallel Assign() est lent sur certains appareilsSalut tout le monde,
il semble y avoir un problème avec Parallel Assign() en combinaison avec certains systèmes.
J'ai accès à 3 PC Windows 10 avec JMP 16.1. :
- Ordinateur portable : Core i5-8350U (4 cœurs) à 1,9 GHz, 16 Go de RAM
- Ancienne station de travail : Xeon E5-1660 v4 (8 cœurs) à 3,2 GHz, 256 Go de RAM
- Nouvelle station de travail Xeon W-2145 (8 cœurs) @3,7 GHz, 128 Go de RAM
J'ai comparé les performances de la version parallèle et séquentielle de mon script de test en utilisant différentes tailles de problèmes sur tous les systèmes (scipt ci-dessous).
Le résultat était étonnamment mauvais. Seulement sur mon portable la version parallèle est légèrement plus rapide que la version séquentielle, mais jusqu'à plus de 2 fois plus lente sur les postes de travail.
Quelqu'un a-t-il rencontré des problèmes de performances similaires avec Parallel Assign() ? Ou est-ce que je l'utilise mal ? Qu'est-ce qui se passe ici?
Rob


n_different_ids = 100000;
<BR />// Just generate random data. Every 15 rows must be processed at the same time.
DT_Data = J( 15*n_different_ids, 9, 0 );
For ( i = 1, i <= n_different_ids, i++,
DT_Data[15*(i-1)+(1::15),0] = i + J( 15, 9, Random Normal() );
);
<BR />// some function
F_percentile = Function( {x , p},
x = Sort Ascending(x);
n = N Rows(x);
index = 1 + (n - 1) * p;
index_ibelow = Floor(index);
index_iabove = Ceiling(index);
h = index - index_ibelow;
result = (1 - h) * x[index_ibelow] + h * x[index_iabove];
result;
);
<BR />// parallel version
DT_Features = J( n_different_ids, 16, 0 );
start=tick seconds();
Parallel Assign( {
DT_Data = DT_Data,
F_percentile = Name Expr( F_percentile )
},
DT_Features[i,j] = (
i_same_group = Loc(DT_Data[15*(i-1)+(1::15), 1]);
data = DT_Data[15*(i-1)+i_same_group, 1+Ceiling(j/2)];
If (mod(j,2),
result = F_percentile(data, 0.95);
,
result = F_percentile(data, 0.05);
);
result;
)
);
time_parallel = tick seconds()-start;
Show(time_parallel);
Wait(0.1);
<BR />// sequential version
DT_Features = J( n_different_ids, 16, 0 );
start=tick seconds();
for(i=1,i<=n_different_ids,i++,
for(j=1,j<=16,j++,
i_same_group = Loc(DT_Data[15*(i-1)+(1::15), 1]);
data = DT_Data[15*(i-1)+i_same_group, 1+Ceiling(j/2)];
If (mod(j,2),
result = F_percentile(data, 0.95);
,
result = F_percentile(data, 0.05);
);
DT_Features[i,j] =result;
);
);
time_sequential = tick seconds()-start;
Show(time_sequential);
ScriptRe: Parallel Assign() est lent sur certains appareilsIl s'agit d'une machine JMP16/win10 à 4 processeurs 16 Go ~ 3 GHz sous VirtualBox. Je vois la vitesse à laquelle je m'attendrais (pas 4X, mais toujours bonne.)
n_different_ids = 100 000 ;
time_parallel = 13.98333333333333;
time_sequential = 37.7333333333333;
n_different_ids = 1 000 000 ;
time_parallel = 141.233333333333;
time_sequential = 375.016666666667;
L'affectation parallèle copie une grande matrice pour chaque CPU, mais les graphiques linéaires ne suggèrent pas qu'il s'agisse d'un problème de pagination, à ces tailles.
Regardez le moniteur de tâches Windows pour l'utilisation du processeur et de la mémoire (et du disque) et voyez si cela explique quelque chose. J'ai vu 100 % lors de l'attribution parallèle et 25 % lors du test séquentiel. J'ai également vu 7 Go utilisés lors de l'attribution parallèle plus importante.
Gestionnaire des tâches
Re: Parallel Assign() est lent sur certains appareilsSalut Craige,
Je regarde juste ma station de travail la moins performante maintenant (ci-dessous). Je n'ai rien vu de suspect dans le gestionnaire de tâches. À l'exception du processeur, rien n'est proche de la pleine occupation.
Ce que j'ai aussi remarqué, c'est que JMP 15.2.1 est toujours plus rapide dans les versions parallèle et séquentielle. Dans le cas de n=100.000 JMP 16.1 prend environ 36s/18s (parallèle/séquentiel) et JMP 15.2.1 31s/15s ce qui est un peu mieux mais encore loin des bonnes performances parallèles. Malheureusement, je n'ai plus d'ancienne version disponible. J'ai écrit ce code à l'aide de JMP 12 et je n'ai pas remarqué de problèmes de performances à l'époque (et les PC que j'utilisais étaient également différents).
Rob

Re: Parallel Assign() est lent sur certains appareilsJe peux confirmer ce comportement sur mon ordinateur portable (Win 10, JMP 16.1) :
time_parallel = 158,7 ;
time_sequential = 157.766666666667;
n=1000000
Re: Parallel Assign() est lent sur certains appareilsPas certain. J'ai envoyé une note sur ce fil à JMP ; vous voudrez peut-être aussi parler au support technique.
Je suppose (et c'est tout !) C'est que JMP devra changer quelque chose pour récupérer les performances sur le nouveau matériel. Avec seulement 4 processeurs virtuels, je ne peux pas voir la même chose que vous voyez.
Re: Parallel Assign() est lent sur certains appareilsJ'ai également limité le nombre de cœurs du gestionnaire de tâches disponibles pour JMP à 2, 4 et 8 sur le nouveau poste de travail. La version parallèle reste toujours plus lente que la version séquentielle. Je suppose que JMP utilise des bibliothèques obsolètes en arrière-plan qui fonctionnent mal sur les nouvelles architectures matérielles.
Merci Craige, je vais contacter le support technique à ce sujet.
Re: Parallel Assign() est lent sur certains appareilsPour ma machine 4 cœurs 3,6 GHz et N=100k :
J'obtiens une accélération de 1,4X en utilisant le code parallèle sur séquentiel (12,8 s parallèle contre 17,8 s séquentiel). Ce n'est pas aussi bon que l'accélération 2,7X que Craige voyait et c'est mieux que le comportement de ralentissement que vous voyiez sur les postes de travail. Cependant, je voulais voir si je pouvais en tirer un peu plus de performances, alors j'ai fait quelques modifications.
J'ai supprimé la surcharge d'appel de fonction (copies d'arguments de matrice, etc.) en utilisant des expressions à la place. Cela m'a permis d'atteindre une accélération de 2,5X (4,5s en parallèle contre 11,3s en séquentiel) et un peu plus rapide que l'original. Et enfin, j'ai essayé de réorganiser un peu les boucles et j'ai réduit la version séquentielle à 4s. C'est plus rapide que la version parallèle mais le réarrangement n'est pas aussi facile à faire avec Parallel Assign. J'ai testé différents N et ces modèles semblaient tenir, mais je n'ai pas fait un balayage complet comme dans votre tableau ci-dessus. Trouvez le code ci-joint.
Parallèle : 12,78
Séquentiel : 17,80
Parallel_Expr : 4,50
Sequential_Expr : 11,27
Sequential_Expr_Opt : 3,98
Re: Parallel Assign() est lent sur certains appareilsOh, wahou merci ! Exécution de votre script sur ma nouvelle station de travail que je reçois
Parallèle : 37.08333333333139
Séquentiel : 19.7166666666453
Parallel_Expr : 6.93333333331975
Sequential_Expr : 12.5333333333256
Sequential_Expr_Opt : 4.54999999998836
Ne considérons pas celui de Sequential_Expr_Opt car c'est une comparaison injuste. 
Vous venez de remplacer la fonction par une expression et j'obtiens une accélération d'environ 1.5 pour la version séquentielle et de plus de 5 (!!!) pour la version parallèle ? C'est une excellente solution de contournement. Alors qu'est-ce que j'apprends de cela? Ne jamais utiliser de fonctions en JSL ? C'est un peu désagréable car les fonctions rendent le code plus lisible et plus facile et plus sûr à utiliser et à modifier pour les autres. Cependant, je pense qu'il y a toujours un problème quelque part dans les coulisses car ma version parallèle d'origine prend toujours deux fois plus de temps que la version séquentielle d'origine et ce n'est pas le cas sur la machine virtuelle de Craige.
Mise à jour : voici l'analyse complète sur la nouvelle station de travail :


Re: Parallel Assign() est lent sur certains appareilsJ'ai suivi les conseils de Craiges et contacté le support technique il y a deux semaines. Après quelques questions sur mes PC, j'ai reçu aujourd'hui la réponse que les développeurs ont été impliqués pour enquêter sur le comportement et résoudre les problèmes dans une future version de JMP.
Néanmoins, merci encore Evan d'avoir accéléré ce script spécifique.
Re: Parallel Assign() est lent sur certains appareilssalut @Robbb , deux réflexions :
Programmation pour la vitesse
L'objectif de votre code peut avoir un effet important sur la façon dont vous l'écrivez.Pour la grande majorité des scripts, le temps supplémentaire nécessaire pour appeler une fonction ou copier un symbole n'a pas d'importance, donc oui, vous devez utiliser des fonctions et rendre le code facile à interpréter.D'un autre côté, si vous travaillez sur un projet de grande envergure et qui sera répété suffisamment de fois pour que vous vous souciez du temps que cela prendra, alors oui, vous voudrez peut-être commencer à échanger quelques subtilités contre des performances brutes.Je vous encourage cependant à ne consacrer que du temps à optimiser les choses qui comptent vraiment.Ne passez pas une heure de plus à coder quelque chose maintenant, puis passez une heure de plus à comprendre ce que vous avez fait après un an parce que vous l'avez rendu plus complexe en essayant de l'accélérer, juste pour faire gagner aux utilisateurs 20 secondes supplémentaires une fois par jour .
Compromis parallèle
Lorsque vous décidez d'exécuter ou non en parallèle, vous devez équilibrer la surcharge de la configuration de ce thread « enfant » avec le travail qu'il va faire.Imaginez que vous alliez exécuter des tâches parallèles en ouvrant une autre copie de JMP, en ouvrant une table de données et en cliquant sur Exécuter. Si vous le laissez fonctionner pendant une heure, tant mieux, vous gagnerez beaucoup de temps en laissant un seul script faire tout, mais si ce script doit s'exécuter pendant 20 secondes, vous avez probablement passé plus de temps à le démarrer que vous n'avez économisé.Oui, la surcharge ici est beaucoup plus petite, mais la copie de symboles et l'allocation de mémoire prennent du temps.Assurez-vous que le travail que votre script effectuera une fois l'environnement configuré est important.Une façon d'y parvenir est de diviser votre boucle en seulement 4 parties et de faire en sorte que chaque thread travaille sur un quart des valeurs à la fois.Alors, divisez votre liste en quatre parties, chacune avec un quart des lignes, puis demandez à votre script de traiter séquentiellement chaque sous-liste. De cette façon, vous réduisez le temps passé à configurer les threads enfants de n row() fois à 4.
Re: Parallel Assign() est lent sur certains appareilssalut @ih ,
se mettre d'accord.
Les frais généraux liés à l'installation d'un enfant n'ont pas beaucoup d'importance dans mon cas, je n'ai donc pas passé beaucoup de temps à rendre cela aussi efficace que possible. Ce script n'est pas destiné à s'exécuter seulement quelques minutes. Avant de commencer ce sujet, j'ai fait exactement ce que vous avez suggéré. J'ai divisé mon ensemble de données en 8 parties et il a été terminé en 0,5 jours. Pour plus d'intérêt, j'ai également essayé la version "Sequential_Expr_Opt" d'Evan plus tard, et il m'a fallu entre 1,5 et 4 jours pour terminer mon ensemble de données (j'ai commencé jeudi matin, je n'ai pas fini vendredi après-midi mais lundi matin).
Ce fil était pour montrer qu'il y a quelque chose qui ne va pas dans les coulisses en général. Dans le passé, j'ai remarqué de temps en temps de mauvaises performances parallèles de JMP et cela m'a dérangé. J'aime JMP et j'aime essayer des choses avec ce que les autres disent qu'on ne peut pas faire avec JMP. Et je suis plus qu'heureux que les développeurs s'y penchent.
Cependant, je dois dire qu'il existe de meilleurs outils pour traiter des ensembles de données vraiment volumineux que JMP. Du moins en ce moment. 