2012-02-15 63 views
5

Mi CPU es un Core i3 330M con 2 núcleos y 4 hilos. Cuando ejecuto el comando cat /proc/cpuinfo en mi terminal, es como si tuviera 4 CPUS. Cuando uso la función OpenMP get_omp_num_procs() también obtengo 4.OpenMP y núcleos/hilos

Ahora tengo una clase de vector C++ estándar, me refiero a una clase de matriz doble de tamaño fijo que no usa plantillas de expresión. He paralelizado cuidadosamente todos los métodos de mi clase y obtengo la aceleración "esperada".

La pregunta es: ¿puedo adivinar la velocidad esperada en un caso tan simple? Por ejemplo, si agrego dos vectores sin bucles para-paralelos, obtengo algo de tiempo (usando el comando de tiempo de shell). Ahora, si uso OpenMP, ¿debería dividir el tiempo entre 2 o 4, de acuerdo con la cantidad de núcleos/hilos? Insisto en que solo estoy preguntando por este problema simple en particular, donde no hay interdependencia en los datos y todo es lineal (adición de vectores).

Aquí hay un código:

Vector Vector::operator+(const Vector& rhs) const 
{ 
    assert(m_size == rhs.m_size); 
    Vector result(m_size); 
    #pragma omp parallel for schedule(static) 
    for (unsigned int i = 0; i < m_size; i++) 
      result.m_data[i] = m_data[i]+rhs.m_data[i]; 

    return result; 
} 

ya he leído este post: OpenMP thread mapping to physical cores.

Espero que alguien me diga más acerca de cómo OpenMP hace el trabajo en este caso simple. Debo decir que soy un principiante en informática paralela.

Gracias!

Respuesta

3

EDIT: Ahora que se ha agregado algún código.

En ese ejemplo particular, hay muy pocos cálculos y mucho acceso a la memoria. Por lo tanto, el rendimiento dependerá en gran medida de:

  • El tamaño del vector.
  • Cómo lo está cronometrando. (¿Tiene un bucle externo para fines de temporización)
  • Si los datos ya están en caché.

Para tamaños de vector más grandes, es probable que el rendimiento esté limitado por el ancho de banda de su memoria. En ese caso, el paralelismo no ayudará mucho. Para tamaños más pequeños, dominará la sobrecarga de la rosca. Si está obteniendo la aceleración "esperada", probablemente esté en algún punto intermedio donde el resultado sea óptimo.

Me niego a dar números duros porque, en general, el rendimiento "adivinar", especialmente en aplicaciones de subprocesos múltiples es una causa perdida a menos que tenga conocimientos previos de prueba o conocimiento íntimo tanto del programa como del sistema en el que se ejecuta.

Así como un simple ejemplo tomado de mi respuesta aquí: How to get 100% CPU usage from a C program

En un Core i7 920 @ 3.5 GHz (4 núcleos, 8 hilos):

Si funciono con 4 hilos, el resultado es:

This machine calculated all 78498 prime numbers under 1000000 in 39.3498 seconds 

Si funciono con 4 hilos y explícitamente (utilizando Administrador de tareas) fijar los hilos en 4 núcleos físicos distintos, el resultado es:

This machine calculated all 78498 prime numbers under 1000000 in 30.4429 seconds 

Esto muestra lo impredecible que es incluso para una aplicación muy simple y embarazosamente paralela. Las aplicaciones que implican una gran cantidad de memoria y sincronización se ponen mucho más feas ...

1

Para agregar a Mysticals answer. Su problema es puramente ancho de banda de memoria limitado a. Eche un vistazo al STREAM benchmark. Ejecútelo en su computadora en casos únicos y de subprocesos múltiples, y observe los resultados de la Tríada: este es su caso (bueno, casi, ya que su vector de salida es al mismo tiempo uno de sus vectores de entrada). Calcule la cantidad de datos que mueve y sabrá exactamente qué rendimiento esperar.

¿Funciona el multi-threading para este problema? Sí. Es raro que un solo núcleo de CPU pueda saturar todo el ancho de banda de la memoria del sistema. Las computadoras modernas equilibran el ancho de banda de memoria disponible con la cantidad de núcleos disponibles. Desde mi experiencia, necesitarás alrededor de la mitad de los núcleos para saturar el ancho de banda de la memoria con una simple operación de memcopy. Puede tomar algunos más si hace algunos cálculos en el camino.

Tenga en cuenta que en los sistemas NUMA deberá unir los hilos a los núcleos de la CPU y utilizar la asignación de memoria local para obtener resultados óptimos. Esto se debe a que en dichos sistemas cada CPU tiene su propia memoria local, a la que el acceso es más rápido. Todavía puede acceder a la memoria completa del sistema, como en los SMP habituales, pero esto implica un costo de comunicación: las CPU tienen que intercambiar datos explícitamente. La vinculación de subprocesos a las CPU y el uso de la asignación local es extremadamente importante. Fallar en hacer esto mata la escalabilidad. Compruebe libnuma si desea hacer esto en Linux.