update exerciseC

This commit is contained in:
morales-gregorio 2024-08-29 23:17:47 +02:00
parent 8c7ed4a1a9
commit b1a8862eb8
3 changed files with 65 additions and 75 deletions

View file

@ -1,67 +1,53 @@
import sys import os
import collections
import numpy as np import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patheffects as PathEffects
dts = collections.defaultdict(dict) N_processes = 5
N_threads = 5
for fname in sys.argv[1:]: # Load measured timings
values = open(fname).read().split() times = np.empty((N_processes, N_threads))
n1 = int(values[0]) for fname in os.listdir('timings'):
n2 = int(values[1]) values = open(f'timings/{fname}').read().split()
n_processes = int(values[0])
n_threads = int(values[1])
dt = float(values[2]) dt = float(values[2])
times[n_processes-1][n_threads-1] = dt
print(times)
dts[n1][n2] = dt """ Plot measured time"""
fig_time, axs_time = plt.subplots()
im = axs_time.imshow(times.T, origin='lower')
axs_time.set_title('Computation time')
fig_time.colorbar(im, ax=axs_time, label='Measured computation time (s)')
print(dts) """ Plot speedup """
N1 = max(dts) workers = np.arange(N_processes + 1)[:, None] * np.arange(N_threads + 1)
N2 = max(max(v) for v in dts.values()) speedup = times[0, 0] / times
print(N1, N2) fig_speedup, axs_speedup = plt.subplots()
im = axs_speedup.imshow(speedup.T, origin='lower')
axs_speedup.set_title('Computation speed-up')
fig_speedup.colorbar(im, ax=axs_speedup, label='Speed-up')
x = np.empty((N1 + 1, N2 + 1)) # Set same style for both plots
for n1, values in dts.items(): for axs, data in zip([axs_time, axs_speedup], [times, speedup]):
for n2, v in values.items(): axs.set_xlabel('# processes')
x[n1, n2] = v axs.set_ylabel('# threads')
axs.set_xticks(np.arange(N_processes))
axs.set_xticklabels(np.arange(N_processes)+1)
axs.set_yticks(np.arange(N_threads))
axs.set_yticklabels(np.arange(N_threads)+1)
x[:, 0] = np.nan for i in range(N_processes):
x[0, :] = np.nan for j in range(N_threads):
txt = axs.text(i, j, f'{data[i, j]:.2f}', fontsize=10, color='w',
ha='center', va='center', fontweight='bold')
txt.set_path_effects([PathEffects.withStroke(linewidth=0.5, foreground='k')])
axs.spines[['right', 'top']].set_visible(False)
print(x) # Save plots
fig_time.savefig('time.png', dpi=300)
fig_speedup.savefig('speedup.png', dpi=300)
from matplotlib import pyplot
fig, axes = pyplot.subplots()
im = axes.imshow(x, origin='lower')
axes.set_ylabel('# processes')
axes.set_xlabel('# threads')
axes.spines[['right', 'top']].set_visible(False)
axes.set_title('time')
fig.colorbar(im, ax=axes, label='s')
fig_small, axes = pyplot.subplots()
im = axes.imshow(x[:5, :5], origin='lower')
axes.set_ylabel('# processes')
axes.set_xlabel('# threads')
axes.spines[['right', 'top']].set_visible(False)
axes.set_title('time')
fig_small.colorbar(im, ax=axes, label='s')
workers = np.arange(N1 + 1)[:, None] * np.arange(N2 + 1)
speedup = x[1,1] / x
speedup[:, 0] = np.nan
speedup[0, :] = np.nan
figs, axes = pyplot.subplots()
im = axes.imshow(speedup, origin='lower')
axes.set_ylabel('# processes')
axes.set_xlabel('# threads')
axes.spines[['right', 'top']].set_visible(False)
axes.set_title('speedup')
figs.colorbar(im, ax=axes, label='s')
fig.savefig('time.svg')
fig_small.savefig('time_inset.svg')
figs.savefig('speedup.svg')
pyplot.show()

View file

@ -3,17 +3,11 @@ import sys
from multiprocessing import Pool as ProcessPool from multiprocessing import Pool as ProcessPool
import time import time
def process_image(fname): def process_image(input_tuple):
n_threads = os.getenv('OMP_NUM_THREADS', '(unset)')
print(f"Worker {fname=} OMP_NUM_THREADS={n_threads}")
# An image is an array with width, height and three (RGB) color channels fname, A = input_tuple
# (Sometimes there is a transparency channel too: RGBA) n_threads = os.getenv('OMP_NUM_THREADS', '(unset)')
im = Image.open(fname) print(f"Worker {fname=} OMP_NUM_THREADS={n_threads}", flush=True)
try:
A = np.median(im, axis=2)[::4, ::4]
except:
A = np.array(im)[::4, ::4]
# Decompose image # Decompose image
U, S, Vh = np.linalg.svd(A) U, S, Vh = np.linalg.svd(A)
@ -36,10 +30,10 @@ if __name__ == '__main__':
fnames = sys.argv[3:] fnames = sys.argv[3:]
# Check that the output folders exist, or create them if needed # Check that the output folders exist, or create them if needed
if not os.path.isdir('processed_images'): os.mkdir('processed_images')
if not os.path.isdir('timings'): os.mkdir('timings') if not os.path.isdir('timings'): os.mkdir('timings')
if not os.path.isdir('processed_images'): os.mkdir('processed_images')
print(f"Controller with {n_processes} processes and {n_threads} threads / worker") print(f"Controller with {n_processes} processes and {n_threads} threads / worker", flush=True)
# The environment that is set in the parent is inherited by child workers, # The environment that is set in the parent is inherited by child workers,
# we need to set the variable before numpy is imported! # we need to set the variable before numpy is imported!
@ -50,19 +44,28 @@ if __name__ == '__main__':
import numpy as np import numpy as np
from PIL import Image from PIL import Image
# Time the execution # I/O Load the images
image_arrays = []
for fname in fnames:
im = Image.open(fname)
A = np.array(im)
image_arrays.append((fname, A))
# Time the execution of the pool map
start_time = time.time() start_time = time.time()
with ProcessPool(n_processes) as p: with ProcessPool(n_processes) as p:
new_images = p.map(process_image, fnames) new_images = p.map(process_image, image_arrays)
elapsed_time = time.time() - start_time elapsed_time = time.time() - start_time
# I/O save the processed images
for im, fname in zip(new_images, fnames): for im, fname in zip(new_images, fnames):
im = Image.fromarray(im) im = Image.fromarray(im)
im.save(fname.replace('images', 'processed_images')) im.save(fname.replace('images', 'processed_images'))
print(f'{n_processes} processes and {n_threads} threads and {len(fnames)} jobs: {elapsed_time}') print(f'{n_processes} processes and {n_threads} threads and {len(fnames)} jobs: {elapsed_time}\n',
flush=True)
# IO: Save the timing to a unique txt file # I/O: Save the timing to a unique txt file
filename = f'timings/{n_processes:02}_processes_{n_threads:02}_threads.txt' filename = f'timings/{n_processes:02}_processes_{n_threads:02}_threads.txt'
with open(filename, 'w') as file: with open(filename, 'w') as file:
file.write(f'{n_processes} {n_threads} {elapsed_time:.6f}') file.write(f'{n_processes} {n_threads} {elapsed_time:.6f}')

View file

@ -1,7 +1,8 @@
# This is bash, it executes the python script multiple times # This is bash
for i in {1..10} # It runs the python script multiple times with different arguments
for i in {1..5} # Number of processes
do do
for j in {1..10} for j in {1..5} # Number of threads
do do
python process_images.py $i $j images/* python process_images.py $i $j images/*
done done