|
| 1 | +from charm4py import ray, charm |
| 2 | +import numpy as np |
| 3 | +import matplotlib.pyplot as plt |
| 4 | +import os |
| 5 | + |
| 6 | +# Compute whether a point is in the Mandelbrot set |
| 7 | +def mandelbrot_fast(re, im, max_iter): |
| 8 | + zr = zi = 0.0 |
| 9 | + for i in range(max_iter): |
| 10 | + zr2 = zr * zr |
| 11 | + zi2 = zi * zi |
| 12 | + if zr2 + zi2 > 4.0: |
| 13 | + return i |
| 14 | + zi = 2 * zr * zi + im |
| 15 | + zr = zr2 - zi2 + re |
| 16 | + return max_iter |
| 17 | + |
| 18 | +# Remote task to compute a tile |
| 19 | +@ray.remote |
| 20 | +def compute_tile(x_start, x_end, y_start, y_end, width, height, max_iter): |
| 21 | + tile = np.zeros((y_end - y_start, x_end - x_start), dtype=np.uint16) |
| 22 | + for y in range(y_start, y_end): |
| 23 | + for x in range(x_start, x_end): |
| 24 | + re = 3.5 * (x / width) - 2.5 |
| 25 | + im = 2.0 * (y / height) - 1.0 |
| 26 | + tile[y - y_start, x - x_start] = mandelbrot_fast(re, im, max_iter) |
| 27 | + return tile |
| 28 | + |
| 29 | +def generate_mandelbrot_image_optimized(width=12000, height=8000, max_iter=200, tile_size=1000, max_pending=1000): |
| 30 | + # Pre-create the empty file with the correct size |
| 31 | + total_bytes = 2 * width * height # 2 bytes per pixel (uint16) |
| 32 | + with open("output/mandelbrot_large.dat", "wb") as f: |
| 33 | + f.seek(total_bytes - 1) |
| 34 | + f.write(b'\0') |
| 35 | + result_image = np.memmap("output/mandelbrot_large.dat", dtype=np.uint16, mode='w+', shape=(height, width)) |
| 36 | + pending = [] |
| 37 | + |
| 38 | + for y in range(0, height, tile_size): |
| 39 | + for x in range(0, width, tile_size): |
| 40 | + x_end = min(x + tile_size, width) |
| 41 | + y_end = min(y + tile_size, height) |
| 42 | + tile_ref = compute_tile.remote(x, x_end, y, y_end, width, height, max_iter) |
| 43 | + pending.append(((x, y), tile_ref)) |
| 44 | + |
| 45 | + if len(pending) >= max_pending: |
| 46 | + (x0, y0), tile = pending.pop(0) |
| 47 | + tile = ray.get(tile) |
| 48 | + result_image[y0:y0+tile.shape[0], x0:x0+tile.shape[1]] = tile |
| 49 | + |
| 50 | + for (x0, y0), tile_ref in pending: |
| 51 | + tile = ray.get(tile_ref) |
| 52 | + result_image[y0:y0+tile.shape[0], x0:x0+tile.shape[1]] = tile |
| 53 | + |
| 54 | + return result_image |
| 55 | + |
| 56 | + |
| 57 | +def main(args): |
| 58 | + output_path = "output/mandelbrot_large.dat" |
| 59 | + os.makedirs(os.path.dirname(output_path), exist_ok=True) |
| 60 | + ray.init() |
| 61 | + # Run the benchmark |
| 62 | + image = generate_mandelbrot_image_optimized(width=int(args[1]), height=int(args[2]), max_iter=int(args[3]), tile_size=int(args[4])) |
| 63 | + # Optional: show the result |
| 64 | + plt.imshow(image, cmap='hot') |
| 65 | + plt.title("Mandelbrot Set (Ray)") |
| 66 | + plt.axis('off') |
| 67 | + plt.savefig("mandelbrot_ray.png", dpi=300, bbox_inches='tight') |
| 68 | + os.remove('output/mandelbrot_large.dat') |
| 69 | + charm.exit() |
| 70 | + |
| 71 | +charm.start(main) |
0 commit comments