Cómo obtener el 100% del uso de la CPU de un programa C

79

Esta es una pregunta bastante interesante, así que permítanme preparar la escena. Trabajo en el Museo Nacional de Computación y acabamos de conseguir poner en funcionamiento una supercomputadora Cray Y-MP EL de 1992, ¡y realmente queremos ver qué tan rápido puede ir!

Decidimos que la mejor manera de hacer esto era escribir un programa C simple que calcule los números primos y muestre cuánto tiempo tomó hacerlo, luego ejecute el programa en una computadora de escritorio moderna y rápida y compare los resultados.

Rápidamente se nos ocurrió este código para contar números primos:

Lo cual en nuestra computadora portátil de doble núcleo con Ubuntu (The Cray ejecuta UNICOS), funcionó perfectamente, obteniendo el 100% de uso de la CPU y tomando aproximadamente 10 minutos más o menos. Cuando llegué a casa, decidí probarlo en mi PC de juegos moderna de núcleo hexagonal, y aquí es donde tenemos nuestros primeros problemas.

Primero adapté el código para ejecutarlo en Windows, ya que eso es lo que estaba usando la PC para juegos, pero me entristeció descubrir que el proceso solo obtenía alrededor del 15% de la potencia de la CPU. Pensé que Windows debía ser Windows, así que arranqué en un Live CD de Ubuntu pensando que Ubuntu permitiría que el proceso se ejecutara con todo su potencial como lo había hecho antes en mi computadora portátil.

¡Sin embargo, solo obtuve un 5% de uso! Entonces, mi pregunta es, ¿cómo puedo adaptar el programa para que se ejecute en mi máquina de juego en Windows 7 o en Linux en vivo al 100% de uso de la CPU? Otra cosa que sería genial pero no necesaria es si el producto final puede ser un .exe que pueda distribuirse y ejecutarse fácilmente en máquinas con Windows.

¡Muchas gracias!

PD: Por supuesto, este programa no funcionó realmente con los procesadores especializados Crays 8, y ese es otro problema ... Si sabe algo sobre cómo optimizar el código para que funcione en las supercomputadoras Cray de los 90, ¡díganos también!

viajante
fuente
8
No puedo creer que no haya una etiqueta unicos . ;)
Edward Thomson
32
Es extraño que este programa de un solo hilo tomara el 100% del uso de la CPU en el procesador DUAL CORE)))
mikithskegg
24
¿Soy el único que no encuentra esta pregunta interesante en absoluto? Viene uno, ejecutando un solo programa de rosca en una máquina de n-core y preguntando por qué se utiliza 1 / n de la CPU es simplemente ... no importa, sólo downvote :-)
Gunther Páez
16
@drhirsch Bueno, la pregunta muestra un esfuerzo de investigación. Hice +1 por eso, incluso si al OP le falta algo fundamental sobre la computación de múltiples núcleos.
Mysticial
9
@drhirsch Hay muchas preguntas poco interesantes en el sitio. Sin embargo, interesante o no es subjetivo. Puede que le falten los fundamentos y eso no es subjetivo. Como dijo Mystical, muestra un esfuerzo de investigación y no es tan fácil de responder como parece.
Carl

Respuestas:

81

Si desea un 100% de CPU, debe usar más de 1 núcleo. Para hacer eso, necesita varios hilos.

Aquí hay una versión paralela que usa OpenMP:

Tuve que aumentar el límite para 1000000que tardara más de 1 segundo en mi máquina.

Salida:

Esta máquina calculó todos los 78498 números primos por debajo de 1000000 en 29,753 segundos

Aquí está su CPU al 100%:

ingrese la descripción de la imagen aquí

Mística
fuente
1
@ cha0site Sí, respondí principalmente a la pregunta de la máquina de juego. Definitivamente hay formas más interesantes de vincular la CPU. Uno de los puntos de referencia más notorios que he hecho es mi respuesta a esta pregunta , que sobrecalentó 2 de las 4 máquinas que probé.
Mysticial
1
@Mystical Offtopic: ¿Qué hardware está ejecutando? Mi AMD Hex-Core @ 3.2Ghz lo hizo en 92 segundos ...
bag-man
1
@Owen: Tiene un Core i7 2600K ... Estoy celoso.
cha0site
19
¡Ay! Demasiado ... mucho ... rosa!
Mateen Ulhaq
2
@MohammadFadin en.wikipedia.org/wiki/Parallel_computing Básicamente, necesita poder procesar múltiples tareas en paralelo para poder utilizar una computadora de múltiples núcleos.
Mysticial
24

Está ejecutando un proceso en una máquina de varios núcleos, por lo que solo se ejecuta en un núcleo.

La solución es bastante fácil, ya que solo está tratando de vincular el procesador: si tiene N núcleos, ejecute su programa N veces (en paralelo, por supuesto).

Ejemplo

Aquí hay un código que ejecuta los NUM_OF_COREStiempos de su programa en paralelo. Es el código POSIXy, lo usa fork, por lo que debe ejecutarlo en Linux. Si lo que estoy leyendo sobre Cray es correcto, podría ser más fácil portar este código que el código OpenMP en la otra respuesta.

Salida

cha0site
fuente
Ah, como cuando necesitas ejecutar Prime95, tienes varias instancias ... ¿Seguramente hay una manera de que un proceso use múltiples núcleos? Como hacen los programas de descifrado de hash.
bag-man
Bueno, un proceso podría usar subprocesos para hacer multiprocesamiento, pero no creo que eso sea lo que quisiste decir, ya que un subproceso es casi un proceso separado en este contexto. De lo que realmente estamos hablando aquí es de "jefes de ejecución", ya sean hilos o procesos. Entonces, no, no hay forma de hacer que un programa de un solo subproceso se ejecute en múltiples núcleos, debe reescribirlo. Y a veces es muy difícil. Y a veces es realmente imposible.
cha0site
Bueno, supongo que no será tan difícil como hacer que el programa funcione también para Cray. Teniendo en cuenta que soy bastante nuevo en esto (lo que me delató: P), ¿dónde sería un buen lugar para comenzar?
bag-man
@Owen: Bueno, UNICOSparece que es algo similar a Unix (Wikipedia lo hace pensar de todos modos), así que probablemente lo haya hecho fork(). Deberías aprender a usar eso, creo.
cha0site
2
¡Oooh! Hice +1 ahora que tiene el ejemplo. :)
Mysticial
7

¡Realmente queremos ver qué tan rápido puede ir!

Su algoritmo para generar números primos es muy ineficiente. Compararlo con primegen que genera los primos 50847534 hasta 1000000000 en solo 8 segundos en un Pentium II-350.

Para consumir todas las CPU fácilmente, podría resolver un vergonzosamente paralelo , por ejemplo, calcular el conjunto de Mandelbrot o usar la programación genética para pintar Mona Lisa en múltiples subprocesos (procesos).

Otro enfoque es tomar un programa de referencia existente para la supercomputadora Cray y portarlo a una PC moderna.

jfs
fuente
No importa que el algoritmo sea ineficiente porque el objetivo no es calcular los números primos, es realizar una tarea genéricamente difícil y ver cuánto mejor o peor es que en un escritorio moderno. Un algoritmo eficiente haría esa comparación más difícil e incluso podría arruinar los resultados si es tan bueno que aprovecha deliberadamente las características / peculiaridades de la CPU moderna.
Numeron
5

La razón por la que obtiene un 15% en un procesador de núcleo hexadecimal es porque su código usa 1 núcleo al 100%. 100/6 = 16.67%, que usando un promedio móvil con programación de procesos (su proceso se estaría ejecutando con prioridad normal) podría reportarse fácilmente como 15%.

Por lo tanto, para usar el 100% de la CPU, necesitaría usar todos los núcleos de su CPU: inicie 6 rutas de código de ejecución paralela para una CPU de núcleo hexadecimal y tenga esta escala hasta la cantidad de procesadores que tenga su máquina Cray :)

Carl
fuente
El problema de hacer esto es que ¿cómo puedo obtener una cifra clara de la velocidad de cada una de las máquinas? También tiene el Cray "procesadores vectoriales" Al parecer, por lo que requiere una carga de trabajo más que esto para conseguir que se ejecute correctamente
bolsa de hombre-
No lo se. Probablemente diferencias en los procesos de programación.
Carl
2

También sé muy consciente de cómo está cargando la CPU. Una CPU puede realizar muchas tareas diferentes, y aunque muchas de ellas se informarán como "cargando la CPU al 100%", es posible que cada una use el 100% de diferentes partes de la CPU. En otras palabras, es muy difícil comparar el rendimiento de dos CPU diferentes, y especialmente dos arquitecturas de CPU diferentes. La ejecución de la tarea A puede favorecer a una CPU sobre otra, mientras que la ejecución de la tarea B puede ser fácilmente al revés (ya que las dos CPU pueden tener diferentes recursos internamente y pueden ejecutar código de manera muy diferente).

Esta es la razón por la que el software es tan importante como el hardware para que las computadoras funcionen de manera óptima. De hecho, esto también es muy cierto para las "supercomputadoras".

Una medida del rendimiento de la CPU podría ser instrucciones por segundo, pero, de nuevo, las instrucciones no se crean de la misma manera en diferentes arquitecturas de CPU. Otra medida podría ser el rendimiento de E / S de la caché, pero la infraestructura de la caché tampoco es igual. Entonces, una medida podría ser la cantidad de instrucciones por vatio utilizadas, ya que la entrega y disipación de energía suelen ser un factor limitante al diseñar una computadora de clúster.

Entonces, su primera pregunta debería ser: ¿Qué parámetro de rendimiento es importante para usted? ¿Qué quieres medir? Si desea ver qué máquina obtiene la mayor cantidad de FPS de Quake 4, la respuesta es fácil; su plataforma de juegos lo hará, ya que Cray no puede ejecutar ese programa en absoluto ;-)

Saludos, Steen

Steen Schmidt
fuente
2

TLDR; La respuesta aceptada es ineficiente e incompatible. El siguiente algoritmo funciona 100x más rápido.

El compilador gcc disponible en MAC no se puede ejecutar omp. Tuve que instalar llvm (brew install llvm ). Pero no vi que la CPU inactiva se estuviera cayendo mientras se ejecutaba la versión OMP.

Aquí hay una captura de pantalla mientras se estaba ejecutando la versión OMP. ingrese la descripción de la imagen aquí

Alternativamente, utilicé el hilo POSIX básico, que se puede ejecutar con cualquier compilador c y vi que casi toda la CPU se agotó cuando nos of thread= no of cores= 4 (MacBook Pro, Intel Core i5 de 2,3 GHz). Aquí está el programa:

Observe cómo se agota toda la CPU: ingrese la descripción de la imagen aquí

PD: si aumenta el número de subprocesos, el uso real de la CPU disminuirá (intente hacer que el número de subprocesos sea = 20.) ya que el sistema usa más tiempo en el cambio de contexto que la computación real.

Por cierto, mi máquina no es tan robusta como @mystical (respuesta aceptada). Pero mi versión con subprocesos POSIX básicos funciona mucho más rápido que OMP. Aquí está el resultado:

ingrese la descripción de la imagen aquí

PS Aumente la carga de subprocesos a 2,5 millones para ver el uso de la CPU, ya que se completa en menos de un segundo.

sapy
fuente
0

Intente paralelizar su programa usando, por ejemplo, OpenMP. Es un marco muy sencillo y eficaz para la realización de programas paralelos.

mikithskegg
fuente
0

Para una mejora rápida en un núcleo, elimine las llamadas al sistema para reducir el cambio de contexto. Elimina estas líneas:

El primero es particularmente malo, ya que generará un nuevo proceso en cada iteración.

Joel
fuente
0

Simplemente intente comprimir y descomprimir un archivo grande, nada como operaciones pesadas de E / S puede usar cpu.

Nima Mohammadi
fuente