Насколько надежен current_kernel_time ()? - PullRequest
8 голосов
/ 07 января 2011

Я работаю над сравнительным тестированием производительности драйвера SDIO UART Linux / Android и использую current_kernel_time () в начале и в конце реализации функций чтения, записи, которые нужно проанализировать, а затем распечатывать разницу во времени.

Большую часть времени я получаю разницу во времени в 0 (ноль) наносекунд (независимо от размера данных для чтения / записи: 16-2048 байт), что, по логике, я считаю неправильным, только очень немногиеполучить некоторые значения, надеюсь, что они верны.

Насколько надежен current_kernel_time ()?

Почему я получаю 0ns в большинстве случаев?

Я планирую профилировать на уровне ядра, чтобы получить больше деталей ... прежде чем кто-то сможет пролить свет на это поведение ... Кто-нибудь наблюдал что-то подобное раньше ...

Также,Любые предложения, которые помогут / исправят мой подход к тестированию, также приветствуются!

Спасибо.

РЕДАКТИРОВАТЬ:
Это код чтения из ядра Linux версии 2.6.32.9.Я добавил current_kernel_time (), как показано ниже под # ifdef-endif:

static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *status)
{
#ifdef SDIO_UART_DEBUG
struct timespec time_spec1, time_spec2;
time_spec1 = current_kernel_time();
#endif

    struct tty_struct *tty = port->tty;
    unsigned int ch, flag;
    int max_count = 256;

    do {
        ch = sdio_in(port, UART_RX);
        flag = TTY_NORMAL;
        port->icount.rx++;

        if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
                        UART_LSR_FE | UART_LSR_OE))) {
            /*
             * For statistics only
             */
            if (*status & UART_LSR_BI) {
                *status &= ~(UART_LSR_FE | UART_LSR_PE);
                port->icount.brk++;
            } else if (*status & UART_LSR_PE)
                port->icount.parity++;
            else if (*status & UART_LSR_FE)
                port->icount.frame++;
            if (*status & UART_LSR_OE)
                port->icount.overrun++;

            /*
             * Mask off conditions which should be ignored.
             */
            *status &= port->read_status_mask;
            if (*status & UART_LSR_BI) {
                flag = TTY_BREAK;
            } else if (*status & UART_LSR_PE)
                flag = TTY_PARITY;
            else if (*status & UART_LSR_FE)
                flag = TTY_FRAME;
        }

        if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
            tty_insert_flip_char(tty, ch, flag);

        /*
         * Overrun is special.  Since it's reported immediately,
         * it doesn't affect the current character.
         */
        if (*status & ~port->ignore_status_mask & UART_LSR_OE)
            tty_insert_flip_char(tty, 0, TTY_OVERRUN);

        *status = sdio_in(port, UART_LSR);
    } while ((*status & UART_LSR_DR) && (max_count-- > 0));
    tty_flip_buffer_push(tty);

#ifdef SDIO_UART_DEBUG
time_spec2 = current_kernel_time();
printk(KERN_INFO "\n MY_DBG : read took: %ld nanoseconds",
    (time_spec2.tv_sec  - time_spec1.tv_sec) * 1000000000 + (time_spec2.tv_nsec - time_spec1.tv_nsec));
#endif

}

1 Ответ

11 голосов
/ 07 января 2011

current_kernel_time предназначен для хронометража, а не для измерения производительности.Он возвращает значение, основанное не на фактическом таймере, а на временном значении, которое обновляется прерыванием таймера.Таким образом, точность зависит от периода прерывания таймера.и вы получаете плохое разрешение.

Однако, возможно, getnstimeofday больше подходит для ваших нужд, так как он также считывает фактический источник часов для настройки значения времени.Он должен быть более мелкозернистым.

Исходя из ядра source , возможно, лучшая функция - getrawmonotonic, в маловероятном случае, когда системное время корректируется в обратном направлении во время измерения.*

...