草庐IT

c++ - 在 32 位系统上使用 int64_t 而不是 int32_t 对性能有什么影响?

coder 2023-05-01 原文

我们的 C++ 库目前使用 time_t 来存储时间值。我开始在某些地方需要亚秒级精度,因此无论如何都需要更大的数据类型。此外,在某些地方解决 2038 年问题可能很有用。因此,我正在考虑完全切换到具有底层 int64_t 值的单个 Time 类,以替换所有位置的 time_t 值。

现在我想知道在 32 位操作系统或 32 位 CPU 上运行此代码时这种更改对性能的影响。 IIUC 编译器将生成代码以使用 32 位寄存器执行 64 位算术。但是如果这太慢了,我可能不得不使用更差异化的方式来处理时间值,这可能会使软件更难维护。

我感兴趣的是:

  • 哪些因素会影响这些操作的性能?可能是编译器和编译器版本;但是操作系统或 CPU 品牌/型号也会影响这一点吗?普通的 32 位系统会使用现代 CPU 的 64 位寄存器吗?
  • 在 32 位上模拟时哪些操作会特别慢?或者哪个几乎没有放缓?
  • 在 32 位系统上使用 int64_t/uint64_t 是否有任何现有的基准测试结果?
  • 有没有人对这种性能影响有自己的经验?

  • 我对 Intel Core 2 系统上 Linux 2.6(RHEL5、RHEL6)上的 g++ 4.1 和 4.4 最感兴趣;但了解其他系统(如 Sparc Solaris + Solaris CC、Windows + MSVC)的情况也会很好。

    最佳答案

    which factors influence performance of these operations? Probably the compiler and compiler version; but does the operating system or the CPU make/model influence this as well?



    主要是处理器架构(和模型 - 请阅读我在本节中提到处理器架构的模型)。编译器可能有一些影响,但大多数编译器在这方面做得很好,所以处理器架构的影响会比编译器大。

    操作系统不会有任何影响(除了“如果你改变操作系统,你需要使用不同类型的编译器来改变编译器的功能”在某些情况下 - 但这可能影响很小)。

    Will a normal 32-bit system use the 64-bit registers of modern CPUs?



    这不可能。如果系统处于 32 位模式,它将充当 32 位系统,额外的 32 位寄存器完全不可见,就像系统实际上是“真正的 32 位系统”一样.

    which operations will be especially slow when emulated on 32-bit? Or which will have nearly no slowdown?



    加法和减法更糟糕,因为这些必须按两个操作的顺序进行,而第二个操作需要第一个完成 - 如果编译器只是对独立数据生成两个加法运算,则情况并非如此。

    如果输入参数实际上是 64 位,乘法会变得更糟——例如,2^35 * 83 比 2^31 * 2^31 差。这是因为处理器可以很好地将 32 x 32 位乘法生成为 64 位结果 - 大约 5-10 个时钟周期。但是 64 x 64 位乘法需要相当多的额外代码,因此需要更长的时间。

    除法是一个与乘法类似的问题 - 但在这里可以在一侧取 64 位输入,将其除以 32 位值并得到 32 位值。由于很难预测这何时起作用,因此 64 位除法可能几乎总是很慢。

    数据还将占用两倍的缓存空间,这可能会影响结果。并且作为类似的结果,一般分配和传递数据所需的时间是最小值的两倍,因为要操作的数据量是原来的两倍。

    编译器还需要使用更多的寄存器。

    are there any existing benchmark results for using int64_t/uint64_t on 32-bit systems?



    可能吧,但我不知道。即使有,对你来说也只是有点意义,因为操作的组合对操作的速度非常关键。

    如果性能是您的应用程序的重要组成部分,则对您的代码(或其中的某些代表性部分)进行基准测试。如果 Benchmark X 给出的结果慢 5%、25% 或 103% 并不重要,如果您的代码在相同情况下慢或快的完全不同。

    does anyone have own experience about this performance impact?



    我为 64 位架构重新编译了一些使用 64 位整数的代码,并发现性能有了很大的提高——在某些代码位上提高了 25%。

    将您的操作系统更改为同一操作系统的 64 位版本,也许会有帮助?

    编辑:

    因为我喜欢找出这些东西的不同之处,所以我编写了一些代码,并使用了一些原始模板(仍在学习这一点 - 模板并不是我 HitTest 门的话题,我必须说 - 给我bitfddling 和指针算术,我会(通常)做对......)

    这是我写的代码,试图复制一些常见的函数:
    #include <iostream>
    #include <cstdint>
    #include <ctime>
    
    using namespace std;
    
    static __inline__ uint64_t rdtsc(void)
    {
        unsigned hi, lo;
        __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
        return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
    }
    
    template<typename T>
    static T add_numbers(const T *v, const int size)
    {
        T sum = 0;
        for(int i = 0; i < size; i++)
        sum += v[i];
        return sum;
    }
    
    
    template<typename T, const int size>
    static T add_matrix(const T v[size][size])
    {
        T sum[size] = {};
        for(int i = 0; i < size; i++)
        {
        for(int j = 0; j < size; j++)
            sum[i] += v[i][j];
        }
        T tsum=0;
        for(int i = 0; i < size; i++)
        tsum += sum[i];
        return tsum;
    }
    
    
    
    template<typename T>
    static T add_mul_numbers(const T *v, const T mul, const int size)
    {
        T sum = 0;
        for(int i = 0; i < size; i++)
        sum += v[i] * mul;
        return sum;
    }
    
    template<typename T>
    static T add_div_numbers(const T *v, const T mul, const int size)
    {
        T sum = 0;
        for(int i = 0; i < size; i++)
        sum += v[i] / mul;
        return sum;
    }
    
    
    template<typename T> 
    void fill_array(T *v, const int size)
    {
        for(int i = 0; i < size; i++)
        v[i] = i;
    }
    
    template<typename T, const int size> 
    void fill_array(T v[size][size])
    {
        for(int i = 0; i < size; i++)
        for(int j = 0; j < size; j++)
            v[i][j] = i + size * j;
    }
    
    
    
    
    uint32_t bench_add_numbers(const uint32_t v[], const int size)
    {
        uint32_t res = add_numbers(v, size);
        return res;
    }
    
    uint64_t bench_add_numbers(const uint64_t v[], const int size)
    {
        uint64_t res = add_numbers(v, size);
        return res;
    }
    
    uint32_t bench_add_mul_numbers(const uint32_t v[], const int size)
    {
        const uint32_t c = 7;
        uint32_t res = add_mul_numbers(v, c, size);
        return res;
    }
    
    uint64_t bench_add_mul_numbers(const uint64_t v[], const int size)
    {
        const uint64_t c = 7;
        uint64_t res = add_mul_numbers(v, c, size);
        return res;
    }
    
    uint32_t bench_add_div_numbers(const uint32_t v[], const int size)
    {
        const uint32_t c = 7;
        uint32_t res = add_div_numbers(v, c, size);
        return res;
    }
    
    uint64_t bench_add_div_numbers(const uint64_t v[], const int size)
    {
        const uint64_t c = 7;
        uint64_t res = add_div_numbers(v, c, size);
        return res;
    }
    
    
    template<const int size>
    uint32_t bench_matrix(const uint32_t v[size][size])
    {
        uint32_t res = add_matrix(v);
        return res;
    }
    template<const int size>
    uint64_t bench_matrix(const uint64_t v[size][size])
    {
        uint64_t res = add_matrix(v);
        return res;
    }
    
    
    template<typename T>
    void runbench(T (*func)(const T *v, const int size), const char *name, T *v, const int size)
    {
        fill_array(v, size);
    
        uint64_t long t = rdtsc();
        T res = func(v, size);
        t = rdtsc() - t;
        cout << "result = " << res << endl;
        cout << name << " time in clocks " << dec << t  << endl;
    }
    
    template<typename T, const int size>
    void runbench2(T (*func)(const T v[size][size]), const char *name, T v[size][size])
    {
        fill_array(v);
    
        uint64_t long t = rdtsc();
        T res = func(v);
        t = rdtsc() - t;
        cout << "result = " << res << endl;
        cout << name << " time in clocks " << dec << t  << endl;
    }
    
    
    int main()
    {
        // spin up CPU to full speed...
        time_t t = time(NULL);
        while(t == time(NULL)) ;
    
        const int vsize=10000;
    
        uint32_t v32[vsize];
        uint64_t v64[vsize];
    
        uint32_t m32[100][100];
        uint64_t m64[100][100];
    
    
        runbench(bench_add_numbers, "Add 32", v32, vsize);
        runbench(bench_add_numbers, "Add 64", v64, vsize);
    
        runbench(bench_add_mul_numbers, "Add Mul 32", v32, vsize);
        runbench(bench_add_mul_numbers, "Add Mul 64", v64, vsize);
    
        runbench(bench_add_div_numbers, "Add Div 32", v32, vsize);
        runbench(bench_add_div_numbers, "Add Div 64", v64, vsize);
    
        runbench2(bench_matrix, "Matrix 32", m32);
        runbench2(bench_matrix, "Matrix 64", m64);
    }
    

    编译:
    g++ -Wall -m32 -O3 -o 32vs64 32vs64.cpp -std=c++0x
    

    结果是:注意:请参阅下面的 2016 年结果 - 由于在 64 位模式下使用 SSE 指令的差异,这些结果略显乐观,但在 32 位模式下没有使用 SSE。
    result = 49995000
    Add 32 time in clocks 20784
    result = 49995000
    Add 64 time in clocks 30358
    result = 349965000
    Add Mul 32 time in clocks 30182
    result = 349965000
    Add Mul 64 time in clocks 79081
    result = 7137858
    Add Div 32 time in clocks 60167
    result = 7137858
    Add Div 64 time in clocks 457116
    result = 49995000
    Matrix 32 time in clocks 22831
    result = 49995000
    Matrix 64 time in clocks 23823
    

    如您所见,加法和乘法并没有那么糟糕。 split 变得非常糟糕。有趣的是,矩阵加法根本没有太大区别。

    在 64 位上是否更快?我听到你们中的一些人问:
    使用相同的编译器选项,只是 -m64 而不是 -m32 - yupp,快得多:
    result = 49995000
    Add 32 time in clocks 8366
    result = 49995000
    Add 64 time in clocks 16188
    result = 349965000
    Add Mul 32 time in clocks 15943
    result = 349965000
    Add Mul 64 time in clocks 35828
    result = 7137858
    Add Div 32 time in clocks 50176
    result = 7137858
    Add Div 64 time in clocks 50472
    result = 49995000
    Matrix 32 time in clocks 12294
    result = 49995000
    Matrix 64 time in clocks 14733
    

    编辑,2016 年更新 :
    在编译器的 32 位和 64 位模式下,有和没有 SSE 的四种变体。

    这些天我通常使用 clang++ 作为我常用的编译器。我尝试用 g++ 编译(但它仍然是与上面不同的版本,因为我已经更新了我的机器 - 我也有一个不同的 CPU)。由于 g++ 无法在 64 位中编译 no-sse 版本,因此我没有看到这一点。 (无论如何,g++ 给出了类似的结果)

    作为一个短表:
    Test name      | no-sse 32 | no-sse 64 | sse 32 | sse 64 |
    ----------------------------------------------------------
    Add uint32_t   |   20837   |   10221   |   3701 |   3017 |
    ----------------------------------------------------------
    Add uint64_t   |   18633   |   11270   |   9328 |   9180 |
    ----------------------------------------------------------
    Add Mul 32     |   26785   |   18342   |  11510 |  11562 |
    ----------------------------------------------------------
    Add Mul 64     |   44701   |   17693   |  29213 |  16159 |
    ----------------------------------------------------------
    Add Div 32     |   44570   |   47695   |  17713 |  17523 |
    ----------------------------------------------------------
    Add Div 64     |  405258   |   52875   | 405150 |  47043 |
    ----------------------------------------------------------
    Matrix 32      |   41470   |   15811   |  21542 |   8622 |
    ----------------------------------------------------------
    Matrix 64      |   22184   |   15168   |  13757 |  12448 |
    

    带有编译选项的完整结果。
    $ clang++ -m32 -mno-sse 32vs64.cpp --std=c++11 -O2
    $ ./a.out
    result = 49995000
    Add 32 time in clocks 20837
    result = 49995000
    Add 64 time in clocks 18633
    result = 349965000
    Add Mul 32 time in clocks 26785
    result = 349965000
    Add Mul 64 time in clocks 44701
    result = 7137858
    Add Div 32 time in clocks 44570
    result = 7137858
    Add Div 64 time in clocks 405258
    result = 49995000
    Matrix 32 time in clocks 41470
    result = 49995000
    Matrix 64 time in clocks 22184
    
    $ clang++ -m32 -msse 32vs64.cpp --std=c++11 -O2
    $ ./a.out
    result = 49995000
    Add 32 time in clocks 3701
    result = 49995000
    Add 64 time in clocks 9328
    result = 349965000
    Add Mul 32 time in clocks 11510
    result = 349965000
    Add Mul 64 time in clocks 29213
    result = 7137858
    Add Div 32 time in clocks 17713
    result = 7137858
    Add Div 64 time in clocks 405150
    result = 49995000
    Matrix 32 time in clocks 21542
    result = 49995000
    Matrix 64 time in clocks 13757
    
    
    $ clang++ -m64 -msse 32vs64.cpp --std=c++11 -O2
    $ ./a.out
    result = 49995000
    Add 32 time in clocks 3017
    result = 49995000
    Add 64 time in clocks 9180
    result = 349965000
    Add Mul 32 time in clocks 11562
    result = 349965000
    Add Mul 64 time in clocks 16159
    result = 7137858
    Add Div 32 time in clocks 17523
    result = 7137858
    Add Div 64 time in clocks 47043
    result = 49995000
    Matrix 32 time in clocks 8622
    result = 49995000
    Matrix 64 time in clocks 12448
    
    
    $ clang++ -m64 -mno-sse 32vs64.cpp --std=c++11 -O2
    $ ./a.out
    result = 49995000
    Add 32 time in clocks 10221
    result = 49995000
    Add 64 time in clocks 11270
    result = 349965000
    Add Mul 32 time in clocks 18342
    result = 349965000
    Add Mul 64 time in clocks 17693
    result = 7137858
    Add Div 32 time in clocks 47695
    result = 7137858
    Add Div 64 time in clocks 52875
    result = 49995000
    Matrix 32 time in clocks 15811
    result = 49995000
    Matrix 64 time in clocks 15168
    

    关于c++ - 在 32 位系统上使用 int64_t 而不是 int32_t 对性能有什么影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16841382/

    有关c++ - 在 32 位系统上使用 int64_t 而不是 int32_t 对性能有什么影响?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    5. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    8. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

      我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

    随机推荐