net even getest
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| #include <iostream>
#include <cstdlib>
#include <intrin.h>
void addbuf1(char * pDest, const char * pSrc1, const char * pSrc2, int len)
{
char carry = 0;
for (int i = 0; i < len; i++)
{
char c = pSrc1[i] + pSrc2[i] + carry;
carry = c / 10;
pDest[i] = c % 10;
}
}
void addbuf2(char * pDest, const char * pSrc1, const char * pSrc2, int len)
{
char carry = 0;
for (int i = 0; i < len; i++)
{
char c = pSrc1[i] + pSrc2[i] + carry;
if (c >= 10)
{
c -= 10;
carry = 1;
}
else
{
carry = 0;
}
pDest[i] = c;
}
}
int result(const char * pBuf, int len)
{
int c = 0;
for (int i = 0; i < len; i++)
c += pBuf[i];
return c;
}
int wmain()
{
const int cBufSize = 1024;
char buf1[cBufSize], buf2[cBufSize], dest[cBufSize];
for (int i = 0; i < cBufSize; i++)
{
buf1[i] = rand() % 10;
buf2[i] = rand() % 10;
}
for (int i = 0; i < 10; i++)
{
int t = -(int)__rdtsc();
addbuf1(dest, buf1, buf2, cBufSize);
t += (int)__rdtsc();
std::cout << "div: " << t << " - " << result(dest, cBufSize) << std::endl;
t = -(int)__rdtsc();
addbuf2(dest, buf1, buf2, cBufSize);
t += (int)__rdtsc();
std::cout << "if: " << t << " - " << result(dest, cBufSize) << std::endl;
}
} |
div: 21616 - 4688
if: 14784 - 4688
div: 21272 - 4688
if: 12000 - 4688
div: 21272 - 4688
if: 14800 - 4688
div: 21272 - 4688
if: 13776 - 4688
div: 21272 - 4688
if: 14096 - 4688
div: 21296 - 4688
if: 12008 - 4688
div: 21248 - 4688
if: 11536 - 4688
div: 21240 - 4688
if: 11496 - 4688
div: 21248 - 4688
if: 11504 - 4688
div: 21264 - 4688
if: 11696 - 4688
MSVC++ genereert helaas nooit CMOV instructies, maar met branching is de code dus alsnog bijna 2x zo snel.
.edit: met CMOV implementatie erbij
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| void addbuf3(char * pDest, const char * pSrc1, const char * pSrc2, int len)
{
char carry = 0;
int ten = 10;
for (int i = 0; i < len; i++)
{
char c = pSrc1[i] + pSrc2[i] + carry;
__asm {
xor eax, eax
cmp c, 10
cmovge eax, ten
setge carry
sub c, al
}
pDest[i] = c;
}
} |
div: 21632 - 4688
if: 15272 - 4688
cmov:13936 - 4688
---
div: 21272 - 4688
if: 12344 - 4688
cmov:13912 - 4688
---
div: 21272 - 4688
if: 14792 - 4688
cmov:13936 - 4688
---
div: 21520 - 4688
if: 14568 - 4688
cmov:14056 - 4688
---
div: 21328 - 4688
if: 14784 - 4688
cmov:13904 - 4688
---
div: 21272 - 4688
if: 14488 - 4688
cmov:13936 - 4688
---
div: 21464 - 4688
if: 14792 - 4688
cmov:13864 - 4688
---
div: 21288 - 4688
if: 12576 - 4688
cmov:13888 - 4688
---
div: 21272 - 4688
if: 12264 - 4688
cmov:13864 - 4688
---
div: 21264 - 4688
if: 15008 - 4688
cmov:13880 - 4688
Scheelt dus niet zo heel veel.
.edit3: grappig trouwens dat de if versie ook wat duurder is geworden. Waarschijnlijk doet de branch predictor z'n werk minder goed nu er wat meer code is.
.edit4: overigens is er ook nog de hele oude AAM instructie die nooit iemand gebruikt. Die deelt AL door 10 en zet het resultaat in AH en de rest in AL, precies wat de TS wil. Maar die instructie is zo unoptimized als de pest en is nog een stuk langzamer dan een IDIV op een 32 bits register (ik kom daarmee op zo'n 27000 cycles voor een functie die gebruik maakt van AAM)
[
Voor 29% gewijzigd door
.oisyn op 26-06-2010 01:15
]