更改C代码以完全运行(包括if的所有部分)

时间:2013-07-11 08:00:26

标签: c performance testing automation dead-code

注意:我意识到我的问题不明确。我现在修改了它,并为首先犯错而道歉。

我有一个大型 C项目,它将在嵌入式系统上运行。我使用 ARM编译器。 代码分布在多个子文件夹中,由.c和.h文件组成。

我希望总结多少次调用哪些函数,以便识别死代码以及加速最常用的函数。 ARM编译器有一些删除无法访问代码的选项,当函数指针发挥作用时它会失败 所以,我想通过代码的每个分支并记录对函数的调用次数。

例如(这是一个非常简单的程序,用于演示我正在寻找的内容,而不是原始代码):

void foo1(void)
{
    printf("Number is divisible by 5");
}
void foo2(void)
{
    printf("Number is divisible by 10");
}
void foo3(void)
{
    printf("Number is divisible by neither 10 nor 5");
}
void foo4(void)
{
    printf("foo4 called");
}


int main (void)
{
    int x;

    x = rand (11);

    if (! x%10)
    {
        foo2();
        foo1();
    }
    else if (! x%5)       foo1();
    else             foo3();

    return 0;
}

我希望运行整个代码,以便访问if分支的所有部分(即foo1,foo2和foo3)。这将帮助我确定调用哪个函数多少次。 在上面的例子中,foo1()比foo2()更频繁地被调用,并且永远不会调用foo4()。 因此,识别和删除foo4()并优化foo1()。

是有意义的

运行整体代码的任何想法/工具?

我认为修改主要功能的方法之一是:

int main (void)
{
    int x ;

    x = rand (11);

    //*************************************************
    //starting modification
    int a = 1; //added by me
    if_1: //added by me
    if (a == 1)
    {
        foo1(); //original code
        foo2(); //original code

        a=2; //added by me
        goto if_1; //added by me
    }

    else if (a==2)
    {
        foo2(); //original code
        a=3; //added by me
        goto if_1: //added by me
    }
    else             foo3(); //original code
    //end of modification
    //********************************************************        

    return 0;
}

这种方式贯穿原始代码。 知道如何进行这种修改吗?

3 个答案:

答案 0 :(得分:2)

int main (void)
{
    int x = 5;
#ifdef DEBUG
    int debug_i, debug_data[] = { 5, 10, 20 };
    for(debug_i = 0;debug_i<sizeof debug_data / sizeof *debug_data;++debug_i){
        x = debug_data[debug_i];
#endif
    if (x==5)        foo1();
    else if (x==10)  foo2();
    else             foo3();
#ifdef DEBUG
    }
#endif

    return 0;
}

答案 1 :(得分:0)

您也可以通过这种方式更改main()功能

int main (void)
{
    int x = 5;
    while () {
       if (x==5)        { foo1(); x=10;}
       else if (x==10)  { foo2(); x=0; }
       else             { foo3(); break;}
    }
    return 0;
}

答案 2 :(得分:0)

您基本上要求的是所谓的 profiling (每个函数被调用多少次)和代码覆盖(遍历代码的每个分支)。如果您使用gcc,则应查看用于分析的-p选项和用于代码覆盖的--coverage选项。这两个选项都会向程序添加代码,以便在运行程序时进行测量。然后,程序gprof用于查看分析结果,程序gcov用于查看代码覆盖率。

我不完全理解您为什么要更改原始程序。上述方法依赖于精心构造的程序测试输入,以提供代表性执行(用于分析)和高代码覆盖。在您的示例程序中,编译器可能会优化对foo2foo3的调用,因为没有可能的程序输入会触发这些调用。相反,如果您的程序看起来像:

#include <stdio.h>

void foo1(void)
{
    printf("Value is 5");
}

void foo2(void)
{
    printf("Number is 10");
}

void foo3(void)
{
    printf("Number is neither 10 nor 5");
}

int main (int argc, char ** argv)
{
    switch (argc)
    {
    case 5: foo1(); break;
    case 10: foo2(); break;
    default: foo3(); break;
    }

    return 0;
}

然后以a.out 1a.out 1 2 3 4a.out 1 2 3 4 5 6 7 8 9运行该程序将使程序通过所有分支。这三次运行将完全覆盖该计划。

应该注意的是,分析和代码覆盖本身就是一门艺术。在生成测试集以获得高代码覆盖率方面已经进行了大量研究,但我认为没有广泛建立的工具来生成这样的测试集。主要是因为做起来并不容易。然而,手动制作提供高代码覆盖率的测试集是软件测试中的标准过程。