Почему этот тестовый код использует такой высокий процессор?
Код ниже работает, он отправляет все правильные данные, и он получает правильные данные.
Когда я использую его для тестирования очень быстрого сервера, загрузка процессора составляет ~10%. Однако, когда я тестирую медленный сервер, он возрастает до ~50% - так же, как сервер, который я тестирую / тестирую на стресс *.
Что происходит, что top
Репортаж.
Почему он использует так много процессора? Я подозреваю, что неправильно использую опрос, но не знаю как?
Процессорное время для медленного сервера в 4 раза больше, чем у эталонного теста, а для быстрого сервера - в 7 раз больше, чем у эталонного.
int flags = fcntl(sockfd, F_GETFL, 0);
assert(flags != -1);
assert(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) != -1);
int32 red = 0;
struct pollfd pollfd = {
.fd = sockfd,
.events = POLLIN | POLLOUT
};
do {
assert(poll(&pollfd, 1, -1) == 1);
if (pollfd.revents & POLLOUT) {
int n;
while ((n = send(sockfd, buf__+bufOffset, bufLength-bufOffset, MSG_NOSIGNAL)) > 0) {
bufOffset += n;
if (n != bufLength-bufOffset)
break;
}
assert(!(n == -1 && errno != EAGAIN && errno != EWOULDBLOCK));
}
if (pollfd.revents & POLLIN) {
int r;
while ((r = read(sockfd, recvBuf, MIN(recvLength-red, recvBufLength))) > 0) {
// assert(memcmp(recvBuf, recvExpectedBuf+red, r) == 0);
red += r;
if (r != MIN(recvLength-red, recvBufLength))
break;
}
assert(!(r == -1 && errno != EAGAIN && errno != EWOULDBLOCK));
}
} while (bufOffset < bufLength);
assert(fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK) != -1);
int r;
while ((r = read(sockfd, recvBuf, MIN(recvLength-red, recvBufLength))) > 0) {
// assert(memcmp(recvBuf, recvExpectedBuf+red, r) == 0);
red += r;
}
assert(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) != -1);
assert(red == recvLength);
int r = read(sockfd, recvBuf, 1);
assert((r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) || r == 0);
* (Сейчас я использую и тест, и сервер на одной и той же машине. Связь через TCP.)
3 ответа
Причина в том, что вы заняты ожиданием. Если read
а также write
вернуть EAGAIN
или же EWOULDBLOCK
Вы звоните им постоянно. Добавить select
который будет ждать, пока сокет не будет готов для чтения или записи до этого.
Задача решена.
Это не было точно искаженное использование процессора. Неэффективный сервер отправлял 8-байтовые пакеты с TCP_NODELAY, поэтому я получал миллионы уведомлений об опросе, чтобы прочитать только 8 байт. Оказывается, вызов read(2) был довольно дорогим, и вызова его десятки тысяч раз в секунду было достаточно, чтобы ракета "время, проведенное в системном режиме", показала ~56%, которая была добавлена к "времени, проведенному в пользовательском режиме". "производить очень высокую загрузку процессора.
Так что, если я наконец понял это, вы сравниваете соотношение %CPU
сообщается сверху к соотношению темпа прироста TIME+
сообщается сверху, и они не согласны. (Было бы проще, если бы вы сказали, из каких столбцов вы читали!) Насколько я могу судить, оба рассчитываются из одних и тех же полей в базовом /proc
данные, так что они не должны быть в состоянии сильно не согласиться.
И я не могу повторить это. Я поместил ваш код в тестовую программу и запустил его без каких-либо изменений, кроме исправления переопределения int r
ошибка компиляции и добавление того, что я считаю разумными объявлениями для всего, что вы оставили. Я подключил его к серверу, который читает строки от клиента и потребляет немного ресурсов процессора после каждого перед отправкой строки назад. Результатом было то, что топ показал %CPU
около 99 для сервера и 2 для клиента и около 50 к 1 в TIME+
колонка.
Я не нахожу ничего плохого в использовании poll
,
Мне не нравится твое использование assert
хотя - когда утверждения отключены, программе будет не хватать многих важных системных вызовов.