为什么我在Linux中进行系统调用的时间几乎是0 us?

时间:2019-05-29 11:19:42

标签: c linux-kernel operating-system system-calls

现在,我正在研究系统内核实践课程。但是,当我将系统调用与用户调用进行比较时,奇怪的是系统调用返回的时间计数为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 个答案:

答案 0 :(得分:1)

让我们看一个循环:

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是否成功,然后释放内存)