
Entonces tengo un programa escrito en C++.
Puede decirme cuánto tiempo tomó hacer todos los cálculos y realiza muchos cálculos bastante pesados de múltiples subprocesos.
Me acabo de dar cuenta de que si ejecuto el programa exactamente en la misma máquina, me lleva entre 20 y 21 segundos hacer todos los cálculos si lo inicio desde el TTY, y solo alrededor de 0,2 segundos si lo inicio desde el terminal GNOME.
¿Qué está causando eso? Es literalmente exactamente el mismo archivo en la misma máquina.
Respuesta1
Alguna teoría de fondo
Bueno, tanto con lo que trabajas después de CTRL+ ALT+ F1como con GNOME Terminal son diferentes implementaciones del mismo concepto:emulandoel llamado terminal de pantalla completa.
Lo primero se llama terminal virtual (VT) en Linux, o normalmente simplemente "consola". Utiliza un modo de vídeo especial de "sólo texto" que todavía proporcionan las tarjetas de vídeo de hardware en las plataformas compatibles con x86 (es decir, las de la herencia "IBM PC"). Esta última es una aplicación GUI.
Ambos proporcionan a las aplicaciones que se ejecutan con su ayuda un conjunto de funciones que dicha aplicación espera de un "dispositivo terminal" (más detalles y sugerencias adicionales—aquí).
El problema en cuestión
Bien, pasemos ahora a la lentitud percibida.
Estoy seguro de que el quid de su problema es que su programa realiza las llamadas E/S de "bloqueo". Es decir, cada vez que haces algo como
std::cout << "Hello, world" << endl;
en su código, primero el código de la biblioteca estándar de C++ vinculado a su aplicación se activa y maneja la salida del material enviado al lugar indicadoarroyo.
Después de cierto procesamiento (y generalmente algo de almacenamiento en búfer), estos datos deben abandonar el proceso en ejecución de su programa y obtener salida a cualquier medio al que su programa envíe su salida. En Linux (y otros sistemas compatibles con Unix), esto requiere llamar al kernel, a través de un servidor dedicado.llamada al sistema(ollamada al sistemapara abreviar) llamado write()
.
Entonces, la stdlib de C++ finalmente realiza esa write()
llamada al sistema y luego espera a que se complete; es decir, espera a que el núcleo responda "OK, el receptor de los datos dijo que los adquirió".
Como puede deducir, el receptor de los datos que genera su programa es el terminal (emulador) que ejecuta su programa, ya sea un VT de Linux o una instancia del Terminal GNOME en sus pruebas. (El panorama completo es más complicado ya que el kernel no enviará los datos directamente a un emulador de terminal en ejecución, pero no compliquemos la descripción).
¡Y entonces, la velocidad con la que write()
se completa esa llamada al sistema depende en gran medida de qué tan rápido la maneja el receptor de los datos! En su caso, GNOME Terminal lo hace mucho más rápido.
Mi opinión sobre la diferencia es que el controlador VT procesa diligentemente todos los datos que se le envían, los desplaza, etc., mientras que GNOME Terminal optimiza las ráfagas de datos entrantes procesando solo la parte final (lo que se ajuste al tamaño de la pantalla del terminal) y coloca el descansa en el llamado "búfer de desplazamiento" que tienen la mayoría de los emuladores de terminal GUI.
Las conclusiones para hacer
Lo crucial a tener en cuenta es que tan pronto como su programa realiza cualquier E/S junto con cálculos, y usted mide la velocidad de cálculo del programa usando un temporizador de "reloj de pared", normalmente puede medir la velocidad de esa E/S. Oh, no la velocidad de los cálculos.
Tenga en cuenta que la E/S es complicada: su proceso puede seradelantado(detenido con sus recursos entregados a otro proceso) por el sistema operativo cada vez que está a punto de esperar a que algún recurso de E/S esté disponible para escritura, como la unidad de disco duro.
Entonces, la forma segura de medir el rendimiento "bruto" de los cálculos es tener alguna función en su programa para deshabilitar todas las E/S. Si eso no es posible o sería demasiado feo de implementar, al menos intente dirigir toda la salida a un llamado "dispositivo nulo", /dev/null
ejecutando su programa como
$ ./program >/dev/null
El dispositivo nulo simplemente descarta todos los datos que se le pasan. Entonces, sí, aún así, cada ronda de E/S realizada por C++ stdlib llegará al kernel, pero al menos tendrá una velocidad de escritura casi constante (y casi instantánea).
Si necesitas ambas medidasylos datos generados, considere crear un llamado disco RAM y redirigir la salida a un archivo ubicado allí.
Una cosa más sobre la medición: tenga en cuenta que incluso en un sistema aparentemente inactivo que ejecuta un sistema operativo básico (como su Ubuntu o lo que sea), la CPU nunca duerme; siempre hay algunas tareas que se realizan en segundo plano. Esto significa que medir el rendimiento de cálculo incluso sin ninguna E/S o con una especie de E/S "deshabilitada" (como se explicó anteriormente) seguirá produciendo resultados diferentes en cada ejecución.
Para compensar esto, una buena evaluación comparativa significa ejecutar el cálculo con los mismos datos de entrada varios miles de veces y promediar los resultados entre el número de ejecuciones.