现在,我正在研究系统内核实践课程。但是,当我将系统调用与用户调用进行比较时,奇怪的是系统调用返回的时间计数为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毫秒,这样可以在内核中快速进行计算吗?
答案 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是否成功,然后释放内存)