【问题标题】:May changing unsigned int to size_t impact performances?将 unsigned int 更改为 size_t 会影响性能吗?
【发布时间】:2016-05-03 12:41:34
【问题描述】:

在我将一些遗留代码从 win32 移植到 win64 之后,在我讨论了消除“可能丢失数据”警告 (What's the best strategy to get rid of "warning C4267 possible loss of data"?) 的最佳策略之后。我将在我的代码中用size_t 替换许多unsigned int

但是,我的代码在性能方面至关重要(我什至无法在 Debug 中运行它……太慢了)。

我做了一个快速的基准测试:

#include "stdafx.h"

#include <iostream>
#include <chrono>
#include <string>

template<typename T> void testSpeed()
{
    auto start = std::chrono::steady_clock::now();

    T big = 0;
    for ( T i = 0; i != 100000000; ++i )
        big *= std::rand();

    std::cout << "Elapsed " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() << "ms" << std::endl;
}

int main()
{
    testSpeed<size_t>();
    testSpeed<unsigned int>();

    std::string str;
    std::getline( std::cin, str ); // pause

    return 0;
}

为 x64 编译,它输出:

Elapsed 2185ms
Elapsed 2157ms

为 x86 编译,它输出:

Elapsed 2756ms
Elapsed 2748ms

所以显然使用size_t 而不是unsigned int 对性能影响不大。但真的总是这样吗(很难以这种方式对性能进行基准测试)。

unsigned int 更改为size_t 是否/可能会影响 CPU 性能(现在将操作 64 位对象而不是 32 位对象)?

【问题讨论】:

  • 查看生成的汇编代码并尝试测量性能。
  • 您进行了基准测试吗?结果如何?你是怎么检查的?如果没有代码显示,答案是“是的,它可能影响性能”。但目前尚不清楚是哪个方向。
  • @CoryKramer:OP 声明他使用 Win64,后者使用 64 位 size_t 和 IL32。所以结论是正确的。
  • size_t 表示对象的大小。您不应该将其用于其他含义。此外,int_fast32_tuint_fast32_t 是类型定义,它们将解析为至少 32 位的某种 int 大小,这对于该平台来说是最快的。而且您不应该破坏您的代码以避免虚假警告。如果警告是真实的,并且您确实需要更大的类型才能使代码正常工作,那么您必须使用更大的类型。如果警告是虚假的,那么除了更改类型之外,还可以通过其他方式忽略、禁用或隐藏它们。
  • @M.M 如果警告是虚假的,则忽略、禁用或以其他方式隐藏它们 如果以后的更改引入了需要的代码,那么这样做的问题就会出现 您已禁用的警告。 IMO 最好只使用适合正在使用的函数/方法的较大尺寸,而不是忽略或禁用警告,因为您“知道”您的代码是正确的。如果编写您用来将代码转换为可运行二进制文件的编译器的人因为认为您正在做的事情不可靠而花费额外的时间发出警告,那么您最好听听他​​们的意见。

标签: c++ performance


【解决方案1】:

绝对不是。在现代(甚至更早的)CPU 上,64 位整数运算的执行速度与 32 位运算一样快。

在我的 i7 4600u 上进行算术运算 a * b / c 的示例:

(int32_t) * (int32_t) / (int32_t):1.3 纳秒
(int64_t) * (int64_t) / (int64_t):1.3 纳秒

为 x64 目标(与您的目标相同)编译的两个测试。

但是,如果您的代码管理充满整数的大对象(大整数数组,fox 示例),如果缓存未命中计数增加,使用size_t 而不是unsigned int 可能会对性能产生影响(更大的数据可能会超过缓存容量)。检查对性能影响的最可靠方法是在这两种情况下测试您的应用程序。使用您自己的 typedef'ed 类型对 size_tunsigned int 进行基准测试。

【讨论】:

  • 64 位操作会略微增加 x86-64 上的代码大小,因为更多指令需要 REX 前缀。这通常并不重要。 Silvermont 的 imul r64, r64 的延迟和吞吐量比 imul r32, r32 稍差,而 Atom 的 64 位乘法性能很多差。对于像移位、加/减和布尔这样的简单操作,指令时序没有区别。 (见Agner Fog's tables)。没错,在“普通”CPU 上,64 位整数运算是全速的。
  • 你说得对,主要的速度问题是缓存占用。值得研究一下常用的数据结构,看看它们是否仍然适用于 uint32_t。不必担心在size_tuint32_t 之间进行转换:当写入寄存器的 32 位低半部分时,在 x86-64 上免费发生到 64 位的零扩展。所以用size_t临时就好了,除非代码依赖于无符号环绕...
  • 在包括 Haswell 在内的 Intel CPU 上,使用 64 位整数除以非编译时常量的值要慢得多。 Trial-division code runs 2x faster as 32-bit on Windows than 64-bit on LinuxCan 128bit/64bit hardware unsigned division be faster in some cases than 64bit/32bit division on x86-64 Intel/AMD CPUs?。如果除数是常数(这是很正常的情况),您的测试结果仅对吞吐量有意义。 (同样有符号的 64 位 idiv 比无符号 div 慢)
猜你喜欢
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 2018-08-25
  • 2023-01-18
  • 2021-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多