Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 向量性能差<;布尔>;在64位目标中使用VS2012_C++_Performance_Vector_Boolean - Fatal编程技术网

C++ 向量性能差<;布尔>;在64位目标中使用VS2012

C++ 向量性能差<;布尔>;在64位目标中使用VS2012,c++,performance,vector,boolean,C++,Performance,Vector,Boolean,对该类进行基准测试: struct Sieve { std::vector<bool> isPrime; Sieve (int n = 1) { isPrime.assign (n+1, true); isPrime[0] = isPrime[1] = false; for (int i = 2; i <= (int)sqrt((double)n); ++i) if (isPrime[i]) for (int j

对该类进行基准测试:

struct Sieve {
  std::vector<bool> isPrime;

  Sieve (int n = 1) {
    isPrime.assign (n+1, true);
    isPrime[0] = isPrime[1] = false;

    for (int i = 2; i <= (int)sqrt((double)n); ++i)
      if (isPrime[i]) 
        for (int j = i*i; j <= n; j += i)
          isPrime[j] = false;
  }
};
我测试了
sizeof(bool)
,两个版本都是
1
。 当我用
vector
替换
vector
时,64位和32位版本的性能变得相同。为什么呢

以下是
S(100000000)
(发布模式,先32位,后64位)的运行时间:

vector
0.97s 3.12s
vector
0.99s 0.99s
vector
1.57s 1.59s

我还用VS2010做了一个理智测试(由Wouter Huysentruit的回答提示),结果是0.98s和0.88s。因此,VS2012实现存在一些问题

我向你提交了一份bug报告

编辑

下面的许多答案都评论了使用
int
进行索引的不足之处。这可能是真的,但即使是伟大的巫师自己在他的书中也使用了标准的
(inti=0;i
,因此这种模式不应该导致显著的性能损失。另外,这个问题是在2013次会议期间提出的,而C++ Guurs的主持小组评论了他们早期使用“代码> SsiZixt <代码>索引和返回类型<代码> siz()/<代码>的错误建议。他们说:“对不起,我们还年轻……”

这个问题的标题可以改为:从VS2010升级到VS2012时,此代码的性能下降超过3倍

编辑

我粗略地尝试查找索引
I
j
的内存对齐方式,发现这个插入指令的版本:

struct Sieve {
  vector<bool> isPrime;

  Sieve (int n = 1) {
    isPrime.assign (n+1, true);
    isPrime[0] = isPrime[1] = false;

    for (int i = 2; i <= sqrt((double)n); ++i) {
      if (i == 17) cout << ((int)&i)%16 << endl;
      if (isPrime[i]) 
        for (int j = i*i; j <= n; j += i) {
          if (j == 4) cout << ((int)&j)%16 << endl;
          isPrime[j] = false;
        }
    }
  }
};
struct-Sieve{
向量互质;
筛(int n=1){
isPrime.assign(n+1,true);
isPrime[0]=isPrime[1]=false;
for(int i=2;i
vector
是一个非常特殊的容器,它专门为每个项目使用1位,而不是提供正常的容器语义。我怀疑编译64位时位操作逻辑要昂贵得多(它仍然使用32位块来保存位或其他原因).
vector
的行为与普通的
vector
一样,因此没有特殊的逻辑


您也可以使用没有专门化的
deque

我在VS2010中用
vector
测试过这一点:32位需要1452ms,而64位需要1264ms才能在i3上完成

VS2012中的相同测试(这次在i7上)需要700ms(32位)和2730ms(64位),因此VS2012中的编译器有问题。也许您可以将此测试用例作为错误报告给Microsoft

更新

问题是,当使用int作为迭代器时,VS2012编译器对内部for循环中的一部分代码使用临时堆栈变量。下面列出的部件是
+=运算符
std::vector::iterator
中代码的一部分

作为迭代器的大小\u t

当使用
size\u t
作为迭代器时,部分代码如下所示:

or  rax, -1
sub rax, rdx
shr rax, 5
lea rax, QWORD PTR [rax*4+4]
sub r8, rax
or  rcx, -1
sub rcx, r8
shr rcx, 5
shl rcx, 2
mov rax, -4
sub rax, rcx
mov rdx, QWORD PTR _Tmp$6[rsp]
add rdx, rax
在这里,所有指令都使用非常快的CPU寄存器

int作为迭代器

当使用
int
作为迭代器时,相同的部分如下所示:

or  rax, -1
sub rax, rdx
shr rax, 5
lea rax, QWORD PTR [rax*4+4]
sub r8, rax
or  rcx, -1
sub rcx, r8
shr rcx, 5
shl rcx, 2
mov rax, -4
sub rax, rcx
mov rdx, QWORD PTR _Tmp$6[rsp]
add rdx, rax
在这里,您可以看到正在使用的_Tmp$6 stack变量,这会导致速度减慢

将编译器指向正确的方向

有趣的是,您可以直接使用
vector::iterator
将编译器指向正确的方向

struct Sieve {
  std::vector<bool> isPrime;

  Sieve (int n = 1) {
    isPrime.assign(n + 1, true);

    std::vector<bool>::iterator it1 = isPrime.begin();
    std::vector<bool>::iterator end = it1 + n;
    *it1++ = false;
    *it1++ = false;
    for (int i = 2; i <= (int)sqrt((double)n); ++it1, ++i)
        if (*it1)
            for (std::vector<bool>::iterator it2 = isPrime.begin() + i * i; it2 <= end; it2 += i)
                *it2 = false;
  }
};
struct-Sieve{
std::向量互质;
筛(int n=1){
isPrime.assign(n+1,true);
std::vector::iterator it1=isPrime.begin();
std::vector::iterator end=it1+n;
*it1++=false;
*it1++=false;
对于(int i=2;i<代码>:ST::vector < /COD>)并不是直接的错误。性能差异最终是由您在循环中使用签名的32位<代码> int >代码>类型而导致的,编译器的一些登记分配很差。例如,考虑您最内层的循环:

for (int j = i*i; j <= n; j += i)
    isPrime[j] = false;
无论如何都应该这样做,因为混合使用有符号和无符号类型,特别是当这些类型的宽度不同时,是危险的,并且可能导致意外错误

请注意,使用std::vector也可以“解决”问题在于,但原因不同:访问
std::vector
元素所需的下标计算要比访问
std::vector
元素所需的下标计算简单得多。优化器能够为更简单的计算生成更好的代码



(*)我并不研究代码生成,我也不是一个专家,无论是在汇编还是低级性能优化方面,而是从生成的代码来看,并且在这里报告VisualC++ 2010生成更好的代码,我猜想编译器有改进的机会。ed被转发给编译器团队,以便他们可以查看。

调试或发布版本?有一个空间优化的
vector
模板专门化,请参阅。@HugoCorrá
位集
具有固定大小(模板参数)@DyP,这解释了为什么
vector
vector
之间有区别,但没有解释32位和64位之间的区别。@DyP我知道更有效的实现,我将对它们进行测试。我想知道这种特殊行为的原因。下面Wouter Huysentruit的回答与是理论。我建议避免使用VisualC++,因为它使用非常小的块大小。请参阅确认。我的计时是:64位0.88秒,vs2010.32位版本0.98S。您能查看VS2010与VS2012的代码>矢量?H代码/代码> 2012版本是否总是U?se
unsigned int
作为基础st