【问题标题】:Benchmarking C bubblesort performance compared to Julia与 Julia 相比,对 C 冒泡排序性能进行基准测试
【发布时间】:2022-07-24 06:51:59
【问题描述】:

我想对 C 和 Julia 的性能进行正式比较。为此,我想比较不同的排序算法,从气泡开始。在 Julia 中,我这样写:

using BenchmarkTools

function bubble_sort(v::AbstractArray{T}) where T<:Real
    for _ in 1:length(v)-1
        for i in 1:length(v)-1
            if v[i] > v[i+1]
                v[i], v[i+1] = v[i+1], v[i]
            end
        end
    end
    return v
end

v = rand(Int32, 100_000)
@timed bubble_sort(_v)

在 C 代码的情况下(我不知道用 C 编程,所以我为代码道歉):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static void swap(int *xp, int *yp){
    int temp = *xp;
    *xp = *yp;
    *yp = temp;
}

void bubble_sort(int arr[], int n){
    int i, j;
    for (j = 0; j < n - 1; j++){
        for (i = 0; i < n - 1; i++){
            if (arr[i] > arr[i+1]){
                swap(&arr[i], &arr[i+1]);
            }
        }
    }
}

int main(){
    int arr_sz = 100000;
    int arr[arr_sz], i;
    for (i = 0; i < arr_sz; i++){
        arr[i] = rand();
    }
    double cpu_time_used;
    clock_t begin = clock();
    bubble_sort(arr, arr_sz);
    clock_t end = clock();
    cpu_time_used = ((double) (end - begin)) / CLOCKS_PER_SEC;
    printf("time %f\n", cpu_time_used);
    return 0;
}

性能差异是(在我的电脑上):

Julia C
20s ~50s

我想我在 C 代码中有一个很大的错误,但我无法找到它,或者只是 Julia 在循环中更快?

更新:性能优化

  • 在 Julia 中将类型更改为 int32,使其与 C 相同
  • swap 静态方法(平均提高 1 秒)
  • 编译优化(详见下文)

我使用了不同的优化标志,而不是 gcc main.c,还有 clang 编译器。结果:

Time (s)
Julia 19.13
gcc -O main.c 47.58
gcc -O1 main.c 15.98
gcc -O2 main.c 19.52
gcc -O3 main.c 19.20
gcc -Os main.c 17.72
clang -O0 main.c 51.59
clang -O1 main.c 16.78
clang -O2 main.c 13.53
clang -O3 main.c 13.57
clang -Ofast main.c 12.39
clang -Os main.c 18.85
clang -Oz main.c 15.64
clang -Og main.c 16.37

【问题讨论】:

  • 正在在启用所有编译器优化的情况下进行编译,不是吗?
  • static void swap(int *xp, int *yp){...} 可能会产生很大的不同。 (或只是:内联)
  • FWIW 看起来您正在将苹果与橙子进行比较。 Julia 代码对 Int64 进行排序,而您的 C 程序可能使用 32 位整数。
  • @Frankie_C 不是。 gcc 会自己内联它。
  • @KonradRudolph 你是对的测试:-O0 时间 40.925213,-O1 时间 15.323867,-O2 时间 18.280225,-O3 时间 28.776320,@9876404 时间 28.776320,@9876443。刚刚在我的机器上测试了这个程序

标签: c performance julia


【解决方案1】:

在您发现您的初始测量是针对为调试而编译的代码进行的,而不是完全优化的,具有不同的数据集、不同的编译器平台和不同的整数表示之后,似乎这个问题可能已经重新打开。

我想我在 C 代码中有一个很大的错误,但我无法找到它,或者只是 Julia 在循环中更快?

我可以用a quote from the C standard 回答这个有点尴尬(在我看来)的双重问题:“本国际标准中的语义描述描述了与优化问题无关的抽象机器的行为。”简而言之,C 中没有速度;这是 C 的 implementations 中出现的一个属性。如果没有您的 implementation(例如,包括您的硬件),我们无法重现您的 speed .

Julia 很可能在她的规范中有类似的条款。要点是:一些漂亮的优化可能会确定您的排序数组没有任何必要的副作用,因此理论上这些可能会被优化掉。在这种情况下,我希望这两个程序的输出都接近 0.0。这是您的完美优化编译器;一种可以发现对程序逻辑没有实际影响的代码,并优化掉死代码

我们并不总是有循环不变的代码运动,因此这里可能有第五个元素是有道理的:您的编译器版本。如果底层 llvm 不同,您可能会得到不同的统计信息,例如:

与已有 10 多年历史的 LLVM 2.7 相比,LLVM 11 编译经过优化的代码所需的时间往往要长 2 倍,因此生成的代码运行速度快 10-20%(在任一方向上偶尔会出现异常值)。

-- source

也许有一天,您会用两个程序的 0.0s 输出来更新这个问题。那么这个问题就真的失去意义了。


很难说这里还有什么问题,@cbk。 cmets 部分通过这四项改进显着减少了 C 程序的运行时间。这个问题在这里甚至不再有意义了,因为它在很大程度上通过在最后回答自己来抵消自己。

也许这只是新手应该回答自己的问题用答案(你可以这样做)而不是用回答它的编辑来腐烂问题的情况之一。 . 尽管如此,这个问题现在在问题列表中显示为未回答。我会投票关闭,原因是“问题应该包括更多细节”,但我怀疑你可能会包括一个在程序集生成后停止编译的例子,当 OP 似乎掩盖了解决方案时,我们需要的细节更多类似于“您对这些回答您最初问题的 cmets 有什么不了解的地方?”然而,这个问题在表面上的意义却千差万别……我们会打一场近距离/重新开战吗?

【讨论】:

    猜你喜欢
    • 2015-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2015-09-13
    相关资源
    最近更新 更多