美文网首页
从数据专用性解决,Openmp并发变慢的问题

从数据专用性解决,Openmp并发变慢的问题

作者: sea_monster | 来源:发表于2020-06-10 10:03 被阅读0次

从数据专用性解决,Openmp并发变慢的问题

题目如下

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

void Usage(char prog_name[]);

void Get_args(
    char*    argv[]        /* in  */,
    long*     bin_count_p   /* out */,
    float*   min_meas_p    /* out */,
    float*   max_meas_p    /* out */,
    long*     data_count_p  /* out */);

void Gen_data(
    float   min_meas    /* in  */, 
    float   max_meas    /* in  */, 
    float   data[]      /* out */,
    long     data_count  /* in  */);

void Gen_bins(
    float min_meas      /* in  */, 
    float max_meas      /* in  */, 
    float bin_maxes[]   /* out */, 
    long   bin_counts[]  /* out */, 
    long   bin_count     /* in  */);

long Which_bin(
    float    data         /* in */, 
    float    bin_maxes[]  /* in */, 
    long      bin_count    /* in */, 
    float    min_meas     /* in */);

void Print_histo(
    float    bin_maxes[]   /* in */, 
    long      bin_counts[]  /* in */, 
    long      bin_count     /* in */, 
    float    min_meas      /* in */);

//////////////////////////////////////////////////////////////////////
    
//请修改该函数
int main(int argc, char* argv[]) 
{
    long bin_count, i, bin;
    float min_meas, max_meas;
    float* bin_maxes;
    long* bin_counts;
    long data_count;
    float* data;

    struct timeval begin_time, end_time;
    double run_time_ms;

    /* Check and get command line args */
    if (argc != 5) Usage(argv[0]); 
    Get_args(argv, &bin_count, &min_meas, &max_meas, &data_count);

    /* Allocate arrays needed */
    bin_maxes = malloc(bin_count*sizeof(float));
    bin_counts = malloc(bin_count*sizeof(long));
    data = malloc(data_count*sizeof(float));

    /* Generate the data */
    Gen_data(min_meas, max_meas, data, data_count);

    /* Create bins for storing counts */
    Gen_bins(min_meas, max_meas, bin_maxes, bin_counts, bin_count);

    gettimeofday(&begin_time, NULL);

    /*
        请将下面这个for循环用OpenMP并行化
        要求及注意事项:
            1)程序的命令行(即main函数)在最后面增加一个参数thread_count,表示线程数量;
            2)先用./histogram 10 0 1 200000000测试单线程的运行时间,然后分别以10 0 1 200000000 2和10 0 1 200000000 4作为参数进行测试;
            3)Which_bin函数参数的意义见函数实现处的说明。
    */
    /* Count number of values in each bin */
    for (i = 0; i < data_count; i++) {
        bin = Which_bin(data[i], bin_maxes, bin_count, min_meas);
        bin_counts[bin]++;
    }
   
    gettimeofday(&end_time, NULL);
    run_time_ms =
        (end_time.tv_sec - begin_time.tv_sec)*1000 +
        (end_time.tv_usec - begin_time.tv_usec)*1.0/1000;
    printf("run_time = %lfms\n", run_time_ms);

    /* Print the histogram */
    Print_histo(bin_maxes, bin_counts, bin_count, min_meas);

    free(data);
    free(bin_maxes);
    free(bin_counts);
    return 0;
}  /* main */

//请修改该函数
void Usage(char prog_name[] /* in */) 
{
    fprintf(stderr, "usage: %s ", prog_name); 
    fprintf(stderr, "<bin_count> <min_meas> <max_meas> <data_count>\n");
    exit(0);
}  /* Usage */

//请修改该函数
void Get_args(
    char*    argv[]        /* in  */,
    long*     bin_count_p   /* out */,
    float*   min_meas_p    /* out */,
    float*   max_meas_p    /* out */,
    long*     data_count_p  /* out */) 
{
    *bin_count_p = strtol(argv[1], NULL, 10);
    *min_meas_p = strtof(argv[2], NULL);
    *max_meas_p = strtof(argv[3], NULL);
    *data_count_p = strtol(argv[4], NULL, 10);
}  /* Get_args */


void Gen_data(
        float   min_meas    /* in  */, 
        float   max_meas    /* in  */, 
        float   data[]      /* out */,
        long     data_count  /* in  */) 
{
    long i;
    srandom(0);
    for (i = 0; i < data_count; i++)
        data[i] = min_meas + (max_meas - min_meas)*random()/((double) RAND_MAX);
}  /* Gen_data */


void Gen_bins(
      float min_meas      /* in  */, 
      float max_meas      /* in  */, 
      float bin_maxes[]   /* out */, 
      long   bin_counts[]  /* out */, 
      long   bin_count     /* in  */) 
{
    float bin_width;
    long   i;

    bin_width = (max_meas - min_meas)/bin_count;

    for (i = 0; i < bin_count; i++) {
        bin_maxes[i] = min_meas + (i+1)*bin_width;
        bin_counts[i] = 0;
    }
}  /* Gen_bins */

/*---------------------------------------------------------------------
 * Function:  Which_bin
 * Purpose:   Use binary search to determine which bin a measurement 
 *            belongs to
 * In args:   data:       the current measurement,              数据
 *            bin_maxes:  list of max bin values,               每个bin的上边界
 *            bin_count:  number of bins,                       bin的数量
 *            min_meas:   the minimum possible measurement,     数据的最小值
 * Return:    the number of the bin to which data belongs,      bin的编号
 * Notes:      
 * 1.  The bin to which data belongs satisfies
 *
 *            bin_maxes[i-1] <= data < bin_maxes[i] 
 *
 *     where, bin_maxes[-1] = min_meas
 * 2.  If the search fails, the function prlongs a message and exits
 */
long Which_bin(
      float   data          /* in */, 
      float   bin_maxes[]   /* in */, 
      long     bin_count     /* in */, 
      float   min_meas      /* in */) 
{
   long bottom = 0, top =  bin_count-1;
   long mid;
   float bin_max, bin_min;

   while (bottom <= top) {
      mid = (bottom + top)/2;
      bin_max = bin_maxes[mid];
      bin_min = (mid == 0) ? min_meas: bin_maxes[mid-1];
      if (data >= bin_max) 
         bottom = mid+1;
      else if (data < bin_min)
         top = mid-1;
      else
         return mid;
   }
   
   return top;    //bug? added by XiongZhi

   /* Whoops! */
    printf("bottom = %ld, top = %ld\n", bottom, top);
    fprintf(stderr, "Data = %f doesn't belong to a bin!\n", data);
    fprintf(stderr, "Quitting\n");
    exit(-1);
}  /* Which_bin */


void Print_histo(
        float  bin_maxes[]   /* in */, 
        long    bin_counts[]  /* in */, 
        long    bin_count     /* in */, 
        float  min_meas      /* in */) 
{
    long i, j;
    float bin_max, bin_min;

    for (i = 0; i < bin_count; i++) {
        bin_max = bin_maxes[i];
        bin_min = (i == 0) ? min_meas: bin_maxes[i-1];
        printf("%.3f-%.3f:\t", bin_min, bin_max);
        //for (j = 0; j < bin_counts[i]; j++)
            // printf("X");
        printf("%ld", bin_counts[i]);  //altered by XiongZhi
        printf("\n");
   }
}  /* Print_histo */

解决方案

主要代码详解
1)c_bin_counts二维数组初始化,大小为(NUM_THREADS, bin_count); 主要用于分别保存不同线程各自的计算结果,实现各个线程间的数据专用性

image.png
2)主要代码详解:
image.png

感想:
之前学习openmp并发,一直弄不懂的问题,在本次实验中学会了。一开始使用openmp就是直接使用#pragma omp for schedule(dynamic, 10000)直接进行加速,但是一直不明白哪里出了问题。随后根据数据的专用性,使用临时的动态数组以及为每一个线程分配一个独立的数组,大大减少大家同时访问一块内存的可能性,大大加速了代码。本次实验加深了对openmp的理解,也充分的了解到了openmp的缺陷和易用性。

但本代码存在部分缺陷,有待有心人解决。

源代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <omp.h>
#include <string.h>
void Usage(char prog_name[]);
// g++ -o main main.cpp -fopenmp
void Get_args(
        char*    argv[]        /* in  */,
        long*     bin_count_p   /* out */,
        float*   min_meas_p    /* out */,
        float*   max_meas_p    /* out */,
        long*     data_count_p  /* out */,
        long*     thread_num   /* out */);

void Gen_data(
        float   min_meas    /* in  */,
        float   max_meas    /* in  */,
        float   data[]      /* out */,
        long     data_count  /* in  */);

void Gen_bins(
        float min_meas      /* in  */,
        float max_meas      /* in  */,
        float bin_maxes[]   /* out */,
        long   bin_counts[]  /* out */,
        long   bin_count     /* in  */);

long Which_bin(
        float    data         /* in */,
        float    bin_maxes[]  /* in */,
        long      bin_count    /* in */,
        float    min_meas     /* in */);

void Print_histo(
        float    bin_maxes[]   /* in */,
        long      bin_counts[]  /* in */,
        long      bin_count     /* in */,
        float    min_meas      /* in */);

//////////////////////////////////////////////////////////////////////

//请修改该函数
int main(int argc, char* argv[])
{
    long NUM_THREADS;
    long bin_count, i, bin;
    float min_meas, max_meas;
    float* bin_maxes;
    long* bin_counts;
    long data_count;
    float* data;
    long** c_bin_counts;
    struct timeval begin_time, end_time;
    double run_time_ms;

    /* Check and get command line args */
    if (argc != 6) Usage(argv[0]);
    Get_args(argv, &bin_count, &min_meas, &max_meas, &data_count, &NUM_THREADS);
    /* Allocate arrays needed */
    bin_maxes =(float*)malloc(bin_count*sizeof(float));
    bin_counts = (long*)malloc(bin_count*sizeof(long));
    data = (float*)malloc(data_count*sizeof(float));
    c_bin_counts = (long**)malloc(NUM_THREADS*sizeof(long));

    for(int k=0; k<NUM_THREADS; ++k){
        c_bin_counts[k] = (long*)malloc(bin_count*sizeof(long));
        memset(c_bin_counts[k], 0, sizeof(long)*bin_count);
    }
    /* Generate the data */
    Gen_data(min_meas, max_meas, data, data_count);

    /* Create bins for storing counts */
    Gen_bins(min_meas, max_meas, bin_maxes, bin_counts, bin_count);


    gettimeofday(&begin_time, NULL);

    /*
        请将下面这个for循环用OpenMP并行化
        要求及注意事项:
            1)程序的命令行(即main函数)在最后面增加一个参数thread_count,表示线程数量;
            2)先用./histogram 10 0 1 200000000 测试单线程的运行时间,然后分别以10 0 1 200000000 2和10 0 1 200000000 4作为参数进行测试;
            3)Which_bin函数参数的意义见函数实现处的说明。
    */
    /* Count number of values in each bin */

    omp_set_num_threads(NUM_THREADS);
    int rank;
#pragma omp parallel private(i, bin, rank) shared(c_bin_counts)
    {
        rank = -1;
        long* a;
#pragma omp for  schedule(guided)
        for(int i=0; i<data_count; ++i){
            bin = Which_bin(data[i], bin_maxes, bin_count, min_meas);
            if(rank==-1){
                rank = omp_get_thread_num();
                a = (long*)malloc(bin_count*sizeof(long));
                memset(a, 0, sizeof(long)*bin_count);
            }
            a[bin] += 1;
        }
        for(int k=0; k<bin_count; ++k){
            c_bin_counts[rank][k] += a[k];
        }
        free(a);
    }
    for (int k = 0; k < NUM_THREADS; ++k) {
        for (int j = 0; j < bin_count; ++j) {
            bin_counts[j] += c_bin_counts[k][j];
        }
    }
    
    gettimeofday(&end_time, NULL);
    run_time_ms =
            (end_time.tv_sec - begin_time.tv_sec)*1000 +
            (end_time.tv_usec - begin_time.tv_usec)*1.0/1000;
    printf("run_time = %lfms\n", run_time_ms);

    /* Print the histogram */
    Print_histo(bin_maxes, bin_counts, bin_count, min_meas);
    
    for(int k=0; k<NUM_THREADS; ++k){
        free(c_bin_counts[k]);
    }
    free(c_bin_counts);
    free(data);
    free(bin_maxes);
    free(bin_counts);
    return 0;
}  /* main */

//请修改该函数
void Usage(char prog_name[] /* in */)
{
    fprintf(stderr, "usage: %s ", prog_name);
    fprintf(stderr, "<bin_count> <min_meas> <max_meas> <data_count> <thread_num>\n");
    exit(0);
}  /* Usage */

//请修改该函数
void Get_args(
        char*    argv[]        /* in  */,
        long*     bin_count_p   /* out */,
        float*   min_meas_p    /* out */,
        float*   max_meas_p    /* out */,
        long*     data_count_p  /* out */,
        long*     thread_num  /* out */)
{
    *bin_count_p = strtol(argv[1], NULL, 10);
    *min_meas_p = strtof(argv[2], NULL);
    *max_meas_p = strtof(argv[3], NULL);
    *data_count_p = strtol(argv[4], NULL, 10);
    *thread_num = strtol(argv[5], NULL, 10);
}  /* Get_args */


void Gen_data(
        float   min_meas    /* in  */,
        float   max_meas    /* in  */,
        float   data[]      /* out */,
        long     data_count  /* in  */)
{
    long i;
    srand(0);
    for (i = 0; i < data_count; i++)
        data[i] = min_meas + (max_meas - min_meas)*rand()/((double) RAND_MAX);
}  /* Gen_data */


void Gen_bins(
        float min_meas      /* in  */,
        float max_meas      /* in  */,
        float bin_maxes[]   /* out */,
        long   bin_counts[]  /* out */,
        long   bin_count     /* in  */)
{
    float bin_width;
    long   i;

    bin_width = (max_meas - min_meas)/bin_count;

    for (i = 0; i < bin_count; i++) {
        bin_maxes[i] = min_meas + (i+1)*bin_width;
        bin_counts[i] = 0;
    }
}  /* Gen_bins */

/*---------------------------------------------------------------------
 * Function:  Which_bin
 * Purpose:   Use binary search to determine which bin a measurement
 *            belongs to
 * In args:   data:       the current measurement,              数据
 *            bin_maxes:  list of max bin values,               每个bin的上边界
 *            bin_count:  number of bins,                       bin的数量
 *            min_meas:   the minimum possible measurement,     数据的最小值
 * Return:    the number of the bin to which data belongs,      bin的编号
 * Notes:
 * 1.  The bin to which data belongs satisfies
 *
 *            bin_maxes[i-1] <= data < bin_maxes[i]
 *
 *     where, bin_maxes[-1] = min_meas
 * 2.  If the search fails, the function prlongs a message and exits
 */
long Which_bin(
        float   data          /* in */,
        float   bin_maxes[]   /* in */,
        long     bin_count     /* in */,
        float   min_meas      /* in */)
{
    long bottom = 0, top =  bin_count-1;
    long mid;
    float bin_max, bin_min;

    while (bottom <= top) {
        mid = (bottom + top)/2;
        bin_max = bin_maxes[mid];
        bin_min = (mid == 0) ? min_meas: bin_maxes[mid-1];
        if (data >= bin_max)
            bottom = mid+1;
        else if (data < bin_min)
            top = mid-1;
        else
            return mid;
    }

    return top;    //bug? added by XiongZhi

    /* Whoops! */
    printf("bottom = %ld, top = %ld\n", bottom, top);
    fprintf(stderr, "Data = %f doesn't belong to a bin!\n", data);
    fprintf(stderr, "Quitting\n");
    exit(-1);
}  /* Which_bin */


void Print_histo(
        float  bin_maxes[]   /* in */,
        long    bin_counts[]  /* in */,
        long    bin_count     /* in */,
        float  min_meas      /* in */)
{
    long i, j;
    float bin_max, bin_min;

    for (i = 0; i < bin_count; i++) {
        bin_max = bin_maxes[i];
        bin_min = (i == 0) ? min_meas: bin_maxes[i-1];
        printf("%.3f-%.3f:\t", bin_min, bin_max);
        //for (j = 0; j < bin_counts[i]; j++)
        // printf("X");
        printf("%ld", bin_counts[i]);  //altered by XiongZhi
        printf("\n");
    }
}  /* Print_histo */

相关文章

网友评论

      本文标题:从数据专用性解决,Openmp并发变慢的问题

      本文链接:https://www.haomeiwen.com/subject/utjutktx.html