Почему мой счетчик времени системного вызова в Linux почти равен 0 нам? - PullRequest
0 голосов
/ 29 мая 2019

В настоящее время я работаю над курсом по системному ядру.Однако, когда я сравниваю системный вызов с пользовательским вызовом, странно, что системный вызов возвращает счетчик времени 0 us (иногда возвращает 1).Но я передаю count = 1e8, что является довольно большим числом.

Я сомневаюсь, что вычисления не произошли, потому что результат не используется.Затем я меняю add как result = result + 1 и печатаю окончательный результат.Тем не менее, результат правильный, и отсчет времени от 0 или 1 меняется на 2-6.

long yanpan_oper(int* result,int num1,int num2,char* op)
{
    if(op)
    {
        if(*op == '+')
        {
            *result = num1 + num2;
        }
        else if(*op == '-')
        {
            *result = num1 - num2;
        }
        else if(*op == '*')
        {
            *result = num1*num2;
        }
        else if(*op == '\\')
        {
            if(num2!=0)
                *result = num1/num2;
            else
                printk("divided number can't be zero!\n");
        }else
            printk("unrecongized operator %c\n", *op);
    }else
    {
        printk("operation is empty.\n");
    }
    return 0;
}
SYSCALL_DEFINE1(yanpan_func, int, count)
{
    printk("The count is %d.\n", count);
    struct timeval tstart, tend;
    do_gettimeofday(&tstart);
    int i;
    for(i=0;i<count;i++) // +
    {
        int result;
        char op_add = '+';
        yanpan_oper(&result, i, 10, &op_add);
    }
    for(i=0;i<count;i++) // -
    {
        int result;
        char op_sub = '-';
        yanpan_oper(&result, i, 10, &op_sub);
    }
    for(i=0;i<count;i++) // *
    {
        int result;
        char op_mul = '*';
        yanpan_oper(&result, i, 2, &op_mul);
    }
    for(i=0;i<count;i++) // '//'
    {
        int result;
        char op_div = '\\';
        yanpan_oper(&result, i, 10, &op_div);
    }
    do_gettimeofday(&tend);
    long delta_time = 1000000*(tend.tv_sec - tstart.tv_sec) + (tend.tv_usec - tstart.tv_usec);
    printk("The start time is %ld.\n", tstart.tv_sec*1000000+tstart.tv_usec);
    printk("The end time is %ld.\n", tend.tv_sec*1000000+tend.tv_usec);
    printk("Syscall time use:%ld usec", delta_time);
    return delta_time;
}

Я пробовал много раз, но результат не изменился.Вычисление пользовательских вызовов с той же суммой занимает около 1300 мс, могут ли вычисления происходить в ядре так быстро?

1 Ответ

1 голос
/ 29 мая 2019

Давайте посмотрим на один цикл:

for(i=0;i<count;i++) // +
{
    int result;
    char op_add = '+';
    yanpan_oper(&result, i, 10, &op_add);
}

Это вызовет функцию yanpan_oper count раз.Но каждый раз он будет перезаписывать предыдущий результат, сохраненный в result, без использования этого значения для вычисления.Скорее всего, компилятор просто оптимизировал весь цикл, заменив его одним единственным вызовом yanpan_oper, поскольку цикл for фактически эквивалентен простому выполнению тела цикла.

Кроме того, тело цикла ТОЛЬКОвлияет на переменные внутри тела цикла, поэтому компилятор может не только решить оставить последнюю итерацию.Он может пропустить практически весь код, так что вы фактически выполняете следующее:

SYSCALL_DEFINE1(yanpan_func, int, count)
{
    printk("The count is %d.\n", count);
    struct timeval tstart, tend;
    do_gettimeofday(&tstart);
    do_gettimeofday(&tend);
    long delta_time = 1000000*(tend.tv_sec - tstart.tv_sec) + (tend.tv_usec - tstart.tv_usec);
    printk("The start time is %ld.\n", tstart.tv_sec*1000000+tstart.tv_usec);
    printk("The end time is %ld.\n", tend.tv_sec*1000000+tend.tv_usec);
    printk("Syscall time use:%ld usec", delta_time);
    return delta_time;
}

Вот несколько советов, как обмануть оптимизатор:

// Create input that cannot be calculated at compile time
int input1[count];
int input2[count];
srand(time(NULL));
for(int i=0; i<count; i++) { 
    input1[i] = rand()%1000;
    input2[i] = rand()%1000;
}

// Store the output, so that the optimizer cannot take away the loop
int output[count];

// Start timer
for(i=0;i<count;i++) // +
{
    char op_add = '+';
    yanpan_oper(&output[i], input1[i], input2[i], &op_add);
}
// End timer

// Use the output to that the optimizer cannot remove the array, and thus
// also the loop
for(int i=0; i<count; i++) 
    printf("%d ", output[i]);

Заметьтечто эти массивы могут быть слишком большими для стека.Если это так, используйте вместо этого:

int *input1 = malloc(count * sizeof(*input1));
int *input2 = malloc(count * sizeof(*input2));
srand(time(NULL));
for(int i=0; i<count; i++) { 
    input1[i] = rand()%1000;
    input2[i] = rand()%1000;
}

int *output = malloc(count * sizeof(*output));

(Не забудьте проверить, успешно ли работает malloc, и освободить память впоследствии)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...