Подтвердить что ты не робот

Vmsplice() и TCP

В исходной реализации vmsplice() было предложено, чтобы, если у вас был буфер пользователя на уровне пользователя 2x максимальное количество страниц, которые могли бы вставляется в трубу, удаленная vmsplice() во второй половине буфера гарантирует, что ядро ​​было выполнено с использованием первой половины буфера.

Но в конце концов это было не так, и особенно для TCP, страницы ядра сохранялись до получения ACK с другой стороны. Исправление этого было оставлено как будущая работа, и, следовательно, для TCP, ядру все равно пришлось бы копировать страницы из канала.

vmsplice() имеет параметр SPLICE_F_GIFT, который имеет отношение к этому, но проблема в том, что в этом есть две другие проблемы - как эффективно получать свежие страницы из ядра и как уменьшить кеш-хаус. Первая проблема заключается в том, что mmap требует, чтобы ядро ​​очистило страницы, а вторая проблема заключается в том, что хотя mmap может использовать функцию fa kscrubd в ядре, что увеличивает рабочий набор процесса (кэширование).

Исходя из этого, у меня есть следующие вопросы:

  • Каково текущее состояние уведомления пользователей о безопасном повторном использовании страниц? Меня особенно интересуют страницы splice() d на сокет (TCP). Что-нибудь случилось за последние 5 лет?
  • Является ли mmap/vmsplice/splice/munmap текущей лучшей практикой для нулевого копирования на сервере TCP или у нас есть лучшие варианты сегодня?
4b9b3361

Ответ 1

Да, из-за того, что сокет TCP удерживается на страницах в течение неопределенного времени, вы не можете использовать схему двойной буферизации, упомянутую в примере кода. Кроме того, в моем примере использования страницы поступают из кругового буфера, поэтому я не могу подарить страницы ядру и выделять свежие страницы. Я могу проверить, что я вижу повреждение данных в полученных данных.

Я прибегал к опросу уровня очереди отправки сокета TCP до тех пор, пока он не дренируется до 0. Это исправляет повреждение данных, но является субоптимальным, поскольку удаление очереди отправки на 0 влияет на пропускную способность.

n = ::vmsplice(mVmsplicePipe.fd.w, &iov, 1, 0);
while (n) {
    // splice pipe to socket
    m = ::splice(mVmsplicePipe.fd.r, NULL, mFd, NULL, n, 0);
    n -= m;
}

while(1) {
    int outsize=0;
    int result;

    usleep(20000);

    result = ::ioctl(mFd, SIOCOUTQ, &outsize);
    if (result == 0) {
        LOG_NOISE("outsize %d", outsize);
    } else {
        LOG_ERR_PERROR("SIOCOUTQ");
        break;
    }
    //if (outsize <= (bufLen >> 1)) {
    if (outsize == 0) {
        LOG("outsize %d <= %u", outsize, bufLen>>1);
        break;
    }
};