// À FAIRE : écrire ici votre nom et numéro de machine : // Nom : ... // Prénom : ... // Numéro de machine : ... /******************************************************************** * Copyright (C) 2018 by UCBL / LIP * * Initial author: Matthieu Moy * ********************************************************************/ #include #include #include #include #include #include #define NB_THREADS 10 // Taille des images : #define WIDTH 10240 #define HEIGHT 10240 // Taille de l'histogramme #define RANGE 256 typedef unsigned char pixel; typedef pixel **image_t; typedef unsigned histogram_t[RANGE]; ///////////////////////// Fonctions auxiliaires (rien à modifier) template class delta_time { public: void start() { clock_gettime(ID, &m_start); } void stop() { clock_gettime(ID, &m_stop); } std::string to_string() { std::stringstream s; double diff_sec = m_stop.tv_sec - m_start.tv_sec; double diff_nsec = m_stop.tv_nsec - m_start.tv_nsec; double diff = diff_sec + (diff_nsec/1e9); s << diff*1e3 << " ms"; return s.str(); } private: struct timespec m_start; struct timespec m_stop; }; ///////////////////////// Images : image_t new_image() { image_t image = new pixel *[WIDTH]; for (unsigned i = 0; i < WIDTH; i++) image[i] = new pixel[HEIGHT]; return image; } void init_image_black(image_t image) { // noir (0) par défaut for (unsigned i = 0; i < WIDTH; i++) for (unsigned j = 0; j < HEIGHT; j++) image[i][j] = 0; } void init_image_fancy(image_t image) { init_image_black(image); // Bande blanche en haut (pic dans l'histogramme) for (unsigned i = 0; i < WIDTH; i++) for (unsigned j = 0; j < HEIGHT / 4; j++) image[i][j] = 255; // Dégradé noir -> blanc sur une bande (histogramme plat) for (unsigned i = 0; i < WIDTH; i++) for (unsigned j = HEIGHT / 4; j < HEIGHT / 2; j++) image[i][j] = ((float)i) / WIDTH * 256; } void delete_image(image_t image) { for (unsigned i = 0; i < WIDTH; i++) delete [] image[i]; delete [] image; } ///////////////////////// Histogrammes : /** * Affiche l'histogramme "h" sur la sortie standard. */ void display_hist(histogram_t h) { for (unsigned i = 0; i < RANGE; i++) { std::cout << "h[" << i << "] = " << h[i] << std::endl; } } /** * Initialise l'histogramme h à 0 */ void init_hist(histogram_t h) { for (unsigned i = 0; i < RANGE; i++) { h[i] = 0; } } /** * Compare deux histogrammes. Affiche les différences sur cerr s'il y * en a. Renvoie -1 en cas de différence, 0 si h1 et h2 sont * identiques. */ int compare_hist(histogram_t h1, histogram_t h2) { int ret = 0; for (unsigned i = 0; i < RANGE; i++) { if (h1[i] != h2[i]) { std::cerr << "Error while comparing histograms: " << h1[i] << " = h1[" << i << "] != h2[" << i << "] = " << h2[i] << std::endl; ret = -1; } } return ret; } ///////////////////////// Fin des fonctions auxiliaires. ///////////////////////// Écrivez votre code ci-dessous. /** * Calcule l'histogramme de l'image "image" dans le tableau * "histogram". * * "histogram" doit être initialisé à 0 avant l'appel de cette * fonction. */ void compute_histogram(image_t image, histogram_t histogram) { for (unsigned i = 0; i < WIDTH; i++) { for (unsigned j = 0; j < HEIGHT; j++) { histogram[image[i][j]]++; } } } /** * Même spécification externe que compute_histogram(), mais cette * version réalise un calcul multi-thread (version 1 : calcul local * puis chaque thread écrit dans la variable partagée). */ void histogram_threads_v1(image_t image, histogram_t histogram) { // La ligne suivante est là pour avoir un programme qui // marche, mais il faut la supprimer et la remplacer par le // vrai code multi-thread: compute_histogram(image, histogram); // À CHANGER ou À SUPPRIMER } /** * Même spécification externe que compute_histogram(), mais cette * version réalise un calcul multi-thread (version 2 : chaque thread * calcule dans une case de tableau ; la fonction main s'occupe de * rassembler les résultats des calculs). */ void histogram_threads_v2(image_t image, histogram_t histogram) { // La ligne suivante est là pour avoir un programme qui // marche, mais il faut la supprimer et la remplacer par le // vrai code multi-thread: compute_histogram(image, histogram); // À CHANGER ou À SUPPRIMER } int main() { // Pour compter le temps delta_time real; delta_time cpu; histogram_t h; histogram_t h_t1; histogram_t h_t2; image_t image = new_image(); // Essayer aussi init_image_black ici: init_image_fancy(image); init_hist(h); init_hist(h_t1); init_hist(h_t2); real.start(); cpu.start(); compute_histogram(image, h); real.stop(); cpu.stop(); std::cout << "[Version séquentielle] Temps réel passé : " << real.to_string() << ", temps CPU : " << cpu.to_string() << std::endl; real.start(); cpu.start(); histogram_threads_v1(image, h_t1); real.stop(); cpu.stop(); std::cout << "[Threads v1] Temps réel passé : " << real.to_string() << ", temps CPU : " << cpu.to_string() << std::endl; real.start(); cpu.start(); histogram_threads_v2(image, h_t2); real.stop(); cpu.stop(); std::cout << "[Threads v2] Temps réel passé : " << real.to_string() << ", temps CPU : " << cpu.to_string() << std::endl; int ret = 0; if (compare_hist(h, h_t1)) { std::cerr << "h_t1 is incorrect" << std::endl; ret = 1; } if (compare_hist(h, h_t2)) { std::cerr << "h_t2 is incorrect" << std::endl; ret = 1; } delete_image(image); display_hist(h); return ret; } /* Analyse des performances. Performances obtenues : A FAIRE Votre explication des performances obtenues : A FAIRE */