162 lines
5.3 KiB
C++
162 lines
5.3 KiB
C++
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
typedef struct calc_hist_data_t
|
|
{
|
|
float *data_start; // start of the sequence chunk
|
|
float *data_end; // end of the sequence chunk
|
|
int a, b; // min and max range element values
|
|
int bin_count; // length of histogram
|
|
float interval; // how much to jump from bin to bin
|
|
} calc_hist_data_t;
|
|
|
|
// Computes a histogram based off on a sequence chunk.
|
|
void *calculate_histogram(void *hist_data)
|
|
{
|
|
calc_hist_data_t *arg = (calc_hist_data_t *)hist_data;
|
|
|
|
// Allocate some space to hold our locally computed histogram.
|
|
int *local_histogram = static_cast<int *>(calloc(arg->bin_count, sizeof(*local_histogram)));
|
|
|
|
// Computes the histogram of this data chunk.
|
|
for (float *pos = arg->data_start; pos != arg->data_end; ++pos)
|
|
{
|
|
int bin_index = (*pos - arg->a) / arg->interval;
|
|
local_histogram[bin_index] += 1;
|
|
}
|
|
|
|
// Exits the thread and returns my local histogram to the joiner.
|
|
pthread_exit(local_histogram);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
// Selects a "random" seed for the rand engine.
|
|
srand((unsigned int)time(NULL));
|
|
|
|
float a, b; // Min and max range values.
|
|
int data_count; // Length of the random numbers sequence.
|
|
int bin_count; // Number of bins in the histogram.
|
|
|
|
printf("Type in the values for: <a> <b> <data_count> <bin_count>: ");
|
|
fflush(stdout);
|
|
scanf("%f %f %d %d", &a, &b, &data_count, &bin_count);
|
|
|
|
// Interval between each bin.
|
|
float bin_size = (b - a) / (float)bin_count;
|
|
|
|
// Query the number of processors on this machine.
|
|
int thread_count = 1;
|
|
|
|
// Chunk size for each thread.
|
|
int thread_data_count = data_count / thread_count;
|
|
|
|
// Extra size that will be distributed to chunks later.
|
|
int spare_data_count = data_count % thread_count;
|
|
|
|
// Holds the sequence of the generated random numbers in the range [a, b].
|
|
float *data = static_cast<float *>(malloc(data_count * sizeof(*data)));
|
|
|
|
// Generate the sequence of random numbers in ther range [a, b].
|
|
for (int i = 0; i < data_count; ++i)
|
|
{
|
|
data[i] = (float)rand() / (float)RAND_MAX * (b - a) + a;
|
|
}
|
|
|
|
// Holds the handle of each thread.
|
|
pthread_t threads[thread_count];
|
|
|
|
// Holds the argument for each thread.
|
|
calc_hist_data_t *args = static_cast<calc_hist_data_t *>(calloc(thread_count, sizeof(*args)));
|
|
|
|
// Current chunk data start for an iteration.
|
|
float *local_data = data;
|
|
|
|
for (int i = 0; i < thread_count; ++i)
|
|
{
|
|
// Take `spare_data_count` into account when separating a chunk and
|
|
// decrement it at each iteration. This works because
|
|
// `spare_data_count` will never be equal to or greater than
|
|
// `thread_data_count`.
|
|
int chunk_start_length = thread_data_count + !!spare_data_count;
|
|
|
|
// Assigns this sequence chunk to this thread to process.
|
|
args[i] = (calc_hist_data_t){
|
|
.data_start = local_data,
|
|
.data_end = local_data + thread_data_count + !!spare_data_count,
|
|
.a = static_cast<int>(a),
|
|
.b = static_cast<int>(b),
|
|
.bin_count = bin_count,
|
|
.interval = bin_size,
|
|
};
|
|
|
|
// Advances the chunk start for the next iteration.
|
|
local_data += thread_data_count + !!spare_data_count;
|
|
|
|
if (spare_data_count)
|
|
--spare_data_count;
|
|
|
|
// Instantiate a thread to compute this chunk's histogram.
|
|
pthread_create(&threads[i], NULL, calculate_histogram,
|
|
(void *)&args[i]);
|
|
}
|
|
|
|
// Holds the sum of all local histograms.
|
|
int *histogram = static_cast<int *>(calloc(bin_count, sizeof(*histogram)));
|
|
|
|
// Computes the sum of all local histograms.
|
|
for (long i = 0; i < thread_count; ++i)
|
|
{
|
|
int *local_histogram = NULL;
|
|
// Wait for the thread `i` to finish running and sum its returned local
|
|
// histogram into our global histogram.
|
|
pthread_join(threads[i], (void **)&local_histogram);
|
|
for (int i = 0; i < bin_count; ++i)
|
|
{
|
|
histogram[i] += local_histogram[i];
|
|
}
|
|
free(local_histogram);
|
|
}
|
|
|
|
// Now, let's pretty print some information.
|
|
{
|
|
int max_bin_count = 0;
|
|
|
|
// Get the maximum bin counting value.
|
|
for (int i = 0; i < bin_count; ++i)
|
|
{
|
|
if (histogram[i] > max_bin_count)
|
|
max_bin_count = histogram[i];
|
|
}
|
|
|
|
// Pretty prints the histogram vector.
|
|
printf(
|
|
"sequence range: [%.2f, %.2f]\nsequence length: %d\nnumber of "
|
|
"bins: %d\n"
|
|
"bin_size: %.2f\n",
|
|
a, b, data_count, bin_count, bin_size);
|
|
for (int i = 0; i < bin_count; ++i)
|
|
{
|
|
float bin_index = (float)i * bin_size + a;
|
|
printf("[%.2f, %.2f) |", bin_index, bin_index + bin_size);
|
|
int row_width = ((float)histogram[i] / (float)max_bin_count) * 40.f;
|
|
for (int j = 0; j < row_width; ++j)
|
|
{
|
|
printf("#");
|
|
}
|
|
printf(" %d\n", histogram[i]);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
// You already know: looking for freeeeeedom!
|
|
free(data);
|
|
free(args);
|
|
free(histogram);
|
|
|
|
// Last thing that main() should do.
|
|
pthread_exit(NULL);
|
|
} |