VC2008的编译参数问题

do_fork 2009-12-15 02:11:15
#include <stdio.h>

char *power_2(int n, char *pos)
{
static unsigned int d[750000], w=10000;
unsigned int x = n / 18, t=1U<<18, b=0, g=0, i;
d[0] = 1 << (n % 18);
if (d[0] > w) {
d[++b] = d[0]/w;
d[0] %= w;
}
while (x--) {
for (i=0; i<=b; i++) {
d[i] = d[i] * t + g;
g = d[i] / w;
d[i] %= w;
}
while (g) {
d[++b] = g%w;
g /= w;
}
}
i = sprintf(pos, "%u", d[b]);
if (i<2 && b)
sprintf(pos+1, "%u", d[--b]);
pos[2] = 0;
return pos;
}

int main()
{
char pos[16];
puts(power_2(4000000, pos));
return 0;
}


以上是计算2的n次方的最高位和次高位的代码。
power_2(4000000, pos) 表示计算2的4M次方


虚拟机实测数据:
计算大小(单位:百万次方),耗费时间:
1: 4.747s
2: 18.966s
3: 43.180s
4: 79.086s

想着虚拟机肯定跑不过物理机的,于是拿VC2008编译了一下,
在物理机中执行,计算2的0.5M次方竟然花了11秒多,1M次方要40多秒
计算1M次方时,虚拟机中的性能接近物理机的10倍...

gcc 4.4.2 用的 -O3 参数编译,
VC2008 sp1编译选项是 release /O2 /Ot

就算gcc优化能力再强,10倍的差距也不太可能,怀疑是别的原因

物理机:AMD X2 240 + 2G*2 + 32位 Windows 7家庭高级版
虚拟机: VirtualBox 3.0.10 + 32位 Debian Linux sid版
...全文
438 28 打赏 收藏 举报
写回复
28 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Daven172 2009-12-20
这个真的要顶!
  • 打赏
  • 举报
回复
skyworth98 2009-12-19
上面的编译参数为/Ox,
以下的为/O2



; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01

TITLE e:\Projects\Power2\Power2\Power2.c
.686P
.XMM
include listing.inc
.model flat

INCLUDELIB OLDNAMES

PUBLIC ??_C@_02GMHACPFF@?$CFu?$AA@ ; `string'
EXTRN @__security_check_cookie@4:PROC
EXTRN __imp__sprintf:PROC
EXTRN __imp__puts:PROC
; COMDAT ??_C@_02GMHACPFF@?$CFu?$AA@
CONST SEGMENT
??_C@_02GMHACPFF@?$CFu?$AA@ DB '%u', 00H ; `string'
?w@?1??power_2@@9@9 DD 02710H ; `power_2'::`2'::w
PUBLIC _power_2
?d@?1??power_2@@9@9 DD 0b71b0H DUP (?) ; `power_2'::`2'::d
; Function compile flags: /Ogtpy
; File e:\projects\power2\power2\power2.c
; COMDAT _power_2
_TEXT SEGMENT
_x$ = 8 ; size = 4
_pos$ = 8 ; size = 4
_power_2 PROC ; COMDAT

; 4 : {

push ebp
mov ebp, DWORD PTR _pos$[esp]
push esi
push edi

; 5 : static unsigned int d[750000], w=10000;
; 6 : unsigned int x = n / 18, t=1U<<18, b=0, g=0, i;

xor edi, edi
mov eax, 55555 ; 0000d903H
xor esi, esi

; 7 : d[0] = 1 << (n % 18);

mov DWORD PTR ?d@?1??power_2@@9@9, 1024 ; 00000400H
push ebx
npad 5
$LL8@power_2:

; 8 : if (d[0] > w) {
; 9 : d[++b] = d[0]/w;
; 10 : d[0] %= w;
; 11 : }
; 12 : while (x--) {

dec eax
mov DWORD PTR _x$[esp+12], eax

; 13 : for (i=0; i<=b; i++) {

xor ecx, ecx
npad 9
$LL24@power_2:

; 14 : d[i] = d[i] * t + g;

mov eax, DWORD PTR ?d@?1??power_2@@9@9[ecx*4]
shl eax, 18 ; 00000012H
lea edx, DWORD PTR [eax+esi]
mov DWORD PTR ?d@?1??power_2@@9@9[ecx*4], edx

; 15 : g = d[i] / w;

mov eax, -776530087 ; d1b71759H
mul edx

; 16 : d[i] %= w;

mov eax, DWORD PTR ?d@?1??power_2@@9@9[ecx*4]
shr edx, 13 ; 0000000dH
mov esi, edx
xor edx, edx
mov ebx, 10000 ; 00002710H
div ebx
inc ecx
mov DWORD PTR ?d@?1??power_2@@9@9[ecx*4-4], edx
cmp ecx, edi
jbe SHORT $LL24@power_2

; 17 : }
; 18 : while (g) {

test esi, esi
je SHORT $LN25@power_2
$LL3@power_2:

; 19 : d[++b] = g%w;

mov eax, -776530087 ; d1b71759H
mul esi
shr edx, 13 ; 0000000dH
mov ecx, edx
imul ecx, 10000 ; 00002710H
sub esi, ecx
inc edi
mov DWORD PTR ?d@?1??power_2@@9@9[edi*4], esi

; 20 : g /= w;

mov esi, edx
test esi, esi
jne SHORT $LL3@power_2
$LN25@power_2:

; 8 : if (d[0] > w) {
; 9 : d[++b] = d[0]/w;
; 10 : d[0] %= w;
; 11 : }
; 12 : while (x--) {

mov eax, DWORD PTR _x$[esp+12]
test eax, eax
jne SHORT $LL8@power_2

; 21 : }
; 22 : }
; 23 : i = sprintf(pos, "%u", d[b]);

mov edx, DWORD PTR ?d@?1??power_2@@9@9[edi*4]
mov esi, DWORD PTR __imp__sprintf
push edx
push OFFSET ??_C@_02GMHACPFF@?$CFu?$AA@
push ebp
call esi
add esp, 12 ; 0000000cH
pop ebx

; 24 : if (i<2 && b)

cmp eax, 2
jae SHORT $LN23@power_2
test edi, edi
je SHORT $LN23@power_2

; 25 : sprintf(pos+1, "%u", d[--b]);

mov eax, DWORD PTR ?d@?1??power_2@@9@9[edi*4-4]
push eax
lea ecx, DWORD PTR [ebp+1]
push OFFSET ??_C@_02GMHACPFF@?$CFu?$AA@
push ecx
call esi
add esp, 12 ; 0000000cH
$LN23@power_2:
pop edi
pop esi

; 26 : pos[2] = 0;

mov BYTE PTR [ebp+2], 0

; 27 : return pos;

mov eax, ebp
pop ebp

; 28 : }

ret 0
_power_2 ENDP
_TEXT ENDS
PUBLIC __$ArrayPad$
PUBLIC _main
EXTRN ___security_cookie:DWORD
; Function compile flags: /Ogtpy
; COMDAT _main
_TEXT SEGMENT
_pos$ = -20 ; size = 16
__$ArrayPad$ = -4 ; size = 4
_main PROC ; COMDAT

; 31 : {

sub esp, 20 ; 00000014H
mov eax, DWORD PTR ___security_cookie
xor eax, esp
mov DWORD PTR __$ArrayPad$[esp+20], eax

; 32 : char pos[16];
; 33 : puts(power_2(1000000, pos));

lea eax, DWORD PTR _pos$[esp+20]
push eax
call _power_2
push eax
call DWORD PTR __imp__puts

; 34 : return 0;
; 35 : }

mov ecx, DWORD PTR __$ArrayPad$[esp+28]
add esp, 8
xor ecx, esp
xor eax, eax
call @__security_check_cookie@4
add esp, 20 ; 00000014H
ret 0
_main ENDP
_TEXT ENDS
END


  • 打赏
  • 举报
回复
晴天1999 2009-12-19
新手哈!多多指教哟
  • 打赏
  • 举报
回复
skyworth98 2009-12-18
楼主,给VC2008编译器加上 /FAs 参数,让编译器产生汇编代码,
然后和虚拟机里面产生的汇编代码相比较看看。

这个直接是看不出什么原因的,我个人觉得,要解决这个问题,最快的方法就是比较汇编代码。
因为都是在同一个CPU上执行的,能引起这种差不多数量级上的差别的,要么就是算法问题,
要么就是指令问题。 由于源代码都是一样的,那就只好比较汇编代码了。
  • 打赏
  • 举报
回复
skyworth98 2009-12-18
VC 2008 SP1


; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01

TITLE e:\Projects\Power2\Power2\Power2.c
.686P
.XMM
include listing.inc
.model flat

INCLUDELIB OLDNAMES

EXTRN @__security_check_cookie@4:PROC
EXTRN __imp__sprintf:PROC
EXTRN __imp__puts:PROC
?w@?1??power_2@@9@9 DD 02710H ; `power_2'::`2'::w
$SG-5 DB '%u', 00H
ORG $+1
$SG-6 DB '%u', 00H
PUBLIC _power_2
?d@?1??power_2@@9@9 DD 0b71b0H DUP (?) ; `power_2'::`2'::d
; Function compile flags: /Ogtpy
; File e:\projects\power2\power2\power2.c
; COMDAT _power_2
_TEXT SEGMENT
_pos$ = 8 ; size = 4
_power_2 PROC ; COMDAT

; 4 : {

push ebx
push ebp
push esi
push edi

; 5 : static unsigned int d[750000], w=10000;
; 6 : unsigned int x = n / 18, t=1U<<18, b=0, g=0, i;

xor edi, edi
mov ebp, 55555 ; 0000d903H
xor esi, esi

; 7 : d[0] = 1 << (n % 18);

mov DWORD PTR ?d@?1??power_2@@9@9, 1024 ; 00000400H
npad 9
$LL8@power_2:

; 8 : if (d[0] > w) {
; 9 : d[++b] = d[0]/w;
; 10 : d[0] %= w;
; 11 : }
; 12 : while (x--) {

dec ebp

; 13 : for (i=0; i<=b; i++) {

xor ecx, ecx
$LL24@power_2:

; 14 : d[i] = d[i] * t + g;

mov eax, DWORD PTR ?d@?1??power_2@@9@9[ecx*4]
shl eax, 18 ; 00000012H
lea edx, DWORD PTR [eax+esi]
mov DWORD PTR ?d@?1??power_2@@9@9[ecx*4], edx

; 15 : g = d[i] / w;

mov eax, -776530087 ; d1b71759H
mul edx

; 16 : d[i] %= w;

mov eax, DWORD PTR ?d@?1??power_2@@9@9[ecx*4]
shr edx, 13 ; 0000000dH
mov esi, edx
xor edx, edx
mov ebx, 10000 ; 00002710H
div ebx
inc ecx
mov DWORD PTR ?d@?1??power_2@@9@9[ecx*4-4], edx
cmp ecx, edi
jbe SHORT $LL24@power_2

; 17 : }
; 18 : while (g) {

test esi, esi
je SHORT $LN25@power_2
$LL3@power_2:

; 19 : d[++b] = g%w;

mov eax, -776530087 ; d1b71759H
mul esi
shr edx, 13 ; 0000000dH
mov ecx, edx
imul ecx, 10000 ; 00002710H
sub esi, ecx
inc edi
mov DWORD PTR ?d@?1??power_2@@9@9[edi*4], esi

; 20 : g /= w;

mov esi, edx
test esi, esi
jne SHORT $LL3@power_2
$LN25@power_2:

; 8 : if (d[0] > w) {
; 9 : d[++b] = d[0]/w;
; 10 : d[0] %= w;
; 11 : }
; 12 : while (x--) {

test ebp, ebp
jne SHORT $LL8@power_2

; 21 : }
; 22 : }
; 23 : i = sprintf(pos, "%u", d[b]);

mov edx, DWORD PTR ?d@?1??power_2@@9@9[edi*4]
mov ebx, DWORD PTR _pos$[esp+12]
mov esi, DWORD PTR __imp__sprintf
push edx
push OFFSET $SG-5
push ebx
call esi
add esp, 12 ; 0000000cH

; 24 : if (i<2 && b)

cmp eax, 2
jae SHORT $LN23@power_2
test edi, edi
je SHORT $LN23@power_2

; 25 : sprintf(pos+1, "%u", d[--b]);

mov eax, DWORD PTR ?d@?1??power_2@@9@9[edi*4-4]
push eax
lea ecx, DWORD PTR [ebx+1]
push OFFSET $SG-6
push ecx
call esi
add esp, 12 ; 0000000cH
$LN23@power_2:
pop edi
pop esi
pop ebp

; 26 : pos[2] = 0;

mov BYTE PTR [ebx+2], 0

; 27 : return pos;

mov eax, ebx
pop ebx

; 28 : }

ret 0
_power_2 ENDP
_TEXT ENDS
PUBLIC __$ArrayPad$
PUBLIC _main
EXTRN ___security_cookie:DWORD
; Function compile flags: /Ogtpy
; COMDAT _main
_TEXT SEGMENT
_pos$ = -20 ; size = 16
__$ArrayPad$ = -4 ; size = 4
_main PROC ; COMDAT

; 31 : {

sub esp, 20 ; 00000014H
mov eax, DWORD PTR ___security_cookie
xor eax, esp
mov DWORD PTR __$ArrayPad$[esp+20], eax

; 32 : char pos[16];
; 33 : puts(power_2(1000000, pos));

lea eax, DWORD PTR _pos$[esp+20]
push eax
call _power_2
push eax
call DWORD PTR __imp__puts

; 34 : return 0;
; 35 : }

mov ecx, DWORD PTR __$ArrayPad$[esp+28]
add esp, 8
xor ecx, esp
xor eax, eax
call @__security_check_cookie@4
add esp, 20 ; 00000014H
ret 0
_main ENDP
_TEXT ENDS
END


  • 打赏
  • 举报
回复
do_fork 2009-12-18
gcc生成的汇编, 用的 -O2, -O3代码太长,性能跟O2差别在百分之十以内,就不贴O3了
	.file	"k.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%u"
.text
.p2align 4,,15
.globl power_2
.type power_2, @function
power_2:
pushl %ebp
movl $954437177, %edx
movl %esp, %ebp
pushl %edi
xorl %edi, %edi
pushl %esi
pushl %ebx
subl $44, %esp
movl 8(%ebp), %ebx
movl %ebx, %eax
imull %edx
movl %ebx, %eax
sarl $31, %eax
sarl $2, %edx
subl %eax, %edx
movl $1, %eax
leal (%edx,%edx,8), %ecx
movl %ebx, %edx
addl %ecx, %ecx
subl %ecx, %edx
movl %edx, %ecx
sall %cl, %eax
cmpl $10000, %eax
movl %eax, d.1844
jbe .L3
movl $10000, %ecx
xorl %edx, %edx
divl %ecx
movw $1, %di
movl %eax, d.1844+4
movl %edx, d.1844
.L3:
movl %ebx, %eax
movl $954437177, %ecx
imull %ecx
sarl $31, %ebx
sarl $2, %edx
subl %ebx, %edx
movl %edx, -28(%ebp)
movl -28(%ebp), %eax
testl %eax, %eax
je .L15
.p2align 4,,7
.p2align 3
.L8:
xorl %ecx, %ecx
xorl %ebx, %ebx
movl %ecx, %edx
.p2align 4,,7
.p2align 3
.L4:
movl d.1844(,%ebx,4), %esi
movl $-776530087, %eax
sall $18, %esi
leal (%edx,%esi), %esi
mull %esi
shrl $13, %edx
imull $10000, %edx, %eax
subl %eax, %esi
movl %esi, d.1844(,%ebx,4)
addl $1, %ebx
cmpl %ebx, %edi
jae .L4
testl %edx, %edx
movl %edx, %ecx
je .L5
leal 1(%edi), %ebx
leal d.1844(,%ebx,4), %esi
jmp .L6
.p2align 4,,7
.p2align 3
.L16:
addl $1, %ebx
.L6:
movl $-776530087, %eax
movl %ebx, %edi
mull %ecx
shrl $13, %edx
imull $10000, %edx, %eax
subl %eax, %ecx
movl %ecx, (%esi)
addl $4, %esi
testl %edx, %edx
movl %edx, %ecx
jne .L16
.L5:
subl $1, -28(%ebp)
movl -28(%ebp), %eax
testl %eax, %eax
jne .L8
.L15:
movl d.1844(,%edi,4), %eax
movl $.LC0, 4(%esp)
movl %eax, 8(%esp)
movl 12(%ebp), %eax
movl %eax, (%esp)
call sprintf
cmpl $1, %eax
ja .L9
testl %edi, %edi
je .L9
movl d.1844-4(,%edi,4), %eax
movl $.LC0, 4(%esp)
movl %eax, 8(%esp)
movl 12(%ebp), %eax
addl $1, %eax
movl %eax, (%esp)
call sprintf
.L9:
movl 12(%ebp), %edx
movb $0, 2(%edx)
movl %edx, %eax
addl $44, %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.size power_2, .-power_2
.p2align 4,,15
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
leal 16(%esp), %eax
movl %eax, 4(%esp)
movl $4000000, (%esp)
call power_2
movl %eax, (%esp)
call puts
xorl %eax, %eax
leave
ret
.size main, .-main
.local d.1844
.comm d.1844,3000000,32
.ident "GCC: (Debian 4.4.2-5) 4.4.2"
.section .note.GNU-stack,"",@progbits
  • 打赏
  • 举报
回复
老邓 2009-12-18
不好意思,这两天要上一节公开课,一直没抽出时间来装虚拟机...
  • 打赏
  • 举报
回复
skyworth98 2009-12-18
不至于差别这么大,偶尔Debug版本比Release版本还要快些

[Quote=引用 1 楼 loaden 的回复:]
确定物理机没使用Debug版本?
[/Quote]
  • 打赏
  • 举报
回复
skyworth98 2009-12-18
gcc没怎么用过,应该也有产生 ASM Listing的选项吧?
  • 打赏
  • 举报
回复
晴天1999 2009-12-17
新手哈!多多指教哟!
  • 打赏
  • 举报
回复
li825127671 2009-12-17
学了
  • 打赏
  • 举报
回复
LittleJohny 2009-12-17
mark
  • 打赏
  • 举报
回复
do_fork 2009-12-17
up
  • 打赏
  • 举报
回复
do_fork 2009-12-15
[Quote=引用 2 楼 benbshmily 的回复:]
计算2的n次方的最高位和次高位的代码.
好精炼的算法。fork兄能否解释下你的算法呢?我愚昧,看不懂,18是个啥。
谢谢。
[/Quote]

就是模拟手算,将大的计算分解,2^n == ((2^18)^(n/18)) * 2^(n%18)
选18是因为 9999 * (2^18) + 进位 不会超过 unsigned int 的表示范围
  • 打赏
  • 举报
回复
do_fork 2009-12-15
确定是Release,产生的exe文件是9216字节,计算1M仍需43秒
  • 打赏
  • 举报
回复
tomorrowtwo 2009-12-15
学习一下!
  • 打赏
  • 举报
回复
jernymy 2009-12-15
mark先
  • 打赏
  • 举报
回复
do_fork 2009-12-15
10楼的测试结果,跟我的比较接近,
X2 240整数运算能力,可能跟PE2160在一个数量级
  • 打赏
  • 举报
回复
do_fork 2009-12-15
[Quote=引用 10 楼 skyworth98 的回复:]
PE2160 Dual@1.8GHz, /O2 1M,25~30s,但是系统中有其他进程在运行。
/Ox 1M, 35~40s.

感觉楼主的机器是不是有些什么软件在强CPU?

引用楼主 do_fork 的回复:
C/C++ code#include <stdio.h>char*power_2(int n,char*pos)
{static unsignedint d[750000], w=10000;
        unsignedint x= n/18, t=1U < <18, b=0, g=0, i;
        d[0]=1 < < (n%18);if (d[0]> w) {
                d[++b]= d[0]/w;
                d[0]%= w;
        }while (x--) {for (i=0; i <=b; i++) {
                        d[i]= d[i]* t+ g;
                        g= d[i]/ w;
                        d[i]%= w;
                }while (g) {
                        d[++b]= g%w;
                        g/= w;
                }
        }
        i= sprintf(pos,"%u", d[b]);if (i <2&& b)
                sprintf(pos+1,"%u", d[--b]);
        pos[2]=0;return pos;
}int main()
{char pos[16];
        puts(power_2(4000000, pos));return0;
}

以上是计算2的n次方的最高位和次高位的代码。
power_2(4000000, pos) 表示计算2的4M次方


虚拟机实测数据:
计算大小(单位:百万次方),耗费时间:
1:  4.747s
2: 18.966s
3: 43.180s
4: 79.086s

想着虚拟机肯定跑不过物理机的,于是拿VC2008编译了一下,
在物理机中执行,计算2的0.5M次方竟然花了11秒多,1M次方要40多秒
计算1M次方时,虚拟机中的性能接近物理机的10倍...

gcc 4.4.2 用的 -O3 参数编译,
VC2008 sp1编译选项是 release /O2 /Ot

就算gcc优化能力再强,10倍的差距也不太可能,怀疑是别的原因

物理机:AMD X2 240 + 2G*2 + 32位 Windows 7家庭高级版
虚拟机: VirtualBox 3.0.10 + 32位 Debian Linux sid版

[/Quote]

我是双核的CPU,即使有个进程比较占用CPU,也不应该有如此大的差距,
何况两者运行之时,系统中其它软件环境基本是一样的,没有吃CPU的软件在运行
  • 打赏
  • 举报
回复
do_fork 2009-12-15
没有用自己写的计时方法测试

虚拟机是用 $ time cmd 获得的时间,
这是Linux内置计时功能,几十年实践检验了

真实机上,是我用
echo %TIME% && cmd
echo %TIME%
然后人工计算出来的时间差

多次测试下,结果跟手机上的秒表计时结果大致一样


所以才很疑惑
  • 打赏
  • 举报
回复
加载更多回复(8)
发帖
C语言

6.6w+

社区成员

C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
帖子事件
创建了帖子
2009-12-15 02:11
社区公告
暂无公告