Loading OpenMP/exercises/Mandelbrot/openmp_solution/.backups/Makefile.pre_warnfix 0 → 100644 +39 −0 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/.backups/Makefile.pre_warnfix: 39 added lines, 0 removed lines. Original line number Diff line number Diff line # OpenMP Mandelbrot renderer # # make build mandelbrot_omp (optimised, -fopenmp) # make profile build mandelbrot_omp.profile with -DPROFILE: it also writes # <output>.dat, a per-pixel thread map for plot_thread_map.py # make debug build with -O0 -g # make clean remove objects and executables # # No external library is required: PNG output goes through the # single-header stb_image_write.h, and libm is not needed. CC ?= gcc CFLAGS ?= -O3 -march=native -mtune=native -Wall -Wextra OMP = -fopenmp LDFLAGS ?= TARGET = mandelbrot_omp SRCS = mandelbrot.omp.c mandelbrot_utilities.omp.c OBJS = $(SRCS:.c=.o) HEADERS = mandelbrot_omp.h mandelbrot_loop.omp.h stb_image_write.h all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(OMP) -o $@ $(OBJS) $(LDFLAGS) %.o: %.c $(HEADERS) $(CC) $(CFLAGS) $(OMP) -c -o $@ $< profile: $(SRCS) $(HEADERS) $(CC) $(CFLAGS) $(OMP) -DPROFILE -o $(TARGET).profile $(SRCS) $(LDFLAGS) debug: CFLAGS = -O0 -g -Wall -Wextra debug: clean $(TARGET) clean: rm -f $(TARGET) $(TARGET).profile $(OBJS) .PHONY: all profile debug clean OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot.omp.c.pre_warnfix 0 → 100644 +361 −0 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot.omp.c.pre_warnfix: 361 added lines, 0 removed lines. Original line number Diff line number Diff line /* ────────────────────────────────────────────────────────────────────────── * │ │ │ This file is part of the exercises for the Lectures on │ │ "Foundations of High Performance Computing" │ │ given at │ │ Master in HPC and │ │ Master in Data Science and Scientific Computing │ │ @ SISSA, ICTP and University of Trieste │ │ │ │ contact: luca.tornatore@inaf.it │ │ │ │ This is free software; you can redistribute it and/or modify │ │ it under the terms of the GNU General Public License as published by │ │ the Free Software Foundation; either version 3 of the License, or │ │ (at your option) any later version. │ │ This code is distributed in the hope that it will be useful, │ │ but WITHOUT ANY WARRANTY; without even the implied warranty of │ │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the │ │ GNU General Public License for more details. │ │ │ │ You should have received a copy of the GNU General Public License │ │ along with this program. If not, see <http://www.gnu.org/licenses/> │ │ │ * ────────────────────────────────────────────────────────────────────────── */ /* OpenMP Mandelbrot renderer for the HPC final-exam exercise. This is the OpenMP solution of the serial baseline in ../ : the pixel loop (mandelbrot_loop.h) is distributed among threads with a scheduling policy chosen at run time through --mode, and per-thread timings are collected to discuss load balancing. Compile with -DPROFILE to also dump, next to the image, a map of which thread computed each pixel (<output>.dat), to be plotted with plot_thread_map.py. Command-line parsing and image writers (PPM or PNG, through the stb header) are in mandelbrot_utilities.c; shared declarations are in mandelbrot_omp.h. Have fun. */ // hint for timing // you can use either the TIME macro that you find in the examples/timing.h header // or // omp_get_wtime() // that returns the wall-clock time per thread // #include "mandelbrot.omp.h" /* ======================================================================================== : ------------------------------------------------------ : : CALCULATION FUNCTIONS : : ------------------------------------------------------ : */ /* Compute the Mandelbrot escape iteration for one point c = cr + i ci. This is the direct scalar kernel, clean, keeps the operation count easy to read. This can be heavility optimized. */ static unsigned int mandelbrot_escape (double cr, // real part of the pixel centre double ci, // imaginary part of the pixel centre unsigned int kmax // maximum number of iterations ) { double zr; double zi; double zr_next; double zr2; double zi2; unsigned int k; zr = 0.0; zi = 0.0; k = 0; while (k < kmax) { zr2 = zr * zr; zi2 = zi * zi; if (zr2 + zi2 > 4.0) break; zr_next = zr2 - zi2 + cr; zi = 2.0 * zr * zi + ci; zr = zr_next; k += 1; } return k; } /* Map one iteration count to an RGB colour. Interior points are black. The outside palette is deliberately simple. It might be fun experimenting by advanced colouring or smooth-potential formulas. Don't be distracted by this, though */ static void colour_from_iteration (unsigned int iteration, // escape iteration count unsigned int kmax, // maximum iteration count unsigned char *rgb // output triplet: red, green, blue ) { double t; double one_minus_t; if (iteration >= kmax) { rgb[0] = 0u; rgb[1] = 0u; rgb[2] = 0u; return; } t = (double) iteration / (double) kmax; one_minus_t = 1.0 - t; rgb[0] = (unsigned char) (255.0 * 9.0 * one_minus_t * t * t * t); rgb[1] = (unsigned char) (255.0 * 15.0 * one_minus_t * one_minus_t * t * t); rgb[2] = (unsigned char) (255.0 * 8.5 * one_minus_t * one_minus_t * one_minus_t * t); } static void render_image (options_t *options, // view, factors, and kmax image_geometry_t *geometry, // image dimensions and pixel spacing unsigned char *image // complete row-major RGB image buffer #if defined(PROFILE) , unsigned char *timage #endif ) { uint64_t Nrows = geometry->height; uint64_t Ncols = geometry->width; char schedule_type[20] = {0}; int nthreads; #pragma omp parallel #pragma omp single nthreads = omp_get_num_threads(); double threads_atimers[nthreads]; #if defined(PROFILE) double threads_ctimers[nthreads]; memset( threads_ctimers, 0, nthreads*sizeof(double)); #endif double time_all = CPU_TIME_W; #pragma omp parallel { int myid = omp_get_thread_num(); double mytime = CPU_TIME_T; double my_calc_time = 0; if ( options->mode == 0) { #pragma omp single sprintf( schedule_type, "static, max chunk" ); #pragma omp for nowait #include "mandelbrot_loop.omp.h" } else if (options->mode > 0) { #pragma omp single sprintf( schedule_type, "static, %d-line chunk", options->mode); #pragma omp for schedule(static, options->mode) nowait #include "mandelbrot_loop.omp.h" } else { #pragma omp single { options->mode * -1; sprintf( schedule_type, "dynamic, %d points chunk", options->mode ); } #pragma omp for collapse(2) schedule(dynamic, options->mode) nowait #include "mandelbrot_loop.omp.h" } mytime = CPU_TIME_T - mytime; threads_atimers[ myid ] = mytime; #if defined(PROFILE) threads_ctimers[myid] = my_calc_time; #endif } time_all = CPU_TIME_W - time_all; double atmin = threads_atimers[0]; double atmax = threads_atimers[0]; #if defined(PROFILE) double ctmin = threads_ctimers[0]; double ctmax = threads_ctimers[0]; #endif for ( int t = 1; t < nthreads; t++ ) { atmin = ( atmin < threads_atimers[t] ? atmin : threads_atimers[t] ); atmax = ( atmax > threads_atimers[t] ? atmax : threads_atimers[t] ); #if defined(PROFILE) ctmin = ( ctmin < threads_ctimers[t] ? ctmin : threads_ctimers[t] ); ctmax = ( ctmax > threads_ctimers[t] ? ctmax : threads_ctimers[t] ); #endif } printf("\n\nMandelbrot set with %d threads and scheduling %s\n" "took %g sec overall\n" " ·································\n" "thread min time: %g\n" "thread max time: %g\n" #if defined(PROFILE) " ·································\n" "thread calc min time: %g\n" "thread calc max time: %g\n" #endif " ·································\n", nthreads, schedule_type, time_all, atmin, atmax #if defined(PROFILE) , ctmin, ctmax #endif ); return; } /* ======================================================================================== */ /* Program entry point. */ int main (int argc, // number of command-line tokens char **argv // command-line token vector ) { options_t options; image_geometry_t geometry; render_stats_t stats; unsigned char *image; #if defined(PROFILE) unsigned char *timage; #endif size_t image_bytes; int parse_status; double inside_fraction; double average_iterations; uint64_t pixel_count; set_default_options (&options); parse_status = parse_command_line (argc, argv, &options); if (parse_status > 0) return EXIT_SUCCESS; if (parse_status < 0 || validate_options (&options) != 0 || make_geometry (&options, &geometry) != 0) return EXIT_FAILURE; if ((size_t) geometry.width > SIZE_MAX / (size_t) geometry.height || (size_t) geometry.width * (size_t) geometry.height > SIZE_MAX / 3u) { fprintf (stderr, "Image is too large for this platform\n"); return EXIT_FAILURE; } image_bytes = (size_t) geometry.width * (size_t) geometry.height * 3u; image = (unsigned char *) malloc (image_bytes); if (image == NULL) { fprintf (stderr, "Unable to allocate image buffer (%zu bytes)\n", image_bytes); return EXIT_FAILURE; } fprintf (stderr, "Rendering %u x %u pixels, kmax = %u, view = [%.17g, %.17g] x [%.17g, %.17g]\n", geometry.width, geometry.height, options.kmax, options.xmin, options.xmax, options.ymin, options.ymax); if (options.dx_factor != DEFAULT_DX_FACTOR) { fprintf (stderr, "Note: --dx-factor is accepted for assignment-interface compatibility; " "this OpenMP version does not use it.\n"); } #if defined(PROFILE) timage = (unsigned char *) malloc (image_bytes); render_image (&options, &geometry, image, timage); #else render_image (&options, &geometry, image); #endif int errio; if ( options.format == _MANDEL_PPM_ ) errio = write_ppm_image (image, geometry.width, geometry.height, options.output_path); else if ( options.format == _MANDEL_PNG_ ) errio = write_png_rgb8 (options.output_path, geometry.width, geometry.height, image); else { fprintf (stderr, "Unknown output format %u\n", options.format); errio = -1; } free (image); if ( errio != 0 ) return EXIT_FAILURE; #if defined(PROFILE) char buffer[strlen(options.output_path)+5]; sprintf( buffer, "%s.dat", options.output_path); if (write_ppm_image (timage, geometry.width, geometry.height, buffer) != 0) { free (timage); return EXIT_FAILURE; } free (timage); #endif if ( options.mode == 0) { pixel_count = (uint64_t) geometry.width * (uint64_t) geometry.height; inside_fraction = (double) stats.inside_pixels / (double) pixel_count; average_iterations = (double) stats.total_iterations / (double) pixel_count; printf ("output_file %s\n", options.output_path); printf ("width %u\n", geometry.width); printf ("height %u\n", geometry.height); printf ("kmax %u\n", options.kmax); printf ("iteration_checksum %016llx\n", (unsigned long long) stats.checksum); printf ("inside_pixels %llu\n", (unsigned long long) stats.inside_pixels); printf ("inside_fraction %.17g\n", inside_fraction); printf ("average_iterations %.17g\n", average_iterations); printf ("total_iterations %llu\n", (unsigned long long) stats.total_iterations); } return EXIT_SUCCESS; } OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot_loop.omp.h.pre_warnfix 0 → 100644 +28 −0 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot_loop.omp.h.pre_warnfix: 28 added lines, 0 removed lines. Original line number Diff line number Diff line for ( int row = 0; row < Nrows; row++ ) for ( int col = 0; col < Ncols; col++ ) { #if defined(PROFILE) double my_inner_time = CPU_TIME_T; #endif double ci = options->ymax - ((double) row + 0.5) * geometry->dy; double cr = options->xmin + ((double) col + 0.5) * geometry->dx; unsigned int iteration = mandelbrot_escape (cr, ci, options->kmax); #if defined(PROFILE) my_inner_time = CPU_TIME_T - my_inner_time; my_calc_time += my_inner_time; #endif size_t pixel_offset = ((size_t) row * (size_t) geometry->width + (size_t) col) * 3u; colour_from_iteration (iteration, options->kmax, &image[pixel_offset]); #if defined(PROFILE) timage[pixel_offset] = myid; #endif } OpenMP/exercises/Mandelbrot/openmp_solution/Makefile +8 −2 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/Makefile: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -9,15 +9,21 @@ # No external library is required: PNG output goes through the # single-header stb_image_write.h, and libm is not needed. # Disable make's built-in rules: otherwise, if a prerequisite of our %.o rule # is missing (e.g. a misspelled header), make silently falls back to its own # "%.o: %.c" rule, which does not pass $(OMP), and the OpenMP pragmas are # ignored without any error. MAKEFLAGS += --no-builtin-rules CC ?= gcc CFLAGS ?= -O3 -march=native -mtune=native -Wall -Wextra OMP = -fopenmp LDFLAGS ?= TARGET = mandelbrot_omp SRCS = mandelbrot.omp.c mandelbrot_utilities.c SRCS = mandelbrot.omp.c mandelbrot_utilities.omp.c OBJS = $(SRCS:.c=.o) HEADERS = mandelbrot_omp.h mandelbrot_loop.h stb_image_write.h HEADERS = mandelbrot.omp.h mandelbrot_loop.omp.h stb_image_write.h all: $(TARGET) Loading OpenMP/exercises/Mandelbrot/openmp_solution/mandelbrot.omp.c +90 −28 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/mandelbrot.omp.c: 90 added lines, 28 removed lines. Original line number Diff line number Diff line Loading @@ -134,20 +134,57 @@ colour_from_iteration (unsigned int iteration, // escape iteration count } static void /* Render the whole image with OpenMP. The scheduling policy is selected by options->mode (0: static; n > 0: static with n-row chunks; n < 0: dynamic with -n pixel chunks over the collapsed loops). Per-thread timings are collected and printed. The diagnostics in *stats are computed after the parallel region from the stored iteration counts, in row-major order, so they are identical to those of the serial renderer for any schedule and thread count. Returns 0 on success, -1 if the iteration buffer cannot be allocated. */ static int render_image (options_t *options, // view, factors, and kmax image_geometry_t *geometry, // image dimensions and pixel spacing unsigned char *image // complete row-major RGB image buffer unsigned char *image, // complete row-major RGB image buffer render_stats_t *stats // output diagnostics #if defined(PROFILE) , unsigned char *timage , unsigned char *timage // per-pixel thread id map (R channel) #endif ) { uint64_t Nrows = geometry->height; uint64_t Ncols = geometry->width; unsigned int Nrows = geometry->height; unsigned int Ncols = geometry->width; size_t Npixels = (size_t) Nrows * (size_t) Ncols; // The schedule is decided once, by the master, before the parallel region: // options->mode is shared and must not be modified inside it. int mode = options->mode; int chunk = ( mode < 0 ? -mode : mode ); char schedule_type[64]; if ( mode == 0 ) snprintf( schedule_type, sizeof(schedule_type), "static, max chunk" ); else if ( mode > 0 ) snprintf( schedule_type, sizeof(schedule_type), "static, %d-line chunk", chunk ); else snprintf( schedule_type, sizeof(schedule_type), "dynamic, %d points chunk", chunk ); char schedule_type[20] = {0}; if ( Npixels > SIZE_MAX / sizeof(unsigned int) ) { fprintf (stderr, "Image is too large for the iteration buffer\n"); return -1; } unsigned int *iterations = (unsigned int *) malloc (Npixels * sizeof(unsigned int)); if ( iterations == NULL ) { fprintf (stderr, "Unable to allocate the iteration buffer (%zu bytes)\n", Npixels * sizeof(unsigned int)); return -1; } int nthreads; #pragma omp parallel Loading @@ -167,31 +204,24 @@ render_image (options_t *options, // view, factors, and kmax { int myid = omp_get_thread_num(); double mytime = CPU_TIME_T; #if defined(PROFILE) double my_calc_time = 0; #endif if ( options->mode == 0) if ( mode == 0 ) { #pragma omp single sprintf( schedule_type, "static, max chunk" ); #pragma omp for nowait #include "mandelbrot_loop.h" #include "mandelbrot_loop.omp.h" } else if (options->mode > 0) else if ( mode > 0 ) { #pragma omp single sprintf( schedule_type, "static, %d-line chunk", options->mode); #pragma omp for schedule(static, options->mode) nowait #include "mandelbrot_loop.h" #pragma omp for schedule(static, chunk) nowait #include "mandelbrot_loop.omp.h" } else { #pragma omp single { options->mode * -1; sprintf( schedule_type, "dynamic, %d points chunk", options->mode ); } #pragma omp for collapse(2) schedule(dynamic, options->mode) nowait #include "mandelbrot_loop.h" #pragma omp for collapse(2) schedule(dynamic, chunk) nowait #include "mandelbrot_loop.omp.h" } mytime = CPU_TIME_T - mytime; Loading @@ -202,6 +232,24 @@ render_image (options_t *options, // view, factors, and kmax } time_all = CPU_TIME_W - time_all; // diagnostics, serially and in row-major order, as in the serial code uint64_t checksum = FNV_OFFSET_BASIS; uint64_t total_iterations = 0u; uint64_t inside_pixels = 0u; for ( size_t p = 0; p < Npixels; p++ ) { checksum = checksum_update_uint (checksum, iterations[p]); total_iterations += (uint64_t) iterations[p]; inside_pixels += (iterations[p] >= options->kmax); } stats->checksum = checksum; stats->total_iterations = total_iterations; stats->inside_pixels = inside_pixels; free (iterations); double atmin = threads_atimers[0]; double atmax = threads_atimers[0]; Loading Loading @@ -239,7 +287,7 @@ render_image (options_t *options, // view, factors, and kmax #endif ); return; return 0; } Loading Loading @@ -306,9 +354,24 @@ main (int argc, // number of command-line tokens #if defined(PROFILE) timage = (unsigned char *) malloc (image_bytes); render_image (&options, &geometry, image, timage); if (timage == NULL) { fprintf (stderr, "Unable to allocate thread-map buffer (%zu bytes)\n", image_bytes); free (image); return EXIT_FAILURE; } if (render_image (&options, &geometry, image, &stats, timage) != 0) { free (timage); free (image); return EXIT_FAILURE; } #else render_image (&options, &geometry, image); if (render_image (&options, &geometry, image, &stats) != 0) { free (image); return EXIT_FAILURE; } #endif Loading Loading @@ -340,8 +403,8 @@ main (int argc, // number of command-line tokens free (timage); #endif if ( options.mode == 0) { // the statistics are schedule-independent (see render_image), hence they // are printed for every mode and can be compared with the serial run pixel_count = (uint64_t) geometry.width * (uint64_t) geometry.height; inside_fraction = (double) stats.inside_pixels / (double) pixel_count; average_iterations = (double) stats.total_iterations / (double) pixel_count; Loading @@ -355,7 +418,6 @@ main (int argc, // number of command-line tokens printf ("inside_fraction %.17g\n", inside_fraction); printf ("average_iterations %.17g\n", average_iterations); printf ("total_iterations %llu\n", (unsigned long long) stats.total_iterations); } return EXIT_SUCCESS; } Loading
OpenMP/exercises/Mandelbrot/openmp_solution/.backups/Makefile.pre_warnfix 0 → 100644 +39 −0 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/.backups/Makefile.pre_warnfix: 39 added lines, 0 removed lines. Original line number Diff line number Diff line # OpenMP Mandelbrot renderer # # make build mandelbrot_omp (optimised, -fopenmp) # make profile build mandelbrot_omp.profile with -DPROFILE: it also writes # <output>.dat, a per-pixel thread map for plot_thread_map.py # make debug build with -O0 -g # make clean remove objects and executables # # No external library is required: PNG output goes through the # single-header stb_image_write.h, and libm is not needed. CC ?= gcc CFLAGS ?= -O3 -march=native -mtune=native -Wall -Wextra OMP = -fopenmp LDFLAGS ?= TARGET = mandelbrot_omp SRCS = mandelbrot.omp.c mandelbrot_utilities.omp.c OBJS = $(SRCS:.c=.o) HEADERS = mandelbrot_omp.h mandelbrot_loop.omp.h stb_image_write.h all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(OMP) -o $@ $(OBJS) $(LDFLAGS) %.o: %.c $(HEADERS) $(CC) $(CFLAGS) $(OMP) -c -o $@ $< profile: $(SRCS) $(HEADERS) $(CC) $(CFLAGS) $(OMP) -DPROFILE -o $(TARGET).profile $(SRCS) $(LDFLAGS) debug: CFLAGS = -O0 -g -Wall -Wextra debug: clean $(TARGET) clean: rm -f $(TARGET) $(TARGET).profile $(OBJS) .PHONY: all profile debug clean
OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot.omp.c.pre_warnfix 0 → 100644 +361 −0 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot.omp.c.pre_warnfix: 361 added lines, 0 removed lines. Original line number Diff line number Diff line /* ────────────────────────────────────────────────────────────────────────── * │ │ │ This file is part of the exercises for the Lectures on │ │ "Foundations of High Performance Computing" │ │ given at │ │ Master in HPC and │ │ Master in Data Science and Scientific Computing │ │ @ SISSA, ICTP and University of Trieste │ │ │ │ contact: luca.tornatore@inaf.it │ │ │ │ This is free software; you can redistribute it and/or modify │ │ it under the terms of the GNU General Public License as published by │ │ the Free Software Foundation; either version 3 of the License, or │ │ (at your option) any later version. │ │ This code is distributed in the hope that it will be useful, │ │ but WITHOUT ANY WARRANTY; without even the implied warranty of │ │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the │ │ GNU General Public License for more details. │ │ │ │ You should have received a copy of the GNU General Public License │ │ along with this program. If not, see <http://www.gnu.org/licenses/> │ │ │ * ────────────────────────────────────────────────────────────────────────── */ /* OpenMP Mandelbrot renderer for the HPC final-exam exercise. This is the OpenMP solution of the serial baseline in ../ : the pixel loop (mandelbrot_loop.h) is distributed among threads with a scheduling policy chosen at run time through --mode, and per-thread timings are collected to discuss load balancing. Compile with -DPROFILE to also dump, next to the image, a map of which thread computed each pixel (<output>.dat), to be plotted with plot_thread_map.py. Command-line parsing and image writers (PPM or PNG, through the stb header) are in mandelbrot_utilities.c; shared declarations are in mandelbrot_omp.h. Have fun. */ // hint for timing // you can use either the TIME macro that you find in the examples/timing.h header // or // omp_get_wtime() // that returns the wall-clock time per thread // #include "mandelbrot.omp.h" /* ======================================================================================== : ------------------------------------------------------ : : CALCULATION FUNCTIONS : : ------------------------------------------------------ : */ /* Compute the Mandelbrot escape iteration for one point c = cr + i ci. This is the direct scalar kernel, clean, keeps the operation count easy to read. This can be heavility optimized. */ static unsigned int mandelbrot_escape (double cr, // real part of the pixel centre double ci, // imaginary part of the pixel centre unsigned int kmax // maximum number of iterations ) { double zr; double zi; double zr_next; double zr2; double zi2; unsigned int k; zr = 0.0; zi = 0.0; k = 0; while (k < kmax) { zr2 = zr * zr; zi2 = zi * zi; if (zr2 + zi2 > 4.0) break; zr_next = zr2 - zi2 + cr; zi = 2.0 * zr * zi + ci; zr = zr_next; k += 1; } return k; } /* Map one iteration count to an RGB colour. Interior points are black. The outside palette is deliberately simple. It might be fun experimenting by advanced colouring or smooth-potential formulas. Don't be distracted by this, though */ static void colour_from_iteration (unsigned int iteration, // escape iteration count unsigned int kmax, // maximum iteration count unsigned char *rgb // output triplet: red, green, blue ) { double t; double one_minus_t; if (iteration >= kmax) { rgb[0] = 0u; rgb[1] = 0u; rgb[2] = 0u; return; } t = (double) iteration / (double) kmax; one_minus_t = 1.0 - t; rgb[0] = (unsigned char) (255.0 * 9.0 * one_minus_t * t * t * t); rgb[1] = (unsigned char) (255.0 * 15.0 * one_minus_t * one_minus_t * t * t); rgb[2] = (unsigned char) (255.0 * 8.5 * one_minus_t * one_minus_t * one_minus_t * t); } static void render_image (options_t *options, // view, factors, and kmax image_geometry_t *geometry, // image dimensions and pixel spacing unsigned char *image // complete row-major RGB image buffer #if defined(PROFILE) , unsigned char *timage #endif ) { uint64_t Nrows = geometry->height; uint64_t Ncols = geometry->width; char schedule_type[20] = {0}; int nthreads; #pragma omp parallel #pragma omp single nthreads = omp_get_num_threads(); double threads_atimers[nthreads]; #if defined(PROFILE) double threads_ctimers[nthreads]; memset( threads_ctimers, 0, nthreads*sizeof(double)); #endif double time_all = CPU_TIME_W; #pragma omp parallel { int myid = omp_get_thread_num(); double mytime = CPU_TIME_T; double my_calc_time = 0; if ( options->mode == 0) { #pragma omp single sprintf( schedule_type, "static, max chunk" ); #pragma omp for nowait #include "mandelbrot_loop.omp.h" } else if (options->mode > 0) { #pragma omp single sprintf( schedule_type, "static, %d-line chunk", options->mode); #pragma omp for schedule(static, options->mode) nowait #include "mandelbrot_loop.omp.h" } else { #pragma omp single { options->mode * -1; sprintf( schedule_type, "dynamic, %d points chunk", options->mode ); } #pragma omp for collapse(2) schedule(dynamic, options->mode) nowait #include "mandelbrot_loop.omp.h" } mytime = CPU_TIME_T - mytime; threads_atimers[ myid ] = mytime; #if defined(PROFILE) threads_ctimers[myid] = my_calc_time; #endif } time_all = CPU_TIME_W - time_all; double atmin = threads_atimers[0]; double atmax = threads_atimers[0]; #if defined(PROFILE) double ctmin = threads_ctimers[0]; double ctmax = threads_ctimers[0]; #endif for ( int t = 1; t < nthreads; t++ ) { atmin = ( atmin < threads_atimers[t] ? atmin : threads_atimers[t] ); atmax = ( atmax > threads_atimers[t] ? atmax : threads_atimers[t] ); #if defined(PROFILE) ctmin = ( ctmin < threads_ctimers[t] ? ctmin : threads_ctimers[t] ); ctmax = ( ctmax > threads_ctimers[t] ? ctmax : threads_ctimers[t] ); #endif } printf("\n\nMandelbrot set with %d threads and scheduling %s\n" "took %g sec overall\n" " ·································\n" "thread min time: %g\n" "thread max time: %g\n" #if defined(PROFILE) " ·································\n" "thread calc min time: %g\n" "thread calc max time: %g\n" #endif " ·································\n", nthreads, schedule_type, time_all, atmin, atmax #if defined(PROFILE) , ctmin, ctmax #endif ); return; } /* ======================================================================================== */ /* Program entry point. */ int main (int argc, // number of command-line tokens char **argv // command-line token vector ) { options_t options; image_geometry_t geometry; render_stats_t stats; unsigned char *image; #if defined(PROFILE) unsigned char *timage; #endif size_t image_bytes; int parse_status; double inside_fraction; double average_iterations; uint64_t pixel_count; set_default_options (&options); parse_status = parse_command_line (argc, argv, &options); if (parse_status > 0) return EXIT_SUCCESS; if (parse_status < 0 || validate_options (&options) != 0 || make_geometry (&options, &geometry) != 0) return EXIT_FAILURE; if ((size_t) geometry.width > SIZE_MAX / (size_t) geometry.height || (size_t) geometry.width * (size_t) geometry.height > SIZE_MAX / 3u) { fprintf (stderr, "Image is too large for this platform\n"); return EXIT_FAILURE; } image_bytes = (size_t) geometry.width * (size_t) geometry.height * 3u; image = (unsigned char *) malloc (image_bytes); if (image == NULL) { fprintf (stderr, "Unable to allocate image buffer (%zu bytes)\n", image_bytes); return EXIT_FAILURE; } fprintf (stderr, "Rendering %u x %u pixels, kmax = %u, view = [%.17g, %.17g] x [%.17g, %.17g]\n", geometry.width, geometry.height, options.kmax, options.xmin, options.xmax, options.ymin, options.ymax); if (options.dx_factor != DEFAULT_DX_FACTOR) { fprintf (stderr, "Note: --dx-factor is accepted for assignment-interface compatibility; " "this OpenMP version does not use it.\n"); } #if defined(PROFILE) timage = (unsigned char *) malloc (image_bytes); render_image (&options, &geometry, image, timage); #else render_image (&options, &geometry, image); #endif int errio; if ( options.format == _MANDEL_PPM_ ) errio = write_ppm_image (image, geometry.width, geometry.height, options.output_path); else if ( options.format == _MANDEL_PNG_ ) errio = write_png_rgb8 (options.output_path, geometry.width, geometry.height, image); else { fprintf (stderr, "Unknown output format %u\n", options.format); errio = -1; } free (image); if ( errio != 0 ) return EXIT_FAILURE; #if defined(PROFILE) char buffer[strlen(options.output_path)+5]; sprintf( buffer, "%s.dat", options.output_path); if (write_ppm_image (timage, geometry.width, geometry.height, buffer) != 0) { free (timage); return EXIT_FAILURE; } free (timage); #endif if ( options.mode == 0) { pixel_count = (uint64_t) geometry.width * (uint64_t) geometry.height; inside_fraction = (double) stats.inside_pixels / (double) pixel_count; average_iterations = (double) stats.total_iterations / (double) pixel_count; printf ("output_file %s\n", options.output_path); printf ("width %u\n", geometry.width); printf ("height %u\n", geometry.height); printf ("kmax %u\n", options.kmax); printf ("iteration_checksum %016llx\n", (unsigned long long) stats.checksum); printf ("inside_pixels %llu\n", (unsigned long long) stats.inside_pixels); printf ("inside_fraction %.17g\n", inside_fraction); printf ("average_iterations %.17g\n", average_iterations); printf ("total_iterations %llu\n", (unsigned long long) stats.total_iterations); } return EXIT_SUCCESS; }
OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot_loop.omp.h.pre_warnfix 0 → 100644 +28 −0 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/.backups/mandelbrot_loop.omp.h.pre_warnfix: 28 added lines, 0 removed lines. Original line number Diff line number Diff line for ( int row = 0; row < Nrows; row++ ) for ( int col = 0; col < Ncols; col++ ) { #if defined(PROFILE) double my_inner_time = CPU_TIME_T; #endif double ci = options->ymax - ((double) row + 0.5) * geometry->dy; double cr = options->xmin + ((double) col + 0.5) * geometry->dx; unsigned int iteration = mandelbrot_escape (cr, ci, options->kmax); #if defined(PROFILE) my_inner_time = CPU_TIME_T - my_inner_time; my_calc_time += my_inner_time; #endif size_t pixel_offset = ((size_t) row * (size_t) geometry->width + (size_t) col) * 3u; colour_from_iteration (iteration, options->kmax, &image[pixel_offset]); #if defined(PROFILE) timage[pixel_offset] = myid; #endif }
OpenMP/exercises/Mandelbrot/openmp_solution/Makefile +8 −2 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/Makefile: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -9,15 +9,21 @@ # No external library is required: PNG output goes through the # single-header stb_image_write.h, and libm is not needed. # Disable make's built-in rules: otherwise, if a prerequisite of our %.o rule # is missing (e.g. a misspelled header), make silently falls back to its own # "%.o: %.c" rule, which does not pass $(OMP), and the OpenMP pragmas are # ignored without any error. MAKEFLAGS += --no-builtin-rules CC ?= gcc CFLAGS ?= -O3 -march=native -mtune=native -Wall -Wextra OMP = -fopenmp LDFLAGS ?= TARGET = mandelbrot_omp SRCS = mandelbrot.omp.c mandelbrot_utilities.c SRCS = mandelbrot.omp.c mandelbrot_utilities.omp.c OBJS = $(SRCS:.c=.o) HEADERS = mandelbrot_omp.h mandelbrot_loop.h stb_image_write.h HEADERS = mandelbrot.omp.h mandelbrot_loop.omp.h stb_image_write.h all: $(TARGET) Loading
OpenMP/exercises/Mandelbrot/openmp_solution/mandelbrot.omp.c +90 −28 Changes for OpenMP/exercises/Mandelbrot/openmp_solution/mandelbrot.omp.c: 90 added lines, 28 removed lines. Original line number Diff line number Diff line Loading @@ -134,20 +134,57 @@ colour_from_iteration (unsigned int iteration, // escape iteration count } static void /* Render the whole image with OpenMP. The scheduling policy is selected by options->mode (0: static; n > 0: static with n-row chunks; n < 0: dynamic with -n pixel chunks over the collapsed loops). Per-thread timings are collected and printed. The diagnostics in *stats are computed after the parallel region from the stored iteration counts, in row-major order, so they are identical to those of the serial renderer for any schedule and thread count. Returns 0 on success, -1 if the iteration buffer cannot be allocated. */ static int render_image (options_t *options, // view, factors, and kmax image_geometry_t *geometry, // image dimensions and pixel spacing unsigned char *image // complete row-major RGB image buffer unsigned char *image, // complete row-major RGB image buffer render_stats_t *stats // output diagnostics #if defined(PROFILE) , unsigned char *timage , unsigned char *timage // per-pixel thread id map (R channel) #endif ) { uint64_t Nrows = geometry->height; uint64_t Ncols = geometry->width; unsigned int Nrows = geometry->height; unsigned int Ncols = geometry->width; size_t Npixels = (size_t) Nrows * (size_t) Ncols; // The schedule is decided once, by the master, before the parallel region: // options->mode is shared and must not be modified inside it. int mode = options->mode; int chunk = ( mode < 0 ? -mode : mode ); char schedule_type[64]; if ( mode == 0 ) snprintf( schedule_type, sizeof(schedule_type), "static, max chunk" ); else if ( mode > 0 ) snprintf( schedule_type, sizeof(schedule_type), "static, %d-line chunk", chunk ); else snprintf( schedule_type, sizeof(schedule_type), "dynamic, %d points chunk", chunk ); char schedule_type[20] = {0}; if ( Npixels > SIZE_MAX / sizeof(unsigned int) ) { fprintf (stderr, "Image is too large for the iteration buffer\n"); return -1; } unsigned int *iterations = (unsigned int *) malloc (Npixels * sizeof(unsigned int)); if ( iterations == NULL ) { fprintf (stderr, "Unable to allocate the iteration buffer (%zu bytes)\n", Npixels * sizeof(unsigned int)); return -1; } int nthreads; #pragma omp parallel Loading @@ -167,31 +204,24 @@ render_image (options_t *options, // view, factors, and kmax { int myid = omp_get_thread_num(); double mytime = CPU_TIME_T; #if defined(PROFILE) double my_calc_time = 0; #endif if ( options->mode == 0) if ( mode == 0 ) { #pragma omp single sprintf( schedule_type, "static, max chunk" ); #pragma omp for nowait #include "mandelbrot_loop.h" #include "mandelbrot_loop.omp.h" } else if (options->mode > 0) else if ( mode > 0 ) { #pragma omp single sprintf( schedule_type, "static, %d-line chunk", options->mode); #pragma omp for schedule(static, options->mode) nowait #include "mandelbrot_loop.h" #pragma omp for schedule(static, chunk) nowait #include "mandelbrot_loop.omp.h" } else { #pragma omp single { options->mode * -1; sprintf( schedule_type, "dynamic, %d points chunk", options->mode ); } #pragma omp for collapse(2) schedule(dynamic, options->mode) nowait #include "mandelbrot_loop.h" #pragma omp for collapse(2) schedule(dynamic, chunk) nowait #include "mandelbrot_loop.omp.h" } mytime = CPU_TIME_T - mytime; Loading @@ -202,6 +232,24 @@ render_image (options_t *options, // view, factors, and kmax } time_all = CPU_TIME_W - time_all; // diagnostics, serially and in row-major order, as in the serial code uint64_t checksum = FNV_OFFSET_BASIS; uint64_t total_iterations = 0u; uint64_t inside_pixels = 0u; for ( size_t p = 0; p < Npixels; p++ ) { checksum = checksum_update_uint (checksum, iterations[p]); total_iterations += (uint64_t) iterations[p]; inside_pixels += (iterations[p] >= options->kmax); } stats->checksum = checksum; stats->total_iterations = total_iterations; stats->inside_pixels = inside_pixels; free (iterations); double atmin = threads_atimers[0]; double atmax = threads_atimers[0]; Loading Loading @@ -239,7 +287,7 @@ render_image (options_t *options, // view, factors, and kmax #endif ); return; return 0; } Loading Loading @@ -306,9 +354,24 @@ main (int argc, // number of command-line tokens #if defined(PROFILE) timage = (unsigned char *) malloc (image_bytes); render_image (&options, &geometry, image, timage); if (timage == NULL) { fprintf (stderr, "Unable to allocate thread-map buffer (%zu bytes)\n", image_bytes); free (image); return EXIT_FAILURE; } if (render_image (&options, &geometry, image, &stats, timage) != 0) { free (timage); free (image); return EXIT_FAILURE; } #else render_image (&options, &geometry, image); if (render_image (&options, &geometry, image, &stats) != 0) { free (image); return EXIT_FAILURE; } #endif Loading Loading @@ -340,8 +403,8 @@ main (int argc, // number of command-line tokens free (timage); #endif if ( options.mode == 0) { // the statistics are schedule-independent (see render_image), hence they // are printed for every mode and can be compared with the serial run pixel_count = (uint64_t) geometry.width * (uint64_t) geometry.height; inside_fraction = (double) stats.inside_pixels / (double) pixel_count; average_iterations = (double) stats.total_iterations / (double) pixel_count; Loading @@ -355,7 +418,6 @@ main (int argc, // number of command-line tokens printf ("inside_fraction %.17g\n", inside_fraction); printf ("average_iterations %.17g\n", average_iterations); printf ("total_iterations %llu\n", (unsigned long long) stats.total_iterations); } return EXIT_SUCCESS; }