Tecnología de copia cero en Linux (2)

 

Proceso tradicional de copia de E / S

 Por ejemplo: lea el archivo y envíelo con socket

 Lea primero, luego envíe, y de hecho pase por 1 ~ 4 copias cuatro veces.

  1. La primera vez: lea el archivo del disco en el búfer del núcleo del sistema operativo;

  2. La segunda vez: copie los datos del búfer del núcleo al búfer de la aplicación de la aplicación;

  3. El tercer paso: copie los datos en el búfer de la aplicación de aplicación en el búfer de envío de la red de sockets (el búfer perteneciente al núcleo del sistema operativo);

  4. La cuarta vez: copie los datos del buffer de socket a la tarjeta de red, y la tarjeta de red transmite los datos.

 

                  

           Figura 1. Transferencia de datos tradicional mediante llamadas al sistema de lectura y escritura

 

  De la manera tradicional, leer el archivo de disco y enviarlo a través de la red, las cuatro copias de datos después de pasar es muy tedioso. IO real de lectura y escritura, se requiere una interrupción de IO, y la CPU necesita responder a la interrupción (con el cambio de contexto). Aunque más tarde se introdujo DMA para hacerse cargo de la solicitud de interrupción de la CPU, hay "copias innecesarias" en las cuatro copias.

 

Digresión: ¿Qué es el DMA?

  De hecho, la tecnología DMA es fácil de entender. En esencia, la tecnología DMA es que colocamos un chip independiente en la placa base. En la transmisión de datos de la memoria y los dispositivos de E / S, ya no controlamos la transmisión de datos a través de la CPU, sino directamente a través del controlador DMA (DMA? Controlador, denominado DMAC). Este chip, podemos pensar en él como un coprocesador (coprocesador)

 

Introducción a varias formas de lograr cero copias en Linux

E / S directa en Linux

  Si la aplicación puede acceder directamente al almacenamiento de la interfaz de red, no es necesario atravesar el bus de almacenamiento antes de que la aplicación acceda a los datos, y la sobrecarga causada por la transmisión de datos será mínima. Las aplicaciones o las funciones de la biblioteca que se ejecutan en modo de usuario pueden acceder directamente al almacenamiento del dispositivo de hardware. El núcleo del sistema operativo no participa en ninguna otra cosa en el proceso de transmisión de datos, excepto el trabajo de configuración de almacenamiento virtual necesario. Direct I / O permite que los datos se transfieran directamente entre aplicaciones y dispositivos periféricos sin la necesidad de soporte de caché de página del núcleo del sistema operativo. Para obtener detalles de implementación específicos de la tecnología de E / S directa, puede consultar otro artículo sobre developerWorks "Introducción al mecanismo de E / S directa en Linux", este artículo no hace demasiada descripción.

             

               Figura 2. Transferencia de datos mediante E / S directa

 

Tecnología de copia cero para la transmisión de datos sin pasar por el espacio de direcciones de la aplicación

Use mmap ()

En Linux, una forma de reducir la cantidad de copias es llamar a mmap () en lugar de llamar a read, como:

tmp_buf = mmap (archivo, len); 
escribir (socket, tmp_buf, len); 

  La aplicación llama a mmap (), los datos en el disco se copiarán al búfer del núcleo a través de DMA, y luego el sistema operativo compartirá este búfer del núcleo con la aplicación, de modo que no sea necesario copiar el contenido del búfer del núcleo al espacio del usuario . Luego, la aplicación llama a write () y el sistema operativo copia directamente el contenido del búfer del núcleo al búfer del zócalo. Todo esto ocurre en el estado del núcleo. Finalmente, el búfer del zócalo envía los datos a la tarjeta de red. Del mismo modo, mirar la imagen es simple:
              

              Figura 3. Uso de mmap () en lugar de read ()

 

  Al usar mmap () en lugar de read (), la cantidad de copias de datos requeridas por el sistema operativo ya puede reducirse a la mitad. Cuando se necesita transmitir una gran cantidad de datos, esto tendrá una mejor eficiencia. Sin embargo, esta mejora también tiene un precio. Existen problemas potenciales con el uso de mma () p. Cuando se realiza la asignación de memoria en el archivo, se llama a la llamada al sistema write (). Si otros procesos truncan el archivo en este momento, la señal de error del bus SIGBUS interrumpirá la llamada al sistema write (), porque el que se está ejecutando en este momento es un Acceso incorrecto al almacenamiento. Esta señal hará que el proceso se cierre, y este problema se puede resolver mediante los dos métodos siguientes:

  1. Instale un nuevo procesador de señal para SIGBUS para que la llamada al sistema write () devuelva el número de bytes escritos antes de que se interrumpiera, y errno se establece en éxito. Pero este método también tiene sus defectos, no puede reflejar la causa raíz de este problema, porque la señal BIGBUS solo muestra que algunos procesos tienen algunos errores graves.
  2. El segundo método resuelve este problema a través de bloqueos de arrendamiento de archivos. Este método es relativamente mejor. Podemos agregar un bloqueo de arrendamiento para leer o escribir archivos a través del kernel. Cuando otro proceso intenta truncar el archivo que transfiere el usuario, el kernel enviará al usuario una señal en tiempo real: señal RT_SIGNAL_LEASE, esta señal le indicará al usuario que el kernel está dañado Si el usuario escribe o lee un bloqueo de préstamo en ese archivo, la llamada al sistema write () se interrumpirá y el proceso será cancelado por la señal SIGBUS. El valor de retorno es el número de bytes escritos antes de la interrupción, y errno también será Establecido para el éxito. El bloqueo de arrendamiento de archivos debe establecerse antes de que la memoria asigne el archivo.

  El uso de mmap es compatible con POSIX, pero el uso de mmap puede no necesariamente lograr el rendimiento ideal de transmisión de datos. Durante el proceso de transferencia de datos, aún se requiere una operación de copia de la CPU, y la operación de mapeo también es una operación de almacenamiento virtual muy costosa. Esta operación requiere cambiar la tabla de páginas y vaciar el TLB (invalidar el contenido del TLB) para mantener la consistencia del almacenamiento. Sin embargo, debido a que el mapeo es generalmente aplicable a un rango mayor, para datos de la misma longitud, el costo del mapeo es mucho más bajo que el costo de la copia de la CPU.

 

Utilice sendfile ()

Comenzando con el kernel 2.1, Linux introdujo sendfile para simplificar las operaciones:

#include <sys / sendfile.h> ssize \ _t sendfile ( int  out \ _fd, int  in \ _fd, off \ _t * offset, size_t count);

  La llamada al sistema sendfile () transfiere el contenido del archivo (bytes) entre el infd que representa el archivo de entrada y el outfd que representa el archivo de salida. El descriptor outfd debe apuntar a un socket, y el archivo al que apunta infd debe ser compatible con mmap. Estas limitaciones limitan el uso de sendfile, de modo que sendfile solo puede transferir datos del archivo al socket, y viceversa.

                    

                   Figura 4. Use sendfile () para la transferencia de datos

 

  sendfile () no solo reduce las operaciones de copia de datos, sino que también reduce el cambio de contexto. La transferencia de datos siempre ocurre solo en el espacio del kernel. Primero: la llamada al sistema sendfile () usa el motor DMA para copiar los datos en el archivo al búfer del núcleo del sistema operativo, y luego los datos se copian al búfer del núcleo relacionado con el socket. A continuación, el motor DMA copia los datos del búfer del zócalo del núcleo al motor de protocolo. Si otro proceso trunca el archivo mientras el usuario llama a la llamada del sistema sendfile () para la transferencia de datos, entonces la llamada al sistema sendfile () simplemente devolverá el número de bytes transferidos antes de que se interrumpiera la aplicación del usuario, y se establecerá errno Por el éxito Si el sistema operativo agrega un bloqueo de préstamo al archivo antes de llamar a sendfile (), la operación y el estado de retorno de sendfile () serán los mismos que mmap () / write ().

 

  La llamada al sistema sendfile () no necesita copiar o asignar datos al espacio de direcciones de la aplicación, por lo que sendfile () solo se aplica al caso en el que el espacio de direcciones de la aplicación no necesita procesar los datos accedidos. En comparación con el método mmap (), dado que los datos transmitidos por sendfile no cruzan el límite de la aplicación del usuario / kernel del sistema operativo, sendfile () también reduce en gran medida la sobrecarga de la gestión de almacenamiento. Sin embargo, sendfile () también tiene muchas limitaciones, como se detalla a continuación:

  • sendfile () está limitado a aplicaciones de red basadas en archivos, como servidores web. Se dice que la implementación de sendfile () en el kernel de Linux es solo para usar el programa Apache de sendfile () en otras plataformas.
  • Debido a que la transmisión de red es asíncrona, es difícil implementar la implementación de emparejamiento en el receptor de la llamada al sistema sendfile (), por lo que esta tecnología generalmente no se usa en el receptor de la transmisión de datos.
  • Según las consideraciones de rendimiento, sendfile () todavía necesita una operación de copia de la CPU desde el archivo al búfer de socket, lo que hace que los datos transferidos contaminen el caché de la página.

 

Sendfile () con función de recopilación de copias DMA

  La tecnología sendfile () presentada en la sección anterior todavía requiere una operación adicional de copia de datos para la transmisión de datos. Al introducir un poco de ayuda de hardware, esta única operación de copia de datos también se puede evitar. Para evitar la copia de datos causada por el núcleo del sistema operativo, se necesita una interfaz de red que admita la operación de recopilación, lo que significa que los datos a transmitir se pueden dispersar en diferentes ubicaciones del almacenamiento en lugar de almacenarse en almacenamiento continuo. De esta manera, los datos leídos del archivo no necesitan copiarse en el búfer del socket, sino que solo necesitan pasar el descriptor del búfer a la pila de protocolos de red, y luego crean un paquete de datos en el búfer Estructura relacionada, y luego combine todos los datos en un paquete de datos de red a través de la función de recopilación y copia de DMA. El motor DMA de la tarjeta de red leerá el encabezado del paquete y los datos de múltiples ubicaciones en una sola operación. El buffer de socket en Linux versión 2.4 puede cumplir esta condición. Esta es la conocida tecnología de copia cero utilizada en Linux. Este método no solo reduce la sobrecarga causada por múltiples cambios de contexto, sino que también reduce el procesamiento. El número de copias de datos causadas por el dispositivo. Para aplicaciones de usuario, el código no ha cambiado. Primero, la llamada al sistema sendfile () usa el motor DMA para copiar el contenido del archivo al búfer del núcleo, luego, el descriptor del búfer con la ubicación del archivo y la información de longitud se agrega al búfer del zócalo. Este proceso no requiere datos de El búfer del núcleo del sistema operativo se copia en el búfer del zócalo, y el motor DMA copia los datos directamente del búfer del núcleo al motor de protocolo, lo que evita la última copia de datos.

             

                  Figura 5. sendfile con la función de copia de recopilación DMA

 

  De esta manera, la CPU no solo evita la operación de copia de datos durante el proceso de transmisión de datos, en teoría, la CPU nunca tendrá ninguna relación con los datos transmitidos, lo que juega un papel positivo en el rendimiento de la CPU: primero, La memoria caché no está contaminada; en segundo lugar, no es necesario mantener la consistencia de la memoria caché y no es necesario actualizar la memoria caché antes o después de la transferencia de datos DMA. En la práctica, sin embargo, esto último es muy difícil de lograr. El búfer de origen puede ser parte de la memoria caché de la página, lo que significa que se puede acceder mediante operaciones de lectura generales, y el acceso también se puede realizar de manera tradicional. Mientras la CPU pueda acceder al área de almacenamiento, la consistencia de la memoria caché debe mantenerse limpiando la memoria caché antes de la transferencia DMA. Además, la realización de esta función de recopilación y copia de datos requiere soporte de hardware y controlador de dispositivo.

 

empalme()

  splice () es un método similar a mmap () y sendfile () en Linux. También se puede utilizar para la transferencia de datos entre el espacio de direcciones de la aplicación del usuario y el espacio de direcciones del sistema operativo. splice () es adecuado para aplicaciones de usuario que pueden determinar la ruta de transmisión de datos, no necesita usar el búfer del espacio de direcciones de usuario para operaciones explícitas de transmisión de datos. Luego, cuando los datos solo se transfieren de un lugar a otro, y los datos transferidos en el proceso no necesitan ser procesados ​​por la aplicación del usuario, spice () se convierte en una mejor opción. splice () puede mover datos en bloques en el espacio de direcciones del sistema operativo, reduciendo así la mayoría de las operaciones de copia de datos. Además, la transmisión de datos de splice () se puede realizar de forma asíncrona, la aplicación del usuario puede regresar primero de la llamada al sistema y el proceso del núcleo del sistema operativo controlará el proceso de transmisión de datos para continuar. splice () puede verse como una implementación similar a una canalización basada en flujo. La canalización puede conectar dos descriptores de archivo entre sí, y la persona que llama de splice puede controlar la interacción mutua de dos dispositivos (o pilas de protocolos) en el núcleo del sistema operativo Conectar

  La llamada al sistema splice () es muy similar a sendfile (). La aplicación de usuario debe tener dos descriptores de archivo abiertos, uno para dispositivos de entrada y otro para dispositivos de salida. A diferencia de sendfile (), splice () permite que dos archivos se conecten entre sí, no solo los archivos al socket para la transmisión de datos. Para el caso especial de enviar datos desde un descriptor de archivo a un socket, la llamada al sistema sendfile () siempre se ha utilizado, y el empalme siempre ha sido un mecanismo, y no se limita a la función de sendfile (). En otras palabras, sendfile () es solo un subconjunto de splice (). En Linux 2.6.23, la implementación del mecanismo sendfile () desapareció, pero la API y las funciones correspondientes todavía existen, pero la API y la correspondiente La función se implementa utilizando el mecanismo splice ().  

  En el proceso de transmisión de datos, el mecanismo de empalme () envía alternativamente operaciones de lectura y escritura del descriptor de archivo relacionado, y el búfer de lectura puede reutilizarse para operaciones de escritura. También utiliza un control de flujo simple para bloquear solicitudes de escritura a través de una marca de agua predefinida. Los experimentos han demostrado que el uso de este método para transferir datos de un disco a otro aumentará el rendimiento en un 30% a 70%. Durante la transferencia de datos, la carga de la CPU también se reducirá a la mitad.

  El kernel de Linux 2.6.17 introdujo la llamada al sistema splice (), pero este concepto ha existido durante mucho tiempo. En 1988, Larry McVoy propuso este concepto, que se consideraba como una técnica para mejorar el rendimiento de E / S de los sistemas del lado del servidor. Aunque a menudo se mencionó en los años siguientes, la llamada al sistema de empalme nunca fue Se ha implementado en el núcleo del sistema operativo Linux convencional hasta la aparición de la versión 2.6.17 de Linux. La llamada al sistema de empalme requiere cuatro parámetros, dos de los cuales son descriptores de archivo, uno para la longitud del archivo y uno para controlar cómo copiar datos. La llamada al sistema de empalme se puede implementar de forma síncrona o asíncrona. Cuando se utiliza el modo asíncrono, la aplicación del usuario sabrá que la transmisión de datos ha sido terminada por la señal SIGIO. La interfaz de la llamada al sistema splice () es la siguiente:

empalme largo ( int fdin, int fdout, size_t len, unsigned int flags);

  Llamar a la llamada al sistema splice () hará que el núcleo del sistema operativo se mueva hacia arriba para leer bytes de datos del origen de datos fdin a fdout. Este proceso de movimiento de datos solo pasa a través del espacio del núcleo del sistema operativo y requiere un número mínimo de copias. El uso de la llamada al sistema splice () requiere que se use uno de estos dos descriptores de archivo para representar un dispositivo de tubería. No es difícil ver que este diseño tiene limitaciones, y las versiones posteriores de Linux mejorarán en este tema. Los indicadores de parámetro se utilizan para indicar el método de ejecución de la operación de copia Los indicadores actuales tienen los siguientes valores:

  • SPLICE_F_NONBLOCK: la operación de empalme no se bloqueará. Sin embargo, si el descriptor de archivo no está configurado como E / S no bloqueable, la llamada al empalme aún puede estar bloqueada.
  • SPLICE_F_MORE: dígale al núcleo del sistema operativo que vendrán más datos de la próxima llamada al sistema de empalme.
  • SPLICE_F_MOVE: si la salida es un archivo, este valor hará que el núcleo del sistema operativo intente leer los datos directamente desde el búfer de la tubería de entrada en el espacio de direcciones de salida. No se realiza ninguna operación de copia de datos durante este proceso de transferencia de datos.

  La llamada al sistema Splice () utiliza el mecanismo de búfer de tubería propuesto por Linux, por lo que al menos uno de los dos parámetros del descriptor de archivo de esta llamada al sistema debe referirse al dispositivo de tubería. Para admitir el mecanismo de empalme, Linux agrega las siguientes dos definiciones a la estructura file_operations para dispositivos y sistemas de archivos:

ssize_t (* splice_write) ( estructura inode * pipe, strucuct file * out , 
                      size_t len, unsigned int flags); 
ssize_t ( * splice_read) ( estructura inode * in , strucuct file * pipe, 
                      size_t len, unsigned int flags);

  Estas dos nuevas operaciones pueden mover bytes len entre la tubería y dentro o fuera de acuerdo con la configuración de las banderas. El sistema de archivos de Linux ha implementado las operaciones que tienen las funciones anteriores y se pueden usar, y también implementa una función generic_splice_sendpage () para la conexión con el socket.

 

Tecnología de copia cero optimizada para la transferencia de datos entre el espacio de direcciones de la aplicación y el núcleo

  Las tecnologías de copia cero antes mencionadas se implementan evitando la copia de datos entre las aplicaciones del usuario y el búfer del núcleo del sistema operativo en la mayor medida posible. Las aplicaciones que usan las tecnologías de copia cero anteriores generalmente se limitan a ciertas Situación: los datos no pueden procesarse en el núcleo del sistema operativo o los datos no pueden procesarse en el espacio de direcciones del usuario. La tecnología de copia cero propuesta en esta sección conserva la tecnología tradicional de transferencia de datos entre el espacio de direcciones de la aplicación del usuario y el espacio de direcciones del núcleo del sistema operativo, pero está optimizada para la transmisión. Sabemos que la transferencia de datos entre el software y el hardware del sistema puede mejorarse mediante la transferencia DMA, pero no existe una herramienta similar para la transferencia de datos entre las aplicaciones del usuario y los sistemas operativos. La tecnología introducida en esta sección se propone para esta situación.

 

Usar copia en escritura

  En algunos casos, el caché de páginas en el núcleo del sistema operativo Linux puede ser compartido por múltiples aplicaciones, y el sistema operativo puede asignar páginas en el búfer de espacio de direcciones de la aplicación del usuario al espacio de direcciones del núcleo del sistema operativo. Si una aplicación desea llamar a la llamada del sistema write () en estos datos compartidos, puede destruir los datos compartidos en el búfer del núcleo. La llamada tradicional del sistema write () no proporciona ninguna operación de bloqueo explícito. Linux Introdujo una tecnología de copia en escritura para proteger los datos.

 

¿Qué es copiar en escritura?

  Copy-on-write es una estrategia de optimización en la programación de computadoras. Su idea básica es esta: si varias aplicaciones necesitan acceder al mismo dato al mismo tiempo, a estas aplicaciones se les pueden asignar punteros a este dato. A una aplicación le parece que todos tienen una copia de los datos. Cuando una de las aplicaciones necesita modificar su propia copia de los datos, necesita copiar los datos en el espacio de direcciones de la aplicación. Es decir, la aplicación tiene una copia verdaderamente privada de los datos, esto se hace para evitar que la aplicación realice cambios en este dato para que otras aplicaciones lo vean. Este proceso es transparente para la aplicación. Si la aplicación nunca realizará ningún cambio en el dato al que se accede, nunca es necesario copiar los datos en el espacio de direcciones de la aplicación. Esta es también la principal ventaja de copiar en escritura.

  La implementación de copia en escritura requiere el apoyo de la MMU. La MMU necesita saber qué páginas especiales en el espacio de direcciones del proceso son de solo lectura. Cuando los datos deben escribirse en estas páginas, la MMU emitirá una excepción al núcleo del sistema operativo y al sistema operativo. El núcleo asignará nuevo espacio de almacenamiento físico, y la página que se escribirá con datos debe corresponder a la nueva ubicación de almacenamiento físico.

  El mayor beneficio de la copia en escritura es que puede ahorrar memoria. Pero para el núcleo del sistema operativo, la copia en escritura aumenta la complejidad de su procesamiento.

 

Realización de la transmisión de datos y sus limitaciones.

Remitente de datos

  Para el remitente de la transmisión de datos, la implementación es relativamente simple: bloquee las páginas físicas relacionadas con el búfer de la aplicación y asigne estas páginas al espacio de direcciones del núcleo del sistema operativo e identifíquelas como "escribir" solo ". Cuando vuelve la llamada del sistema, tanto la aplicación de usuario como la pila de red pueden leer los datos en el búfer. Después de que el sistema operativo haya transferido todos los datos, la aplicación puede escribir en los datos. Si la aplicación intenta escribir en los datos antes de que se complete la transferencia de datos, se generará una excepción, en cuyo momento el sistema operativo copiará los datos en el búfer de la aplicación y restablecerá la asignación en el lado de la aplicación. Una vez completada la transmisión de datos, desbloquee las páginas bloqueadas y restablezca el logotipo de COW.

Receptor de datos

  Para el lado receptor de datos, la implementación de esta tecnología necesita lidiar con situaciones mucho más complicadas. Si la llamada al sistema read () se emite antes de que llegue el paquete, y la aplicación está bloqueada, entonces la llamada al sistema read () le dirá al sistema operativo dónde deben almacenarse los datos en el paquete recibido. En este caso, la reasignación de página no es necesaria en absoluto, y la tarjeta de interfaz de red puede proporcionar suficiente soporte para que los datos se almacenen directamente en el búfer de la aplicación del usuario. Si la recepción de datos es asíncrona, antes de que se emita la llamada al sistema read (), el sistema operativo no sabe dónde escribir los datos, porque no conoce la ubicación del búfer de la aplicación del usuario, por lo que el núcleo del sistema operativo primero debe almacenar los datos en Ve a tu propio búfer.

Limitaciones

  La técnica de copia en escritura puede causar una gran sobrecarga de procesamiento del sistema operativo. Todos los buffers relacionados deben estar alineados con la página, y el número de páginas MMU utilizadas debe ser un número entero. Para el remitente, esto no causará ningún problema. Pero para el receptor, debe ser capaz de manejar situaciones más complejas. En primer lugar, el tamaño del paquete de datos debe ser apropiado, y el tamaño debe ser el correcto para cubrir una página completa de datos, lo que limita la red cuyo tamaño de MTU es mayor que la página de memoria del sistema, como FDDI y ATM. En segundo lugar, para reasignar la página al flujo del paquete de datos sin ninguna interrupción, la parte de datos en el paquete de datos debe ocupar un número entero de páginas. Para el caso de recibir datos de forma asincrónica, para mover los datos de manera eficiente al espacio de direcciones del usuario, puede usar dicho método: usando el soporte de la tarjeta de interfaz de red, el paquete de datos entrantes se puede dividir en dos partes: el encabezado y los datos Los datos se almacenan en un búfer separado, y el sistema de almacenamiento virtual asignará los datos al búfer de espacio de dirección del usuario. Hay dos requisitos previos para usar este método, que se mencionan anteriormente: uno es que el búfer de la aplicación debe estar alineado con la página y debe ser continuo en el almacenamiento virtual; el segundo es que los datos transferidos tienen el tamaño de una página Solo entonces se puede dividir el paquete de datos. De hecho, estos dos requisitos previos son difíciles de cumplir. Si el búfer de la aplicación no está alineado con la página, o el tamaño del paquete excede una página, entonces los datos deben copiarse. Para el remitente de datos, incluso si los datos están protegidos contra escritura para la aplicación durante la transmisión, la aplicación aún debe evitar el uso de estos búferes ocupados, porque la sobrecarga causada por la operación de copia en escritura es muy grande De Sin una notificación de extremo a extremo a este nivel, es difícil para una aplicación saber si se ha liberado un búfer o si todavía se está utilizando.

  Esta técnica de copia cero es más adecuada para situaciones en las que los eventos de copia en escritura ocurren con menos frecuencia, porque la sobrecarga de un evento de copia en escritura es mucho mayor que la sobrecarga de una copia de la CPU. En la práctica, la mayoría de las aplicaciones a menudo reutilizarán el mismo búfer varias veces, por lo que después de usar los datos una vez, no desasigne la página del espacio de direcciones del sistema operativo, lo que mejorará la eficiencia. Teniendo en cuenta que se puede acceder nuevamente a la misma página, por lo que mantener el mapeo de la página puede ahorrar gastos generales de administración. Sin embargo, este tipo de reserva de mapeo no reducirá los gastos generales causados ​​por el movimiento de ida y vuelta de la tabla de páginas y el vaciado TLB. Al bloquear o desbloquear debido a la copia en escritura, se debe cambiar el indicador de solo lectura de la página.

 

Buffer Sharing

  Hay otro método para usar el búfer compartido del mecanismo de preasignación para transferir rápidamente datos entre el espacio de direcciones de la aplicación y el núcleo del sistema operativo. La arquitectura que adoptó la idea de compartir el búfer se implementó por primera vez en Solaris, y la arquitectura utiliza el concepto de "fbufs". Este método necesita modificar la API. La transferencia de datos entre el espacio de direcciones de la aplicación y el espacio de direcciones del núcleo del sistema operativo debe implementarse en estricta conformidad con la arquitectura de fbufs, y la comunicación entre los núcleos del sistema operativo también se realiza en estricta conformidad con la arquitectura de fbufs. Cada aplicación tiene un grupo de búferes, que se asigna al espacio de direcciones del usuario y al espacio de direcciones del núcleo al mismo tiempo, y solo se pueden crear cuando sea necesario. Al completar una operación de almacenamiento virtual para crear un búfer, fbufs puede reducir efectivamente la mayoría de los problemas de rendimiento causados ​​por el mantenimiento de la consistencia del almacenamiento. Esta tecnología todavía está en la etapa experimental en Linux.

¿Por qué expandir la API de E / S de Linux?

  Las interfaces de entrada y salida de Linux tradicionales, como las llamadas al sistema de lectura y escritura, se basan en la copia, es decir, los datos deben copiarse entre el núcleo del sistema operativo y el búfer definido por la aplicación. Para las llamadas al sistema de lectura, la aplicación del usuario presenta el núcleo del sistema operativo con un búfer preasignado, y el núcleo debe poner los datos leídos en este búfer. Para escribir llamadas del sistema, siempre que la llamada del sistema regrese, la aplicación del usuario puede reutilizar libremente el búfer de datos.

  Para admitir el mecanismo anterior, Linux debe poder crear y eliminar mapas de almacenamiento virtual para cada operación. El mecanismo de la reasignación de esta página depende de varios factores, como la configuración de la máquina, la arquitectura de la memoria caché, la sobrecarga causada por el procesamiento incorrecto de TLB y si el procesador es un procesador único o múltiples procesadores. Si puede evitar la sobrecarga de las operaciones de almacenamiento virtual / TLB al procesar solicitudes de E / S, el rendimiento de E / S mejorará enormemente. fbufs es tal mecanismo. El uso de la arquitectura fbufs puede evitar las operaciones de almacenamiento virtual. Según los datos, la estructura de fbufs en la estación de trabajo de procesador único DECStation ™ 5000/200 logrará un rendimiento mucho mejor que el método de reasignación de páginas mencionado anteriormente. Si desea utilizar la arquitectura fbufs, debe extender la API de Linux para lograr una tecnología efectiva y completa de copia cero.

Introducción al principio de Fast Buffers

  Los datos de E / S se almacenan en memorias intermedias llamadas fbufs, y cada una de esas memorias intermedias contiene una o más páginas de almacenamiento virtual consecutivas. El acceso de la aplicación a fbuf se logra a través del dominio de protección, hay dos formas de la siguiente manera:

  • Si a la aplicación se le asigna fbuf, entonces la aplicación tiene acceso a fbuf
  • Si la aplicación recibe el fbuf a través de IPC, la aplicación también tiene acceso a este fbuf

  Para el primer caso, el dominio de protección se llama el "originador" de fbuf, para el último caso, el dominio de protección se llama el "receptor" de fbuf.

  La interfaz de E / S de Linux tradicional admite el intercambio de datos entre el espacio de direcciones de la aplicación y el kernel del sistema operativo. Esta operación de intercambio hace que se copien todos los datos. Si se usa fbufs, el búfer que contiene los datos debe intercambiarse, lo que elimina las operaciones de copia redundantes. La aplicación transfiere el fbuf al núcleo del sistema operativo, lo que puede reducir la sobrecarga de la copia de datos causada por la llamada tradicional del sistema de escritura. Del mismo modo, las aplicaciones reciben datos a través de fbuf, lo que también puede reducir la sobrecarga de la copia de datos generada por las llamadas tradicionales del sistema de lectura. Como se muestra a continuación:

                             

                      图 6. API de E / S de Linux

 

 El subsistema de E / S o la aplicación pueden asignar fbufs a través del administrador de fbufs. Una vez que se asignan fbufs, estos fbufs se pueden pasar del programa al subsistema de E / S, o del subsistema de E / S al programa. Después de su uso, estos fbufs se devolverán al grupo de búferes fbufs.

 La implementación de fbufs tiene las siguientes características, como se muestra en la Figura 9:

  • fbuf debe asignarse desde el grupo de búferes fbufs. Cada fbuf tiene un objeto, ya sea un programa de aplicación o el núcleo del sistema operativo. El fbuf se puede transferir entre la aplicación y el sistema operativo. Después de usar el fbuf, debe volver a liberarse al grupo de búferes de fbufs específico. Durante el proceso de transferencia de fbuf, deben llevar información relevante sobre el grupo de búferes de fbufs.
  • Cada grupo de búferes de fbufs se asociará con una aplicación, y una aplicación solo se puede asociar como máximo con un grupo de búferes de fbufs. La aplicación solo está calificada para acceder a su propio grupo de búferes.
  • fbufs no requiere la reasignación de direcciones virtuales, porque para cada aplicación, pueden reutilizar el mismo conjunto de búferes. De esta manera, la información convertida por el almacenamiento virtual se puede almacenar en caché y se puede eliminar la sobrecarga del subsistema de almacenamiento virtual.
  • El subsistema de E / S (controlador de dispositivo, sistema de archivos, etc.) puede asignar fbufs y colocar los datos entrantes directamente en estos fbuf. De esta manera, se pueden evitar las operaciones de copia entre memorias intermedias.

 

                       

                   Figura 7. arquitectura de fbufs 

 

  Como se mencionó anteriormente, este método requiere la modificación de la API. Si desea usar la arquitectura fbufs, tanto la aplicación como el controlador del kernel del sistema operativo Linux deben usar la nueva API. Si la aplicación quiere enviar datos, debe ser del grupo de búferes. Obtenga un fbuf, complete los datos y luego envíe los datos a través del descriptor de archivo. Los fbufs recibidos pueden ser retenidos por la aplicación por un período de tiempo, luego de eso, la aplicación puede usarlos para continuar enviando otros datos o devolverlos al grupo de búferes. Sin embargo, en algunos casos, necesita volver a ensamblar los datos en el paquete de datos, luego la aplicación que recibe los datos a través de fbuf necesita copiar los datos a otro búfer. Además, las aplicaciones no pueden modificar los datos que el núcleo está procesando actualmente. En base a esto, la arquitectura fbufs introduce el concepto de bloqueos obligatorios para garantizar su implementación. Para las aplicaciones, si los fbufs se han enviado al kernel del sistema operativo, la aplicación ya no procesará estos fbufs.

Algunos problemas con fbufs

  La gestión de agrupaciones de almacenamiento intermedio compartidas requiere una estrecha cooperación entre las aplicaciones, el software de red y los controladores de dispositivos. Para el extremo receptor de datos, el hardware de la red debe poder transferir los paquetes de datos entrantes al grupo de almacenamiento intermedio de almacenamiento correcto asignado por el extremo receptor utilizando DMA. Además, la aplicación cambiará el contenido de los datos enviados previamente al almacenamiento compartido con poco cuidado, resultando en corrupción de datos, pero este tipo de problema es difícil de depurar en el lado de la aplicación. Al mismo tiempo, el modelo de almacenamiento compartido es difícil de asociar con otros tipos de objetos de almacenamiento, pero la estrecha cooperación entre aplicaciones, software de red y controladores de dispositivos requiere el apoyo de otros administradores de almacenamiento. Para la tecnología de búfer compartido, aunque esta tecnología parece prometedora, no solo necesita cambiar la API, sino que también necesita cambiar el controlador, y esta tecnología en sí tiene algunos problemas sin resolver El problema es que esta tecnología está actualmente solo en la etapa experimental. En el sistema de prueba, esta tecnología ha mejorado enormemente el rendimiento, pero la instalación general de esta nueva arquitectura aún parece no ser factible. Este mecanismo de preasignación de buffers compartidos a veces requiere copiar datos a otro buffer debido a problemas de granularidad.

 

Resumen

  Esta serie de artículos presenta la tecnología de copia cero en Linux, y este artículo es la segunda parte. Este artículo ofrece una introducción más detallada a varias tecnologías de copia cero que aparecen en el sistema operativo Linux propuesto en la primera parte del artículo, describiendo principalmente sus respectivas ventajas, desventajas y escenarios aplicables. Para la transmisión de datos en red, la aplicación de la tecnología de copia cero se ve obstaculizada por muchos factores arquitectónicos, incluida la arquitectura de almacenamiento virtual y la arquitectura de protocolo de red. Por lo tanto, la tecnología de copia cero solo es aplicable en algunas situaciones muy especiales, como los servicios de archivos o el uso de un protocolo especial para comunicaciones de gran ancho de banda. Sin embargo, la viabilidad de la aplicación de la tecnología de copia cero en las operaciones de disco es mucho mayor, probablemente debido a que las operaciones de disco tienen las características de sincronización, y la unidad de transmisión de datos se lleva a cabo de acuerdo con la granularidad de las páginas.

  Se han propuesto e implementado muchas tecnologías de copia cero para la plataforma del sistema operativo Linux, pero no todas estas tecnologías de copia cero se utilizan ampliamente en los sistemas operativos del mundo real. Por ejemplo, la arquitectura de fbufs parece atractiva de muchas maneras, pero su uso requiere cambios en la API y los controladores, y tiene algunas otras dificultades de implementación, lo que hace que fbufs solo permanezca en la etapa experimental. La tecnología de reasignación dinámica de direcciones solo requiere una pequeña cantidad de modificación del sistema operativo. Aunque el software del usuario no necesita ser modificado, la arquitectura de almacenamiento virtual actual no admite operaciones frecuentes de reasignación de direcciones virtuales. Y para garantizar la coherencia del almacenamiento, el TLB y el caché de primer nivel deben actualizarse después de la reasignación. De hecho, el alcance de la tecnología de copia cero que usa la reasignación de direcciones es muy pequeño, porque la sobrecarga de las operaciones de almacenamiento virtual a menudo es mayor que la sobrecarga de la copia de la CPU. Además, para eliminar completamente el acceso de la CPU al almacenamiento, generalmente se requiere hardware adicional para soportar, y este tipo de soporte de hardware no es muy popular, pero también es muy costoso.

  El propósito de esta serie de artículos es ayudar a los lectores a resolver la perspectiva de estas tecnologías de copia cero que aparecen en el sistema operativo Linux para ayudar a mejorar los problemas de rendimiento encontrados durante la transmisión de datos. Los detalles de implementación específicos de varias tecnologías de copia cero no se describen en detalle en esta serie de artículos. Al mismo tiempo, la tecnología de copia cero se ha desarrollado y mejorado constantemente. Esta serie de artículos no cubre todas las tecnologías de copia cero que aparecen en Linux.

 

Supongo que te gusta

Origin www.cnblogs.com/myseries/p/12714886.html
Recomendado
Clasificación