win (Win7 x64, Corei7 3.4HGz) 및 Mac (10.12.3 Core i7 2.7 HGz)에서 openmp의 성능을 테스트하는 코드를 작성했습니다.LLVM/OpenMP에서 매우 느린 뮤텍스
- xcode에서 컴파일 된 기본값을 설정하는 콘솔 응용 프로그램을 만들었습니다. 내가 LLVM 3.7 및 OpenMP 5 (opm.h에서 KMP_VERSION_MAJOR = 5를 정의하고 KMP_VERSION_MINOR = 0을 정의하고 KMP_VERSION_BUILD = 20150701, libiopm5)를 MacOS 10.12.3 (CPU - Corei7 2700GHz)에서 찾는다.
- 나는 VS2010 Sp1을 사용한다. 추가 c/C++ -> 최적화 -> 최적화 = 속도 최대화 (O2), c/C++ -> 최적화 -> 선호 Soze 또는 속도 = 빠른 코드 (Ot)를 설정합니다.
응용 프로그램을 단일 스레드로 실행하면 시간 차이는 프로세서의 빈도 비율 (약)에 해당합니다. 그러나 4 개의 스레드를 실행하면 그 차이가 실체가됩니다. win program이 빠르면 70 번에서 mac 프로그램이 빨라집니다.
#include <cmath>
#include <mutex>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <omp.h>
#include <boost/chrono/chrono.hpp>
static double ActionWithNumber(double number)
{
double sum = 0.0f;
for (std::uint32_t i = 0; i < 50; i++)
{
double coeff = sqrt(pow(std::abs(number), 0.1));
double res = number*(1.0-coeff)*number*(1.0-coeff) * 3.0;
sum += sqrt(res);
}
return sum;
}
static double TestOpenMP(void)
{
const std::uint32_t len = 4000000;
double *a;
double *b;
double *c;
double sum = 0.0;
std::mutex _mutex;
a = new double[len];
b = new double[len];
c = new double[len];
for (std::uint32_t i = 0; i < len; i++)
{
c[i] = 0.0;
a[i] = sin((double)i);
b[i] = cos((double)i);
}
boost::chrono::time_point<boost::chrono::system_clock> start, end;
start = boost::chrono::system_clock::now();
double k = 2.0;
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < len; i++)
{
c[i] = k*a[i] + b[i] + k;
if (c[i] > 0.0)
{
c[i] += ActionWithNumber(c[i]);
}
else
{
c[i] -= ActionWithNumber(c[i]);
}
std::lock_guard<std::mutex> scoped(_mutex);
sum += c[i];
}
end = boost::chrono::system_clock::now();
boost::chrono::duration<double> elapsed_time = end - start;
double sum2 = 0.0;
for (std::uint32_t i = 0; i < len; i++)
{
sum2 += c[i];
c[i] /= sum2;
}
if (std::abs(sum - sum2) > 0.01) printf("Incorrect result.\n");
delete[] a;
delete[] b;
delete[] c;
return elapsed_time.count();
}
int main()
{
double sum = 0.0;
const std::uint32_t steps = 5;
for (std::uint32_t i = 0; i < steps; i++)
{
sum += TestOpenMP();
}
sum /= (double)steps;
std::cout << "Elapsed time = " << sum;
return 0;
}
나는 "mac"과 "win"의 openmp 성능을 비교하기 위해 여기에 뮤텍스를 사용합니다. "Win"함수는 0.39 초의 시간을 반환합니다. "Mac"함수는 25 초, 즉 70 배 느린 시간을 반환합니다.
이 차이가 나는 원인은 무엇입니까?
먼저 내 게시물을 편집 해 주셔서 감사합니다 (텍스트를 쓰는 중역을 사용합니다). 실제 앱에서는 거대한 매트릭스 (20000х20000)의 값을 임의의 순서로 업데이트합니다. 각 스레드는 새 값을 결정하고이를 특정 셀에 씁니다. 대부분의 경우 다른 스레드가 다른 행에 쓰기 때문에 각 행에 대한 뮤텍스를 만듭니다. 하지만 분명히 2 개의 쓰레드가 한 줄에 쓰고 긴 자물쇠가있는 경우에. 현재 레코드의 순서는 FEM 요소에 의해 결정되므로 다른 스레드에서 행을 나눌 수 없습니다. 전체 매트릭스에 대한 쓰기를 차단하므로 중요한 섹션을 넣기 만하면됩니다.
나는 실제 응용 프로그램과 같은 코드를 작성했습니다.
static double ActionWithNumber(double number)
{
const unsigned int steps = 5000;
double sum = 0.0f;
for (u32 i = 0; i < steps; i++)
{
double coeff = sqrt(pow(abs(number), 0.1));
double res = number*(1.0-coeff)*number*(1.0-coeff) * 3.0;
sum += sqrt(res);
}
sum /= (double)steps;
return sum;
}
static double RealAppTest(void)
{
const unsigned int elementsNum = 10000;
double* matrix;
unsigned int* elements;
boost::mutex* mutexes;
elements = new unsigned int[elementsNum*3];
matrix = new double[elementsNum*elementsNum];
mutexes = new boost::mutex[elementsNum];
for (unsigned int i = 0; i < elementsNum; i++)
for (unsigned int j = 0; j < elementsNum; j++)
matrix[i*elementsNum + j] = (double)(rand() % 100);
for (unsigned int i = 0; i < elementsNum; i++) //build FEM element like Triangle
{
elements[3*i] = rand()%(elementsNum-1);
elements[3*i+1] = rand()%(elementsNum-1);
elements[3*i+2] = rand()%(elementsNum-1);
}
boost::chrono::time_point<boost::chrono::system_clock> start, end;
start = boost::chrono::system_clock::now();
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < elementsNum; i++)
{
unsigned int* elems = &elements[3*i];
for (unsigned int j = 0; j < 3; j++)
{
//in here set mutex for row with index = elems[j];
boost::lock_guard<boost::mutex> lockup(mutexes[i]);
double res = 0.0;
for (unsigned int k = 0; k < 3; k++)
{
res += ActionWithNumber(matrix[elems[j]*elementsNum + elems[k]]);
}
for (unsigned int k = 0; k < 3; k++)
{
matrix[elems[j]*elementsNum + elems[k]] = res;
}
}
}
end = boost::chrono::system_clock::now();
boost::chrono::duration<double> elapsed_time = end - start;
delete[] elements;
delete[] matrix;
delete[] mutexes;
return elapsed_time.count();
}
int main()
{
double sum = 0.0;
const u32 steps = 5;
for (u32 i = 0; i < steps; i++)
{
sum += RealAppTest();
}
sum /= (double)steps;
std::cout<<"Elapsed time = " << sum;
return 0;
}
프로그램이 실제로 25 초 동안 실행됩니까? (시계를 볼 때) –
예. 나는 watch time을 위해 boost :: chrono :: system_clock을 사용한다. –
이러한 성능 고려 사항에 대해 시스템의 컴파일러 옵션 및 하드웨어 구성은 물론 [mcve]와 같이 문제를 이해하고 재현 할 수있는 자세한 정보를 지정해야합니다. 또한 clang 3.7은 OpenMP 3.1 만 지원하며, OpenMP 5.0은 아직 최종 버전이 아닙니다. VS2010은 확실히 그것을 구현하지 않습니다. – Zulan