2010-04-05 13 views
2

Je n'arrive pas à obtenir un programme simple (avec beaucoup d'accès à la mémoire) pour obtenir un timing cohérent sous Linux. J'utilise un noyau 2.6, et le programme est exécuté sur un processeur dual-core avec la priorité en temps réel. J'essaie de désactiver les effets de cache en déclarant les matrices de mémoire comme volatiles. Voici les résultats et le programme. Quelles sont les sources possibles des valeurs aberrantes?Obtenir la cohérence de la synchronisation sous Linux

Résultats:

Number of trials: 100 
Range: 0.021732s to 0.085596s 
Average Time: 0.058094s 
Standard Deviation: 0.006944s 
Extreme Outliers (2 SDs away from mean): 7 
Average Time, excluding extreme outliers: 0.059273s 

Programme:

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

#include <sched.h> 
#include <sys/time.h> 

#define NUM_POINTS 5000000 
#define REPS 100 

unsigned long long getTimestamp() { 
    unsigned long long usecCount; 
    struct timeval timeVal; 
    gettimeofday(&timeVal, 0); 
    usecCount = timeVal.tv_sec * (unsigned long long) 1000000; 
    usecCount += timeVal.tv_usec; 
    return (usecCount); 
} 

double convertTimestampToSecs(unsigned long long timestamp) { 
    return (timestamp/(double) 1000000); 
} 

int main(int argc, char* argv[]) { 
    unsigned long long start, stop; 
    double times[REPS]; 
    double sum = 0; 
    double scale, avg, newavg, median; 
    double stddev = 0; 
    double maxval = -1.0, minval = 1000000.0; 
    int i, j, freq, count; 
    int outliers = 0; 
    struct sched_param sparam; 

    sched_getparam(getpid(), &sparam); 
    sparam.sched_priority = sched_get_priority_max(SCHED_FIFO); 
    sched_setscheduler(getpid(), SCHED_FIFO, &sparam); 

    volatile float* data; 
    volatile float* results; 

    data = calloc(NUM_POINTS, sizeof(float)); 
    results = calloc(NUM_POINTS, sizeof(float)); 

    for (i = 0; i < REPS; ++i) { 
    start = getTimestamp(); 
    for (j = 0; j < NUM_POINTS; ++j) { 
     results[j] = data[j]; 
    } 
    stop = getTimestamp(); 
    times[i] = convertTimestampToSecs(stop-start); 
    } 

    free(data); 
    free(results); 

    for (i = 0; i < REPS; i++) { 
    sum += times[i]; 

    if (times[i] > maxval) 
     maxval = times[i]; 

    if (times[i] < minval) 
     minval = times[i]; 
    } 
    avg = sum/REPS; 

    for (i = 0; i < REPS; i++) 
    stddev += (times[i] - avg)*(times[i] - avg); 
    stddev /= REPS; 
    stddev = sqrt(stddev); 

    for (i = 0; i < REPS; i++) { 
    if (times[i] > avg + 2*stddev || times[i] < avg - 2*stddev) { 
     sum -= times[i]; 
     outliers++; 
    } 
    } 
    newavg = sum/(REPS-outliers); 

    printf("Number of trials: %d\n", REPS); 
    printf("Range: %fs to %fs\n", minval, maxval); 
    printf("Average Time: %fs\n", avg); 
    printf("Standard Deviation: %fs\n", stddev); 
    printf("Extreme Outliers (2 SDs away from mean): %d\n", outliers); 
    printf("Average Time, excluding extreme outliers: %fs\n", newavg); 

    return 0; 
} 
+0

Courez-vous en tant que root '(sinon vous ne pourrez pas utiliser SCHED_FIFO). En outre, volatile ne va pas autour des effets de cache CPU. Voir aussi http://stackoverflow.com/questions/88/ – nos

+0

Yup - Je l'utilise en tant que root. De plus, je ne vois pas quelle partie de cet article parle du cache. –

+0

Il parle de la résolution de gettimeofday, pas des caches :) – nos

Répondre

3

Assurez-vous que vous avez pas d'autres processus prenant du temps CPU. Attention en particulier pour les économiseurs d'écran et tout ce qui fait régulièrement des mises à jour GUI (par exemple une horloge ou similaire). Essayez de définir l'affinité de l'UC pour votre processus d'analyse comparative afin de la verrouiller sur un cœur (par exemple, taskset à partir de la ligne de commande). Faites votre processus de benchmark si vous ne faites pas de pagination - typiquement vous voulez avoir une boucle externe qui court N fois et ensuite chronométrer les dernières N-1 exécutions.

+0

Je suis à peu près sûr que le fait de mettre le processus en priorité en temps réel me protège de toutes ces choses de l'interface graphique. L'audio est parfois aussi RT, mais je me suis assuré qu'il n'y avait rien de ce genre en cours d'exécution. Je l'ai limité à un noyau comme vous l'avez dit. Comme vous pouvez le voir à partir des résultats, il y a 7 valeurs aberrantes, donc exclure le premier ne fera pas l'affaire. Les valeurs aberrantes sont réparties uniformément entre les essais. –

+0

@Jim: Je ne serais pas trop sûr de la priorité en temps réel - essayez de vous débarrasser complètement de l'interface graphique et exécutez simplement depuis une console ('sudo init 1') et utilisez' taskset' pour assurer l'affinité CPU. –

+0

'init 1' a fait l'affaire. Il est bon de savoir qu'il y a des choses de l'interface graphique qui peuvent gâcher un processus RT. Cependant, je ne comprends pas très bien ce qui se passe là-bas. Les seuls processus RT sur mon système sont 'migration/0',' migration/1', 'watchdog/0', et' watchdog/1'. Merci! –