Skip to content

Commit 21359c4

Browse files
committed
In C with improved thread handling.
1 parent 69edaff commit 21359c4

File tree

4 files changed

+424
-0
lines changed

4 files changed

+424
-0
lines changed

modern/build_c.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
for i in {1,2,4,6,8,12}
4+
do
5+
echo "Speccy standard, 32x22, 15 max iteration, $i thread"
6+
gcc -o man_speccy_$i -Ofast -DWIDTH=32 -DHEIGHT=22 -DMAX_ITER=15 -DNUM_THREADS=$i mandelbrot.c -lpthread
7+
done
8+
9+
for i in {1,2,4,6,8,12}
10+
do
11+
echo "EGA/NTSC standard, 320x200, 16 max iteration, $i thread"
12+
gcc -o man_ega_$i -Ofast -DWIDTH=320 -DHEIGHT=200 -DMAX_ITER=16 -DNUM_THREADS=$i mandelbrot.c -lpthread
13+
done
14+
15+
for i in {1,2,4,6,8,12,16,24,32,48,64,96,128}
16+
do
17+
echo "4K UHD, 3840x2160, 2000 max iteration, $i thread"
18+
gcc -o man_4k_2000_$i -Ofast -DWIDTH=3840 -DHEIGHT=2160 -DMAX_ITER=2000 -DNUM_THREADS=$i mandelbrot.c -lpthread
19+
done

modern/mandelbrot.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <pthread.h>
4+
5+
#ifndef WIDTH
6+
#define WIDTH 3840
7+
#endif
8+
9+
#ifndef HEIGHT
10+
#define HEIGHT 2160
11+
#endif
12+
13+
#ifndef MAX_ITER
14+
#define MAX_ITER 2000
15+
#endif
16+
17+
#ifndef NUM_THREADS
18+
#define NUM_THREADS 12
19+
#endif
20+
21+
#if NUM_THREADS > HEIGHT
22+
#error "Can't have more threads than pixel rows!"
23+
#endif
24+
25+
void set_pixel(unsigned char *img, int x, int y, unsigned char *color);
26+
unsigned char *create_image(int w, int h);
27+
void write_ppm(char *name, int w, int h, unsigned char *img);
28+
29+
unsigned char **palette;
30+
31+
unsigned char cga_palette[16][3] = { // CGA 16-color palette, as RGB
32+
{0x00,0x00,0x00},
33+
{0x00,0x00,0xAA},
34+
{0x00,0xAA,0x00},
35+
{0x00,0xAA,0xAA},
36+
{0xAA,0x00,0x00},
37+
{0xAA,0x00,0xAA},
38+
{0xAA,0x55,0x00},
39+
{0xAA,0xAA,0xAA},
40+
{0x55,0x55,0x55},
41+
{0x55,0x55,0xFF},
42+
{0x55,0xFF,0x55},
43+
{0x55,0xFF,0xFF},
44+
{0xFF,0x55,0x55},
45+
{0xFF,0x55,0xFF},
46+
{0xFF,0xFF,0x55},
47+
{0xFF,0xFF,0xFF}
48+
};
49+
50+
int next_row=0;
51+
pthread_mutex_t lock;
52+
unsigned char *img;
53+
54+
void dorow(int py) {
55+
int px,i;
56+
double xz,yz,x,y,xt;
57+
58+
for (px=0; px<WIDTH; px++) {
59+
xz = (double)px*3.5/WIDTH-2.5;
60+
yz = (double)py*2.0/HEIGHT-1.0;
61+
x = 0.0;
62+
y = 0.0;
63+
for (i=0; i<MAX_ITER; i++) {
64+
if (x*x+y*y > 4) {
65+
break;
66+
}
67+
xt = x*x - y*y + xz;
68+
y = 2*x*y + yz;
69+
x = xt;
70+
}
71+
if (i >= MAX_ITER) {
72+
i = 0;
73+
}
74+
set_pixel(img, px, py, palette[i]);
75+
}
76+
}
77+
78+
void *rowthread(void *v) {
79+
int row;
80+
81+
for(;;) {
82+
pthread_mutex_lock(&lock);
83+
row=next_row++;
84+
pthread_mutex_unlock(&lock);
85+
if(row>=HEIGHT) break;
86+
dorow(row);
87+
}
88+
}
89+
90+
int main() {
91+
double start, end;
92+
struct timespec tspec;
93+
int py,i;
94+
pthread_t rowthreads[NUM_THREADS-1];
95+
96+
img = create_image(WIDTH, HEIGHT);
97+
palette=malloc(MAX_ITER*sizeof(unsigned char *));
98+
for (int j=0; j<MAX_ITER; j++) palette[j]=malloc(3*sizeof(unsigned char));
99+
clock_gettime(CLOCK_REALTIME, &tspec);
100+
start = tspec.tv_sec+1e-9*tspec.tv_nsec;
101+
102+
for (i=0; i<MAX_ITER; i++) {
103+
if (i<16) {
104+
palette[i][0] = cga_palette[i][0];
105+
palette[i][1] = cga_palette[i][1];
106+
palette[i][2] = cga_palette[i][2];
107+
} else if (i % 16 == 0) {
108+
palette[i][0] = i & 0x10 ? 255 : 0;
109+
palette[i][1] = i & 0x20 ? 255 : 0;
110+
palette[i][2] = i & 0x40 ? 255 : 0;
111+
if ((i & 0x70) == 0) {
112+
palette[i][0] = 255;
113+
palette[i][1] = 128;
114+
}
115+
} else {
116+
palette[i][0] = palette[i-1][0] > 16 ? palette[i-1][0] - 16 : 0;
117+
palette[i][1] = palette[i-1][1] > 16 ? palette[i-1][1] - 16 : 0;
118+
palette[i][2] = palette[i-1][2] > 16 ? palette[i-1][2] - 16 : 0;
119+
}
120+
}
121+
122+
for (i=0; i<NUM_THREADS-1; i++)
123+
pthread_create(rowthreads+i, NULL, rowthread, NULL);
124+
rowthread(NULL);
125+
for(i=0; i<NUM_THREADS-1; i++) pthread_join(rowthreads[i], NULL);
126+
127+
128+
write_ppm("mandelbrot.ppm", WIDTH, HEIGHT, img);
129+
130+
clock_gettime(CLOCK_REALTIME, &tspec);
131+
end = tspec.tv_sec+1e-9*tspec.tv_nsec;
132+
133+
printf("Elapsed Time: %f s\n", end-start);
134+
135+
return 0;
136+
}
137+
138+
unsigned char *create_image(int w, int h) {
139+
unsigned char *rv;
140+
141+
return rv = malloc(w*h*3);
142+
}
143+
144+
void set_pixel(unsigned char *img, int x, int y, unsigned char *color) {
145+
img[3*(x+y*WIDTH)+0] = color[0]; // Red
146+
img[3*(x+y*WIDTH)+1] = color[1]; // Green
147+
img[3*(x+y*WIDTH)+2] = color[2]; // Blue
148+
}
149+
150+
void write_ppm(char *name, int w, int h, unsigned char *img) {
151+
FILE *out;
152+
153+
if (!(out=fopen(name, "w"))) {
154+
fprintf(stderr, "Unable to open %s for writing\n", name);
155+
return;
156+
}
157+
fprintf(out, "P6\n%d %d\n255\n", WIDTH, HEIGHT);
158+
fwrite(img, 3, w*h, out);
159+
fclose(out);
160+
}
161+

modern/mandelbrot_2.c

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <pthread.h>
4+
#include <getopt.h>
5+
#include <errno.h>
6+
7+
#ifndef WIDTH
8+
#define WIDTH 3840
9+
#endif
10+
11+
#ifndef HEIGHT
12+
#define HEIGHT 2160
13+
#endif
14+
15+
#ifndef MAX_ITER
16+
#define MAX_ITER 2000
17+
#endif
18+
19+
#ifndef NUM_THREADS
20+
#define NUM_THREADS 12
21+
#endif
22+
23+
#if NUM_THREADS > HEIGHT
24+
#error "Can't have more threads than pixel rows!"
25+
#endif
26+
27+
void set_pixel(unsigned char *img, int x, int y, unsigned char *color);
28+
unsigned char *create_image(int w, int h);
29+
void write_ppm(char *name, int w, int h, unsigned char *img);
30+
31+
unsigned char **palette;
32+
33+
unsigned char cga_palette[16][3] = { // CGA 16-color palette, as RGB
34+
{0x00,0x00,0x00},
35+
{0x00,0x00,0xAA},
36+
{0x00,0xAA,0x00},
37+
{0x00,0xAA,0xAA},
38+
{0xAA,0x00,0x00},
39+
{0xAA,0x00,0xAA},
40+
{0xAA,0x55,0x00},
41+
{0xAA,0xAA,0xAA},
42+
{0x55,0x55,0x55},
43+
{0x55,0x55,0xFF},
44+
{0x55,0xFF,0x55},
45+
{0x55,0xFF,0xFF},
46+
{0xFF,0x55,0x55},
47+
{0xFF,0x55,0xFF},
48+
{0xFF,0xFF,0x55},
49+
{0xFF,0xFF,0xFF}
50+
};
51+
52+
int next_row=0;
53+
pthread_mutex_t lock;
54+
unsigned char *img;
55+
int width=WIDTH;
56+
int height=HEIGHT;
57+
int max_iter=MAX_ITER;
58+
int num_threads=NUM_THREADS;
59+
60+
void dorow(int py) {
61+
int px,i;
62+
double xz,yz,x,y,xt;
63+
64+
for (px=0; px<width; px++) {
65+
xz = (double)px*3.5/width-2.5;
66+
yz = (double)py*2.0/height-1.0;
67+
x = 0.0;
68+
y = 0.0;
69+
for (i=0; i<max_iter; i++) {
70+
if (x*x+y*y > 4) {
71+
break;
72+
}
73+
xt = x*x - y*y + xz;
74+
y = 2*x*y + yz;
75+
x = xt;
76+
}
77+
if (i >= max_iter) {
78+
i = 0;
79+
}
80+
set_pixel(img, px, py, palette[i]);
81+
}
82+
}
83+
84+
void *rowthread(void *v) {
85+
int row;
86+
87+
for(;;) {
88+
pthread_mutex_lock(&lock);
89+
row=next_row++;
90+
pthread_mutex_unlock(&lock);
91+
if(row>=height) break;
92+
dorow(row);
93+
}
94+
}
95+
96+
int main(int argc, char *argv[]) {
97+
double start, end;
98+
struct timespec tspec;
99+
int py,i, opt;
100+
pthread_t *rowthreads;
101+
char opts[]="h:i:t:w:";
102+
struct option long_opts[] = {
103+
{ "height", 1, NULL, 'h'},
104+
{ "width", 1, NULL, 'w'},
105+
{ "iterations", 1, NULL, 'i'},
106+
{ "max_iter", 1, NULL, 'i'},
107+
{ "threads", 1, NULL, 't'},
108+
{ "num_threads", 1, NULL, 't'},
109+
{ NULL, 0, NULL, '\0'}
110+
};
111+
112+
while((opt=getopt_long(argc, argv, opts, long_opts, NULL))!=-1) {
113+
switch(opt) {
114+
case 'h':
115+
errno = 0;
116+
height = strtol(optarg, NULL, 10);
117+
if (errno || height<=0) {
118+
fprintf(stderr, "Invalid height: %s\n", optarg);
119+
return -1;
120+
}
121+
break;
122+
case 'i':
123+
errno = 0;
124+
max_iter = strtol(optarg, NULL, 10);
125+
if (errno || max_iter<=0) {
126+
fprintf(stderr, "Invalid number of iterations: %s\n", optarg);
127+
return -1;
128+
}
129+
break;
130+
case 'w':
131+
errno = 0;
132+
width = strtol(optarg, NULL, 10);
133+
if (errno || width<=0) {
134+
fprintf(stderr, "Invalid width: %s\n", optarg);
135+
return -1;
136+
}
137+
break;
138+
case 't':
139+
errno = 0;
140+
num_threads = strtol(optarg, NULL, 10);
141+
if (errno || num_threads<=0) {
142+
fprintf(stderr, "Invalid number of threads: %s\n", optarg);
143+
return -1;
144+
}
145+
break;
146+
}
147+
}
148+
if (num_threads>height) {
149+
fprintf(stderr, "Number of threads (%d) cannot be greater than height (%d)\n", num_threads, height);
150+
return -1;
151+
}
152+
153+
rowthreads = malloc(sizeof(pthread_t)*num_threads);
154+
img = create_image(width, height);
155+
palette=malloc(max_iter*sizeof(unsigned char *));
156+
for (int j=0; j<max_iter; j++) palette[j]=malloc(3*sizeof(unsigned char));
157+
clock_gettime(CLOCK_REALTIME, &tspec);
158+
start = tspec.tv_sec+1e-9*tspec.tv_nsec;
159+
160+
for (i=0; i<max_iter; i++) {
161+
if (i<16) {
162+
palette[i][0] = cga_palette[i][0];
163+
palette[i][1] = cga_palette[i][1];
164+
palette[i][2] = cga_palette[i][2];
165+
} else if (i % 16 == 0) {
166+
palette[i][0] = i & 0x10 ? 255 : 0;
167+
palette[i][1] = i & 0x20 ? 255 : 0;
168+
palette[i][2] = i & 0x40 ? 255 : 0;
169+
if ((i & 0x70) == 0) {
170+
palette[i][0] = 255;
171+
palette[i][1] = 128;
172+
}
173+
} else {
174+
palette[i][0] = palette[i-1][0] > 16 ? palette[i-1][0] - 16 : 0;
175+
palette[i][1] = palette[i-1][1] > 16 ? palette[i-1][1] - 16 : 0;
176+
palette[i][2] = palette[i-1][2] > 16 ? palette[i-1][2] - 16 : 0;
177+
}
178+
}
179+
180+
for (i=0; i<num_threads-1; i++)
181+
pthread_create(rowthreads+i, NULL, rowthread, NULL);
182+
rowthread(NULL);
183+
for(i=0; i<num_threads-1; i++) pthread_join(rowthreads[i], NULL);
184+
185+
write_ppm("mandelbrot.ppm", width, height, img);
186+
187+
clock_gettime(CLOCK_REALTIME, &tspec);
188+
end = tspec.tv_sec+1e-9*tspec.tv_nsec;
189+
190+
printf("Elapsed Time: %f s\n", end-start);
191+
192+
return 0;
193+
}
194+
195+
unsigned char *create_image(int w, int h) {
196+
unsigned char *rv;
197+
198+
return rv = malloc(w*h*3);
199+
}
200+
201+
void set_pixel(unsigned char *img, int x, int y, unsigned char *color) {
202+
img[3*(x+y*width)+0] = color[0]; // Red
203+
img[3*(x+y*width)+1] = color[1]; // Green
204+
img[3*(x+y*width)+2] = color[2]; // Blue
205+
}
206+
207+
void write_ppm(char *name, int w, int h, unsigned char *img) {
208+
FILE *out;
209+
210+
if (!(out=fopen(name, "w"))) {
211+
fprintf(stderr, "Unable to open %s for writing\n", name);
212+
return;
213+
}
214+
fprintf(out, "P6\n%d %d\n255\n", width, height);
215+
fwrite(img, 3, w*h, out);
216+
fclose(out);
217+
}

0 commit comments

Comments
 (0)