nanosleep の精度

nanosleep が pthread のスケジューリングポリシーと優先度で違いが出るか実験。結果は、変わらない(当たり前?)。それより、 10 ms の nanosleep からオーバヘッド 1ms 程度以内 で復帰できるとは最近の Linux は精度があがってる。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>

#define NUM_OF_REPEAT 10
#define BUF_SIZE      1024

/* milli sec */
#define TIMEOUT 10

#define NELEMS(array) (sizeof(array) / sizeof(array[0]))

typedef struct ThreadTable {
    int   policy;
    int   priority;
} ThreadTable;

int sprint_msec(char *buf)
{
    struct timeval tv;
    struct tm      tm;
    int            len;

    gettimeofday(&tv, NULL);
    localtime_r(&(tv.tv_sec), &tm);

    len = sprintf(buf, "%d [sec], %03ld [msec], %03ld [usec]\n",
                  (int)tv.tv_sec,
                  tv.tv_usec / 1000, tv.tv_usec % 1000);
    return len;
}

/* milli sec */
int calc_elapsed(struct timeval *tv_before, struct timeval *tv_after)
{
    int sec;
    int usec;

    sec  = tv_after->tv_sec - tv_before->tv_sec;
    usec = tv_after->tv_usec - tv_before->tv_usec;

    return (sec * 1000) + (usec / 1000);
}

char *get_policy_str(int num)
{
    switch (num) {
    case SCHED_OTHER:
        return "SCHED_OTHER";
    case SCHED_FIFO:
        return "SCHED_FIFO";
    case SCHED_RR:
        return "SCHED_RR";
    default:
        return "Unknown schedule policy";
        break;
    }
}

void *timer_thread(void *no_use)
{
    char               *p;
    struct timeval      tv_before;
    struct timeval      tv_after;
    struct timespec     ts;
    int                 i;
    int                 sum;
    char                buf[BUF_SIZE];
    int                 policy;
    struct sched_param  param;

    p          = buf;
    sum        = 0;
    ts.tv_sec  = 0;
    ts.tv_nsec = TIMEOUT * 1000 * 1000;

    p += sprint_msec(p);
    for (i = 0; i < NUM_OF_REPEAT; i++) {
        gettimeofday(&tv_before, NULL);
        nanosleep(&ts, NULL);
        gettimeofday(&tv_after, NULL);
        sum += calc_elapsed(&tv_before, &tv_after);
        p += sprint_msec(p);
    }

    /* print info */
    if (0 != pthread_getschedparam(pthread_self(), &policy, &param)) {
        perror("pthread_getschedparam");
        pthread_exit(NULL);
    }
    printf("%s(%d) priority %d\n",
           get_policy_str(policy), policy, param.sched_priority);
    printf("%s", buf);
    printf("average %.3f [msec]\n\n", 1.0 * sum / NUM_OF_REPEAT);

    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char *argv[])
{
    int                i;
    pthread_t          thread;
    pthread_attr_t     attr;
    struct sched_param sched_param;

    ThreadTable thread_table[] = {
        {SCHED_OTHER, 0},
        {SCHED_FIFO,  1},
        {SCHED_FIFO,  50},
        {SCHED_FIFO,  99},
        {SCHED_RR,    1},
        {SCHED_RR,    5},
        {SCHED_RR,    99},
    };

    for (i = 0; i < NELEMS(thread_table); i++) {
        pthread_attr_init(&attr);

        if (0 != pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
            perror("pthread_attr_setinheritsched");
            exit(1);
        }

        if (0 != pthread_attr_setschedpolicy(&attr, thread_table[i].policy)) {
            perror("pthread_attr_setschedpolicy");
            exit(1);
        }

        pthread_attr_getschedparam(&attr, &sched_param);
        sched_param.sched_priority = thread_table[i].priority;
        if (0 != pthread_attr_setschedparam(&attr, &sched_param)) {
            perror("pthread_attr_setschedparam");
            exit(1);
        }

        if (0 != pthread_create(&thread, &attr, &timer_thread, NULL)) {
            fprintf(stderr, "error : pthread_create\n");
            exit(1);
        }

        pthread_join(thread, NULL);
    }

    return 0;
}
SCHED_OTHER(0) priority 0
1264078401 [sec], 389 [msec], 798 [usec]
1264078401 [sec], 401 [msec], 502 [usec]
1264078401 [sec], 413 [msec], 505 [usec]
1264078401 [sec], 425 [msec], 500 [usec]
1264078401 [sec], 437 [msec], 500 [usec]
1264078401 [sec], 449 [msec], 501 [usec]
1264078401 [sec], 461 [msec], 498 [usec]
1264078401 [sec], 473 [msec], 527 [usec]
1264078401 [sec], 485 [msec], 497 [usec]
1264078401 [sec], 497 [msec], 499 [usec]
1264078401 [sec], 509 [msec], 495 [usec]
average 11.100 [msec]

SCHED_FIFO(1) priority 1
1264078401 [sec], 510 [msec], 058 [usec]
1264078401 [sec], 521 [msec], 538 [usec]
1264078401 [sec], 533 [msec], 517 [usec]
1264078401 [sec], 545 [msec], 492 [usec]
1264078401 [sec], 557 [msec], 492 [usec]
1264078401 [sec], 569 [msec], 490 [usec]
1264078401 [sec], 581 [msec], 489 [usec]
1264078401 [sec], 593 [msec], 488 [usec]
1264078401 [sec], 605 [msec], 494 [usec]
1264078401 [sec], 617 [msec], 487 [usec]
1264078401 [sec], 629 [msec], 487 [usec]
average 11.000 [msec]

SCHED_FIFO(1) priority 50
1264078401 [sec], 630 [msec], 566 [usec]
1264078401 [sec], 642 [msec], 500 [usec]
1264078401 [sec], 654 [msec], 485 [usec]
1264078401 [sec], 666 [msec], 484 [usec]
1264078401 [sec], 678 [msec], 483 [usec]
1264078401 [sec], 690 [msec], 481 [usec]
1264078401 [sec], 702 [msec], 484 [usec]
1264078401 [sec], 714 [msec], 482 [usec]
1264078401 [sec], 726 [msec], 482 [usec]
1264078401 [sec], 738 [msec], 479 [usec]
1264078401 [sec], 750 [msec], 481 [usec]
average 11.000 [msec]

SCHED_FIFO(1) priority 99
1264078401 [sec], 750 [msec], 669 [usec]
1264078401 [sec], 762 [msec], 515 [usec]
1264078401 [sec], 774 [msec], 480 [usec]
1264078401 [sec], 786 [msec], 478 [usec]
1264078401 [sec], 798 [msec], 477 [usec]
1264078401 [sec], 810 [msec], 480 [usec]
1264078401 [sec], 822 [msec], 477 [usec]
1264078401 [sec], 834 [msec], 474 [usec]
1264078401 [sec], 846 [msec], 473 [usec]
1264078401 [sec], 858 [msec], 477 [usec]
1264078401 [sec], 870 [msec], 471 [usec]
average 11.000 [msec]

SCHED_RR(2) priority 1
1264078401 [sec], 870 [msec], 668 [usec]
1264078401 [sec], 882 [msec], 487 [usec]
1264078401 [sec], 894 [msec], 468 [usec]
1264078401 [sec], 906 [msec], 469 [usec]
1264078401 [sec], 918 [msec], 465 [usec]
1264078401 [sec], 930 [msec], 467 [usec]
1264078401 [sec], 942 [msec], 468 [usec]
1264078401 [sec], 954 [msec], 464 [usec]
1264078401 [sec], 966 [msec], 462 [usec]
1264078401 [sec], 978 [msec], 461 [usec]
1264078401 [sec], 990 [msec], 460 [usec]
average 11.000 [msec]

SCHED_RR(2) priority 5
1264078401 [sec], 991 [msec], 557 [usec]
1264078402 [sec], 003 [msec], 479 [usec]
1264078402 [sec], 015 [msec], 462 [usec]
1264078402 [sec], 027 [msec], 460 [usec]
1264078402 [sec], 039 [msec], 459 [usec]
1264078402 [sec], 051 [msec], 457 [usec]
1264078402 [sec], 063 [msec], 457 [usec]
1264078402 [sec], 075 [msec], 455 [usec]
1264078402 [sec], 087 [msec], 454 [usec]
1264078402 [sec], 099 [msec], 453 [usec]
1264078402 [sec], 111 [msec], 453 [usec]
average 11.100 [msec]

SCHED_RR(2) priority 99
1264078402 [sec], 111 [msec], 613 [usec]
1264078402 [sec], 123 [msec], 465 [usec]
1264078402 [sec], 135 [msec], 461 [usec]
1264078402 [sec], 147 [msec], 454 [usec]
1264078402 [sec], 159 [msec], 451 [usec]
1264078402 [sec], 171 [msec], 449 [usec]
1264078402 [sec], 183 [msec], 447 [usec]
1264078402 [sec], 195 [msec], 446 [usec]
1264078402 [sec], 207 [msec], 447 [usec]
1264078402 [sec], 219 [msec], 445 [usec]
1264078402 [sec], 231 [msec], 444 [usec]
average 11.000 [msec]