Pregunta

Así que me di cuenta de esta pregunta suena estúpido (y sí estoy usando un doble núcleo), pero me han tratado dos bibliotecas diferentes (Grand Central Dispatch y OpenMP), y cuando se utiliza el reloj () a tiempo el código con y sin el líneas que hacen que sea paralela, la velocidad es la misma. (Para el registro que se utilizan tanto en su propia forma de paralelo para). Informan que se ejecutan en diferentes hilos, pero tal vez se están ejecutando en el mismo núcleo? ¿Hay alguna manera de comprobar? (Ambas bibliotecas son para C, me siento incómodo en las capas inferiores.) Esto es super raro. ¿Alguna idea?

¿Fue útil?

Solución

EDIT:. Añadidos detalles de Grand Central Dispatch en respuesta a los comentarios del OP

Mientras que las otras respuestas aquí son útiles en general, la respuesta específica a su pregunta es que no se debe utilizar clock() para comparar el tiempo. clock() mide el tiempo de CPU que se añade al otro lado de los hilos. Al dividir un trabajo entre los núcleos, se utiliza por lo menos tanto tiempo de CPU (por lo general un poco más debido a enhebrar gastos generales). Búsqueda de reloj () en esta página , para encontrar "Si el proceso es multi-hilo, tiempo de CPU consumida por todos los hilos individuales se agregan de proceso ".

Es sólo que el trabajo se divide entre los hilos, por lo que el tiempo total que tiene que esperar que sea menor. Usted debe utilizar el tiempo de pared (la hora en un reloj de pared). OpenMP proporciona una omp_get_wtime() rutina para hacerlo. Tome la siguiente rutina como un ejemplo:

#include <omp.h>
#include <time.h>
#include <math.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    int i, nthreads;
    clock_t clock_timer;
    double wall_timer;
    for (nthreads = 1; nthreads <=8; nthreads++) {
        clock_timer = clock();
        wall_timer = omp_get_wtime();
        #pragma omp parallel for private(i) num_threads(nthreads)
        for (i = 0; i < 100000000; i++) cos(i);
        printf("%d threads: time on clock() = %.3f, on wall = %.3f\n", \
            nthreads, \
            (double) (clock() - clock_timer) / CLOCKS_PER_SEC, \
            omp_get_wtime() - wall_timer);
    }
}

Los resultados son:

1 threads: time on clock() = 0.258, on wall = 0.258
2 threads: time on clock() = 0.256, on wall = 0.129
3 threads: time on clock() = 0.255, on wall = 0.086
4 threads: time on clock() = 0.257, on wall = 0.065
5 threads: time on clock() = 0.255, on wall = 0.051
6 threads: time on clock() = 0.257, on wall = 0.044
7 threads: time on clock() = 0.255, on wall = 0.037
8 threads: time on clock() = 0.256, on wall = 0.033

Se puede ver que el tiempo clock() no cambia mucho. Consigo 0.254 sin la pragma, así que es un poco más lento usando OpenMP con un hilo que no usar OpenMP en absoluto, pero el tiempo de pared disminuye con cada hilo.

La mejora no siempre va a ser tan bueno debido a, por ejemplo, partes de su cálculo que no son paralelos (ver Amdahl's_law ) o diferentes hilos que luchan sobre la misma memoria.

EDIT: Para Grand Central Dispatch, el GCD referencia estados, que utiliza GCD gettimeofday por el tiempo de pared. Así, se crea una nueva aplicación de cacao, y en applicationDidFinishLaunching pongo:

struct timeval t1,t2;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int iterations = 1; iterations <= 8; iterations++) {
    int stride = 1e8/iterations;
    gettimeofday(&t1,0);
    dispatch_apply(iterations, queue, ^(size_t i) { 
        for (int j = 0; j < stride; j++) cos(j); 
    });
    gettimeofday(&t2,0);
    NSLog(@"%d iterations: on wall = %.3f\n",iterations, \
                t2.tv_sec+t2.tv_usec/1e6-(t1.tv_sec+t1.tv_usec/1e6));
}

y me da los siguientes resultados en la consola:

2010-03-10 17:33:43.022 GCDClock[39741:a0f] 1 iterations: on wall = 0.254
2010-03-10 17:33:43.151 GCDClock[39741:a0f] 2 iterations: on wall = 0.127
2010-03-10 17:33:43.236 GCDClock[39741:a0f] 3 iterations: on wall = 0.085
2010-03-10 17:33:43.301 GCDClock[39741:a0f] 4 iterations: on wall = 0.064
2010-03-10 17:33:43.352 GCDClock[39741:a0f] 5 iterations: on wall = 0.051
2010-03-10 17:33:43.395 GCDClock[39741:a0f] 6 iterations: on wall = 0.043
2010-03-10 17:33:43.433 GCDClock[39741:a0f] 7 iterations: on wall = 0.038
2010-03-10 17:33:43.468 GCDClock[39741:a0f] 8 iterations: on wall = 0.034

, que es casi lo mismo que me estaba anteriormente.

Este es un ejemplo muy artificial. De hecho, usted necesita estar seguro de mantener la optimización en -O0, o de lo contrario el compilador dará cuenta de que no mantenemos cualquiera de los cálculos y no hacemos el bucle en absoluto. Además, el número entero que estoy tomando la cos de es diferente en los dos ejemplos, pero eso no afecta a los resultados demasiado. Ver el STRIDE en la página del manual de dispatch_apply de cómo hacerlo correctamente y por qué iterations es ampliamente comparable a num_threads en este caso.

EDIT: Tomo nota de que la respuesta de Jacob incluye

  

utilizo el omp_get_thread_num ()   función dentro de mi bucle parallelized   imprimir cuyo núcleo está funcionando   en ... De esta manera usted puede estar seguro de que   se está ejecutando en ambos núcleos.

que no es correcta (que ha sido parcialmente fijado por una edición). Usando omp_get_thread_num() es de hecho una buena manera de asegurarse de que su código es multiproceso, pero no muestra "núcleo que se está trabajando en", el cual acaba de hilo. Por ejemplo, el código siguiente:

#include <omp.h>
#include <stdio.h>

int main() {
    int i;
    #pragma omp parallel for private(i) num_threads(50)
    for (i = 0; i < 50; i++) printf("%d\n", omp_get_thread_num());
}

imprime que es el uso de hilos de 0 a 49, pero esto no muestra cuyo núcleo está trabajando, ya que sólo tienen ocho núcleos. Al observar el Monitor de actividad (el PO mencionó GCD, por lo que debe estar en un Mac - ir Window/CPU Usage)!., Se puede ver el cambio entre trabajos núcleos, por lo core = hilo

Otros consejos

Lo más probable es que su tiempo de ejecución no está obligado por los bucles que parallelized.

Mi sugerencia es que un perfil de su código para ver lo que está pasando la mayor parte del tiempo. La mayoría de los ingenieros le dirá que usted debe hacer esto antes de hacer algo drástico para optimizar cosas.

Es difícil de adivinar, sin ningún detalle. Es posible que su aplicación no es ni siquiera por CPU. ¿Viste carga de la CPU, mientras que el código se ejecuta? Lo hizo golpear 100% en al menos un núcleo?

Su pregunta le faltan algunos detalles muy importantes como lo que la naturaleza de su aplicación es, ¿qué parte de ella está tratando de mejorar, de perfiles de resultados (si los hay), etc ...

Una vez dicho esto usted debe recordar varios puntos críticos cuando se acerca a un esfuerzo de mejora del rendimiento:

  • Los esfuerzos siempre deben concentrarse en las áreas de código que han sido probados, por perfiles , que es el ineficiente
  • Paralelización código depende de la CPU será casi nunca mejorar el rendimiento (en una sola máquina de la base). Van a perder un tiempo precioso en cambios de contexto innecesarios y ganar no . Usted puede muy fácilmente empeorar el rendimiento al hacer esto.
  • Incluso si usted está paralelización de código depende de la CPU en una máquina de múltiples núcleos, hay que recordar que nunca tenga ninguna garantía de ejecución en paralelo.

Asegúrese de que no va en contra de estos puntos, debido a una conjetura (si no hay detalles adicionales) dirá que eso es exactamente lo que está haciendo.

Si está utilizando una gran cantidad de memoria dentro del bucle, que puede evitar que sea más rápido. También se puede mirar en la biblioteca pthread, para manejar manualmente roscar.

Yo uso la función omp_get_thread_num() dentro de mi bucle parallelized imprimir cuyo núcleo que está trabajando en si no se especifica num_threads . Para por ejemplo.,

printf("Computing bla %d on core %d/%d ...\n",i+1,omp_get_thread_num()+1,omp_get_max_threads());

Lo anterior va a funcionar para este pragma     #pragma omp paralelo para defecto (ninguno) compartido (a, b, c)

De esta manera usted puede estar seguro de que se está ejecutando en ambos núcleos, ya que sólo 2 hilos será creada.

Por cierto, es OpenMP habilita cuando se está compilando? En Visual Studio tiene que habilitarla en el Páginas de propiedades de , C++ -> Language y establecer OpenMP Support a Yes

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top