linux kernel mmap splice zero-copy

linux - vmsplice() y TCP



kernel mmap (1)

En la vmsplice() original de vmsplice() , se sugirió que si tuviera un búfer de tierra de usuario 2 veces el número máximo de páginas que podrían caber en una tubería, un vmsplice () exitoso en la segunda mitad del búfer garantizaría que el núcleo Se realizó utilizando la primera mitad del búfer.

Pero eso no era cierto después de todo, y particularmente para TCP, las páginas del kernel se mantendrían hasta recibir el ACK del otro lado. Arreglar esto se dejó como trabajo futuro, y por lo tanto para TCP, el kernel todavía tendría que copiar las páginas de la tubería.

vmsplice() tiene la opción SPLICE_F_GIFT que se ocupa de esto, pero el problema es que esto expone otros dos problemas: cómo obtener páginas nuevas del núcleo de manera eficiente y cómo reducir la eliminación de caché. El primer problema es que mmap requiere que el kernel borre las páginas, y el segundo problema es que, aunque mmap podría usar la característica kscrubd lujo en el kernel, eso incrementa el conjunto de trabajo del proceso (caché).

Basado en esto, tengo estas preguntas:

  • ¿Cuál es el estado actual para notificar al usuario sobre la reutilización segura de las páginas? Estoy especialmente interesado en las páginas splice () d en un socket (TCP). ¿Pasó algo en los últimos 5 años?
  • ¿Es mmap / vmsplice / splice / munmap la mejor práctica actual para realizar copias en cero en un servidor TCP o tenemos mejores opciones hoy?

Sí, debido a que el socket TCP se mantiene en las páginas durante un tiempo indeterminado, no puede utilizar el esquema de doble búfer mencionado en el código de ejemplo. Además, en mi caso de uso, las páginas provienen de un búfer circular, por lo que no puedo regalar las páginas al kernel y asignar nuevas páginas. Puedo verificar que estoy viendo datos dañados en los datos recibidos.

Recurrí al sondeo del nivel de la cola de envío del socket TCP hasta que se drena a 0. Esto corrige la corrupción de los datos, pero es subóptimo porque el drenaje de la cola de envío a 0 afecta el rendimiento.

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; } };