Мы попробовали следующий подход к серверному коду и получили очень плохие результаты. Может ли стиль кодирования и распределение памяти повлиять на производительность, и как мы это настраиваем? Мне нужно достичь как минимум 55% выше. Я проверяю свою пропускную способность с помощью wireshark, и я делаю некоторые настройки:
сервер
ethtool -K eth0 tx off
ifdown eth0
ifconfig eth0 mtu 3500
ifup eth0
taskset -c 0 ./server
клиент
ifconfig eth0 mtu 9000
массив
а. Без заполнения каких-либо данных.
unsigned long bytetosent = 4080*65536;
char sendBuff[4080 * 65536];
while(x < bytetosent)
{
int bytesWritten = send(connfd, (const char*)sendBuff+x, 6144, 0);
x += 6144;
}
Пропускная способность: 73%
б. заполнить случайными данными
for(int y=0; y<(4080); y++)
{
sendBuff[y] = (rand() %255);
}
while(x < bytetosent)
{
int bytesWritten = send(connfd, (const char*)sendBuff+x, 6144, 0);
x += 6144;
}
Пропускная способность: 53%
ММАП
pImagePool = mmap( (void *)DDR_RAM_PHYS,MAPPED_SIZE_BUFFER, PROT_READ, MAP_SHARED, _fdMem, 0);
while(x < bytetosent)
{
bytesWritten =send(connfd, ((const char*)(pImagePool))+ x, 6144, 0);
x += 6144;
}
Пропускная способность: 20%
таНос
char *_mBuffer;
_mBuffer = malloc(4080 * 65536);
а. без заполнения каких-либо данных
while(x < bytetosent)
{
bytesWritten =send(connfd, (const char*)_mBuffer+x, 6144, 0);
x += 6144;
}
Пропускная способность: 73%
б. заполнить случайные данные
Пропускная способность: 50%
вектор
vector<char>_pBuffer;
а. копия
copy((char*)(pImagePool), (((char*)(pImagePool))+1000000), back_inserter(_pBuffer));
bytesWritten = send(connfd, &_pBuffer[bytesSent], bytetosent, MSG_CONFIRM);
bytesSent += bytesWritten;
Пропускная способность: очень медленно
б. отталкивать
for(int y=0; y<bytetosent; y++)
{
_pBuffer.push_back(*((char*)pImagePool+y));
}
Пропускная способность: очень очень медленно
Код настройки подключения к моему серверу:
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(8080);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
Мой клиент получает код:
char recvBuff[4080 * 65536];
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
//printf("\n in while\n");
if(0)//fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
}
Я попытался выполнить профилирование времени, используя mmap и memcpy. Результат:
Это считается быстрым?
Всего байт: 40000 * 1088
Время: 0.107197с
Код:
void *pImagePool;
char _cpy[40000 * 1088];
/*Memory Mapping */
const char imagePoolDevice[]="/dev/mem";
int _fdMem;
if( (_fdMem = open( imagePoolDevice, O_RDWR | O_SYNC )) < 0 )
{
printf("Unable to open /dev/mem %d\n", _fdMem);
}
//start
start = chrono::system_clock::now();
pImagePool = mmap(0,MAPPED_SIZE_BUFFER, PROT_READ|PROT_WRITE, MAP_SHARED, _fdMem, DDR_RAM_PHYS);
if( pImagePool == MAP_FAILED ){printf("Mapping Failed\n");}
else{printf("Successful Mapping\n");}
memcpy ( _cpy, &pImagePool, sizeof(_cpy));
//end
end = chrono::system_clock::now();
chrono::duration<double>elapsed_seconds = end - start;
time_t end_time = chrono::system_clock::to_time_t(end);
cout<<"mmap time taken = "<<elapsed_seconds.count()<<endl;
Я наконец-то преодолел проблему путем слепого тестирования, я тестирую с помощью 2 подходов ниже:
Я создаю массив и memcpy указатель возврата mmap на массив. Это увеличивает пропускную способность Ethernet до 55%. Код показан ниже:
char _cpy[40000 * 1088];
pImagePool = mmap(0,MAPPED_SIZE_BUFFER, PROT_READ|PROT_WRITE, MAP_SHARED, _fdMem, DDR_RAM_PHYS);
memcpy ( _cpy, pImagePool, 40000 * 1088);
while(bytesSent != bytetosent)
{
bytesWritten = send(connfd, &_cpy[bytesSent], bytetosent, MSG_CONFIRM);
bytesSent += bytesWritten;
}
скопируйте mmap, чтобы вернуть указатель на вектор, но сначала нужно зарезервировать размер вектора. Извините, я не сделал это правильно в моем предыдущем тестовом коде. Пропускная способность Ethernet увеличивается до 51%.
vector<char>_pBuffer;
pImagePool = mmap(0,MAPPED_SIZE_BUFFER, PROT_READ|PROT_WRITE, MAP_SHARED, _fdMem, DDR_RAM_PHYS);
_pBuffer.reserve(43520000); //40000 * 1088
copy((char*)pImagePool, (char*)pImagePool + 43520000, back_inserter(_pBuffer));
while(bytesSent != bytetosent)
{
bytesWritten = send(connfd, &_pBuffer[bytesSent], bytetosent, MSG_CONFIRM);
bytesSent += bytesWritten;
}
Я не знаю, как работает этот метод, я просто предполагаю, что это копия в кэш-память.