TL; DR: ¿Es posible que el rendimiento del reactor sea limitado? ¿Cómo lo diría? ¿Qué tan caro y escalable (a través de los hilos) es la implementación del io_service?Cómo evitar que el reactor ASIO Boost se convierta en un solo núcleo?
Tengo una aplicación farsamente masiva en paralelo, que se ejecuta en una máquina hyperthreaded-dual-quad-core-Xeon con toneladas de RAM y una rápida RAID SSD. Esto se desarrolla usando boost :: asio.
Esta aplicación acepta conexiones de alrededor de otras 1000 máquinas, lee datos, decodifica un protocolo simple y mezcla los datos en archivos mapeados mediante mmap(). La aplicación también preselecciona las páginas "futuras" de mmap usando madvise (WILLNEED), por lo que es poco probable que bloquee las fallas de página, pero para estar seguro, he intentado generar hasta 300 subprocesos.
Esto se ejecuta en Linux kernel 2.6.32-27-generic (Ubuntu Server x64 LTS 10.04). La versión de Gcc es 4.4.3 y la versión de boost :: asio es 1.40 (ambas son existencias de Ubuntu LTS).
Ejecutando vmstat, iostat y superior, veo que el rendimiento del disco (tanto en TPS como en volumen de datos) está en los dígitos únicos de%. Del mismo modo, la longitud de la cola del disco es siempre mucho menor que la cantidad de subprocesos, por lo que no creo que esté vinculado a E/S. Además, el RSS trepa pero luego se estabiliza en algunos conciertos (como se esperaba) y vmstat no muestra mensajes, por lo que me imagino que no tengo memoria. La CPU es constante al 0-1% de usuario, 6-7% al sistema y el resto está inactivo. ¡Pista! Un "núcleo" completo (recuerde hyper-threading) es 6.25% de la CPU.
Sé que el sistema se está quedando atrás, porque las máquinas del cliente bloquean el envío de TCP cuando hay más de 64kB pendientes, e informan el hecho; todos continúan informando sobre este hecho, y el rendimiento del sistema es mucho menor de lo deseado, previsto y teóricamente posible.
Supongo que estoy conteniendo un bloqueo de algún tipo. Utilizo un bloqueo de nivel de aplicación para proteger una tabla de búsqueda que puede estar mutada, así que clasifiqué esto en 256 bloqueos/tablas de nivel superior para romper esa dependencia. Sin embargo, eso no pareció ayudar en absoluto.
Todos los hilos pasan por una única instancia de io_service global. Ejecutar strace en la aplicación muestra que pasa la mayor parte del tiempo lidiando con llamadas futex, lo que imagino tiene que ver con la implementación basada en el evocado reactor io_service.
¿Es posible que el rendimiento del reactor sea limitado? ¿Cómo lo diría? ¿Qué tan caro y escalable (a través de los hilos) es la implementación del io_service?
EDITAR: Al principio no encontré este otro hilo porque usaba un conjunto de etiquetas que no se solapaban con las mías: -/Es bastante posible que mi problema sea el bloqueo excesivo utilizado en la implementación del boost :: asio reactor. Ver C++ Socket Server - Unable to saturate CPU Sin embargo, la pregunta sigue siendo: ¿Cómo puedo probar esto? ¿Y cómo puedo solucionarlo?
¿Ha comparado el rendimiento con las versiones más nuevas de asio? Boost 1.40 es un poco viejo y hubo algunas mejoras agradables integradas [bastante recientemente] (http://think-async.com/Asio/LinuxPerformanceImprovements). –
Estoy algo obligado a usar Ubuntu 10.04 LTS, que viene con boost 1.40. Tal vez pueda probar esto en un sistema más moderno, pero todavía tiene que implementarse en el stock 10.04. Creo que boost :: asio es solo encabezado, así que quizás esto pueda funcionar ... –
Sam: Lo intenté con el último lanzamiento de Boost, que es 1.47.0. Todavía tiene el mismo problema: el rendimiento se rehúsa a exceder el de un solo núcleo de CPU (aunque todos los núcleos realmente están trabajando, casi todos bloqueados). –