S4x : Programmation Concurrente
Application industrielle concrète
Vous êtes développeur dans une société de service et le CNES (centre national des études spatiales) demandent à votre société de lui proposer de faire une étude technique afin d'optimiser leur programme d'analyse d'images satellitales. Il vous demande de faire une étude comparative de solutions comme Python et C++ pour paralléliser leurs calculs. Ils ont des experts en imagerie spatiale mais pas de développeur avec les compétences requises. Il vous demande aussi de proposer des solutions plus innovantes comme le GPU Computing (Cuda, OpenCL, etc...). Il souhaiterait avoir un prototype afin de pouvoir prendre des décisions en fonction des comparaisons des performances, limitations (taille mémoire, etc...), contraintes logicielles, portabilité (Linux, Windows, ...), etc...
BUT
Développer un outil de traitement d'images en utilisant les concepts vu en cours, en comparant les approches séquentielles et parallèles. Utilisez des algorithmes permettant de tester le côté parallèle (conversion d'espace de couleurs ? filtrage (flou), détection de contours?, ...). Faire des timings et une interface graphique de base pour changer dynamiquement les paramètres et configuration (nombre de threads, etc...).
C'est un projet que vous pourrez continuer par la suite (ajout de réseaux, etc...) ou le montrer pour chercher des stages, etc...
Groupes : 1, 2, ou 3 élèves par groupe, au choix.
ImGui (interface graphique en OpenGL)
NOTE : Les 5 fichiers "imgui_impl_glfw.h", "imgui_impl_opengl3.h", "imgui_impl_opengl3_loader.h", "imgui_impl_glfw.cpp" et "imgui_impl_opengl3.cpp" sont fournis par ImGui. J'ai juste fait une modification pour qu'il utilise mon loader de librairie OpenGL, GLAD, afin de pouvoir utilisé un OpenGL plus récent.
Timer sur GPU
Piur ceux qui veulent comparer les temps CPU et GPU, OpenGL fournit un objet pour calculer le temps des actions passées sur GPU :
// START of program : INITIALIZATION
// Device timer(s) [GPU]
GLuint64 mGPUTime = 0;
GLuint mGPUQueryTimeElapsed;
glCreateQueries( GL_TIME_ELAPSED, 1, &mGPUQueryTimeElapsed );
// ...
// RENDERING LOOP
// Timer: start
glBeginQuery( GL_TIME_ELAPSED, mGPUQueryTimeElapsed );
// GPU kernel
glUseProgram( shaderProgram );
// ...
glDispatchCompute( gridSizeX, gridSizeY, 1 );
// Timer: end
glEndQuery( GL_TIME_ELAPSED );
glGetQueryObjectui64v( mGPUQueryTimeElapsed, GL_QUERY_RESULT, &mGPUTime );
// Display timing
ImGui::Text( "Timing: %f ms", static_cast< float >( mGPUTime * 1.e-6 ) );
// ...
// END of program : CLEANING
// - device timers
glDeleteQueries( 1, &mGPUQueryTimeElapsed );
BONUS : Concurrence ? (pas obligatoire)
Idée : chargement d'images asynchrone.
Pendant la boucle de rendu, demander à un thread d'aller ouvrir et charger une image sans bloquer la boucle de rendu. Tant que le thread n'a pas fini, on interroge s'il a fini et uniquement là, on demande à OpenGL d'updater/créer la texture en envoyant les données du CPU vers la mémoire GPU. C'est ce qu'on fait dans les applications de type GoogleEarth pour charger des bouts de terrain et textures associées (la terre est découpée en tuiles qu'on charge à la demande lorsqu'elles sont visibles depuis la caméra => requêtes web asynchrones sur des serveurs). Il me semble que ça peut se faire avec l'objet C++ "condition" (comme en Python), ou peut-être plus simplement ? Exemple : schéma de l'idée (il faut aller voir la doc et un example de "condition" en C++) :
{
Button::Apply("Load Image")
{
threadImage.load( "xxx.jpg" ); // from file or internet : we would liki to block the rendering loop as few as possible
// => while retrieving data and loading, the rendering loop can continue without blocking from several frames, several secondes, etc...
// à la fin, le thread met à jour la variable isNewImageIsLoaded à true.
}
if ( isNewImageIsLoaded )
{
// create/update OpenGL texture
...
isNewImageIsLoaded = false;
}
}
Il existe aussi les tasks en C++ avec les objets "std::async" et le couple "promise"/"future".