add multithreading
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add:
|
Add:
|
||||||
- "-std=c23"
|
- "-std=gnu23"
|
||||||
- "-xc"
|
- "-xc"
|
||||||
|
- "-march=native"
|
||||||
|
- "-mavx2"
|
||||||
Remove:
|
Remove:
|
||||||
- "-std=c++*"
|
- "-std=c++*"
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
*.png
|
||||||
|
.*
|
||||||
|
!/.gitignore
|
||||||
|
main
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
|
#include <errno.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/random.h>
|
#include <sys/random.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
float noise(float x, float y);
|
float noise(float x, float y);
|
||||||
float linear_interpolation(float a, float b, float t);
|
float linear_interpolation(float a, float b, float t);
|
||||||
@@ -13,14 +17,132 @@ float *pseudo_random_gradient_vector_get(float x, float y);
|
|||||||
|
|
||||||
static unsigned char random_bytes[1024];
|
static unsigned char random_bytes[1024];
|
||||||
|
|
||||||
int main() {
|
enum threaded { THRD_MULTI, THRD_SINGLE };
|
||||||
|
|
||||||
|
struct single_threaded_arg {
|
||||||
|
enum threaded type;
|
||||||
|
unsigned char *buffer;
|
||||||
|
int height;
|
||||||
|
int width;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multi_threaded_arg {
|
||||||
|
enum threaded type;
|
||||||
|
unsigned char *buffer;
|
||||||
|
int height_start;
|
||||||
|
int height_end;
|
||||||
|
int width;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *calculate(void *args) { // TODO: reorder functions by call order
|
||||||
|
int x = 0;
|
||||||
|
int height = 0, width = 0;
|
||||||
|
unsigned char *buffer;
|
||||||
|
|
||||||
|
if (args != NULL) {
|
||||||
|
enum threaded *threaded = (enum threaded *)args;
|
||||||
|
if (*threaded == THRD_SINGLE) {
|
||||||
|
struct single_threaded_arg *arg = (struct single_threaded_arg *)args;
|
||||||
|
height = arg->height;
|
||||||
|
width = arg->width;
|
||||||
|
buffer = arg->buffer;
|
||||||
|
} else if (*threaded == THRD_MULTI) {
|
||||||
|
struct multi_threaded_arg *arg = (struct multi_threaded_arg *)args;
|
||||||
|
|
||||||
|
x = arg->height_start;
|
||||||
|
height = arg->height_end;
|
||||||
|
width = arg->width;
|
||||||
|
buffer = arg->buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height == 0 || width == 0) {
|
||||||
|
printf("things have got seriously wrong!");
|
||||||
|
if (height == 0) {
|
||||||
|
printf(" height is 0!");
|
||||||
|
} else {
|
||||||
|
printf(" width is 0!");
|
||||||
|
}
|
||||||
|
printf(" aborting\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; x < height; ++x) {
|
||||||
|
for (int y = 0; y < width; ++y) {
|
||||||
|
float noise_val = noise(x * 0.05, y * 0.05);
|
||||||
|
unsigned char pixel = (unsigned char)((noise_val + 1.0f) * 127.5f);
|
||||||
|
|
||||||
|
buffer[y + x * width] = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void single_threaded(unsigned char *buffer, int height, int width) {
|
||||||
|
struct single_threaded_arg arg = {
|
||||||
|
.type = THRD_SINGLE, .buffer = buffer, .height = height, .width = width};
|
||||||
|
calculate(&arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void multi_threaded(unsigned char *buffer, int height, int width,
|
||||||
|
int thread_no) {
|
||||||
|
if (thread_no == 1) {
|
||||||
|
single_threaded(buffer, height, width);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t threads[thread_no];
|
||||||
|
const unsigned int rows_per_thread = height / thread_no;
|
||||||
|
printf("rows per thread: %u\n", rows_per_thread);
|
||||||
|
struct multi_threaded_arg *args_arr[thread_no];
|
||||||
|
for (int i = 0; i < thread_no; i++) {
|
||||||
|
const int height_start = i * rows_per_thread;
|
||||||
|
int height_end = (i + 1) * rows_per_thread;
|
||||||
|
if (i == thread_no - 1) {
|
||||||
|
height_end = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct multi_threaded_arg *arg;
|
||||||
|
arg = malloc(sizeof *arg);
|
||||||
|
|
||||||
|
*arg = (struct multi_threaded_arg){.type = THRD_MULTI,
|
||||||
|
.buffer = buffer,
|
||||||
|
.height_start = height_start,
|
||||||
|
.height_end = height_end,
|
||||||
|
.width = width};
|
||||||
|
pthread_create(&threads[i], NULL, calculate, arg);
|
||||||
|
args_arr[i] = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < thread_no; ++i) {
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
free(args_arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
int n = getrandom(random_bytes, 1024, 0);
|
int n = getrandom(random_bytes, 1024, 0);
|
||||||
if (n != 1024) {
|
if (n != 1024) {
|
||||||
fprintf(stderr, "err: getrandom didn't work out as planned\n");
|
fprintf(stderr, "err: getrandom didn't work out as planned\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = 1024, height = 1024;
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "err: must supply 3 params!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int width = atoi(argv[1]), height = atoi(argv[2]);
|
||||||
|
int threads = 1;
|
||||||
|
if (argc == 4) {
|
||||||
|
threads = atoi(argv[3]);
|
||||||
|
|
||||||
|
if (height < threads) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"err: rows < threads. expected: rows >= threads. aborting\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
png_image img;
|
png_image img;
|
||||||
memset(&img, 0, sizeof(img));
|
memset(&img, 0, sizeof(img));
|
||||||
@@ -30,19 +152,26 @@ int main() {
|
|||||||
img.version = PNG_IMAGE_VERSION;
|
img.version = PNG_IMAGE_VERSION;
|
||||||
|
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
printf("PNG IMAGE SIZE: %u\n", PNG_IMAGE_SIZE(img));
|
printf("PNG IMAGE SIZE: %u bytes\n", PNG_IMAGE_SIZE(img));
|
||||||
buffer = malloc(PNG_IMAGE_SIZE(img));
|
buffer = malloc(PNG_IMAGE_SIZE(img));
|
||||||
|
|
||||||
for (int x = 0; x < height; ++x) {
|
struct timespec start, end;
|
||||||
for (int y = 0; y < width; ++y) {
|
|
||||||
float noise_val = noise(x * 0.05, y * 0.05);
|
|
||||||
unsigned char pixel = (unsigned char)((noise_val + 1.0f) * 127.5f);
|
|
||||||
|
|
||||||
buffer[y + x * width] = pixel;
|
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||||
}
|
if (threads < 2)
|
||||||
}
|
single_threaded(buffer, height, width);
|
||||||
|
else
|
||||||
|
multi_threaded(buffer, height, width, threads);
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||||
|
printf("calculation time: %fs.\n", (double)(end.tv_sec - start.tv_sec) +
|
||||||
|
(end.tv_nsec - start.tv_nsec) / 1e9);
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||||
png_image_write_to_file(&img, "noise.png", 0, buffer, 0, NULL);
|
png_image_write_to_file(&img, "noise.png", 0, buffer, 0, NULL);
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||||
|
printf("write to file time (single-threaded): %fs.\n",
|
||||||
|
(double)(end.tv_sec - start.tv_sec) +
|
||||||
|
(end.tv_nsec - start.tv_nsec) / 1e9);
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user