SSE42 および STTNI 命令を試しているところ、奇妙な結果が得られました。PcmpEstrM (明示的な長さの文字列で動作) は、PcmpIstrM (暗黙的な長さの文字列)よりも 2 倍遅くなります。
- 私のi7 3610QM では、差は2366.2 ms 対 1202.3 ms - 97%です。
- i5 では 3470の差はそれほど大きくありませんが、それでも有意です = 3206.2 ms 対 2623.2 ms - 22%。
両方とも「Ivy Bridge」です - 「違い」が非常に異なるのは奇妙です (少なくとも、仕様に技術的な違いは見られません - http://www.cpu-world.com/Compare_CPUs/Intel_AW8063801013511,Intel_CM8063701093302 / )。
Intel 64 and IA-32 Architectures Optimization Reference Manual では、PcmpEstrM と PcmpIstrM の両方で同じスループット = 11 とレイテンシ = 3 について言及しています。したがって、両方に同様のパフォーマンスを期待しています。
Q:私が実際に設計した/予期した違いですか、それともこれらの命令を間違った方法で使用していますか?
以下は、ダミーのテスト シナリオ (VS 2012) です。ロジックは非常に単純です。16MB のテキストをスキャンして、一致する文字を見つけます。干し草の山と針の糸のいずれにもゼロのターミネータが含まれていないため、E と I の両方が同様のパフォーマンスを発揮することを期待しています。
PS: この質問をインテルの開発フォーラムに投稿しようとしましたが、彼らはそれをスパムとして識別しました :(
#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;
}