Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.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++ SSE42&;STTNI-PcmpEstrM比PcmpIstrM慢两倍,是真的吗?_C++_Performance_Sse_Sse4 - Fatal编程技术网

C++ SSE42&;STTNI-PcmpEstrM比PcmpIstrM慢两倍,是真的吗?

C++ SSE42&;STTNI-PcmpEstrM比PcmpIstrM慢两倍,是真的吗?,c++,performance,sse,sse4,C++,Performance,Sse,Sse4,我正在试验SSE42和STTNI指令,并得到了奇怪的结果-PcmpEstrM(适用于显式长度字符串)的运行速度比PcmpIstrM(隐式长度字符串)慢两倍 在我的i7 3610QM上,差异是2366.2毫秒与1202.3毫秒-97% 在i5 3470上,差异不太大,但仍然显著=3206.2毫秒vs.2623.2毫秒-22% 两者都是“常春藤桥”——奇怪的是它们有如此不同的“差异”(至少我看不出它们规格上有任何技术差异) 《英特尔64和IA-32体系结构优化参考手册》提到PcmpEstrM和P

我正在试验SSE42和STTNI指令,并得到了奇怪的结果-PcmpEstrM(适用于显式长度字符串)的运行速度比PcmpIstrM(隐式长度字符串)慢两倍

  • 在我的i7 3610QM上,差异是2366.2毫秒与1202.3毫秒-97%
  • i5 3470上,差异不太大,但仍然显著=3206.2毫秒vs.2623.2毫秒-22%
两者都是“常春藤桥”——奇怪的是它们有如此不同的“差异”(至少我看不出它们规格上有任何技术差异)

《英特尔64和IA-32体系结构优化参考手册》提到PcmpEstrM和PcmpIstrM的吞吐量为11,延迟为3。因此,我期望这两个方面都有类似的表现

Q:是我实际设计/预期的差异,还是我以错误的方式使用这些指令

下面是我的虚拟测试场景(VS 2012)。逻辑非常简单——扫描16MB的文本以找到匹配的字符。因为haystack和针线串都不包含零终止符,所以我希望E和i具有类似的性能

PS:我试着将这个问题发布在,但他们认为它是垃圾邮件:(

#包括“stdafx.h”
#包括
#定义开始计时器(名称)\
{                                           \
大整数频率\
大整数\
大整数t1\
双tms\
const char*\uuu tname=名称\
char__tbuf[0xff]\
\
查询性能频率(和频率)\
查询性能计数器(&u_t0);
#定义结束计时器()\
查询性能计数器(&_t1)\
__tms=(uu t1.QuadPart-u t0.QuadPart)*1000.0/u freq.QuadPart\
sprintf_s(uuu tbuf,sizeof(uu tbuf),“%-32s=%6.1f ms\n”,u tname,uu tms)\
OutputDebugStringA(uu-tbuf)\
printf(uu tbuf)\
}
//4.1.3聚合操作
#定义SSE42_聚合_比特基2

#定义SSE42_AGGOP_EQUAL_ANY根据代码表, PCMPESTRM 取8个OP,而PCMPISTRM 在大多数架构上需要3个OP。这将解释您观察到的性能差异。考虑改写代码,如果可能的话,您可以使用<代码> PCMPISTRM 而不是<代码> PCMPESTRM < /代码>。用rep字符串打褶?在IvyBridge上,他们本应该改进的,现在还说不出来,但是以前的经验(我相信这已经在IvyBridge上测试过了)显示REP的性能接近“for”循环,在字符串比较的情况下,算法上更差,因为调用REP需要指定计数、需要计算字符串长度的内容、需要花费时间的内容以及在大多数情况下实际上不需要的内容……Agner的表中指出,
pcmpestrm
为8µops,而
pcmpistrm
仅为3µops,带有寄存器操作数。这可以解释差异。感谢您参考Agner的表(我不知道它们)。那里的信息似乎是关键。你能发布一个答案让我接受吗?
mov-eax,+++++'
会快得多。或者
imul-eax,eax,0x01010101
movd
之前广播一个字节。然后使用
pshufd
广播到一个向量。另外,你不需要在内联的sm.MSVC为您做这件事。任何超过4个UOP的东西都是微代码,因此这是一个定性的前端差异。此外,Agner确实将吞吐量列为4对3(接近Intel的数字),但周围代码对前端吞吐量的影响是Intel的延迟/吞吐量数字无法帮助您了解的。请参阅中的“性能分析”部分总结了延迟/前端/执行端口如何成为描述指令序列(无分支或缓存未命中)的三个主要“维度”。
#include "stdafx.h"
#include <windows.h>
#define BEGIN_TIMER(NAME)                       \
    {                                           \
        LARGE_INTEGER   __freq;                 \
        LARGE_INTEGER   __t0;                   \
        LARGE_INTEGER   __t1;                   \
        double          __tms;                  \
        const char*     __tname = NAME;         \
        char            __tbuf[0xff];           \
        \
        QueryPerformanceFrequency(&__freq);     \
        QueryPerformanceCounter(&__t0);         
#define END_TIMER()                             \
        QueryPerformanceCounter(&__t1);         \
        __tms = (__t1.QuadPart - __t0.QuadPart) * 1000.0 / __freq.QuadPart; \
        sprintf_s(__tbuf, sizeof(__tbuf), "%-32s = %6.1f ms\n", __tname, __tms ); \
        OutputDebugStringA(__tbuf);             \
        printf(__tbuf);                         \
    }
// 4.1.3 Aggregation Operation
#define SSE42_AGGOP_BITBASE         2
#define SSE42_AGGOP_EQUAL_ANY       (00b << SSE42_AGGOP_BITBASE)
#define SSE42_AGGOP_RANGES          (01b << SSE42_AGGOP_BITBASE)
#define SSE42_AGGOP_EQUAL_EACH      (10b << SSE42_AGGOP_BITBASE)
#define SSE42_AGGOP_EQUAL_ORDERED   (11b << SSE42_AGGOP_BITBASE)
int _tmain(int argc, _TCHAR* argv[])
{
    int cIterations = 1000000;
    int cCycles = 1000;
    int cchData = 16 * cIterations;
    char* testdata = new char[cchData + 16];

    memset(testdata, '*', cchData);
    testdata[cchData - 1] = '+';
    testdata[cchData] = '\0';
    BEGIN_TIMER("PcmpIstrI") {
        for( int i = 0; i < cCycles; i++ ) {
            __asm {
                    push        ecx
                    push        edx
                    push        ebx
                    mov         edi, testdata
                    mov         ebx, cIterations
                    mov         al, '+'
                    mov         ah, al
                    movd        xmm1, eax               // fill low word with pattern
                    pshuflw     xmm1, xmm1, 0           // fill low dqword with pattern
                    movlhps     xmm1, xmm1              // ... and copy it hi dqword
                loop_pcmpistri:
                    PcmpIstrM   xmm1, [edi], SSE42_AGGOP_EQUAL_EACH
                    add         edi, 16
                    sub         ebx, 1
                    jnz         loop_pcmpistri
                    pop         ebx
                    pop         edx
                    pop         ecx
            }
        }
    } END_TIMER();
    BEGIN_TIMER("PcmpEstrI") {
        for( int i = 0; i < cCycles; i++ ) {
            __asm {
                    push        ecx
                    push        edx
                    push        ebx
                    mov         edi, testdata
                    mov         ebx, cIterations
                    mov         al, '+'
                    mov         ah, al
                    movd        xmm1, eax               // fill low word with pattern
                    pshuflw     xmm1, xmm1, 0           // fill low dqword with pattern
                    movlhps     xmm1, xmm1              // ... and copy it hi dqword
                    mov         eax, 15
                    mov         edx, 15
                loop_pcmpestri:
                    PcmpEstrM   xmm1, [edi], SSE42_AGGOP_EQUAL_EACH
                    add         edi, 16
                    sub         ebx, 1
                    jnz         loop_pcmpestri
                    pop         ebx
                    pop         edx
                    pop         ecx
            }
        }
    } END_TIMER();
    return 0;
}