1 votes

Le multicore fait en sorte que l'exécution soit parallèle plutôt que "threadée" ?

J'ai un Makefile pour exécuter une suite de tests qui ressemble à peu près à ceci :

%.diff.png: %.test.png
    echo '$\*: Comparing with good PNG.'

%.test.png: %.pdf
    echo '$\*: Converting PDF to PNG.'

%.pdf: %.tex
    echo '$\*: Generating PDF output.'

avec tous les echo complétées par les tests réels dans le vrai Makefile.

Lorsque j'exécute tous ces tests avec make test (le test n'est pas montré ci-dessus), j'obtiens évidemment une sortie linéaire :

...
umtest200b: Generating PDF output.
umtest200b: Converting PDF to PNG.
umtest200b: Comparing with good PNG.
...

Lorsque j'exécute ces tests avec un make multi-job ( make -j2 test ), les tests sont exécutés dans un ordre "filaire" :

...
umtest202a: Generating PDF output.
umtest202b: Generating PDF output.
...
umtest202a: Converting PDF to PNG.
umtest202b: Converting PDF to PNG.
...
umtest202a: Comparing with good PNG.
umtest202b: Comparing with good PNG.
...

Peut-être pouvez-vous voir le problème ; avant de découvrir si le test échoue, il a déjà été exécuté par tous des générations PDF et des conversions PNG pour tous les autres tests.

Existe-t-il un moyen d'organiser les tests de sorte que, même lorsqu'ils sont exécutés avec plusieurs tâches, les tests soient menés à terme avant de passer au test suivant ? Ou est-ce une tâche pour un meilleur make ?

1voto

Dana the Sane Points 7976

J'ai fait quelques lectures sur le -j le drapeau et je pense que le problème est que cela crée de nouveaux emplois pour règles indépendantes . Les travaux pour chaque image sont indépendants, donc la première dépendance pour chaque cible sera exécutée comme vous le voyez.

Je pense que le principal problème ici est que cette tâche est intrinsèquement sérielle, c'est-à-dire que les dépendances de chaque cible doivent être exécutées dans l'ordre, l'un après l'autre . Ainsi, au sein de chaque cible, vous n'avez pas la possibilité de tirer parti de la multiprogrammation, à ce niveau de granularité .

En make ne semble pas traiter les dépendances dans l'ordre que vous souhaitez, peut-être qu'un cadre de test unitaire prenant en charge les tests parallèles serait plus adapté. Je sais, en cherchant sur Google, que plusieurs d'entre eux existent, mais je ne peux pas recommander quand, car je ne les ai pas utilisés et je ne suis pas sûr du langage que vous utilisez.

1voto

Pavel Shved Points 34706

Sauf si l'ordre d'exécution des cibles est explicitement spécifié, make les exécute dans un arbitraire à la fois en mode parallèle et en mode non parallèle. Cet ordre est soumis à des algorithmes internes de make et dans votre cas, donne des résultats désagréables.

La solution est d'imposer une commande explicite à vos tests.

D'après votre partie du makefile, je suppose qu'il existe une variable "source" non révélée qui contient une liste de cibles à tester (de ces cibles dépendent les cibles implicites). De plus, l'expansion immédiate de cette variable donne des résultats corrects.

Supposons que la variable est comme ça :

list=file1 file2 file3 ... fileN

alors, pour résoudre le problème, il suffirait de générer les dépendances suivantes :

file2: file1
file3: file2 
...
fileN: fileN-1
run_tests: fileN

Comment la générer ? Écrivons une boucle foreach-eval après le site list la variable prend sa valeur :

len=$(words $(list))
$(foreach t,                                                  \
   $(join                                                     \ 
      $(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
      $(list)                                                 \
   )                                                          \
   , $(eval $(t))                                             \
)

Cela va générer une partie du makefile tout comme le fait le préprocesseur C (ou, plus correctement, les macros LISP). Cela fonctionnera comme suit : pour chaque élément t dans la liste formée par join en concaténant (en concaténant chaque élément de la première liste avec l'élément correspondant de la seconde) la liste file2 file3 ... fileN run_tests à chaque élément duquel correspond un suffixe : est ajouté (formant ainsi file2: file3: ... fileN: run_tests: ), avec le répertoire des sources file1 file2 ... fileN ; - pour chacun de ces éléments t dans la liste avec des éléments joints l'évalue comme faisant partie de la source du makefile, agissant ainsi comme les règles montrées ci-dessus ont été prescrites.

Maintenant, il ne vous reste plus qu'à invoquer la cible run_tests et cela se fera un par un.

1voto

Pavel Shved Points 34706

Soudain, une autre idée m'est venue à l'esprit !

%.diff.png:
    $(MAKE) $*.test.png
    echo '$*: Comparing with good PNG.'

Cela résout tout, sauf que les tests peuvent ne pas être invoqués dans le bon ordre (mais en pratique, ils se dérouleront très probablement bien).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X