Ninja: Heuristique : exécutez les tâches avec de grandes entrées avant les tâches avec de petites entrées

Créé le 15 juil. 2016  ·  14Commentaires  ·  Source: ninja-build/ninja

Dans la version LLVM, certains fichiers prennent beaucoup plus de temps à compiler que d'autres. Le nom de fichier de l'un d'eux - un fichier C++ de 30 000 lignes (ne demandez pas) - est assez tard dans l'ordre alphabétique, et il finit souvent par tourner longtemps après que la plupart des autres cibles aient fini de se construire.

Ce serait cool si ninja pouvait, en tant qu'heuristique, regarder les tailles combinées des entrées d'une règle et exécuter les règles avec des entrées plus grandes en premier.

feature

Commentaire le plus utile

Ninja enregistre les temps pour les travaux, il dispose donc de ces informations. Le premier build n'est peut-être pas optimal, mais c'est déjà le cas puisque le journal des deps ninja n'est pas rempli non plus.

Tous les 14 commentaires

Je ne suis pas sûr que le temps de compilation soit uniquement fonction de la taille du fichier.. Je peux imaginer un petit fichier qui est un dur à cuire pour le compilateur, et un gros fichier qui est trivial..

Je ne suis pas sûr que le temps de compilation soit uniquement fonction de la taille du fichier.

Ce n'est pas. Néanmoins, le temps de compilation est certainement positivement corrélé à la taille du fichier. D'où l'intérêt de cette heuristique.

Peut-être aussi que ninja peut faire une sorte de PGO (optimisation guidée par profil) :+1: comme collecter des informations sur le temps nécessaire pour compiler chaque fichier et utiliser ces informations pour hiérarchiser les fichiers dans la prochaine version.

Néanmoins, le temps de compilation est certainement positivement corrélé à la taille du fichier.

Je ne pense pas qu'une heuristique basée sur les fichiers source ait un sens. Par exemple, nous avons un fichier C++ de moins de mille lignes qui se compile presque en une minute (ne demandez pas). En fin de compte, cela dépend de la dureté du fichier pour le préprocesseur et du nombre de modèles qu'il instanciera lors de la compilation.

Bien sûr, on peut supposer qu'un fichier de 30k lignes compilera plus longtemps que 1k, mais ce n'est pas une décision que ninja devrait prendre à mon avis.

comme collecter des informations sur le temps, combien de temps il a fallu pour compiler chaque fichier ...

Ceci est déjà fait dans .ninja_log Vous pouvez utiliser ce script https://github.com/nico/ninjatracing pour l'analyser et le charger dans chrome pour voir comment s'est déroulé le processus de construction.

...et utiliser ces informations pour hiérarchiser les fichiers dans la prochaine version.

donc puisque nous avons déjà les informations sur le temps de construction, ninja pourrait en effet utiliser ces informations dans les prochaines versions. Pourrait réellement aider.

ÉDITER:

Ok, j'ai effectivement jeté un coup d'œil aux temps de compilation. Le fichier qui compile le plus longtemps est https://github.com/llvm-mirror/clang/blob/master/lib/ASTMatchers/Dynamic/Registry.cpp et il n'a que 600 lignes. La métrique de taille de fichier ne fonctionne donc pas du tout pour ce fichier particulier.

llvm_buiild

De plus, je ne vois aucun goulot d'étranglement dans le processus. Mais cela pourrait aider que je construise avec 13 threads.

Salut, au cas où ce ne serait pas clair, je travaille actuellement sur LLVM et clang. J'ai passé les dernières semaines à optimiser la vitesse du backend clang/llvm, et en fait c'est au cours de ce processus que j'ai rencontré ce problème. Vous avez raison de dire qu'une reconstruction propre de clang packs bien. Mais si vous touchez certains en-têtes, vous pouvez facilement finir par attendre l'une de ces très longues compilations, comme x86 isel downing (qui apparaît également tard dans l'alphabet, ce qui aggrave le problème).

L'analyse ci-dessus n'est pas statistiquement significative car elle ne porte que sur un seul dossier. Voici un nuage de points de la taille du fichier cpp (axe des x) par rapport au temps de compilation (axe des y) sur ma machine pour faire une construction propre de clang.

S'il n'y avait pas de corrélation entre la taille du fichier et le temps de compilation, nous nous attendrions à ce que cela ressemble à du bruit aléatoire. Mais comme vous pouvez le voir, il existe une bonne corrélation entre la taille du fichier et le temps de compilation.

plt

Quoi qu'il en soit, pensez à utiliser les temps de compilation passés pour informer la commande est une excellente idée.

Bien sûr, il y a corrélation. Mais je ne pense pas que ce soit suffisamment concluant pour être universel pour tous les projets. Je n'ai pas de données disponibles, donc je peux me tromper ici.

Voir aussi #60 #376 #232

Mais je ne pense pas que ce soit suffisamment concluant pour être universel pour tous les projets.

Peut-être que je ne suis pas clair avec ma suggestion.

La suggestion est, _si vous allez faire un choix arbitraire entre la construction A et B_, alors peut-être utiliser une heuristique pour déterminer quelle cible prendra plus de temps à construire. L'heuristique de "regardez combien de temps ils ont mis à construire la dernière fois" est géniale, bien meilleure que ma suggestion de regarder la taille des fichiers. Mais en l'absence de temps de construction historiques, je m'attendrais à ce que les tailles de fichier soient toujours utiles.

Encore une fois, si une meilleure heuristique (telle que l'une de celles que vous avez mentionnées) s'applique, vous devez l'utiliser. Mais puisque je suggère seulement que cette heuristique soit appliquée en dernier recours, je ne pense pas que le fait qu'elle ne soit pas "universelle" fasse une différence. Nous allions faire un choix arbitraire, et maintenant nous faisons un choix un peu moins arbitraire.

Quoi qu'il en soit, regarder les temps de construction historiques est tellement mieux, je ne me soucie pas vraiment si vous regardez les tailles de fichiers. :)

Ninja a une heuristique pour faire des choix arbitraires entre le bâtiment A et B : il construit celui qui était le premier dans le manifeste. Pourriez-vous mettre votre heuristique dans votre générateur build.ninja à la place ?

@colincross C'est bien pour la commande initiale, mais les commandes ultérieures peuvent utiliser le timing pour être plus précis que les générateurs ne pourraient jamais l'espérer. Personnellement, je ne suis pas trop inquiet du temps de construction initial, mais les générateurs pourraient optimiser de cette façon.

Je pense que l'utilisation de la taille du fichier peut ne pas être suffisante pour le "profilage". Par exemple, un fichier cpp vraiment petit avec beaucoup d'inclusions pourrait être très long à traiter. Et les processus de non-compilation (analyse, copie, génération de fichiers…) ne sont pas liés à la taille du fichier.
Pourtant, c'est une bonne approche pour certaines unités de construction.
Une deuxième approche pourrait consister à enregistrer dans le cache le temps nécessaire à la construction d'un fichier. Les reconstructions pourraient être optimisées en analysant ce cache.

Ninja enregistre les temps pour les travaux, il dispose donc de ces informations. Le premier build n'est peut-être pas optimal, mais c'est déjà le cas puisque le journal des deps ninja n'est pas rempli non plus.

@jlebar ,
J'ai quelque chose de similaire avec https://go.googlesource.com/gollvm/ : J'ai quelques milliers de fichiers source compilés avant que certains n'imposent le crash du compilateur, avec une erreur "mémoire insuffisante".
Actuellement, deux fichiers sont à l'origine d'un tel échec :
https://github.com/llvm/llvm-project/blob/7d3aace3f52f6b3f87aac432aa41ae1cdeb348eb/llvm/lib/Target/AMDGPU/AMDGPULowerIntrinsics.cpp
https://github.com/llvm/llvm-project/blob/7d3aace3f52f6b3f87aac432aa41ae1cdeb348eb/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp
Bien que j'aie des doutes sur le fait que le frontal du compilateur de Golang ait quelque chose à voir avec OpenCL ou OpenGL (il n'y a actuellement aucun événement lié existant sur le backend) - mais le support ARM64 existe, pour la programmation générale du processeur.
Je devrais désactiver certaines parties du projet LLVM, dans la configuration de CMake, dans tous les cas.
Cependant, le premier fichier est 697 sur 2934 fichiers (les processus de compilation antérieurs ont conservé les fichiers .o compilés) et le second (dans une version propre) semble être 817 sur 3214 fichiers.
Il serait préférable de compiler d'abord d'autres fichiers, donc je resterais prédictif sur ceux qui consommeraient le plus de ma RAM. Je serais donc intéressé d'obtenir ces derniers - et de voir lesquels ont des problèmes, car je ne peux pas le savoir avant d'essayer. Ou pourrais-je?

Ivan

@advancedwebdeveloper en effet, il y a une sorte de supposition dans Ninja que vous avez assez de RAM pour tout compiler en parallèle avec le paramètre -jN que vous avez choisi. À la base, ce problème n'est pas causé par l'ordre choisi par Ninja, mais par le fait que Ninja (et tous les autres outils de construction que je connais) ne vous donne qu'un moyen très grossier de limiter le parallélisme -- à savoir, le Drapeau -j .

Cette page vous a été utile?
0 / 5 - 0 notes