【问题标题】:Prevent false sharing using padding使用填充防止虚假共享
【发布时间】:2016-09-27 03:43:38
【问题描述】:

我想计算一个大矩阵的总和,当我使用多个线程或只使用一个线程时,我目前没有看到任何性能改进。我认为问题与错误共享有关,但我还在我的结构中添加了一个填充。请看一看!

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

#define WIDTH 20000 
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;

struct split { // sizeof(split) = 24 
    int start; 
    int end; 
    int* matrix; 
    int i; 
    char padding[64 - 24]; //Padding the private sum variables     forces them into separate cache lines and removes false sharing. Assume cache line is 64 bytes
};

int ran(){ 
    return rand() % 21; 
}
int* createBigMatrix(){
    int* a = malloc(sizeof(int)* WIDTH * WIDTH);
    for (int i = 0; i < WIDTH * WIDTH; i ++){ 
        a[i] = ran(); // fill up the matrix with random numbers
    }
    return a;
}
static int finalSum;
void* partialSum(void* arg){ 
    struct split* a = arg;
    int totalSum = 0; // create local variable
    int i;
    for (i = a->start; i <= a->end; i ++){  
        totalSum += a->matrix[i];
    }
    pthread_mutex_lock(&mylock);
    finalSum += totalSum; // critical section
    pthread_mutex_unlock(&mylock);  
    free(a);

    return 0;
} 
int main(){ //-294925289
    int useMultiThreads = 1; // there is no difference between using one thread or 4 therads
    finalSum = 0;
    pthread_t thread_ids[4];  
    // i want a square matrix of npages width 
    int* c = createBigMatrix();  

    printf("%lu\n", sizeof(struct split));
    if (useMultiThreads){
        // split the tasks evenly amoung 4 threads
        // since there are 20,000x20,000, there must be 400,000,000 cells 
        int start[] = {0, 100000000, 200000000, 300000000};
        int end[] = {99999999, 199999999, 299999999, 399999999}; 
        // calculate sum
        for (int i = 0; i < 4; i ++){
            struct split* a = malloc(sizeof(struct split));
            a->start = start[i];
            a->end = end[i];
            a->matrix = c;
            pthread_create(thread_ids + i, NULL, partialSum, a);
        }

        for (int i = 0; i < 4; i ++){ // join em up
            pthread_join(thread_ids[i], NULL);
        }
    }
    else { // use single thread
        for (int i = 0; i <= 399999999; i ++){
            finalSum += c[i];
        }
    }

    printf("total sum is %d\n", finalSum);
/*
    real    0m4.871s
    user    0m4.844s
    sys     0m0.392s
*/ 
    free(c);
    return 0;
}

【问题讨论】:

  • 似乎没有太大的错误共享空间,因为线程使用的矩阵索引不重叠,无论如何,填充参数结构无济于事。你如何衡量总和所花费的时间?在我看来,这个过程的整体性能将由在求和开始之前创建和加载巨大的数组来主导?
  • 小心你的索引,int 绝对不是大型矩阵的正确类型。还要将a-&gt; 的使用排除在for 循环之外。编译器无法知道*a 是否会在后台发生变化,因此他必须在每次迭代时重新加载。您可以将a 更改为restrict 合格,但更简单的是将值(边界和矩阵)加载到局部变量中并在循环中使用它们。

标签: c caching concurrency pthreads false-sharing


【解决方案1】:

我看不出您的struct 的填充应该与您的代码性能有关。实际数据在指向的矩阵中。

您担心的是缺乏加速,这可能是由于您的代码完全受内存限制。也就是说,要执行求和,必须通过内存总线从内存中获取数据。 (您的矩阵太大而无法放入缓存中。)也就是说,您的计算受限于您的内存总线的带宽,该带宽由您的所有内核共享。

另外请注意,您的代码不是以求和为主,而是以程序顺序部分中对ran() 的调用为主。

【讨论】:

    猜你喜欢
    • 2015-07-28
    • 2015-05-25
    • 1970-01-01
    • 2019-03-07
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 2012-06-17
    相关资源
    最近更新 更多