Заголовок сообщения: Выбор метода вызова процедур СообщениеДобавлено: 29 май 2011, 12:11 [quote="Prof1983"]Задался вопросом какой метод вызова выбрать для функций внешних и внутренних модулей (fastcall, cdecl, stdcall, pascal, safecall)? Для этого написал небольшую тестовую программку (TestCall). http://aikernel.org/files/TestCall.zip - Тестирование скорости работы разных методов вызова функций внутри программы На картинке в приложении отображается кол-во тиков затраченное на вызов тестируемой фукции COUNT_I раз. COUNT_I = 100000000;[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 29 май 2011, 13:39 [quote="Prof1983"]Решил немного улучшить программу. Добавил вывод процентного значения времени которое требуется для вызова COUNT_I раз функций. За 100% принял самый быстрый вызов (fascall/register), остальные высчитываются как = (<Текущее значение Ticks> * 100) div <Значение Ticks самого быстрого (fastcall)> Получил очень странные странные цифры. Подумал, что это может происходить из-за того, что при первом вызове происходит заполнение кеша процессора первого уровня. И дальнейшие выполняются из-за этого быстрее. Поэтому добавил первый расчет, который далее не используется. Но результаты тестирования не изменились. За тем я подумал, что первый вызов для кеширование нужно производить перед каждым большим циклом, а не только в самом начале тестирования. Но все-равно результаты остались прежними. В общем результаты на картинках. Сравните с тем, что было ранее (выше). Прежнюю версию программы можно скачать здесь: http://aikernel.org/files/TestCall-0.2.0.zip Текущую версию программы можно скачать здесь: http://aikernel.org/files/TestCall-0.2.1.zip Самую последнюю версию программы можно скачать здесь: http://aikernel.org/files/TestCall.zip[/quote] TestCall-0.2.1-2.png [26.3 КБ] TestCall-0.2.1-1.png [26.38 КБ]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 29 май 2011, 14:02 [quote="Prof1983"]Нашел в чем проблема. Оказывается, что если выполнять [code]ProcShortFastcallTicks := TestProcShortFastcall(); ShortFastcallLabel.Caption := IntToStr(ProcShortFastcallTicks);[/code]то кол-во тиков у меня около 1600. А если выполнять [code]ProcShortFastcallTicks := TestProcShortFastcall(); S := IntToStr(ProcShortFastcallTicks); ShortFastcallLabel.Caption := S;[/code]то кол-во тиков у меня на компьютере около 2570. Здесь S-String; I-Integer. Хотя подсчет кол-ва тиков находится внутри TestProcShortFastcall() и не должен зависеть от вызывающей процедуры. [code]function TestProcShortFastcall: Integer; var I: Integer; T1: DWORD; T2: DWORD; begin T1 := GetTickCount(); for I := 0 to COUNT_I do ProcFastcall(1, 2); T2 := GetTickCount(); Result := T2 - T1; end;[/code] В общем так можно разбираться долго. Я пришел к выводу, что вопрос метода вызова функций между модулями не сильно важен. Внутри модуля можно реализовать любой вызов, хоть все процедуры внутри модуля на чистом asm писать. Поэтому я выбираю метод вызова для всех межмодульных вызовов как stdcall. Тем более, что аналогичное решение существует в API MS Windows. Кроме этого я встречал описание и сравнение cdecl (Linux) и stdcall, где stdcall был более производителен. К сожалению сейчас ссылки под руками на это сравнение у меня нет.[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 29 май 2011, 19:44 [quote="daner"][quote]Поэтому я выбираю метод вызова для всех межмодульных вызовов как stdcall[/quote] заранее создаете проблемы* с портированием на платформы отличные от win32. ---------------- * проблемы конечно решаемые.[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 29 май 2011, 20:10 [quote="Prof1983"][quote="daner"]заранее создаете проблемы* с портированием на платформы отличные от win32.[/quote]У меня не так много опыта, чтобы предусмотреть на данном этапе возможные проблемы. Но вроде на *nix платформах __stdcall поддерживается не хуже других? Какие могут возникать проблемы при портировании?[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 30 май 2011, 02:31 [quote="daner"]на сколько я знаю, не поддерживаются. обычно просто создаются пустые дефайны (ну типа __stdcall). Т.е. де-факто все равно происходят cdecl вызовы. Хотя, может народ как-то и изголяется на что-то другое.[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 30 май 2011, 07:36 [quote="Prof1983"][quote="daner"]на сколько я знаю, не поддерживаются. обычно просто создаются пустые дефайны (ну типа __stdcall). Т.е. де-факто все равно происходят cdecl вызовы. Хотя, может народ как-то и изголяется на что-то другое.[/quote]Не понимаю. Почему (в компиляторах) в *nix нет реализации __stdcall? Вызов stdcall, на сколько я знаю, - это просто последовательная передача параметров через стек. Отличается от cdecl только тем, что в cdecl дополнительно передается кол-во передаваемых параметров. Вообще мне известны такие типы передачи параметров: register, cdecl. stdcall, pascal, safecall. Отличие pascal от stdcall только в направлении передачи параметров (справа на лево или наоборот). safecall - это защищенный вызов (с фукцией-оберткой, которая отлавливает исключительные ситуации). Так почему (в компиляторах) в *nix нет реализации __stdcall? Хотелось бы увидеть ссылку на источник (можно в личку).[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 01 июн 2011, 12:54 [quote="Prof1983"]Daner, так почему все-таки с вызовом stdcall не в Win32 могут быть проблемы?[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 01 июн 2011, 12:59 [quote="Prof1983"]Сегодня протестировал скорость вызова разными методами (cdecl, stdcall, safecall, register) более сложную функцию и пришел к выводу, что различий по времени нет. Разница составляет несколько процентов, что я считаю не существенным. Поэтому для внешних (экспортируемых) функций модуля принимаю метод вызова stdcall. А внутри модулей можно реализовать как будет удобнее.[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 01 июн 2011, 21:29 [quote="daner"][quote="Prof1983"]Daner, так почему все-таки с вызовом stdcall не в Win32 могут быть проблемы?[/quote] я не знаю. если честно меня этот вопрос вообще никогда не интересовал. я просто знаю, что в gcc это дело не используется, а он все-таки основной компилятор в Linux (это конечно не все *nix платформы но многие, да и на других его тоже используют не слабо). хотя я 100% не буду утверждать, что gcc вообще никак это дело не поддерживает... что-то такое на поддержку stdcall похожее я видел в gcc к MinGW, но пустышка это там или нет, не знаю. На сколько я почитал про stdcall, его вообще придумали for windows и развивали только в нем. Зачем это сделали, остается для загадкой (в то время C уже во всю применял cdecl, а паскал свои вызовы, и какой смысл в перемене мес стека для паскалевского вызова, я так и не понял).[/quote]
Заголовок сообщения: Re: Выбор метода вызова процедур СообщениеДобавлено: 01 июн 2011, 23:31 [quote="Prof1983"][quote="daner"]про stdcall, его вообще придумали for windows и развивали только в нем[/quote]В общем-то у меня тоже такое впечатление сложилось. Я нигде не встречал stdcall в исходниках Unix программ. Хотя читал перевод интервью разработчика одного из ядер (не помню точно толи Linux, то ли Minix). Так вот там был примерно такой вопрос: "Планируете ли вы переходить на stdcall, вместо cdecl". С таким обоснованием, что передача дополнительного параметра в стеке при вызове cdecl не очень хорошо для быстродействия. Попробовал поискать в интернете. Нашел вот это: [quote]Как и большинство других операционных систем, Linux предоставляет т.н. API — набор полезных для программиста функций. В большинстве случаев вызов системной функции производится с помощью прерывания 80h. Следует отметить, что Linux используется fastcall-конвенция передачи параметров. Согласно ей параметры передаются через регистры (в windows, например, используется stdcall, где параметры передаются через стек).[/quote]http://habrahabr.ru/blogs/personal/79454/ Вызов через регистры - самый быстрый способ, но я боюсь, что вызове через регистры функций, написанных в разных средах (Delphi/Си) могут оказаться не совместимыми. Да и не понятно мне, если надо передать штук 10 параметров, а основных регистров всего 4 (AX, BX, CX, DX), то как будут передаваться остальные? В общем, через stdcall для windows проще реализовывать. Ну а при портировании на Unix можно или удалить stdcall или заранее написать макрос типа:[code]AFunction int Func1() { ... }[/code][/quote]