c - 为什么我的linux系统调用时间几乎是0us?

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

现在,我正在学习系统内核实践类(class)。但是,当我将系统调用与用户调用进行比较时,奇怪的是系统调用返回 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;
}

我尝试了很多次,但结果都没有改变。同样数量的用户调用计算大约需要1300ms,内核中的计算能这么快吗?

最佳答案

让我们看一个循环:

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

关于c - 为什么我的linux系统调用时间几乎是0us?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56359402/

相关文章:

c - 当为 char 分配的值太大而无法容纳一个字节时会发生什么?

c - 数据和堆栈部分

windows - Windows 真的在虚拟机中运行吗?

java - 有人知道开源运营管理系统吗?

c - Haskell FFI 关于双指针参数的问题

c - i2c_register_board_info 符号未定义

c - 内核编程 : wait queue uses spinlock internally

c - 填充 skb 中的 header 字段

c - Fork(系统调用) - 进程数

c - 在这种情况下哪种操作系统概念应该更好