为Linux 3.2.x和基于2.6.x的系统编译的代码之间的显着时序差异

时间:2015-03-18 21:36:37

标签: linux gcc kernel porting glibc

我有一个应用程序,它是针对带有2.6.x内核的小型Linux发行版编写,测试和调试的。我最近尝试将项目迁移到基于Debian和3.2.x内核的发行版,我们注意到性能下降。我做了一些原始的基准测试,发现了usleep()时序,函数调用和差异的差异。循环定时等。

我不确定确切的2.6.x内核配置是什么(例如抢占模型等)并且我无法提取内核构建配置信息 - 我们只是把这个系统作为我们的图像一直用于我们的嵌入式应用程序对于3.2.x内核,我为我们的处理器构建了一个优化配置,具有“抢占内核”配置,并删除了一堆完全不需要的可选模块(像HAM无线电设备驱动程序这样的东西 - 完全合理地移除的东西)。

我们的系统是一个近乎实时的应用程序,没有硬实时要求(我们只需要在消耗之前保留某些缓冲区填充计算数据, 以固定速率完成但是一个由硬件控制,实际上我们的CPU负载在最苛刻的应用程序中保持在30%左右 - 我们的性能是保持缓冲区的填充并做一些等待空间的工作。我们使用pthreads,pthread_cond_wait / broadcast等来指示缓冲区状态,控制线程同步等。

首先,关于系统的一些序言。模式中有许多轮询线程:

while (threadRunning)
{
   CheckSomeStuff();
   usleep(polling_interval);
}

其他线程的模式如下:

while (threadRunning) 
{
    pthread_cond_wait(stuff_needed_condition, some_mutex); // wait on signal
    doSomeStuffWhenNeeded();
}

也就是说,我们注意到移植的应用程序中与细微的时序相关的问题,并且算法运行的速度比基于2.6.x内核的系统慢得多。

这个简单的基准是说明性的:

static volatile long g_foo;

static void setfoo(long foo)
{
    g_foo = foo;
}

static void printElapsed(struct timeval t1, struct timeval t2, const char* smsg)
{
    double time_elapsed;
    time_elapsed = (t2.tv_sec - t1.tv_sec)*1e6 + (t2.tv_usec-t1.tv_usec);
    printf("%s elapsed:  %.8f\n", smsg, time_elapsed);
}

static void benchmarks(long sleeptime)
{
    long i;

    double time_elapsed;

    struct timeval t1, t2;

    // test 1
    gettimeofday(&t1, NULL);
    for (i=0;i<sleeptime;i++)
    {
       usleep(1);
    }
    gettimeofday(&t2, NULL);
    printElapsed(t1, t2, "Loop usleep(1)");

    // test 2
    gettimeofday(&t1, NULL);
    usleep(sleeptime);
    gettimeofday(&t2, NULL);
    printElapsed(t1, t2, "Single sleep");


    // test 3
    gettimeofday(&t1, NULL);
    usleep(1);
    gettimeofday(&t2, NULL);
    printElapsed(t1, t2, "Single 1us sleep");

    // test 4
    gettimeofday(&t1, NULL);
    gettimeofday(&t2, NULL);
    printElapsed(t1, t2, "gettimeofday x 2");

    // test 5
    gettimeofday(&t1, NULL);
    for (i=0;i<n;i++)
    {
        setfoo(i);
    }
    gettimeofday(&t2, NULL);
    printElapsed(t1, t2, "loop function call");
}

以下是基准测试结果(是的,我知道输出小数位是傻):

Kernel 2.6.x trial 1:
Loop usleep(1) elapsed:  6063979.00000000
Single sleep elapsed:  100071.00000000
Single 1us sleep elapsed:  63.00000000
gettimeofday x 2 elapsed:  1.00000000
loop function call elapsed:  267.00000000

Kernel 2.6.x trial 2:
Loop usleep(1) elapsed:  6059328.00000000
Single sleep elapsed:  100070.00000000
Single 1us sleep elapsed:  63.00000000
gettimeofday x 2 elapsed:  0.00000000
loop function call elapsed:  265.00000000

Kernel 2.6.x trial 3:
Loop usleep(1) elapsed:  6063762.00000000
Single sleep elapsed:  100064.00000000
Single 1us sleep elapsed:  63.00000000
gettimeofday x 2 elapsed:  1.00000000
loop function call elapsed:  266.00000000


kernel 3.2.65 trial 1:
Loop usleep(1) elapsed:  8944631.00000000
Single sleep elapsed:  100106.00000000
Single 1us sleep elapsed:  96.00000000
gettimeofday x 2 elapsed:  2.00000000
loop function call elapsed:  491.00000000

kernel 3.2.65 trial 2:
Loop usleep(1) elapsed:  8891191.00000000
Single sleep elapsed:  100102.00000000
Single 1us sleep elapsed:  94.00000000
gettimeofday x 2 elapsed:  2.00000000
loop function call elapsed:  396.00000000

kernel 3.2.65 trial 3:
Loop usleep(1) elapsed:  8962089.00000000
Single sleep elapsed:  100171.00000000
Single 1us sleep elapsed:  123.00000000
gettimeofday x 2 elapsed:  2.00000000
loop function call elapsed:  407.00000000

使用内核2.6.x和内核3.2.x的linux操作系统构建之间的壁挂时间差异很大,因为一个循环调用了usleep(1)(对于3.2.x而言为9秒,对于6秒为6秒) 2.6.x)。为了记录,我认为我们没有使用“usleep(1)”的电话;在代码库中的任何地方(但与任何大型应用程序一样,这里和那里可能存在更糟糕的事情)但是这仍然是行为的一个很大的不同。设置静态全局变量的循环次数也有很大差异(3.2上为400微秒,2.6上为260微秒)。

我意识到从glibc到编译器和放大器存在多个混淆问题。设置为linux内核配置。我希望从Stack Overflow中获得一些指导,从哪里开始戳。如果您必须完成此迁移,会做什么?您会看到哪些因素来解决我们看到的性能问题?

有关详细信息,这两个发行版分别为:

Puppy Linux - 内核2.6.35-7 SMP未知内核配置(虽然PREEMPT,我很确定) - glibc 2.6.1 - gcc 4.6.3

Debian wheezy 7.7(剥离) - 来自内核源代码的Linux 3.2.65自定义配置 - gcc 4.7.2 - glibc 2.13(Debian EGLIBC 2.13-38 + deb7u6)

1 个答案:

答案 0 :(得分:0)

您已更新内核,编译器和glibc版本。

不要。一次更新一个事物,并测量效果。然后你就会知道哪些更新实际上导致了你的问题(它可能不是内核)。

你应该只能更新内核,然后只更新旧系统上的glibc。