тестировал програмку, которая загружает библиотеку, выполняет функцию, и дальше обрабатывает результат. но это не суть важно, а дело в том что, для теста брал функции чтоб было побольше вычислений, написал одну коротенькую чтоб считала пи. Запустил, очень долго шурует (на нормальном компе) 26секунд, с всегото 1 млн интервалов. Писал на борланде, но на той машине на которой тестил уже его не было так что сделал тоже самое на вижуале. Запускаю и тут....1.5 сек с такими же параметрами. Я сначало подумал что пару нулей не поставил...не тут то было, все правильно, а рубает мгновено. Начал рытся,искать, поменял версию на дебуг...оп 26 секунд тоже. меняю на релиз 1.5. Думаю ничего себе оптимизация. Пришел домой поставил релиз на борланде, в настройках максимально быстрый код - ну и что бы вы думаете, ничего не дало почти. Ну не может быть чтоб одинакоый сишный код 2 разные компиляторы настолько по-разному перерабатывали. Может я чтото не включил в борланде? Продолжаю эксерименты, теперь с под борланда запускаю библиотечку на студии, запомнил результати. Тоже самое с под студии - на 1 сек быстрее. Чтоб убедится окончательно, вставил прям в функцию команды для измерения времени. Запустил одну и туже функцию абсолютно одинаково через LoadLibrary/GetProcAddress с одинаковыми параметрами и она дает опять таки разницу в секунду. И непонятно почему?! Нервов не хватает... Кстате версии - BDS 2010|Visual 2010 Вот функция Код (Text): double f(double a) { return (4.0 / (1.0 + a*a)); } __declspec(dllexport) double pi(int begin,int intervals,int step) { float h = 1.0 / (double) intervals,x; static double sum = 0.0; int i; int t0=GetTickCount(); for(i = begin; i <= intervals; i += step) { x = h * ((double)i - 0.5); sum += f(x); } sum *= h; int t1=GetTickCount(); printf("%d\n",t1-t0); return sum; }
Может и не поможет. Но в функе ТСа я криминала не вижу, который тормозить может или по разному компилиться для дебуг/релиз. Нужно весь код смотреть. В студии в дебуг версии, память при выделении в хипе инициализируется 0хcd, в релизе не инициализируется - разница в скорости работы может быть большой. Это для примера.
CyberManiac а глянуть в сгенерированный код не вариант? борладна под рукой нету, так что помочь не могу
bolt90 Вызывай BreakPoint(); и далее смотри код в дизасемблере. Можно также _asm int3, но это иногда вызывает выключение оптимизатора. Остановится код в KERNEL32 - надо вернуться пару раз чтобы попасть на "свой" код.
Так как дельтатэ вычисляется в длл, то очевидно что причина в разной скорости её работы может быть только одна - приоритет. Хотя это если вы одинаковые аргументы передаёте.
AsmGuru62 > Вызывай BreakPoint(); и далее смотри код в дизасемблере. с каких это пор компиляторы разучились генерить асм-листинги? на худой конец можно obj дизасмить. там по крайней мере есть часть символьной информации. Malfoy > Так как дельтатэ вычисляется в длл, то очевидно что причина в разной скорости её работы может быть только одна - приоритет. инлайн функции f, разворот цикла, выравнивание и быстрое умножение (которое ms умеет, а борлнад -- нет) вполне объясняют разницу. блин, специально ради вас скачал борланд и сравнил с 2008 студией. ну небо и земля, короче: Код (Text): $LN3@pi: fild DWORD PTR _i$[esp+8] inc eax cmp eax, 100 ; 00000064H fsub ST(0), ST(5) fmul ST(0), ST(4) fstp DWORD PTR tv211[esp+8] fld DWORD PTR tv211[esp+8] mov DWORD PTR _i$[esp+8], eax fmul ST(0), ST(0) fadd ST(0), ST(3) fdivr ST(0), ST(2) faddp ST(1), ST(0) jle SHORT $LN3@pi это код студии. код борланда смотрите сами -- он слишком монстроузный, чтобы его сюда вставлять.
Да у Борланда есть такая придурь, что если программу пускать из среды и при разрешённом встроенном отладчике, некоторые вещи начинают работать сильно медленнее. Запускаем не из среды - и полетело.
сейчас попробую, не из среды. нет, не помагает. приоритеты одинаковые - средний. ну допустим борланд генерирует плохой код. это все равно не обьясняет как может быть такое, что одна и таже функция работает по разному. ну вот посудите. есть библиотека на вижуале с функцией тест которая просто ганяет циклы. создаю проект вижуала кидаю код Код (Text): #include <windows.h> #include<stdio.h> #include<conio.h> void main() { typedef void(fnk)(); fnk *func_addr = (fnk*)GetProcAddress(LoadLibraryA( "C:\\Users\\Администратор\\Documents\\Visual Studio 2010\\Projects\\dll\\Release\\dll.dll"), "test"); func_addr(); getch(); } пишет 1077мс, повторял пару раз, одно и тоже число. создаю консольний проект на борланде копирую тот же листинг, запускаю, пишет 1350. тоже пару раз запусал, ниже не падает. Ну как это понять? нету работы с памятью, просто вычисления. ну и 2 раза вызывается GetTickCount, не в цикле, так что как это может повлиять на столько. нашел одну интересную фичу Код (Text): extern "C" __declspec(dllexport) void test() { int i; double sum = 0; int t=GetTickCount(); for(i = 0; i <= 1000000000; i ++) sum += 1/i; int t2=GetTickCount(); printf("%f %d",sum,t2-t); } Выполняется одинаково 6022 меняем на Код (Text): sum += 1.0/i; 6598 борланд против 5351 вижуал тоесть дробные числа процессор под вижуалом стал делить быстрее, а под борландом дольше. интересно. посмотрим листинги с 1 Код (Text): _test PROC ; COMDAT ; 50 : { 00000 55 push ebp 00001 8b ec mov ebp, esp 00003 83 e4 c0 and esp, -64 ; ffffffc0H 00006 83 ec 34 sub esp, 52 ; 00000034H ; 51 : int i; ; 52 : double sum = 0; 00009 d9 ee fldz 0000b 53 push ebx 0000c 56 push esi 0000d dd 5c 24 2c fstp QWORD PTR _sum$[esp+60] 00011 57 push edi ; 53 : int t=GetTickCount(); 00012 8b 3d 00 00 00 00 mov edi, DWORD PTR __imp__GetTickCount@0 00018 ff d7 call edi 0001a dd 44 24 30 fld QWORD PTR _sum$[esp+64] 0001e 89 44 24 3c mov DWORD PTR _t$[esp+64], eax 00022 b9 03 00 00 00 mov ecx, 3 00027 be 00 e1 f5 05 mov esi, 100000000 ; 05f5e100H $LN3@test: ; 54 : for(i = 1; i <= 1000000000; i ++) ; 55 : sum += 1/i; 0002c 33 d2 xor edx, edx 0002e 8d 59 fe lea ebx, DWORD PTR [ecx-2] 00031 b8 01 00 00 00 mov eax, 1 00036 f7 f3 div ebx 00038 33 d2 xor edx, edx 0003a 8d 59 ff lea ebx, DWORD PTR [ecx-1] 0003d 89 44 24 30 mov DWORD PTR tv545[esp+64], eax 00041 b8 01 00 00 00 mov eax, 1 00046 db 44 24 30 fild DWORD PTR tv545[esp+64] 0004a f7 f3 div ebx 0004c de c1 faddp ST(1), ST(0) 0004e 33 d2 xor edx, edx 00050 8d 59 01 lea ebx, DWORD PTR [ecx+1] 00053 89 44 24 30 mov DWORD PTR tv463[esp+64], eax 00057 b8 01 00 00 00 mov eax, 1 0005c db 44 24 30 fild DWORD PTR tv463[esp+64] 00060 f7 f1 div ecx 00062 de c1 faddp ST(1), ST(0) 00064 33 d2 xor edx, edx 00066 89 44 24 30 mov DWORD PTR tv458[esp+64], eax 0006a b8 01 00 00 00 mov eax, 1 0006f db 44 24 30 fild DWORD PTR tv458[esp+64] 00073 f7 f3 div ebx 00075 de c1 faddp ST(1), ST(0) 00077 33 d2 xor edx, edx 00079 8d 59 02 lea ebx, DWORD PTR [ecx+2] 0007c 89 44 24 30 mov DWORD PTR tv453[esp+64], eax 00080 b8 01 00 00 00 mov eax, 1 00085 db 44 24 30 fild DWORD PTR tv453[esp+64] 00089 f7 f3 div ebx 0008b de c1 faddp ST(1), ST(0) 0008d 33 d2 xor edx, edx 0008f 8d 59 03 lea ebx, DWORD PTR [ecx+3] 00092 89 44 24 30 mov DWORD PTR tv448[esp+64], eax 00096 b8 01 00 00 00 mov eax, 1 0009b db 44 24 30 fild DWORD PTR tv448[esp+64] 0009f f7 f3 div ebx 000a1 de c1 faddp ST(1), ST(0) 000a3 33 d2 xor edx, edx 000a5 8d 59 04 lea ebx, DWORD PTR [ecx+4] 000a8 89 44 24 30 mov DWORD PTR tv443[esp+64], eax 000ac b8 01 00 00 00 mov eax, 1 000b1 db 44 24 30 fild DWORD PTR tv443[esp+64] 000b5 f7 f3 div ebx 000b7 de c1 faddp ST(1), ST(0) 000b9 33 d2 xor edx, edx 000bb 8d 59 05 lea ebx, DWORD PTR [ecx+5] 000be 89 44 24 30 mov DWORD PTR tv438[esp+64], eax 000c2 b8 01 00 00 00 mov eax, 1 000c7 db 44 24 30 fild DWORD PTR tv438[esp+64] 000cb f7 f3 div ebx 000cd de c1 faddp ST(1), ST(0) 000cf 33 d2 xor edx, edx 000d1 8d 59 06 lea ebx, DWORD PTR [ecx+6] 000d4 89 44 24 30 mov DWORD PTR tv433[esp+64], eax 000d8 b8 01 00 00 00 mov eax, 1 000dd db 44 24 30 fild DWORD PTR tv433[esp+64] 000e1 f7 f3 div ebx 000e3 de c1 faddp ST(1), ST(0) 000e5 8d 59 07 lea ebx, DWORD PTR [ecx+7] 000e8 33 d2 xor edx, edx 000ea 83 c1 0a add ecx, 10 ; 0000000aH 000ed 89 44 24 30 mov DWORD PTR tv428[esp+64], eax 000f1 b8 01 00 00 00 mov eax, 1 000f6 db 44 24 30 fild DWORD PTR tv428[esp+64] 000fa f7 f3 div ebx 000fc de c1 faddp ST(1), ST(0) 000fe 4e dec esi 000ff 89 44 24 30 mov DWORD PTR tv423[esp+64], eax 00103 db 44 24 30 fild DWORD PTR tv423[esp+64] 00107 de c1 faddp ST(1), ST(0) 00109 0f 85 1d ff ff ff jne $LN3@test 0010f dd 5c 24 30 fstp QWORD PTR _sum$[esp+64] ; 56 : int t2=GetTickCount(); 00113 ff d7 call edi ; 57 : printf("%f %d",sum,t2-t); 00115 2b 44 24 3c sub eax, DWORD PTR _t$[esp+64] 00119 dd 44 24 30 fld QWORD PTR _sum$[esp+64] 0011d 50 push eax 0011e 83 ec 08 sub esp, 8 00121 dd 1c 24 fstp QWORD PTR [esp] 00124 68 00 00 00 00 push OFFSET ??_C@_05JAALMNKC@?$CFf?5?$CFd?$AA@ 00129 ff 15 00 00 00 00 call DWORD PTR __imp__printf 0012f 83 c4 10 add esp, 16 ; 00000010H ; 58 : } 00132 5f pop edi 00133 5e pop esi 00134 5b pop ebx 00135 8b e5 mov esp, ebp 00137 5d pop ebp 00138 c3 ret 0 _test ENDP а теперь с 1.0 Код (Text): test PROC ; COMDAT ; 50 : { 00000 55 push ebp 00001 8b ec mov ebp, esp 00003 83 e4 c0 and esp, -64 ; ffffffc0H 00006 83 ec 38 sub esp, 56 ; 00000038H ; 51 : int i; ; 52 : double sum = 0; 00009 d9 ee fldz 0000b 56 push esi ; 53 : int t=GetTickCount(); 0000c 8b 35 00 00 00 00 mov esi, DWORD PTR __imp__GetTickCount@0 00012 dd 5c 24 34 fstp QWORD PTR _sum$[esp+60] 00016 57 push edi 00017 ff d6 call esi 00019 d9 e8 fld1 0001b dd 44 24 38 fld QWORD PTR _sum$[esp+64] 0001f 8b f8 mov edi, eax 00021 b8 03 00 00 00 mov eax, 3 00026 89 44 24 34 mov DWORD PTR tv264[esp+64], eax $LN3@test: ; 54 : for(i = 1; i <= 1000000000; i ++) ; 55 : sum += 1.0/i; 0002a 8d 48 fe lea ecx, DWORD PTR [eax-2] 0002d 89 4c 24 38 mov DWORD PTR tv455[esp+64], ecx 00031 db 44 24 38 fild DWORD PTR tv455[esp+64] 00035 8d 50 ff lea edx, DWORD PTR [eax-1] 00038 89 54 24 38 mov DWORD PTR tv449[esp+64], edx 0003c 8d 48 01 lea ecx, DWORD PTR [eax+1] 0003f d8 fa fdivr ST(0), ST(2) 00041 8d 50 02 lea edx, DWORD PTR [eax+2] 00044 de c1 faddp ST(1), ST(0) 00046 db 44 24 38 fild DWORD PTR tv449[esp+64] 0004a 89 4c 24 38 mov DWORD PTR tv439[esp+64], ecx 0004e 8d 48 03 lea ecx, DWORD PTR [eax+3] 00051 d8 fa fdivr ST(0), ST(2) 00053 de c1 faddp ST(1), ST(0) 00055 db 44 24 34 fild DWORD PTR tv264[esp+64] 00059 d8 fa fdivr ST(0), ST(2) 0005b de c1 faddp ST(1), ST(0) 0005d db 44 24 38 fild DWORD PTR tv439[esp+64] 00061 89 54 24 38 mov DWORD PTR tv435[esp+64], edx 00065 8d 50 04 lea edx, DWORD PTR [eax+4] 00068 d8 fa fdivr ST(0), ST(2) 0006a de c1 faddp ST(1), ST(0) 0006c db 44 24 38 fild DWORD PTR tv435[esp+64] 00070 89 4c 24 38 mov DWORD PTR tv432[esp+64], ecx 00074 8d 48 05 lea ecx, DWORD PTR [eax+5] 00077 d8 fa fdivr ST(0), ST(2) 00079 de c1 faddp ST(1), ST(0) 0007b db 44 24 38 fild DWORD PTR tv432[esp+64] 0007f 89 54 24 38 mov DWORD PTR tv429[esp+64], edx 00083 8d 50 06 lea edx, DWORD PTR [eax+6] 00086 d8 fa fdivr ST(0), ST(2) 00088 de c1 faddp ST(1), ST(0) 0008a db 44 24 38 fild DWORD PTR tv429[esp+64] 0008e 89 4c 24 38 mov DWORD PTR tv426[esp+64], ecx 00092 8d 48 07 lea ecx, DWORD PTR [eax+7] 00095 83 c0 0a add eax, 10 ; 0000000aH 00098 d8 fa fdivr ST(0), ST(2) 0009a 89 44 24 34 mov DWORD PTR tv264[esp+64], eax 0009e de c1 faddp ST(1), ST(0) 000a0 db 44 24 38 fild DWORD PTR tv426[esp+64] 000a4 89 54 24 38 mov DWORD PTR tv423[esp+64], edx 000a8 8d 50 fe lea edx, DWORD PTR [eax-2] 000ab d8 fa fdivr ST(0), ST(2) 000ad de c1 faddp ST(1), ST(0) 000af db 44 24 38 fild DWORD PTR tv423[esp+64] 000b3 89 4c 24 38 mov DWORD PTR tv420[esp+64], ecx 000b7 d8 fa fdivr ST(0), ST(2) 000b9 de c1 faddp ST(1), ST(0) 000bb db 44 24 38 fild DWORD PTR tv420[esp+64] 000bf d8 fa fdivr ST(0), ST(2) 000c1 de c1 faddp ST(1), ST(0) 000c3 81 fa 00 ca 9a 3b cmp edx, 1000000000 ; 3b9aca00H 000c9 0f 8e 5b ff ff ff jle $LN3@test 000cf dd d9 fstp ST(1) 000d1 dd 5c 24 38 fstp QWORD PTR _sum$[esp+64] ; 56 : int t2=GetTickCount(); 000d5 ff d6 call esi ; 57 : printf("%f %d",sum,t2-t); 000d7 dd 44 24 38 fld QWORD PTR _sum$[esp+64] 000db 2b c7 sub eax, edi 000dd 50 push eax 000de 83 ec 08 sub esp, 8 000e1 dd 1c 24 fstp QWORD PTR [esp] 000e4 68 00 00 00 00 push OFFSET ??_C@_05JAALMNKC@?$CFf?5?$CFd?$AA@ 000e9 ff 15 00 00 00 00 call DWORD PTR __imp__printf 000ef 83 c4 10 add esp, 16 ; 00000010H ; 58 : } 000f2 5f pop edi 000f3 5e pop esi 000f4 8b e5 mov esp, ebp 000f6 5d pop ebp 000f7 c3 ret 0 _test ENDP я вижу только разницу что теперь вычисления проводятся в fpu, допустим fdiv быстрее div но причем тут борланд, у него что особенные отношение с сопроцессором?
kaspersky Я думал что тс запилил тестовый код в длл и запускал его на бинарях, собранных разными компилерами. Если тестовый код собран на разных компиляторах, то тут и вопроса нет. Я не юзаю скрипты именно потому, что я не знаю и не могу контролировать конечный код.
bolt90 Не знаю у кого из них более особые, но борланд, скорее всего, по умолчанию устанавливает double-точность вычислений, а VC скорее всего single (под float). См. _controlfp\_control87 (или у борланда еще System::Set8087 или Math::SetPrecisionMode) kaspersky При наличии деления в цикле все эти фишки мало что дают
спасибо огромное. _controlfp( PC_24, MCW_PC ); быстро посчитал но неправельно _controlfp( PC_53, MCW_PC ); такая же скорость что и у вижуала _controlfp( PC_64, MCW_PC ); тот старый тормознутый результат получается борланд юзает 64 по умолчанию, а вижуал 53. тогда у меня еще 2 вопроса 1. результат выдал одинаково 53 и 64, когда ипользовать 64 лучше тогда? 2. можно все таки чтото сделать с борландом (ну 20 секунд разницы это уже слишком) чтоб он по лучше код генерировал, я имею ввиду какието настройки и ключи.
bolt90 Во-первых, точность вычислений сказывается только на скорости операций деления и извлечения корня, которые сами по себе являются очень тормозными и их следует всячески избегать, сокращать кол-во за счет выбора алгоритма. Например, в твоем случае можно увеличить скорость почти вдвое, если вычислять не каждый член ряда по отдельности, а сумму двух членов с приведением их к общему знаменателю с использованием одного деления вместо двух. Во-вторых, повышенная точность используется при громоздких промежуточных вычислениях (особенно сумм рядов и интегралов), чтобы уменьшить накопление ошибок округления. Ты же понимаешь, что если каждый член f(x) считается с точностью double, то результирующая сумма будет иметь тем худшую (предельную) точность, чем больше членов суммируется (конечно можно надеяться на компенсацию\усреднение ошибок при суммировании, но максимальное значение и дисперсия ошибки по любому увеличиваются с ростом числа слагаемых). Поэтому если тебе не нужно получать sum с макс.точностью double, то можно юзать и 53-битную точность, если же нужно, то - 64.
bolt90 зачем ты кругом вычисления в double делаешь, если результат всё равно до float округляешь? Чтоб медленнее было? Код (Text): float h = 1.0 / (double) intervals Смысл тут double делить на double, чтоб результат во float записать? Код (Text): x = h * ((double)i - 0.5); Смысл тут из double вычитать double, расширять h до double, умножить и урезать результат до float? Код (Text): sum *= h; И тут расширять h до double для сложения. Ты определись с точностью, и либо везде во float считай (f к константам не забудь дописать - 1.0f), либо всё в double храни. Потому что из-за этих твоих double компилятор SSE использовать не может к примеру.