简体   繁体   中英

Measuring speed up of a multi threaded C program (implementation using Pthreads)

I currently have a multi-threaded C program coded using Pthreads which uses 2 threads. I want to increase the no. of threads and measure speed up upon doing so. I would like to run my code in an automated manner where the no. of threads used keeps getting incremented and I want to graphically display running times of my code. I would love it if I could get a clue in on how to do so especially on how to automate the entire process and plotting it graphically. Here is my code:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 2
#define VECTOR_SIZE 40

struct DOTdata
{
    /* data */
    long X[VECTOR_SIZE];
    long Y[VECTOR_SIZE];
    long sum;
    long compute_length;
};

struct DOTdata dotstr;
pthread_mutex_t mutex_sum;

void *calcDOT(void *);

int main(int argc, char *argv[])
{
    long vec_index;

    for(vec_index = 0 ; vec_index < VECTOR_SIZE ; vec_index++){
        dotstr.X[vec_index] = vec_index + 1;
        dotstr.Y[vec_index] = vec_index + 2; 
    }

    dotstr.sum = 0;
    dotstr.compute_length = VECTOR_SIZE/NUM_THREADS;

    pthread_t call_thread[NUM_THREADS];
    pthread_attr_t attr;
    void *status;

    pthread_mutex_init(&mutex_sum, NULL);

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    long i;

    for(i = 0 ; i < NUM_THREADS ; i++){
        pthread_create(&call_thread[i], &attr, calcDOT, (void *)i);
    }

    pthread_attr_destroy(&attr);

    for (i = 0 ; i < NUM_THREADS ; i++){
        pthread_join(call_thread[i], &status);
    }

    printf("Resultant X*Y is %ld\n", dotstr.sum);
    pthread_mutex_destroy(&mutex_sum);
    pthread_exit(NULL);
}

void *calcDOT(void *thread_id)
{
    long vec_index;
    long start_index;
    long end_index;
    long length;
    long offset;
    long sum = 0;

    offset = (long)thread_id;
    length = dotstr.compute_length;

    start_index = offset * length;
    end_index = (start_index + length) - 1;

    for(vec_index = start_index ; vec_index < end_index ; vec_index++){
        sum += (dotstr.X[vec_index] * dotstr.Y[vec_index]);
    }

    pthread_mutex_lock(&mutex_sum);
    dotstr.sum += sum;
    pthread_mutex_unlock(&mutex_sum);

    pthread_exit((void *)thread_id);

}

I would like to increment my NUM_THREADS parameter and run it after each increment, record the execution time after each increment and plot a graph of execution time vs number of threads.

I tried a naive approach by increasing the number of threads, timing it with time.h and plotting it with gnuplot. Each iteration we double the number of threads and we print the time for an iteration. We use gnuplot to display a graph with number of threads on the x-axis and execution time on the y-axis

在此输入图像描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NUM_THREADS 2
#define VECTOR_SIZE 40

struct DOTdata {
    /* data */
    long X[VECTOR_SIZE];
    long Y[VECTOR_SIZE];
    long sum;
    long compute_length;
};

struct DOTdata dotstr;
pthread_mutex_t mutex_sum;

void *calcDOT(void *);

int main(int argc, char *argv[]) {
    double xvals[VECTOR_SIZE / NUM_THREADS];
    double yvals[VECTOR_SIZE / NUM_THREADS];
    int index = 0;
    for (int count = NUM_THREADS; count < VECTOR_SIZE / NUM_THREADS; count = count * 2) {

        clock_t begin = clock();

        long vec_index;

        for (vec_index = 0; vec_index < VECTOR_SIZE; vec_index++) {
            dotstr.X[vec_index] = vec_index + 1;
            dotstr.Y[vec_index] = vec_index + 2;
        }

        dotstr.sum = 0;
        dotstr.compute_length = VECTOR_SIZE / count;

        pthread_t call_thread[count];
        pthread_attr_t attr;
        void *status;

        pthread_mutex_init(&mutex_sum, NULL);

        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

        long i;

        for (i = 0; i < count; i++) {
            pthread_create(&call_thread[i], &attr, calcDOT, (void *) i);
        }

        pthread_attr_destroy(&attr);

        for (i = 0; i < count; i++) {
            pthread_join(call_thread[i], &status);
        }

        printf("Resultant X*Y is %ld\n", dotstr.sum);
        pthread_mutex_destroy(&mutex_sum);
        clock_t end = clock();
        double time_spent = (double) (end - begin) / CLOCKS_PER_SEC;

        printf("time spent: %f NUM_THREADS: %d\n", time_spent, count);
        xvals[index] = count;
        yvals[index] = time_spent;
        index++;
    }

    FILE * gnuplotPipe = popen ("gnuplot -persistent", "w");

    fprintf(gnuplotPipe, "plot '-' \n");

    for (int i = 0; i < VECTOR_SIZE / NUM_THREADS; i++)
    {
        fprintf(gnuplotPipe, "%lf %lf\n", xvals[i], yvals[i]);
    }

    fprintf(gnuplotPipe, "e");


    pthread_exit(NULL);
}

void *calcDOT(void *thread_id) {
    long vec_index;
    long start_index;
    long end_index;
    long length;
    long offset;
    long sum = 0;

    offset = (long) thread_id;
    length = dotstr.compute_length;

    start_index = offset * length;
    end_index = (start_index + length) - 1;

    for (vec_index = start_index; vec_index < end_index; vec_index++) {
        sum += (dotstr.X[vec_index] * dotstr.Y[vec_index]);
    }

    pthread_mutex_lock(&mutex_sum);
    dotstr.sum += sum;
    pthread_mutex_unlock(&mutex_sum);

    pthread_exit((void *) thread_id);

}

Output

Resultant X*Y is 20900
time spent: 0.000155 NUM_THREADS: 2
Resultant X*Y is 19860
time spent: 0.000406 NUM_THREADS: 4
Resultant X*Y is 17680
time spent: 0.000112 NUM_THREADS: 8
Resultant X*Y is 5712
time spent: 0.000587 NUM_THREADS: 16

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM