WeHack BBS
写个代码生成器测一下编译器的性能 - 可打印的版本

+- WeHack BBS (https://bbs.wehack.space)
+-- 版块: 计算机技术 (https://bbs.wehack.space/forum-5.html)
+--- 版块: 程序设计讨论区 (https://bbs.wehack.space/forum-14.html)
+--- 主题: 写个代码生成器测一下编译器的性能 (/thread-314.html)



写个代码生成器测一下编译器的性能 - vimacs - 10-20-2021

看到一个搞笑的帖子:https://www.mysmth.net/nForum/#!article/CPlusPlus/419878
这个代码用一个大型switch-case来输出答案,结果某编译器编译时堆空间不足。我想实测一下现在的编译器能不能对付这种代码,于是我试着生成了C++,C,Ada,Zig四种语言的版本。

代码:
#!/usr/bin/env python

def print1(s):
    print('    {}'.format(s))

def print2(s):
    print('        {}'.format(s))

def putline_cxx(s):
    return "cout << \"{}\" << endl;".format(s)

def putline_c(s):
    return "puts(\"{}\");".format(s)

def case_start_c(s):
    return "case {}:".format(s)

def case_end_c():
    return "break;"

def putline_ada(s):
    return "Put_Line(\"{}\");".format(s)

def case_start_ada(s):
    return "when {} =>".format(s)

def case_end_ada():
    return ""

def putline_zig(s):
    return "try stdout.writeAll(\"%(str)s\\n\");" % {"str":s}

def case_start_zig(s):
    return "%(str)s => {" % {"str":s}

def case_end_zig():
    return "},"

def gencode(n, putline_code, case_start, case_end):
    posname = ["个", "十", "百", "千", "万"]
    sn = str(n)
    print1(case_start(sn))
    print2(putline_code("是{}位数".format(len(sn))))
    t = n
    idx = 0
    while t > 0:
        print2(putline_code("{}位数是:{}".format(posname[idx], t % 10)))
        t = t // 10
        idx = idx + 1

    print2(putline_code("倒过来是:{}".format("".join([sn[i] for i in range(len(sn)-1,-1,-1)]))))
    print2(case_end())

def gencode_cxx(upper_bound):
    print('''#include <iostream>
using namespace std;

int main()
{
    int x;
    cin >> x;

    switch(x) {
''')

    for i in range(1, upper_bound):
        gencode(i, putline_cxx, case_start_c, case_end_c)

    print('''
    }
}
''')

def gencode_c(upper_bound):
    print('''#include <stdio.h>

int main()
{
    int x;
    scanf("%d", &x);

    switch(x) {
''')

    for i in range(1, upper_bound):
        gencode(i, putline_c, case_start_c, case_end_c)

    print('''
    }
}
''')

def gencode_ada(upper_bound):
    print('''with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Print_Number is
    x: Integer;
begin
    Get(x);
    case x is
''')

    for i in range(1, upper_bound):
        gencode(i, putline_ada, case_start_ada, case_end_ada)

    print('''
        when others => null;
    end case;
end Print_Number;
''')

# 1min for 1 .. 10000
def gencode_zig(upper_bound):
    print(r'''const std = @import("std");
const stdin = std.io.getStdIn();
const stdout = std.io.getStdOut();

fn nextLine(reader: anytype, buffer: []u8) !?[]const u8 {
    var line = (try reader.readUntilDelimiterOrEof(
        buffer,
        '\n',
    )) orelse return null;
    // trim annoying windows-only carriage return character
    if (std.builtin.os.tag == .windows) {
        line = std.mem.trimRight(u8, line, "\r");
    }
    return line;
}

pub fn main() !void {
    var buffer: [100]u8 = undefined;
    const input = (try nextLine(stdin.reader(), &buffer)).?;
    const x = std.fmt.parseInt(i32, input, 0) catch 0;

    switch (x) {
''')

    for i in range(1, upper_bound):
        gencode(i, putline_zig, case_start_zig, case_end_zig)

    print('''
        else => {}
    }
}
''')

if __name__ == "__main__":
    gencode_c(100000)

最后结果可以看原帖下方的评论。编译这些代码都不开优化选项。tcc对付这样的代码毫无压力,1s之内能编译出来。Clang编译C的版本用了10多秒,编译C++版本用了2分半钟。GCC编译这样的代码性能就不行了,C,C++,Ada都是好几分钟都不出代码,不知道卡在哪里。Zig编译时卡在语义分析阶段。


RE: 写个代码生成器测一下编译器的性能 - vimacs - 10-22-2021

GCC 11 用 -fno-bit-tests 应该能提高 GCC 处理大型 switch-case 的速度,有时间再试一下。
另外GCC和Clang编译这样的C++程序的确很耗内存,都用了10多个G,GCC耗的内存更多。


RE: 写个代码生成器测一下编译器的性能 - vimacs - 10-30-2021

用GNAT测了一下,用 -fno-bit-tests 和默认的 -fbit-tests 编译速度有一定的差别,但是不是很大,感觉这个选项还有可能影响了C前端。