Ухудшение производительности потоков в Solaris 11 (sparc) с использованием C ++ 11 с GCC 4.8.0 и нескольких потоков

Я создал простую программу для измерения производительности потоков. Я вырвал части более крупной программы, чтобы проиллюстрировать свою точку зрения. Надеюсь, это не слишком страшно для чтения.

Вот программа:

#include <sstream>
#include <thread>
#include <list>
#include <map>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <string.h>

std::mutex m_totalTranMutex;
int m_totalTrans = 0;
bool m_startThreads = false;
std::condition_variable m_allowThreadStart;
std::mutex m_threadStartMutex;
std::map<int,std::thread::native_handle_type> m_threadNativeHandles;

char *my_strdup(const char *str)
{
size_t len = strlen(str);

char *x = (char *)malloc(len+1);

if(x == nullptr)
return nullptr;

memcpy(x,str,len+1);

return x;
}void DoWork()
{
char abc[50000];
char *s1, *s2;

std::strcpy(abc, "12345");
std::strcpy(abc+20000, "12345");

s1 = my_strdup(abc);
s2 = my_strdup(abc);

free(s1);
free(s2);
}

void WorkerThread(int threadID)
{
{
std::unique_lock<std::mutex> lk(m_threadStartMutex);
m_allowThreadStart.wait(lk, []{return m_startThreads;});
}

double transPerSec = 1 / 99999;
int transactionCounter = 0;
int64_t clockTicksUsed = 0;

std::thread::native_handle_type handle = m_threadNativeHandles[threadID];

std::chrono::high_resolution_clock::time_point current = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point end = start + std::chrono::minutes(1);

int random_num_loops = 0;
double interarrivaltime = 0.0;
double timeHolderReal = 0.0;
while(current < end)
{
std::chrono::high_resolution_clock::time_point startWork = std::chrono::high_resolution_clock::now();

for(int loopIndex = 0; loopIndex < 100; ++loopIndex)
{
for(int alwaysOneHundred = 0; alwaysOneHundred < 100; ++alwaysOneHundred)
{
DoWork();
}
}

std::chrono::high_resolution_clock::time_point endWork = std::chrono::high_resolution_clock::now();

++transactionCounter;
clockTicksUsed += std::chrono::duration_cast<std::chrono::milliseconds>(endWork - startWork).count();

current = std::chrono::high_resolution_clock::now();
}

std::lock_guard<std::mutex> tranMutex(m_totalTranMutex);
std::cout << "Thread " << threadID << " finished with  " << transactionCounter << " transaction." << std::endl;
m_totalTrans += transactionCounter;
}

int main(int argc, char *argv[])
{
std::stringstream ss;

int numthreads = atoi(argv[1]);

std::list<std::thread> threads;

int threadIds = 1;
for(int i = 0; i < numthreads; ++i)
{
threads.push_back(std::thread(&WorkerThread, threadIds));
m_threadNativeHandles.insert(std::make_pair(threadIds, threads.rbegin()->native_handle()));
++threadIds;
}

{
std::lock_guard<std::mutex> lk(m_threadStartMutex);
m_startThreads = true;
}

m_allowThreadStart.notify_all();

//Join until completion
for(std::thread &th : threads)
{
th.join();
}ss << "TotalTran" << std::endl
<< m_totalTrans << std::endl;

std::cout << ss.str();

}

Использование приложения: приложение N
где app — это имя приложения, а N — количество создаваемых потоков. Программа работает в течение 1 минуты.

В Windows я создаю эту программу с помощью Visual Studio 2012. Я запускаю программу на четырехъядерном процессоре I7 (4 ядра, 2 потока на ядро).

Я получаю следующее:

simplethread 1
Thread 1 finished with  1667 transaction.
TotalTran
1667

simplethread 2
Thread 1 finished with  1037 transaction.
Thread 2 finished with  1030 transaction.
TotalTran
2067

simplethread 3
Thread 3 finished with  824 transaction.
Thread 2 finished with  830 transaction.
Thread 1 finished with  837 transaction.
TotalTran
2491

simplethread 4
Thread 3 finished with  688 transaction.
Thread 2 finished with  693 transaction.
Thread 1 finished with  704 transaction.
Thread 4 finished with  691 transaction.
TotalTran
2776

simplethread 8
Thread 2 finished with  334 transaction.
Thread 6 finished with  325 transaction.
Thread 7 finished with  346 transaction.
Thread 1 finished with  329 transaction.
Thread 8 finished with  329 transaction.
Thread 3 finished with  338 transaction.
Thread 5 finished with  331 transaction.
Thread 4 finished with  330 transaction.
TotalTran
2662

E:\Development\Projects\Applications\CPUBenchmark\Debug>simplethread 16
Thread 16 finished with  163 transaction.
Thread 15 finished with  169 transaction.
Thread 12 finished with  165 transaction.
Thread 9 finished with  170 transaction.
Thread 10 finished with  166 transaction.
Thread 4 finished with  164 transaction.
Thread 13 finished with  166 transaction.
Thread 8 finished with  165 transaction.
Thread 6 finished with  165 transaction.
Thread 5 finished with  168 transaction.
Thread 2 finished with  161 transaction.
Thread 1 finished with  159 transaction.
Thread 7 finished with  160 transaction.
Thread 11 finished with  161 transaction.
Thread 14 finished with  163 transaction.
Thread 3 finished with  161 transaction.
TotalTran
2626

Эти цифры выглядят немного бедными. Я ожидал намного ближе к двойному переходу от одного потока, выполняющего X, к двум потокам, выполняющим 2X работу в этой системе. Потоки выполняли примерно одинаковое количество работы, но не так много за одну минуту.

Становится еще более странным, когда я переезжаю в солярис.

На Solaris 11, используя GCC 4.8.0, я собираю эту программу следующим образом:

gcc -o simple simpleThreads.cpp -I. -std = c ++ 11 -DSOLARIS = 1 -lstdc ++ -lm

когда я бегу «./простой 1», я получаю

Thread 1 finished with  19686 transaction.
TotalTran
19686

для «./simple 2» я получаю:

Thread 1 finished with  5248 transaction.
Thread 2 finished with  2484 transaction.
TotalTran
7732

В Solaris двухпотоковый регистр намного медленнее. Я не могу понять, что я делаю не так. Я новичок в C ++ 11 конструкций и потоков. Так что это двойной удар. gcc -v показывает модель потока posix. Любая помощь будет оценена.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]