linux - 为 linux 3.2.x 与基于 2.6.x 的系统编译的代码之间存在巨大的时间差异

标签 linux gcc kernel porting glibc

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

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

我们的系统是一个近乎实时的应用程序,没有严格的实时要求(我们只需要在计算数据被消耗之前用计算数据填充某些缓冲区,以固定速率完成的,但一个由硬件控制,在实践中,对于要求最苛刻的应用程序,我们的 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

对于调用 usleep(1) 的循环的 100,000 个循环,使用内核 2.6.x 和内核 3.2.x 的 Linux 操作系统上的构建之间存在巨大差异(3.2.x 为 9 秒,而内核为 6 秒2.6.x)。郑重声明,我不认为我们正在调用“usleep(1);”代码库中的任何地方(但与任何大型应用程序一样,可能到处都存在更糟糕的事情)但是尽管如此,这在行为上还是有很大的不同。在将静态全局变量设置 100,000 次的循环中也存在很大差异(3.2 上为 400 微秒,而 2.6 上为 260 微秒)。

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

有关更多信息,这两个分布是:

小狗Linux - 内核 2.6.35-7 SMP 未知内核配置(不过我很确定是 PREEMPT) -glibc 2.6.1 - 海合会 4.6.3

Debian wheezy 7.7(精简版) - 来自内核源的 Linux 3.2.65 自定义配置 - 海湾合作委员会 4.7.2 - glibc 2.13 (Debian EGLIBC 2.13-38+deb7u6)

最佳答案

您已经更新了内核、编译器和 glibc 版本。

不要那样做。一次更新一个,并衡量效果。然后您就会知道是哪个更新导致了您的问题(很可能不是内核)。

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

关于linux - 为 linux 3.2.x 与基于 2.6.x 的系统编译的代码之间存在巨大的时间差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29133184/

相关文章:

gcc - _mm256_fmadd_ps 比 _mm256_mul_ps + _mm256_add_ps 慢?

c++ - 如何在 GCC 中禁用#warning 消息?

linux - linux 内核、linux 设备驱动程序或模块编写器程序员是否需要算法分析?

c - 自制内核中的三重故障

linux - 这一行脚本有什么作用?

c++ - AVR - 中断 vector 和全局变量

linux - 从 cron 作业的 shell 脚本启动服务( Upstart )

linux-kernel - 如果 cpu 正在运行进程,谁在运行内核?

Linux:.c 和 Makefile "How to create the .s and .o file so that I can use "make“在终端中?”

linux - 如何在 Linux 命令行中将文本文件打印为 PDF 文件