2008-12-11 15 views
24

Estaba leyendo una reseña del nuevo Intel Atom 330, donde notaron que el Administrador de tareas muestra 4 núcleos: dos núcleos físicos, más dos más simulados por Hyperthreading.Multicore + Hyperthreading: ¿cómo se distribuyen los hilos?

Supongamos que tiene un programa con dos hilos. Supongamos también que estos son los únicos hilos que hacen algún trabajo en la PC, todo lo demás está inactivo. ¿Cuál es la probabilidad de que el SO ponga ambos hilos en el mismo núcleo? Esto tiene enormes implicaciones para el rendimiento del programa.

Si la respuesta es algo más que 0%, ¿hay alguna otra estrategia de mitigación que no sea crear más hilos?

espero habrá diferentes respuestas para Windows, Linux y Mac OS X.


Usando sk's answer como Google forraje, a continuación, siguiendo los enlaces, me encontré con la función GetLogicalProcessorInformation en Windows. Habla de "procesadores lógicos que comparten recursos. Un ejemplo de este tipo de intercambio de recursos sería escenarios de hipertrofia". Esto implica que jalf es correcto, pero no es una respuesta definitiva.

+2

Me gustaría comentar que la política óptima no siempre es ejecutar las dos tareas en diferentes núcleos; por ejemplo, si tiene dos tareas que comparten memoria y realizan muchas operaciones no superpuestas, ejecutarlas en el mismo núcleo puede proporcionar un mayor rendimiento porque la reducción en el caché no compensa el tiempo de ejecución ligeramente más lento que ocasionalmente tiene que compartir el procesador (recuerde, en este escenario, ambos subprocesos usualmente se ejecutarán en paralelo incluso en un núcleo porque están usando diferentes unidades lógicas). – Borealid

+0

Solo como un FYI: si está buscando un rendimiento sin procesar, es posible que desee deshabilitar hyperthreading. A menos que Intel haya finalmente funcionado bien. En el pasado (lo último que medí estaba en un procesador 2x P4 Xeon box con hyperthreading (produciendo 4 procesadores lógicos para el sistema operativo), el rendimiento neto de ejecutar 4 hilos computacionalmente intensivos con hyperthreading habilitado produce un rendimiento neto menor que ejecutar 2 hilos con hyperthreading desactivado. Obviamente, querrá probarlo usted mismo con el último hardware, puede que ya no sea el caso. Pero tenga en cuenta ... –

+2

Ejecutar subprocesos en el mismo núcleo es EXACTAMENTE lo que quiere, a veces. Por ejemplo, cuando ejecuta hilos en núcleos físicos separados, la línea de caché que intercambia núcleos DECIDE el rendimiento. –

Respuesta

2

Puede asegurarse de que ambos hilos se programen para las mismas unidades de ejecución dándoles una afinidad de procesador. Esto se puede hacer en Windows o en Unix, ya sea a través de una API (para que el programa pueda solicitarla) o a través de interfaces administrativas (para que un administrador pueda configurarlo). P.ej. en WinXP puede usar el Administrador de tareas para limitar qué procesador (es) lógico (s) puede ejecutar un proceso.

De lo contrario, la programación será esencialmente aleatoria y puede esperar un uso del 25% en cada procesador lógico.

+0

Si bien nunca he sido de los que le gusta dejar las cosas al sistema operativo, estableciendo un hilo la máscara de afinidad puede ser perjudicial para el rendimiento si las cosas se ponen ocupadas. ¿Sería SetThreadIdealProcessor() una mejor opción? – NTDLS

2

La probabilidad es esencialmente 0% de que el sistema operativo no utilice tantos núcleos físicos como sea posible. Tu sistema operativo no es estúpido. Su trabajo es programar todo, y sabe muy bien qué núcleos tiene disponible. Si ve dos subprocesos intensivos en CPU, se asegurará de que se ejecutan en dos núcleos físicos.

Edición Sólo para elaborar un poco, para la materia de alto rendimiento, una vez llegue a MPI u otros marcos de paralelización graves, que debe de controlar lo que se ejecuta en cada núcleo.

El sistema operativo hará una especie de intento de mejor esfuerzo para utilizar todos los núcleos, pero no tiene la información a largo plazo que usted hace, que "este hilo va a funcionar durante mucho tiempo", o que "tendremos muchos hilos ejecutándose en paralelo". Por lo tanto, no puede tomar decisiones perfectas, lo que significa que su hilo se asignará a un nuevo núcleo de vez en cuando, lo que significa que se encontrará con errores de caché y similares, lo que le costará un poco de tiempo. Para la mayoría de los propósitos, es lo suficientemente bueno, y ni siquiera notará la diferencia de rendimiento. Y también funciona bien con el resto del sistema, si eso importa. (En el sistema de escritorio de alguien, eso es probablemente bastante importante. En una cuadrícula con algunos miles de CPU dedicados a esta tarea, no desea particularmente jugar bien, solo quiere usar cada ciclo de reloj disponible).

Por lo tanto, para HPC a gran escala, sí, querrá que cada hilo permanezca en un núcleo, fijo. Pero para la mayoría de las tareas más pequeñas, en realidad no importará, y puede confiar en el programador del sistema operativo.

+0

Me gustaría creer eso también, pero un poco la evidencia sería útil. –

+0

¿Evidencia de qué? Cree un programa que ejecute dos subprocesos en un ciclo infinito y verifique el uso de la CPU. Descubrirá que cualquier sistema operativo sano asigna un hilo a cada núcleo. ¿Crees que es un problema que los diseñadores de sistemas operativos no han considerado? Por supuesto no. Es un problema fundamental que un sistema operativo * debe * manejar. – jalf

+0

No tengo este sistema a mano para probar, de lo contrario no es una mala sugerencia. –

1

No sé sobre las otras plataformas, pero en el caso de Intel, publican una gran cantidad de info on threading en su Intel Software Network. También tienen un boletín informativo gratuito (The Intel Software Dispatch) que puede suscribirse por correo electrónico y ha tenido muchos de esos artículos últimamente.

8

Linux tiene un programador de hilos bastante sofisticado que es compatible con HT.Algunas de sus estrategias incluyen:

Balanceo de carga pasivo: si una CPU física está ejecutando más de una tarea, el planificador intentará ejecutar cualquier tarea nueva en un segundo procesador físico.

Balanceo de carga activo: si hay 3 tareas, 2 en una CPU física y 1 en la otra cuando el segundo procesador físico permanece inactivo, el planificador intentará migrarle una de las tareas.

Lo hace al intentar mantener la afinidad del hilo porque cuando un hilo migra a otro procesador físico tendrá que volver a llenar todos los niveles de caché de la memoria principal causando un bloqueo en la tarea.

Para responder a su pregunta (al menos en Linux); dado 2 hilos en una máquina de doble núcleo hyperthreaded, cada hilo se ejecutará en su propio núcleo físico.

+0

No veo que eso ocurra en mi máquina. Ejecutando 'stress -c 2' en mi i5-2520M, a veces programa (y mantiene) los dos hilos en los núcleos HT 1 y 2, que se asignan al mismo núcleo físico. Incluso si el sistema está inactivo de lo contrario. (Encontré el HT-> reconocimiento de núcleo físico con procesador 'egrep' | identificación física | ID de núcleo "/ proc/cpuinfo | sed 's/^ procesador/\ nprocesador/g''.) – nh2

+0

Hice este problema más concreto con [esta pregunta] (http://stackoverflow.com/questions/29422073/why-does-linuxs-scheduler-put-two-threads-onto-the-same-physical-core-on-proces). – nh2

5

Un sistema operativo sane intentará programar tareas intensivas computacionalmente en sus propios núcleos, pero surgen problemas cuando se inician cambios de contexto. Los sistemas operativos modernos todavía tienen una tendencia a programar cosas en núcleos donde no hay trabajo en el tiempo de programación, pero esto puede hacer que los procesos en aplicaciones paralelas se intercambien de núcleo a núcleo de manera bastante liberal. Para aplicaciones paralelas, no desea esto, porque pierde datos que el proceso podría haber estado usando en las memorias caché en su núcleo. Las personas usan la afinidad del procesador para controlar esto, pero en Linux, la semántica de sched_affinity() puede variar mucho entre distros/kernels/vendors, etc.

Si está en Linux, puede controlar portables la afinidad del procesador con el Portable Linux Processor Affinity Library (PLPA). Esto es lo que OpenMPI usa internamente para asegurarse de que los procesos se programen en sus propios núcleos en sistemas multinúcleo y multisono; acaban de derivar el módulo como un proyecto independiente. OpenMPI se usa en Los Alamos entre muchos otros lugares, por lo que este es un código bien probado. No estoy seguro de cuál es el equivalente en Windows.

+1

+1, solo tenga en cuenta que la función es 'sched_setaffinity'. – avakar

5

He estado buscando algunas respuestas sobre la programación de subprocesos en Windows, y tengo alguna información empírica que publicaré aquí para cualquier persona que pueda tropezar con esta publicación en el futuro.

Escribí un sencillo programa de C# que lanza dos hilos. En mi caja cuádruple de Windows 7, vi algunos resultados sorprendentes.

Cuando no forcé la afinidad, Windows distribuyó la carga de trabajo de los dos hilos en los cuatro núcleos. Hay dos líneas de código que están comentadas, una que vincula un hilo a una CPU y otra que sugiere una CPU ideal. La sugerencia parecía no tener ningún efecto, pero establecer la afinidad del hilo hizo que Windows ejecutara cada hilo en su propio núcleo.

Para ver mejor los resultados, compile este código utilizando el compilador de libre disponibilidad csc.exe que viene con el cliente .NET Framework 4.0 y ejecútelo en una máquina con múltiples núcleos. Con la línea de afinidad del procesador comentada, el Administrador de tareas mostró los subprocesos repartidos en los cuatro núcleos, cada uno de los cuales funciona aproximadamente al 50%. Con afinidad establecida, los dos subprocesos alcanzaron un máximo de dos núcleos al 100%, con los otros dos núcleos inactivos (que es lo que esperaba ver antes de ejecutar esta prueba).

EDIT: Al principio encontré algunas diferencias en el rendimiento con estas dos configuraciones. Sin embargo, no he podido reproducirlos, así que edité esta publicación para reflejar eso. Todavía encontré el hilo de afinidad interesante ya que no era lo que esperaba.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Threading.Tasks; 

class Program 
{ 
    [DllImport("kernel32")] 
    static extern int GetCurrentThreadId(); 

    static void Main(string[] args) 
    { 
     Task task1 = Task.Factory.StartNew(() => ThreadFunc(1)); 
     Task task2 = Task.Factory.StartNew(() => ThreadFunc(2)); 
     Stopwatch time = Stopwatch.StartNew(); 
     Task.WaitAll(task1, task2); 
     Console.WriteLine(time.Elapsed); 
    } 

    static void ThreadFunc(int cpu) 
    { 
     int cur = GetCurrentThreadId(); 
     var me = Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Where(t => t.Id == cur).Single(); 
     //me.ProcessorAffinity = (IntPtr)cpu;  //using this line of code binds a thread to each core 
     //me.IdealProcessor = cpu;    //seems to have no effect 

     //do some CPU/memory bound work 
     List<int> ls = new List<int>(); 
     ls.Add(10); 
     for (int j = 1; j != 30000; ++j) 
     { 
      ls.Add((int)ls.Average()); 
     } 
    } 
} 
+1

Debe tener en cuenta que si está utilizando el Administrador de tareas para ver el uso, el Administrador de tareas en sí mismo puede ser muy perturbador para el sistema, ya que generalmente se ejecuta con una prioridad potenciada. Intente forzar el Administrador de tareas a baja prioridad y vea si el patrón cambia. –

+0

¿Puedes compartir tus tiempos de ejecución bajo las diferentes configuraciones? –

2

Esta es una pregunta muy buena y relevante. Como todos sabemos, un núcleo hiper-enhebrado no es una verdadera CPU/núcleo. En cambio, es una CPU/núcleo virtual (de ahora en adelante diré núcleo).Se supone que el programador de CPU de Windows a partir de Windows XP es capaz de distinguir núcleos hyperthreading (virtuales) de núcleos reales. Podrías imaginarte entonces que en este mundo perfecto los maneja "bien" y no es un problema. Estarías equivocado.

La propia recomendación de Microsoft para optimizar un servidor BizTalk de Windows 2008 recomienda deshabilitar HyperThreading. Esto sugiere, para mí, que el manejo de núcleos hiperhilo no es perfecto y, a veces, los hilos obtienen una porción de tiempo en un núcleo con hiperproceso y sufren la penalización (una fracción del rendimiento de un núcleo real, 10% I ' Supongo, y Microsoft adivina 20-30%).

Microsoft referencia el artículo en el que sugerimos que deshabilite HyperThreading para mejorar la eficiencia del servidor: http://msdn.microsoft.com/en-us/library/cc615012(BTS.10).aspx

Es la segunda recomendación después de la actualización del BIOS, que es lo importante lo consideran. Dicen:

DE MICROSOFT:

"Desactivar hyper-threading en BizTalk equipos servidor Server y SQL

Es crítica hyper-threading se apagado de Computadoras BizTalk Server . Esta es una configuración de BIOS, que se encuentra típicamente en la configuración del procesador o f la configuración de BIOS. Hyper-threading hace que el servidor parezca tener más procesadores/núcleos de procesador que ; sin embargo, los procesadores de hiperproceso suelen proporcionar entre 20 y 30% del rendimiento de un núcleo de procesador/procesador físico . Cuando BizTalk Server cuenta el número de procesadores para ajustar sus algoritmos de autoajuste ; los procesadores de hiperproceso provocan que estos ajustes sean asimétricos, lo que es perjudicial para el rendimiento general. "

Ahora, ellos dicen que se debe a que arrojando los algoritmos de autoajuste, pero que van a mencionar problemas de contención (lo que sugiere que es un problema de programación más grande, al menos para mí). Léalo como quiera, pero creo que lo dice todo. HyperThreading era una buena idea cuando se usaban sistemas de CPU individuales, pero ahora es solo una complicación que puede dañar el rendimiento en este mundo multinúcleo.

En lugar de deshabilitar por completo HyperThreading , puede usar programas como Process Lasso (gratuito) para establecer las afinidades predeterminadas de CPU para procesos críticos, de modo que sus subprocesos nunca se asignen a CPU virtuales.

Entonces ... No creo que nadie sepa realmente cuán bien el Programador de CPU de Windows maneja las CPU virtuales, pero creo que es seguro decir que XP lo maneja peor, y lo han mejorado gradualmente desde entonces, pero todavía no es perfecto. De hecho, NUNCA puede ser perfecto porque el sistema operativo no tiene ningún conocimiento de qué subprocesos son mejores para poner en estos núcleos virtuales más lentos. Ese puede ser el problema allí, y por qué Microsoft recomienda deshabilitar HyperThreading en entornos de servidores.

También recuerde que incluso SIN HyperThreading, existe el problema de la "vibración central". Si puede mantener un hilo en un solo núcleo, eso es bueno, ya que reduce las penalizaciones de cambio de núcleo.

0

La posibilidad de que el SO envíe 2 hilos activos al mismo núcleo es cero a menos que los hilos estén atados a un núcleo específico (afinidad de hilos).

Las razones detrás de esto son en su mayoría relacionados HW:

  • El sistema operativo (y la CPU) quiere usar la menor cantidad de energía posible para que se ejecute las tareas lo más eficiente posible con el fin de introducir una baja estado de energía lo antes posible.
  • Ejecutar todo en el mismo núcleo hará que se caliente mucho más rápido. En condiciones patológicas, el procesador puede sobrecalentarse y reducir su reloj para que se enfríe. El calor excesivo también hace que los ventiladores de la CPU giren más rápido (piense en computadoras portátiles) y genere más ruido.
  • El sistema nunca está realmente inactivo. Los ISR y los DPC se ejecutan cada ms (en la mayoría de los sistemas operativos modernos).
  • La degradación del rendimiento debido al salto de subprocesos desde el núcleo hasta el núcleo es despreciable en el 99,99% de las cargas de trabajo.
  • En todos los procesadores modernos, el último nivel de caché se comparte, por lo tanto, no es tan malo conmutar los núcleos.
  • Para sistemas Multi-socket (Numa), el sistema operativo minimizará el salto de socket a socket para que el proceso permanezca "cerca" de su controlador de memoria. Este es un dominio complejo cuando se optimiza para tales sistemas (decenas/cientos de núcleos).

BTW, la forma en que el sistema operativo sabe que la topología de la CPU es a través de ACPI, una interfaz proporcionada por el BIOS.

En resumen, todo se reduce a consideraciones de potencia del sistema (duración de la batería, consumo de energía, ruido de la solución de refrigeración).

+0

No estaba pidiendo una lista de razones * por las que * it * no debería *, creo que todos podemos estar de acuerdo en eso. Me preguntaba si el sistema operativo tenía suficiente información para evitarlo y si los planificadores eran lo suficientemente inteligentes como para usar la información. La única parte de su respuesta relevante para eso es la mención de ACPI. –

+0

Mi respuesta proporcionó el "por qué" y el "cómo" planificadores se comportan como lo hacen y también si tienen esta información. ¿Estás buscando fragmentos de código de un kernel como respuesta? Si es así, los kernels de Linux y Darwin son de código abierto ... – egur

Cuestiones relacionadas