Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > msvc2008 bug???


Автор: GoldFinch 6.12.2008, 19:14
Код

#include "stdafx.h"

__declspec(naked) int Foo(int arg)
{__asm{
    _emit 0xCC
    mov eax,[arg]
    ret
}};

int _tmain(int argc, _TCHAR* argv[])
{
    return Foo(1);
}

Код

00401000  /$  CC            INT3
00401001  |.  8B45 08       MOV EAX,DWORD PTR [EBP+8]                ;<<<<< ebp o_O
00401004  \.  C3            RETN
00401005      CC            INT3
...
0040100F      CC            INT3
00401010  /$  6A 01         PUSH 1
00401012  |.  E8 E9FFFFFF   CALL cpp_asm_.00401000
00401017  |.  83C4 04       ADD ESP,4
0040101A  \.  C3            RETN

это баг или "фича"? о_О

Автор: Kallikanzarid 6.12.2008, 19:23
А что ты ожидал? В ebp хранится указатель на фрейм:
http://en.wikipedia.org/wiki/Frame_pointer

Автор: GoldFinch 6.12.2008, 19:33
Kallikanzarid, фрейма нету, какбэ
читай код в 1м посте полностью

Автор: MAKCim 6.12.2008, 19:44
GoldFinch
хм, реально баг получается

Автор: Kallikanzarid 6.12.2008, 20:03
Точно, должно быть esp  smile 
Попробуй поставить сервис пак, может, поможет.

Автор: J0ker 7.12.2008, 01:01
все верно
в прологе esp сохраняется в ebp, и от ebp считаются аргументы
так что все правильно
неправильно в naked использовать аргумент - т.к. компайлер плюет, что вы отказались от пролога и эпилога

Автор: dumb 7.12.2008, 04:46
хм. http://msdn.microsoft.com/en-us/library/4d12973a(VS.80).aspx про аргументы ничего такого не сказано, однако упомянуто авто-отключение Frame pointer optimization для naked функций. т.е. компилер рассчитывает на то, что руками фрэйм таки будет создан, что он и демонстрирует.

Автор: Kallikanzarid 7.12.2008, 08:54
GoldFinch, Если нет желания использовать фрейм, попробуй __fastcall. ЕМНИП, два двойных слова ты с его помощью без проблем передашь даже без фрейма. В принципе можно одним из них передавать указатель на объект, в котором хранятся остальные параметры.

Автор: J0ker 7.12.2008, 09:04
ну прям лень фрейм выставить - 2 инструкции в начале и 2 в конце

Автор: GoldFinch 7.12.2008, 10:29
Kallikanzarid, в msdn сказано что при __fastcall компилятор не гарантирует очередность параметров, т.е. неизвестно какой окажется в eax а какой edx. Кроме того, в большинстве случаев аргументы лежат в стеке.

J0ker, я привык к тому что когда я пишу на асме, я пишу как я хочу, а не так как того хочет конпилятор. может у меня ограничения на длину кода, мне тогда этот фрейм впихнуть некуда, более того, он в ряде случаев просто не нужен.

Автор: Kallikanzarid 7.12.2008, 14:26
GoldFinch, Если бы ты писал под мобильники, то юзал бы явно не студию. Уменьшение размера кода даже на килобайт абсолютно незаметно. Теоретик, блин smile

ЗЫ: Зачем тебе нужны naked функции?

Кстати, если тебе так противен фрейм, можешь спокойно высчитывать расположение параметров сам.

Автор: GoldFinch 7.12.2008, 15:20
Kallikanzarid, если бы ты писал на асме, ты бы знал зачем надо уменьшать код, зачем нужны naked функции
высчитывать расположение параметров самому глупо, этим должен заниматься компилятор, тем более что это асм встроенный в ЯВУ

Автор: Kallikanzarid 7.12.2008, 15:45
Цитата

если бы ты писал на асме, ты бы знал зачем надо уменьшать код, зачем нужны naked функции

О да, я такой глупый, просто оторопь берет!  smile Не желаю экономить 10 байт на функцию - просто кошмар!

Ты хоть профилировщик запускал прежде, чем прибегать к таким мерам? Или тебе 4мб L2-кэша заранее мало?

Цитата

высчитывать расположение параметров самому глупо, этим должен заниматься компилятор

Писать пролог самому глупо, этим должен заниматься компилятор.

ЗЫ:
Цитата

при __fastcall компилятор не гарантирует очередность параметров, т.е. неизвестно какой окажется в eax а какой edx.

А тебе зачем это знать? Обращайся к параметрам по имени.

Автор: GoldFinch 7.12.2008, 16:37
Kallikanzarid, вот есть у меня например такой код:
Код

__declspec(naked) ttt func(...) {__asm jmp $+5 __asm nop __asm push rva __asm call imp_core }

__declspec(naked) void imp_core(int rva)
//make import
{ __asm{
    //_emit 0xCC
    pop eax // =func+0x10
    pop edx // =rva
    add edx,[g_hCore] // = VA
    push edx
    sub edx,eax //=org_func-(func+0x10)
    add edx,0x10-5 //=org_func-(func+5)
    mov [eax-0x10+1],edx
    ret
}}

куда здесь воткнуть ebp фреймы?

Автор: Kallikanzarid 7.12.2008, 16:45
Боюсь даже представить smile А что делает этот код?

Автор: dumb 7.12.2008, 16:53
чем бы не тешилось...
сам же запутаешься в этом г..не(иных слов не подбирается) через неделю.
остается надеяться, что эти извращения не имеют отношения к чему-то, чем будут пользоваться люди.

Автор: GoldFinch 7.12.2008, 17:01
реализует "ленивые" импорты
да там же все понятно, что он делает, всего-то десяток строчек

Автор: GoldFinch 7.12.2008, 17:46
dumb, это хорошо, что ты не понял этого кода. Он призван вызывать священный трепет, а то и ужас, перед асмом у тех ламеров, кто полезет с ИДА узнавать какие импорты юзаются в моей проге. Хотя код крайне тривиален, я думаю найдется немало людей которые испугаются увидев это, и не станут копать мою прогу.
=)

Автор: Kallikanzarid 7.12.2008, 17:51
Цитата

Хотя код крайне тривиален, я думаю найдется немало людей которые испугаются увидев это, и не станут копать мою прогу.

Главное, чтобы босс был не в их числе  smile 

Автор: J0ker 7.12.2008, 19:06
Цитата(GoldFinch @  7.12.2008,  10:29 Найти цитируемый пост)
J0ker, я привык к тому что когда я пишу на асме, я пишу как я хочу, а не так как того хочет конпилятор. может у меня ограничения на длину кода, мне тогда этот фрейм впихнуть некуда, более того, он в ряде случаев просто не нужен.

в документации оговорена спецификация naked - во-первых
во-вторых - как ты хочешь, что-бы компилятор посчитал аргументы? он же не знает твои манипуляции со стеком до использования аргументов - ИМХО вполне оправдано что расчет аргументов опирается на предположение, что фрейм установлен - иначе никак
если не нужен фрейм - считай аргументы сам - компилятор это сделать иначе не может

Добавлено через 3 минуты и 10 секунд
Цитата(GoldFinch @  7.12.2008,  17:46 Найти цитируемый пост)
перед асмом у тех ламеров, кто полезет с ИДА 

несколько противоречивое высказывание  smile 

Автор: GoldFinch 7.12.2008, 19:34
J0ker, впринципе логично, что компилятор не разбирает асм-код
хотя могли бы это и сделать... не бином ньютона =\

Автор: J0ker 7.12.2008, 19:38
Цитата(GoldFinch @  7.12.2008,  19:34 Найти цитируемый пост)
хотя могли бы это и сделать... не бином ньютона =\ 

бином
предположим, ты выделяешь на стеке массив с размером, взятым из одного из параметров - в стиле C99

Автор: GoldFinch 7.12.2008, 19:45
J0ker, хм... ну тогда стоило бы выдавать ошибку компиляции, или хотябы явно написать об этой "фиче" в документации %)

Автор: J0ker 7.12.2008, 20:23
Цитата(GoldFinch @ 7.12.2008,  19:45)
J0ker, хм... ну тогда стоило бы выдавать ошибку компиляции, или хотябы явно написать об этой "фиче" в документации %)

http://msdn.microsoft.com/en-us/library/5ekezyy2(VS.80).aspx
http://msdn.microsoft.com/en-us/library/4d12973a(VS.80).aspx
Цитата

Frame pointer optimization (the /Oy compiler option) is not recommended, but it is automatically suppressed for a naked function.

Автор: GoldFinch 8.12.2008, 00:46
раз уж речь пошла о пользе naked, подскажите как тут избавиться от асма:

Код

//hook #1
void __stdcall OnRenderHook(FPlayerSceneNode *PlayerSceneNode,FRenderInterface *RenderInterface) ;
void __thiscall FPlayerSceneNode::Render(FRenderInterface *);
__declspec(naked) void __stdcall Hook_FPlayerSceneNode_Render(FRenderInterface *) 
{_asm{
    push dword ptr [esp+4]//arg1
    push ecx
    push dword ptr [esp+4]//arg1
    call FPlayerSceneNode::Render
    call OnRenderHook
    ret 4
}}

//hook #2
void __thiscall ALineagePlayerController::PlayerCalcView(class AActor *, class FVector *, class FRotator *);
__declspec(naked) void __stdcall Hook_ALineagePlayerController_PlayerCalcView(class AActor *, class FVector *, class FRotator *) 
{_asm{
    mov eax,dword ptr [esp+0xC]//arg3
    mov eax,dword ptr [eax+4]//2nd field
    mov dword ptr [g_Direction],eax
    jmp ALineagePlayerController::PlayerCalcView
}}

Автор: mes 8.12.2008, 10:52
 smile в упор не понимаю, почему не сделать делегацию средствами языка (cpp), a нужно прибегать к низкоуровневым непереносимым средствам ... smile 

Автор: Kallikanzarid 8.12.2008, 11:07
GoldFinch, ur crazy  smile 
Пожалуйста, скажи, что это профайлер показал, что необходимо вручную передавать параметр через регистр. Или использовать глобальную переменную. Или вручную расчитывать смещение поля в объекте (ничего, кстати, что это нарушает инкапсуляцию?). Не говоря уже о том, что рекомендуется передавать объекты по ссылкам, а не по указателям. Я начинаю боятся за будущее Земли. 

ЗЫ: твой код неэффективен. Ты два раза заносишь в стек один и тот же параметр. Настоящий Программист бы сделал так, чтобы функция Render после вызова оставляла его в стеке, а функция OnRender - использовала повторно. Ты неэффективен!

Автор: dumb 8.12.2008, 11:40
тьфу ты. неужели вместо того, чтобы нормально описать ситуевину, мол "развешиваю хуки в игрушке", надо было "выеживаться" в потугах самоутверждения? этот вопрос риторический.

в данном случае избавляться от асма imho особого смысла нет - тебе нужно сделать совершенно определенные низкоуровневые трики, и если их пытаться переписать на С, получишь кучу неоднозначностей и условностей, не говоря уже о том, что код получится, скорее всего, гораздо менее "прозрачным".
так же как и нет смысла вкрячивать в высокоуровневый код примитивную защиту извращаясь с дефайнами и вставками - для снятия оной вовсе не обязательно, чтобы механизм понимал любой "ламер" - достаточно одного немного продвинутого заинтересованного человека.

mesKallikanzarid, вы не учитываете того, что работа идет с готовым бинарным кодом. товарищ путем предоставления обрывков информации по сути провоцирует нас на такие бессмысленные(в конечном счете) комментарии.

Автор: Kallikanzarid 8.12.2008, 12:10
Чьорт, меня затроллил закомплексованный труъ-ассемблерщег  smile *ушел пить йад*

Автор: ksili 8.12.2008, 12:26
Цитата(Kallikanzarid @  7.12.2008,  18:26 Найти цитируемый пост)
Если бы ты писал под мобильники, то юзал бы явно не студию

Прикинь, я пишу под WinMobile и использую-таки студию

Автор: mes 8.12.2008, 12:42
Цитата(dumb @  8.12.2008,  11:40 Найти цитируемый пост)
вы не учитываете того, что работа идет с готовым бинарным кодом. 

Вместо того чтоб учитывать все возможные предположения, которых в действительности может и не быть (так как в другом топике этого же автора вроде (может и ошибаюсь) подразумевалось о том что исходники на руках) лучше было бы если бы автор описал бы свою ситуацию. Без этого будет имхо затруднительно ответить на вопрос:
Цитата(GoldFinch @  8.12.2008,  00:46 Найти цитируемый пост)
подскажите как тут избавиться от асма:


Автор: GoldFinch 8.12.2008, 13:06
Kallikanzarid, "рекомендуется передавать объекты по ссылкам, а не по указателям" я кнешно не силен в С++, но какая между ними разница? о_О

dumb, какая разница, для чего нужен код? хуки они и есть хуки... а использование ЯВУ вместо такого асма позволит значительно повысить читаемость:

Код

void __thiscall ALineagePlayerController::PlayerCalcView(class AActor *, class FVector *, class FRotator *);
__declspec(naked,noreturn) void __stdcall Hook_ALineagePlayerController_PlayerCalcView(
    class AActor *, class FVector *, class FRotator *Rotator) 

    __asm enter 0,0
    g_Direction=Rotator->Pitch
    __asm leave __asm jmp ALineagePlayerController::PlayerCalcView
}


ЗЫ: а та "примитивная защита" не хуже, чем популярное криптование символьных имен или импорты по хешам. К тому же ей гораздо удобнее пользоваться, т.к. функции(методы) вызываются нормально, а не по указателям.

Автор: Kallikanzarid 8.12.2008, 13:09
Цитата(ksili @ 8.12.2008,  12:26)
Цитата(Kallikanzarid @  7.12.2008,  18:26 Найти цитируемый пост)
Если бы ты писал под мобильники, то юзал бы явно не студию

Прикинь, я пишу под WinMobile и использую-таки студию

Поди еще .NET используешь smile Я имел ввиду настоящие мобильники, с низкими вычислительными мощностями.

Добавлено через 7 минут и 25 секунд
GoldFinch, ссылка на протяжении своей жизни гарантированно указывает на один и тот же объект, то позволяет компилятору включить множество оптимизаций, которые он (справедливо) боится применять к указателям.
http://www.tantalon.com/pete/cppopt/main.htm - устаревший ресурс, но многое все еще справедливо.

Защита дефайнами и вставками элементарно ломается с помощью препроцессора.

Автор: ksili 8.12.2008, 13:16
Цитата(Kallikanzarid @  8.12.2008,  17:09 Найти цитируемый пост)
Поди еще .NET используешь

Не, чисто на С++.

Автор: GoldFinch 8.12.2008, 13:27
Цитата(Kallikanzarid @  8.12.2008,  13:09 Найти цитируемый пост)
Защита дефайнами и вставками элементарно ломается с помощью препроцессора. 

как это? какого препроцессора? о_О

Автор: Kallikanzarid 8.12.2008, 13:31
GoldFinch, Препроцессора С/С++. Прогоняешь через него файлы, и дефайны со вставками волшебным образом исчезают smile 

ksili, как я понимаю, речь идет о смартфонах? Я имел ввиду, что экономить 10 байт может иметь смысл лишь с очень ограниченными платформами, вроде старых мобильников.

Автор: ksili 8.12.2008, 13:37
Цитата(Kallikanzarid @  8.12.2008,  17:31 Найти цитируемый пост)
ksili, как я понимаю, речь идет о смартфонах?

Да, смартфоны, КПК, ... это наш клиент ))

Цитата(Kallikanzarid @  8.12.2008,  17:31 Найти цитируемый пост)
Препроцессора С/С++. Прогоняешь через него файлы, и дефайны со вставками волшебным образом исчезают

Не понял. Ломают обычно бинарник. Как ты его прогоняешь через препроцессор?

Автор: Kallikanzarid 8.12.2008, 13:42
Цитата

Не понял. Ломают обычно бинарник. Как ты его прогоняешь через препроцессор? 

Тогда я ничего не понимаю smile Может, я неправильно истолковал слово "дифайны"?

Автор: mes 8.12.2008, 13:42
Цитата(ksili @  8.12.2008,  13:37 Найти цитируемый пост)
Ломают обычно бинарник.

имелось ввиду несколько другое :
Цитата(dumb @  8.12.2008,  11:40 Найти цитируемый пост)
так же как и нет смысла вкрячивать в высокоуровневый код примитивную защиту извращаясь с дефайнами и вставками - для снятия оной вовсе не обязательно, чтобы механизм понимал любой "ламер" - достаточно одного немного продвинутого заинтересованного человека.


Автор: ksili 8.12.2008, 13:48
Не, ну вы все-таки объясните. На С и асме пишется прога. Я так понимаю с расчётом на то, что её будет сложно взломать, ну или просто разобраться в ее коде в дизассемблере. Всё это предполагает то, что у злоумышленника будет бинарник, и не будет исходников. 
Что тогда такое "дефайн" в исполняемом файле? 
Что исчезнет в таком файле, после его прогона через препроцессор?

Автор: mes 8.12.2008, 14:04
Цитата(ksili @  8.12.2008,  13:48 Найти цитируемый пост)
Не, ну вы все-таки объясните. На С и асме пишется прога. Я так понимаю с расчётом на то, что её будет сложно взломать, ну или просто разобраться в ее коде в дизассемблере. 

по контексту речь идет о некоторых программистах, которые "портят" (с какой целью можно только предполагать) исходный код : 
Цитата
так же как и нет смысла вкрячивать в высокоуровневый код примитивную защиту извращаясь с дефайнами 


Автор: GoldFinch 8.12.2008, 14:10
Kallikanzarid, речь шла от такой защите дефайнами и асм вставками
Код

#define RVA(rva) ;
#define IMPORT_THUNK //nothing

class ALineagePlayerController
{
public:
    IMPORT_THUNK void ALineagePlayerController::PlayerCalcView(class AActor *, class FVector *, class FRotator *) RVA(0xF1EB)
};


__declspec(naked) void imp_engine()
//make import
{ __asm{
    //_emit 0xCC
    pop eax // =func+0x10
    pop edx // =rva
    add edx,[g_hEngine] // = VA
    push edx
    sub edx,eax //=org_func-(func+0x10)
    add edx,0x10-5 //=org_func-(func+5)
    mov [eax-0x10+1],edx
    ret
}}
//==================== THUNCKS ===================================
#define IMPORT_THUNK __declspec(naked)
#define RVA(rva) {__asm jmp $+5 __asm nop __asm push rva __asm call imp_engine }
...
    IMPORT_THUNK void ALineagePlayerController::PlayerCalcView(class AActor *, class FVector *, class FRotator *) RVA(0xF1EB)

после автоанализа в ИДА бинарник выглядит весьма неплохо, на 1й взгляд, да и на 2й взгляд там будет немало возни с восстановлением импортов. и это еще самый простейший вариант)

Автор: mes 8.12.2008, 14:23
Цитата(GoldFinch @  8.12.2008,  14:10 Найти цитируемый пост)
после автоанализа в ИДА бинарник выглядит весьма неплохо, на 1й взгляд, да и на 2й взгляд там будет немало возни с восстановлением импортов. и это еще самый простейший вариант) 

 smile а сколько возни автору коду с подержкой всей этой ..ммм.. защитой. )  интересно в чем прелесть такой овчинки и стоит ли она выделки ?
только ради (мнимой) надежды что код не взломают ?  В принципе могут и не взломать.. это если как в анекдоте про неуловимого Джо... ;)

Автор: ksili 8.12.2008, 14:23
Короче мы (GoldFinchKallikanzaridmes и я) в этой теме - лебедь, рак и щука, и ёщё кто-то четвёртый  smile  smile 

Автор: GoldFinch 8.12.2008, 14:35
mes, возни мало, зато куча преимуществ.
статический импорт не работает, т.к. для него надо иметь заголовочные (.h) файлы идентичные тем что были использованы при компиляции длл, иначе возникает несоответствие таблиц методов.
динамические импорты через getprocaddress неудобны изза использования указателей на методы (obj->*met)() вместо obj->met()
а такими приятно пользоваться в коде + их можно генерить скриптом

Автор: mes 8.12.2008, 14:55
Цитата(GoldFinch @  8.12.2008,  14:35 Найти цитируемый пост)
динамические импорты через getprocaddress неудобны изза использования указателей на методы (obj->*met)() вместо obj->met()

забываете о прокси-классах типа умного указателя. 

Цитата(GoldFinch @  8.12.2008,  14:35 Найти цитируемый пост)
а такими приятно пользоваться в коде + их можно генерить скриптом 

под одну платформу, определенный тип компилятора и небольшой плясочки, чтоб привести целевой бинарник к удобному виду. )

Автор: GoldFinch 8.12.2008, 16:05
Цитата(mes @  8.12.2008,  14:55 Найти цитируемый пост)
под одну платформу, определенный тип компилятора

кроссплатформенность С++ зачастую приводит к очень плохой кодогенерации.
лучше уж генерить хороший код под одну платформу чем *плохой* но чтоб можно было под любую.
когда я пишу код который будет работать внутри готового win32 приложения, мне эта кроссплатформенность *не нужна*

Автор: Kallikanzarid 8.12.2008, 16:25
GoldFinch, [citation needed]

Автор: GoldFinch 8.12.2008, 16:34
Цитата(Kallikanzarid @  8.12.2008,  16:25 Найти цитируемый пост)
GoldFinch, [citation needed] 

???

Автор: Kallikanzarid 8.12.2008, 16:50
Мне не кажется очевидным, что кроссплатформенный исходный код приводит к генерации "плохого" бинарного кода.

Автор: GoldFinch 8.12.2008, 17:15
Kallikanzarid, из-за "кроссплатформенности", в С(++) нет способа средствами языка сгенерить некоторые x86-87 команды, например загрузку констант в FPU. 
Т.е. в некроссплатформенном паскале есть оператор(функция) Pi который генерит fldpi, а в кроссплатформенном С(++) оператора Pi() нет, и способа сгенерить fldpi (и другие константы) тоже нет.
Впрочем код C++ для FPU местами ужасен %) Ни один нормальный программист такого бы не писал.

Автор: Kallikanzarid 8.12.2008, 19:33
Троллинг перерастает в холивар...  smile 
1) Чем плохи заранее обсчитанные константы?
2) Паскаль - не кроссплатформенный?  smile Да что ви говогите!
3) Меня ты продавишь только цифрами, так как плевать я хотел на красоту бинарного кода smile Хочу бенчмарк, в котором те или иные мат. расчеты выполняются сначала в С++, а потом - в асме.
4) А ты можешь вручную оптимизировать расположение инструкций, чтобы минимизировать простой конвеера?

Автор: J0ker 8.12.2008, 19:35
Цитата(GoldFinch @  8.12.2008,  17:15 Найти цитируемый пост)
из-за "кроссплатформенности", в С(++) нет способа средствами языка сгенерить некоторые x86-87 команды

бред
никакой связи тут нет
вопрос лишь в поддержке компилятора

Цитата(GoldFinch @  8.12.2008,  17:15 Найти цитируемый пост)
Впрочем код C++ для FPU местами ужасен

не существует "кода C++ для FPU"
качество кода, сгенерированного компилятором зависит от качества компилятора
оценка качества оптимизированного кода неподготовленными субъектами обычно неадекватна, т.к. понять что оптимально а что нет на уже 2-х процессорных платформах способен только специалист

и вообще на 2-х последних страницах столько бреда, что ужасть  smile 

Автор: GoldFinch 8.12.2008, 20:05
Kallikanzarid,
1) тем что аппаратные константы много лучше программных
2) паскаль - я имел ввиду турбопаскаль, дельфи
3) цифры: 
   fldpi - 2байта
   pi dt 3.14.... / fld [pi] - 10+6 байт
4) если бы ты видел код который те генерит твой компилятор, ты бы не говорил о "минимизации простоя конвеера"
какбэ вот такой код при конфигурации "релиз" - это реальность
.text:1000122F                 mov     eax, dword ptr [g_hEngine]
.text:10001234                 mov     dword ptr [eax+56F5D8h], offset Hook_ALineagePlayerController_PlayerCalcView(AActor *,FVector *,FRotator *)
.text:1000123E                 mov     ecx, dword ptr [g_hEngine]
.text:10001244                 mov     dword ptr [ecx+57B968h], offset loc_10001190
.text:1000124E                 mov     edx, dword ptr [g_hEngine]


J0ker, ок, будет говорить исключительно о компиляторе MSVC. так вот у него кодогенератор - гуан*

насчет кода для FPU - вот так вот в MSVC передаются 32-разрядные значения float
.text:10001344                 fld     [esp+18h+arg_4]
.text:10001348                 fstp    [esp+18h+var_14]
.text:1000134C                 fld     dword ptr [eax+4]
.text:1000134F                 fstp    [esp+18h+var_18]
.text:10001352                 call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)
видимо те кто писали кодогенератор малость не учли, что dword'ы в стек можно запихивать командой push, а не через стек FPU %)

Автор: Kallikanzarid 8.12.2008, 20:15
GoldFinch, объясняю еще раз для самых одаренных. Мне. Плевать. На. Красоту. Ассемблерного. Кода. Если бахвалишься своей труъ-ассемблерностью, подтверди свое превосходство, представив реализацию какого-нибудь численного алгоритма на С++ и на асме. И время, за которое эти реализации выполняются.

Автор: GoldFinch 8.12.2008, 20:24
Kallikanzarid, вот тебе какбэ алгоритм получения 80-разрядной константы Pi, разница в размере - в 8 раз, разница в быстродействии в единицы - десятки раз, в зависимости от расположения константы в кеше или нет.
Не нравится - выбери другой алгоритм, метод, условия измерения и представь свой труъ С++ код, ато я на С++ меньше месяца пишу, могу true с false через strlen() сравнивать.

Автор: J0ker 8.12.2008, 20:42
Цитата(GoldFinch @  8.12.2008,  20:05 Найти цитируемый пост)
0ker, ок, будет говорить исключительно о компиляторе MSVC. так вот у него кодогенератор - гуан*

насчет кода для FPU - вот так вот в MSVC передаются 32-разрядные значения float
.text:10001344                 fld     [esp+18h+arg_4]
.text:10001348                 fstp    [esp+18h+var_14]
.text:1000134C                 fld     dword ptr [eax+4]
.text:1000134F                 fstp    [esp+18h+var_18]
.text:10001352                 call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)
видимо те кто писали кодогенератор малость не учли, что dword'ы в стек можно запихивать командой push, а не через стек FPU %)

видимо тот, кто критикует то, что не понимает, не знает того, что преобразование типов в плавающую точку является реальной операцией, а не кастом на уровне переназвания типа

Автор: GoldFinch 8.12.2008, 20:46
J0ker, и где же ты там преобразование увидел? я тольк увидел преобразование m32real->m80real->m32real. там какбэ fld а не fild

Автор: J0ker 8.12.2008, 20:50
Цитата(GoldFinch @ 8.12.2008,  20:46)
J0ker, и где же ты там преобразование увидел? я тольк увидел преобразование 32разряда->80рязрядов->32разряда

именно
в функции операнды передаются через стек, и при передаче тип должен быть проверен и если он не может быть преобразован то в точке передачи обязан быть выставлен флаг исключения
если данную функцию переписать как инлайн, то все будет оптимизированно на стеке FPU
других решений тут нет и быть не может

Автор: GoldFinch 8.12.2008, 20:56
Цитата(J0ker @  8.12.2008,  20:50 Найти цитируемый пост)
других решений тут нет и быть не может 

а это не решение? о_О
pushd     [esp+18h+arg_4]
pushd     [eax+4]
call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)

Автор: mes 8.12.2008, 21:08
Цитата(GoldFinch @  8.12.2008,  20:56 Найти цитируемый пост)

а это не решение? о_О
pushd     [esp+18h+arg_4]
pushd     [eax+4]


битовое представление floata равного n не  не соответствует битовому представлению этого числа в dword/int (дополненого нулями)

Автор: J0ker 8.12.2008, 21:20
Цитата(GoldFinch @ 8.12.2008,  20:56)
Цитата(J0ker @  8.12.2008,  20:50 Найти цитируемый пост)
других решений тут нет и быть не может 

а это не решение? о_О
pushd     [esp+18h+arg_4]
pushd     [eax+4]
call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)

нет

Автор: GoldFinch 8.12.2008, 21:21
mes, я струдом догадываюсь что такое битовое представление, тем более дополненное нулями О_о, и причем тут это
команда push [mem32] копирует 4 байта по адресу mem32 в стек, и она не обращает внимания на "битовое представление" этих байт.
J0ker, и в каком же месте это не решение?

Автор: J0ker 8.12.2008, 21:29
Цитата(GoldFinch @  8.12.2008,  21:21 Найти цитируемый пост)
J0ker, и в каком же месте это не решение?

в месте преобразования типа - размещение значений с плавающей точкой в памяти и обратная операция сопряжено с преобразованием типов
нельзя корректно положить на стек число с плавающей точкой иначе чем через стек FPU

Автор: mes 8.12.2008, 21:30
Цитата(GoldFinch @  8.12.2008,  21:21 Найти цитируемый пост)
mes, я струдом догадываюсь что такое битовое представление,

сейчас набросаю пример почему не явлется решением :

Цитата(GoldFinch @  8.12.2008,  21:21 Найти цитируемый пост)
копирует 4 байта по адресу mem32 в стек, и она не обращает внимания на "битовое представление" этих байт.


Добавлено @ 21:33
вот примерно что получится в результате вашго решения :
Код

#include <iostream>

union convert
{
    float f;
    int i;
};

int main()
{
   convert c;
   c.i =5;
   std::cout<<c.i<<std::endl;
   ++c.f;
   std::cout<<c.i<<std::endl;

  system("pause");
  return 0;
}


Автор: GoldFinch 8.12.2008, 21:39
J0kermes, жжоте... какие громкие заявления) какая уверенность в правоте своих слов... вы не правы. 
Потому что черное это черное, а белое это белое. Есть много способов премещать значения в памяти, и если вы этого не знаете это не значит что эти способы неверны) Курите документацию к процу и вам откроется истина)

Но какие замечательные высказывания от вроде бы малость разбирающихся в программировании людей... Записал бы, да бред не коллекционирую.

upd:
mes, нет, Ваш код ниразу не соответствует той ситуации.

Автор: mes 8.12.2008, 21:49
Цитата(GoldFinch @  8.12.2008,  21:39 Найти цитируемый пост)
какие громкие заявления)

никакой громкости.. Вам был представлен пример, который показывает что участок памяти трактованный как int, числено не равен этому же участку памяти но трактованному как float.
жаль что Вы даже не захотели этого понять ;)

Цитата(GoldFinch @  8.12.2008,  21:39 Найти цитируемый пост)
Потому что черное это черное, а белое это белое.

И ночью тоже ?

Цитата(GoldFinch @  8.12.2008,  21:39 Найти цитируемый пост)
Есть много способов премещать значения в памяти, и если вы этого не знаете это не значит что эти способы неверны) 

а кто нибудь оспаривал ? речь не о перемещении а о трактовке значения.

Цитата(GoldFinch @  8.12.2008,  21:39 Найти цитируемый пост)
Записал бы, да бред не коллекционирую. 

А вот это действительно громко. Записал бы, но .... я думаю Вы догадались )



Автор: J0ker 8.12.2008, 21:56
так..... тут было потерто обкидывание оппонента какашками  smile 

Автор: mes 8.12.2008, 22:12
Цитата(GoldFinch @  8.12.2008,  21:39 Найти цитируемый пост)
mes, нет, Ваш код ниразу не соответствует той ситуации.


Цитата(J0ker @  8.12.2008,  21:20 Найти цитируемый пост)
pushd     [esp+18h+arg_4]
pushd     [eax+4]
call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)

вот немного изменил код, чтоб легче было понимать что происходит .. желаю приятных эксперементов :
Код


#include <iostream>

union convert
{
    float f;
    int i;
};

float mycast_int2float(int i) // преобразование без учета типа
{
    convert c;
    c.i = i;
    return c.f;
}

void myfunc (float f)
{
    std::cout<< "argument for myfunc = " << f << std::endl;
}

int main()
{
// передача аргумента с  конвертацией типа
  myfunc ('a'); // char
  myfunc (int(5)); // int
  myfunc (6);    // int
  myfunc (7.0); // double
// передача аргумента по битовому представлению
  myfunc (mycast_int2float('a'));
  myfunc (mycast_int2float(5));

  system("pause");
  return 0;
}


Автор: GoldFinch 8.12.2008, 22:17
mes, что за бредовый пруфкод вы пишете? то что мы обсуждаем выглядит так:
Код

#include <windows.h>
#pragma comment(linker,"/ENTRY:main")

int __stdcall Foo(float arg)
{
    return arg == 8/7;
};

int Bar(float arg)
{__asm{
    push dword ptr [arg]
    call Foo
}};

void main()
{    
    if ( Bar(8/7)) 
        MessageBoxA(0,"8//7==8//7","ok",0);
    else
        MessageBoxA(0,"8//7!=8//7",0,0);
}

в строчке "push dword ptr [arg]" float значение передается в стек через push а не через пару fld/fstp
что характерно прога выводит "8/7==8/7"

Автор: J0ker 8.12.2008, 22:25
GoldFinch, я вам объясняю... совершенно спокойно, вот...
преобразование из дабл во флоат - это ОПЕРАЦИЯ - она не может быть выполнена без привлечения FPU либо его эмулятора
если вы в своих примерах замените float на double вы сразу это поймете

Автор: mes 8.12.2008, 22:28
Цитата(GoldFinch @  8.12.2008,  22:17 Найти цитируемый пост)
int Bar(float arg)

A Вы схитрили .. перепешите код изменив эту срочку на
int Bar(int arg)

вот Вам каркас теста :
Код


#include <iostream>

int __stdcall Foo(float arg)
{
    return int(arg)+1;
};
int Bar( int arg)
{
    Foo (arg); // вот вместо этого  передайте параметр через стек  )
};
int main()
{
 std::cout << "Foo(5) = " << Bar(5)<<std::endl;

  system("pause");
  return 0;
}


потом еше можете изменить int на double и посмотреть результат ) 

Автор: J0ker 8.12.2008, 22:39
GoldFinch, вот, разберитесь уже наконец
Код

__declspec(noinline) float foo(float x, float x1)
{
    return x * x1;
00401650  fld         dword ptr [esp+4] 
00401654  fmul        dword ptr [esp+8] 
00401658  fstp        dword ptr [esp+4] 
0040165C  fld         dword ptr [esp+4] 
}
00401660  ret              

..............

__declspec(noinline) double foo1(double x, double x1)
{
    return x * x1;
00401670  fld         qword ptr [esp+4] 
00401674  fmul        qword ptr [esp+0Ch] 
}
00401678  ret              

..................

int _tmain(int argc, _TCHAR* argv[])
{
00401680  push        ebp  
00401681  mov         ebp,esp 
00401683  and         esp,0FFFFFFC0h 
00401686  push        0FFFFFFFFh 
00401688  push        403A20h 
0040168D  mov         eax,dword ptr fs:[00000000h] 
00401693  push        eax  
00401694  sub         esp,70h 
00401697  mov         eax,dword ptr ds:[00406018h] 
0040169C  xor         eax,esp 
0040169E  mov         dword ptr [esp+38h],eax 
004016A2  push        esi  
004016A3  mov         eax,dword ptr ds:[00406018h] 
004016A8  xor         eax,esp 
004016AA  push        eax  
004016AB  lea         eax,[esp+78h] 
004016AF  mov         dword ptr fs:[00000000h],eax 
004016B5  mov         esi,dword ptr [ebp+0Ch] 
    float a = (float)atof(argv[1]);
004016B8  mov         eax,dword ptr [esi+4] 
004016BB  push        eax  
004016BC  call        dword ptr ds:[00404108h] 
004016C2  fstp        dword ptr [esp+34h] 
    float b = (float)atof(argv[2]);
004016C6  mov         ecx,dword ptr [esi+8] 
004016C9  add         esp,4 
004016CC  push        ecx  
004016CD  call        dword ptr ds:[00404108h] 
    
    float y = foo(a, b) * 4.7f;
004016D3  fstp        dword ptr [esp+38h] 
004016D7  fld         dword ptr [esp+38h] 
004016DB  fstp        dword ptr [esp] 
004016DE  push        ecx  
004016DF  fld         dword ptr [esp+38h] 
004016E3  fstp        dword ptr [esp] 
004016E6  call        00401650 
004016EB  fmul        qword ptr ds:[00404650h] 

    double a1 = atof(argv[1]);
004016F1  mov         edx,dword ptr [esi+4] 
004016F4  push        edx  
004016F5  fstp        dword ptr [esp+3Ch] 
004016F9  call        dword ptr ds:[00404108h] 
    double b1 = atof(argv[2]);
004016FF  mov         eax,dword ptr [esi+8] 
00401702  fstp        qword ptr [esp+40h] 
00401706  add         esp,0Ch 
00401709  push        eax  
0040170A  call        dword ptr ds:[00404108h] 

    double y1 = foo1(a1, b1) * 4.7;
00401710  sub         esp,0Ch 
00401713  fstp        qword ptr [esp+8] 
00401717  fld         qword ptr [esp+44h] 
0040171B  fstp        qword ptr [esp] 
0040171E  call        00401670 
00401723  fmul        qword ptr ds:[00404648h] 
00401729  add         esp,10h 

    return (int)(y + y1);
0040172C  fadd        dword ptr [esp+30h] 
00401730  call        00403500 
}
00401735  mov         ecx,dword ptr [esp+78h] 
00401739  mov         dword ptr fs:[00000000h],ecx 
00401740  pop         ecx  
00401741  pop         esi  
00401742  mov         ecx,dword ptr [esp+38h] 
00401746  xor         ecx,esp 
00401748  call        00401F58 
0040174D  mov         esp,ebp 
0040174F  pop         ebp  
00401750  ret              

Автор: GoldFinch 8.12.2008, 22:39
J0ker
Код

.text:10001344                 fld     [esp+18h+arg_4]
.text:10001348                 fstp    [esp+18h+var_14]
.text:1000134C                 fld     dword ptr [eax+4]
.text:1000134F                 fstp    [esp+18h+var_18]
.text:10001352                 call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)

где Вы тут увидели double??? тот самый 64-разрядный double, а не 32-разрядный float?? надеюсь Вы понимаете что мы говорим о 32(тридцатидвух)-разрядных значениях??

но специально для Вас, я перепишу код для double, и даже уберу там баги которых Вы не заметили)))
Код

#include <windows.h>
#pragma comment(linker,"/ENTRY:main")

__declspec(noinline) int __stdcall Foo(double arg)
{
    return arg == 8.0/7.0;
};
 
__declspec(noinline) int __stdcall Bar(double arg)
{__asm{
    push dword ptr [arg+4]
    push dword ptr [arg]
    call Foo
}};

void main()
{    
    if ( Bar(8.0/7.0)) 
        MessageBoxA(0,"8/7==8/7","ok",0);
    else
        MessageBoxA(0,"8/7!=8/7",0,0);
}

какбэ 64-разрядные значения запихиваются в стек двумя push [mem32]

более того, пиши я под x64, там был бы один push [mem64]

Добавлено @ 22:44
J0ker, Вас в вашем коде строчки
00401658  fstp        dword ptr [esp+4] 
0040165C  fld         dword ptr [esp+4] 
не смущают?
и вообще, как эта муть относится к теме?


mes, медленно, вдумчиво, прочитайте еще раз этот код, и Вы поймете что Вы пишите не по теме.
.text:10001344                 fld     [esp+18h+arg_4]
.text:10001348                 fstp    [esp+18h+var_14]
.text:1000134C                 fld     dword ptr [eax+4]
.text:1000134F                 fstp    [esp+18h+var_18]
.text:10001352                 call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)
ну нету в этом коде ничего связанного с int, не-ту

Автор: J0ker 8.12.2008, 23:04
Цитата(GoldFinch @  8.12.2008,  22:39 Найти цитируемый пост)
о специально для Вас, я перепишу код для double, и даже уберу там баги которых Вы не заметили)))

да я собстна не про этот код  smile 
я его даже не читал

Цитата(GoldFinch @  8.12.2008,  22:39 Найти цитируемый пост)
J0ker, Вас в вашем коде строчки
00401658  fstp        dword ptr [esp+4] 
0040165C  fld         dword ptr [esp+4] 
не смущают?

а вас смущает? а что вас смущает?  smile 

Цитата(GoldFinch @  8.12.2008,  22:39 Найти цитируемый пост)
и вообще, как эта муть относится к теме?

когда вы это поймете, дискуссия будет окончена  smile 

Автор: GoldFinch 8.12.2008, 23:09
J0ker, эти строчки - nop. они ничего не делают. И таких строчек в том коде много. Вы вообще смотрели тот код который выложили? Да там оптимизацией и не пахнет.

Добавлено через 6 минут
По оптимизации - вот это вот
004016DE  push        ecx  
004016DF  fld         dword ptr [esp+38h] 
004016E3  fstp        dword ptr [esp] 
004016E6  call        00401650 
заменяется на
push dword ptr [esp+38h]  
call 00401650
и т.д. и т.п.

не верите? проверьте в ольке 

Автор: J0ker 8.12.2008, 23:23
Цитата(GoldFinch @  8.12.2008,  23:09 Найти цитируемый пост)
J0ker, эти строчки - nop. они ничего не делают.

да неужели?
а давайте проверим - вот конкретно эти строчки
Код

// здесь ST0 = +7.5899997329711936e+0000
00401658  fstp        dword ptr [esp+4] 
0040165C  fld         dword ptr [esp+4]
// а здесь ST0 = +7.5899996757507324e+0000

вы мысль улавливаете, да?  smile

Добавлено через 1 минуту и 32 секунды
Цитата(GoldFinch @  8.12.2008,  23:09 Найти цитируемый пост)
По оптимизации - вот это вот
004016DE  push        ecx  
004016DF  fld         dword ptr [esp+38h] 
004016E3  fstp        dword ptr [esp] 
004016E6  call        00401650 
заменяется на
push dword ptr [esp+38h]  
call 00401650
и т.д. и т.п.

не верите? проверьте в ольке 

только если нет преобразования типов
ага  smile 

Автор: GoldFinch 8.12.2008, 23:30
J0ker, уловил. Только в чем смысл округления 80-разрядного значения в стеке сопроцессора до 32-разрядного? Я чтото не представляю себе жизненных случаев где это может пригодиться.

Добавлено @ 23:33
мм... развечто при сравнении... так тогда и надо округлять перед сравнением, а не всегда и везде, иначе какая это оптимизация %)


так или иначе, разговор начался с копирования float в стек, *уже округленного* float в стек.

Автор: J0ker 8.12.2008, 23:36
в том, что вы не можете просто так отрезать лишние биты при трансфере чисел с плавающей точкой
я совершенно согласен, что можно, и даже иногда нужно оптимизировать вычисления на FPU на ассемблере, т.к. стандартные типы пока не вмещают полноразмерные числа с ПТ
но совершенно безосновательно возводить поклеп на умных людей написавших грамотный компилятор

Добавлено через 10 минут
Цитата(GoldFinch @  8.12.2008,  23:30 Найти цитируемый пост)
так или иначе, разговор начался с копирования float в стек, *уже округленного* float в стек.

это вы знаете, что у вас там float, а процессору это нужно доказать  smile 

Автор: GoldFinch 8.12.2008, 23:47
Цитата(J0ker @  8.12.2008,  23:36 Найти цитируемый пост)
в том, что вы не можете просто так отрезать лишние биты при трансфере чисел с плавающей точкой

Так я и не понял с этими отрезаниями.....
У меня в памяти есть 32-разрядный float. Готовый, правильный, безо всяких подвохов float. Почему компилятор не копирует его в стек командой push [mem32], а генерит fld [mem32] / fstp [mem32] ?? В стеке же оказывается одно и тоже значение...
Цитата(J0ker @  8.12.2008,  23:36 Найти цитируемый пост)

я совершенно согласен, что можно, и даже иногда нужно оптимизировать вычисления на FPU на ассемблере, т.к. стандартные типы пока не вмещают полноразмерные числа с ПТ

кто невмещает? в С++ нет 10-байтового вещественного чтоли?

Добавлено через 2 минуты и 56 секунд
действительно нет.... везде есть, а в С++ нет.... как же так %)

Автор: J0ker 8.12.2008, 23:53
c'est la vie

Автор: GoldFinch 8.12.2008, 23:53
Цитата(J0ker @  8.12.2008,  23:36 Найти цитируемый пост)
это вы знаете, что у вас там float, а процессору это нужно доказать 

что доказать????
004016DE  push        ecx  ; sub esp,SizeOf(dword)
004016DF  fld         dword ptr [esp+38h] 
004016E3  fstp        dword ptr [esp] 
004016E6  call        00401650 
float и dword это одно и то же, что тут доказывать процессору?

Автор: J0ker 9.12.2008, 00:00
опа, вот и я не прав
long double в стандарте оказывается... проморгал smile

Добавлено через 2 минуты и 34 секунды
Цитата(GoldFinch @  8.12.2008,  23:53 Найти цитируемый пост)
004016DF  fld         dword ptr [esp+38h] 
004016E3  fstp        dword ptr [esp] 
004016E6  call        00401650 
float и dword это одно и то же, что тут доказывать процессору? 

я ж вам уже сказал - что у вас там лежит в памяти известно только вам

Автор: Kallikanzarid 9.12.2008, 00:27
Итак, it's a showdown!!!

Алгоритм - интегрирование методом трапеций. Интегрируется косинус, при этом специально не используется его свойство периодичности. В общем, смотри код:
Код

#include <cstdlib>
#include <cmath>
#include <iostream>
using namespace std;

const float pi = static_cast<float>( M_PI );

float cosint( float a, float b, int N ) {
    float sum = 0.0f;
    float h = (b - a) / N;
    for( float cur = a + h; cur < b; cur += h )
        sum += cos( cur );
    return ( sum + ( cos(a) + cos(b) ) * 0.5f ) * h;
}

int main() {
    clock_t before = clock();
    float result = cosint( 0.0f, 1000.0f * pi, 10000000 );
    clock_t after = clock();
    
    cout << result << " -- " << (after - before) / 1000.0 << " seconds." << endl;
}



Код, кстати, кроссплатформенней некуда. Компилировал с помощью MinGW со следующими параметрами=:

g++ -msse3 -mfancy-math-387 -m80387 -mhard-float -mtune=pentium4 -march=pentium4 -mthreads -mfp-ret-in-387 -mieee-fp -O3 -funroll-loops  -o showdown.exe showdown.cpp

После этого прогнал через strip:
strip -s showdown.exe

Прикладываю экзешник. Удачи, чувак  smile 

Автор: GoldFinch 9.12.2008, 14:44
Kallikanzarid, ты бы перед тем как выкладывать код с бинарником, убедился бы в их качестве
код - неудобный, хз как у вас а меня еще в школе учили в конце консольной программы вставлять паузу.
функция - неоптимизирована, про использование for я вообще промолчу... 

а самое главное, в бинарнике видно что компилятор заинлайнил cosint() и заменил ее аргументы константами.
получилось както так:
Код

    clock_t before = clock();
    float sum = 0.0f;
    float h = 1000.0f * pi / 10000000;
    for( float cur = h; cur < 1000.0f * pi; cur += h )
        sum += cos( cur );
    result =  ( sum + cos(1000.0f * pi) * 0.5f ) * h;
    clock_t after = clock();

так и было задумано?) а что сразу так не написал?)))

Автор: Kallikanzarid 9.12.2008, 15:09
GoldFinch,

1) За годы практики я убедился, встроенная в саму программу пауза - это зло. Намного лучше создавать для этой цели .bat-файл.
2) Я специально ничего не оптимизировал, чтобы функция выполнялась достаточно долго, и чтобы компилятор мог проявить себя в раскрутке циклов и т. д.
3) for и правда не самый оптимальный (и, к тому же, накапливающий погрешность), но мы ведь спорили об оптимизации FPU-кода, так? Вот я и стараюсь загрузить его по максимуму.
4) Инлайн есть гут smile Оптимизирующий компилятор ведь должен оптимизировать, так? Но в любом случае я сомневаюсь, что один дополнительный вызов бы сделал погоду.
5) Да, так и было задумано smile

Добавлено через 3 минуты и 8 секунд
float вместо double я тоже использовал в своих корыстных целях, дабы векторизация дала прирост x4, а не x2. Хотя этот алгоритм не особенно хорош для SSE, так что, может быть, код там использует только FPU. Хз, я через BIEW не прогонял.

Автор: GoldFinch 9.12.2008, 17:10
Решение "в лоб", без FPU-оптимизации, бинарник (2кб) в архиве
Код

include 'win32a.inc'
include 'hll.inc'
format PE GUI 4.0
;=====================================================
section '.data' data readable writeable
;------------------------
IMPORTS KERNEL32.DLL, <ExitProcess,GetTickCount,Sleep>,\
        USER32.DLL,   <wsprintfA,MessageBoxA>
;------------------------
m dd 100000000 ;8digits=32/4
gRealBuf: dt ?
gMsgBuf db 1024 dup ?
;=====================================================
section '.code' code readable executable
entry $
; float result = cosint( 0.0f, 1000.0f * pi, 10000000 );
      GetTickCount()
      push eax
;A=0
;B=1000.0f * pi
      ;-----------------------------------------------------
      jmp @f
      b_pi dd 1e+3 ;b/pi
      h_pi dd 1e-4 ;h/pi=(b/pi)/N
      _0.5 dd 0.5
@@:
      fldpi ;pi
      fmul [h_pi] ;h

      fldpi ;pi,h
      fmul [b_pi] ;b,h
      fcos ;cos(b),h
      fmul [_0.5] ;sum,h

      fld st1 ;cur,sum,h
      mov ecx,10000000
      dec ecx ;N-1
.loo:               ;cur,sum,h
      fld st0       ;cur,cur,sum,h
      fcos          ;cos(cur),cur,sum,h
      faddp st2,st0 ;cur,sum',h
      fadd st0,st2  ;cur',sum',h
      loop .loo
      fxch st2      ;h,sum,cur
      fmul st0,st1  ;result
      ;-----------------------------------------------------
      GetTickCount()
      pop edx
      sub eax,edx
      fimul [m]
      fbstp tword [gRealBuf]
      wsprintfA(gMsgBuf,"Result = %x.%08x, Time = %dms",[gRealBuf+4],[gRealBuf],eax)
      MessageBoxA(0,gMsgBuf,"Result",0)
      ExitProcess()
;=====================================================
section '.reloc' fixups data discardable


на моем компе код Kallikanzarid'а работает 704мс, мой код работает 563мс, 20% разница
P4 3ГГц, WinXPSp2

Автор: Kallikanzarid 9.12.2008, 18:51
Хорошо... но недостаточно!
Я немного подправил код, сделав цикл целочисленным. Это скостило совсем немного, зато точность возрасла до твоей. Зато потом я дорвался до документации GCC, хехе. В общем, качай.

Автор: J0ker 9.12.2008, 19:34
Kallikanzarid, я те советую воспользоваться OpenMP
и пусть GoldFinch, попробует угнаться  smile 

Автор: GoldFinch 9.12.2008, 19:35
Kallikanzarid, осталось время измерять не +-10%
какбэ clock() вызывает GetSystemTimeAsFileTime, а это очень плохой метод измерения, да и увеличивать время измерения увеличивая время работы тестируемого алгоритма не самый лучший подход

кстати, что это у тя прога весит 275кб и требует несистемную дллку msvcrt.dll? а зачем у тя в архиве дллка mingwm10.dll, для весу?

ЗЫ: между прочим, мы начинали разговор именно о MSVC

Автор: Kallikanzarid 9.12.2008, 19:58
J0ker, у него один проц, скажет, что ничего не заметил  smile 

GoldFinch,

Цитата

кстати, что это у тя прога весит 275кб и требует несистемную дллку msvcrt.dll

Пошли отговорки? ;-) Прога вести 275 кб, потому что использует статический билд libc++. msvcrt.dll есть в каждом дистрибутиве Windows, это реализация рантайма С. Если подумать, использование в качестве бэкэнда для libc++ родной для каждой платформы реализации C runtime - логичный ход со стороны GNU.

Цитата

а зачем у тя в архиве дллка mingwm10.dll, для весу?

ХЗ, но билд ее требует.

Цитата

ЗЫ: между прочим, мы начинали разговор именно о MSVC

Нет уж, теперь ты не отвертишься  smile Кстати, считается, что у MSVC генерируемый код лучше, чем у гнуса.

Цитата

какбэ clock() вызывает GetSystemTimeAsFileTime, а это очень плохой метод измерения

В интересах науки заменил clock() на GetTickCount(). Результат практически не изменился. Архив прилагается.

Цитата

да и увеличивать время измерения увеличивая время работы тестируемого алгоритма не самый лучший подход

Почему? Тут меняется только число итераций. С тем же успехом можно взять компактный алгоритм, прогнать его несколько тысяч раз и взять среднее арифметическое время. На протяжении почти всех итераций код и данные будут в кэше, и это может сказаться, но для сравнения эффективности кода той или иной реализации это не так важно.

Автор: GoldFinch 9.12.2008, 20:12
Kallikanzarid, у меня код 2кб, в 137 раз меньше, если слить секции в 1 - будет весить 1кб, в 275 раз меньше
если я говорил что у MSVC кодогенератор гуан* то зачем выкладывать код сгенереный gcc?
и GetTickCount() тоже плохая идея, я его юзал только чтобы получать результат в секундах, мерить производительность лучше rdtsc
мерять лучше так - сделать небольшую длительность 1 измерения (в идеале меньше 1 кванта времени), выполнить Sleep чтобы измерение началось в начале кванта, замерить, выполнить Sleep, замерить и т.д., а все замеры просуммировать

Автор: Kallikanzarid 9.12.2008, 20:19
Цитата

мерить производительность лучше rdtsc
мерять лучше так - сделать небольшую длительность 1 измерения (в идеале меньше 1 кванта времени), выполнить Sleep чтобы измерение началось в начале кванта, замерить, выполнить Sleep, замерить и т.д., а все замеры просуммировать 

А зачем? ИМХО, картина и так ясна.

Цитата

если я говорил что у MSVC кодогенератор гуан* то зачем выкладывать код сгенереный gcc?

Ты хаил портируемый код и С++ вообще. Можешь поиграться с настройками MSVC в качестве домашнего задания. Бенчмарки показывают, что его код быстрее, чем у GCC.

Цитата

у меня код 2кб, в 137 раз меньше, если слить секции в 1 - будет весить 1кб, в 275 раз меньше

Допустим. И что?  smile 

Предлагаю начать новый раунд эпического противостояния. На этот раз проверим работу с памятью, в частности, с массивами. Выбирай задачу smile

Автор: GoldFinch 9.12.2008, 20:20
Цитата(Kallikanzarid @  9.12.2008,  20:19 Найти цитируемый пост)
Ты хаил портируемый код и С++ вообще. 

цитату

Автор: J0ker 9.12.2008, 20:22
Цитата(GoldFinch @  9.12.2008,  20:12 Найти цитируемый пост)
если я говорил что у MSVC кодогенератор гуан*

мыж уже вроде решили что гуан* не компилятор, а ваше понимание?  smile 

Автор: Kallikanzarid 9.12.2008, 20:25
Цитата:
Цитата

Kallikanzarid, из-за "кроссплатформенности", в С(++) нет способа средствами языка сгенерить некоторые x86-87 команды, например загрузку констант в FPU. 
Т.е. в некроссплатформенном паскале есть оператор(функция) Pi который генерит fldpi, а в кроссплатформенном С(++) оператора Pi() нет, и способа сгенерить fldpi (и другие константы) тоже нет.
Впрочем код C++ для FPU местами ужасен %) Ни один нормальный программист такого бы не писал. 

Как наиболее характерный образчик.

Автор: GoldFinch 9.12.2008, 20:31
Цитата(GoldFinch @  8.12.2008,  20:05 Найти цитируемый пост)
ок, будет говорить исключительно о компиляторе MSVC. так вот у него кодогенератор - гуан*

насчет кода для FPU - вот так вот в MSVC передаются 32-разрядные значения float
.text:10001344                 fld     [esp+18h+arg_4]
.text:10001348                 fstp    [esp+18h+var_14]
.text:1000134C                 fld     dword ptr [eax+4]
.text:1000134F                 fstp    [esp+18h+var_18]
.text:10001352                 call    FCanvasUtil::DrawLine(float,float,float,float,FColor,int)

только в следующем же посте я уточнил что речь идет о MSVC и начал приводить примеры его кодогенерации


Хочешь эпического противостояния? по размеру оптимизировать будем?

Автор: J0ker 9.12.2008, 20:36
Цитата(GoldFinch @  9.12.2008,  20:31 Найти цитируемый пост)
только в следующем же посте я уточнил что речь идет о MSVC и начал приводить примеры его кодогенерации

вы игнорируете мой вопрос?  smile 

Цитата(GoldFinch @  9.12.2008,  20:31 Найти цитируемый пост)
Хочешь эпического противостояния? по размеру оптимизировать будем? 


Kallikanzarid, соглашайтесь - придумайте задачу, использующую как можно больше функций CRT - printf например - пусть затрахается и заодно посоревнуется в оптимизации на реальных программах  smile 

Автор: Kallikanzarid 9.12.2008, 20:36
Оптимизируем по времени выполнения.

Автор: GoldFinch 9.12.2008, 20:43
Kallikanzarid, а что не по размеру? Там в компиляторе даже опция есть, "оптимизировать по размеру", в MSVC по крайней мере

Автор: J0ker 9.12.2008, 20:46
GoldFinch, передергиваете, да?  smile аргУменты кончаются?  smile 

Автор: Kallikanzarid 9.12.2008, 20:50
GoldFinch, по той простой причине, что все ЯВУ постоянно держат в памяти собственный рантайм, так что тут им конкурировать с лишенным оного ассемблером бессмысленно. Тем более, что размер экзешника в наши дни не особенно важен, тем более, если счет идет на килобайты.

Автор: J0ker 9.12.2008, 20:51
Kallikanzarid, можете соглашаться - существуют специальные ужатые версии CRT - http://www.microsoft.com/msj/archive/S569.aspx

Автор: GoldFinch 9.12.2008, 20:52
J0ker, ну у вас-то они уже давно закончились

Автор: Kallikanzarid 9.12.2008, 20:54
J0ker, да ну, зачем мне такие извращения? У меня 1 гиг памяти, полгига видеопамяти, 2 мега кэш второго уровня, 150 гигов дискового пространства и безлимитный интернет на 1 мегабит - а я буду бороться с лишними килобайтами экзешника?

Автор: GoldFinch 9.12.2008, 20:55
Kallikanzarid, это смотря в какой сфере объем не критичен, кое где четверть метра это очень много

Добавлено через 55 секунд
Цитата(Kallikanzarid @  9.12.2008,  20:54 Найти цитируемый пост)
J0ker, да ну, зачем мне такие извращения? У меня 1 гиг памяти, полгига видеопамяти, 2 мега кэш второго уровня, 150 гигов дискового пространства и безлимитный интернет на 1 мегабит - а я буду бороться с лишними килобайтами экзешника? 

поменьше бы таких программистов...

Автор: J0ker 9.12.2008, 20:56
Цитата(Kallikanzarid @ 9.12.2008,  20:54)
J0ker, да ну, зачем мне такие извращения? У меня 1 гиг памяти, полгига видеопамяти, 2 мега кэш второго уровня, 150 гигов дискового пространства и безлимитный интернет на 1 мегабит - а я буду бороться с лишними килобайтами экзешника?

так я предлагаю взять и задачу посложнее - чтоб функций из CRT было побольше задействовано
чел же не понимает, что как только понадобится использовать что-то посложней - то придется либо самому все ручками писать (пусть затрахается), либо подключать ту-же CRT - а результат по размеру буде стремиться к общему - может тогда въедет, что такое мазохизм  smile

Добавлено через 1 минуту и 44 секунды
Цитата(GoldFinch @  9.12.2008,  20:55 Найти цитируемый пост)
Kallikanzarid, это смотря в какой сфере объем не критичен, кое где четверть метра это очень много

а, простите мое любопытство, ГДЕ?

Автор: Kallikanzarid 9.12.2008, 21:02
Цитата

так я предлагаю взять и задачу посложнее - чтоб функций из CRT было побольше задействовано

Не, это уже ниже пояса. Лучше взять вычислительную задачу, но с использованием массивов. А то предыдущая не дала развернуться раскрутке циклов и автоматической векторизации :-(

Добавлено через 1 минуту и 51 секунду
Цитата

поменьше бы таких программистов... 

Как сказать. Я хотел плакать, когда узнал, как разработчики ОС Minuet гордятся своим TCP-стеком. Именно тем фактом, что им удалось сделать TCP-стек. На ассемблере.

Автор: GoldFinch 9.12.2008, 21:16
J0ker, вы когданить видели например графическую ОС которая влезает на дискету?

Kallikanzarid, а ты сделал свой TCP-стек чтобы так говорить? Или знаеш как его сделать?

Автор: Kallikanzarid 9.12.2008, 21:22
Цитата

J0ker, вы когданить видели например графическую ОС которая влезает на дискету?

Kallikanzarid, а ты сделал свой TCP-стек чтобы так говорить? Или знаеш как его сделать? 

1) Я уже давно не видел ни одной дискеты.
2) Нет. Меня этот вопрос не интересовал. Однако я знаю, что в никсах эти стеки были, еще когда меня на свете не было.

ЗЫ: так новый раунд будет? Ты уже выбрал задачу?

Автор: J0ker 9.12.2008, 21:23
Цитата(GoldFinch @  9.12.2008,  21:16 Найти цитируемый пост)
J0ker, вы когданить видели например графическую ОС которая влезает на дискету?

а зачем? у меня и флоповода-то нету  smile 
зато есть стааааарый флеш-драйв купленный лет 5-6 назад размером 512 метров  smile 
и, если мне не изменяет память, размер даже 5-ти дюймового диска был 360кБ в пору моей молодости (извините, перфокарты зацепил только чуть-чуть) - так размер CRT все равно меньше значительно, а всю функциональность иначе вам придется ручками писать и вы все равно придете к тому-же размеру   smile

Добавлено через 1 минуту и 57 секунд
Цитата(GoldFinch @  9.12.2008,  21:16 Найти цитируемый пост)
а ты сделал свой TCP-стек чтобы так говорить? Или знаеш как его сделать? 

я не писал
но знаю как
не вижу здесь никакого геройства кроме гемороя
задача-то тривиальная, все стандарты есть

Автор: Mayk 10.12.2008, 08:25
клйовый тред, в избранное!

Цитата(GoldFinch @  10.12.2008,  00:55 Найти цитируемый пост)

поменьше бы таких программистов... 

Действительно кому нужны программеры которые вместо того чтобы писать 2 часа на асме будут писать пять минут на си?

Цитата(GoldFinch @  10.12.2008,  01:16 Найти цитируемый пост)
вы когданить видели например графическую ОС которая влезает на дискету?

Ну я видел  MenuetOS.  Не  знаю что с ним еще можно сделать кроме как "увидеть". 

Автор: GoldFinch 10.12.2008, 13:07
Цитата(Kallikanzarid @  9.12.2008,  21:22 Найти цитируемый пост)
так новый раунд будет? Ты уже выбрал задачу? 

близкую к реальной задачу значит... допустим так... надо разработать программу для генерации SFX архивов, размер распаковщика определяется следующими требованиями:
архивы хранятся в библиотеке архивов на хостинге с максимально доступным дисковым пространством 100Мб,
файлов примерно 500-550,
размер 1 файла в диапазоне от 10 до 350кБ, 
распаковщик должен быть не более 20% от размера файла

целевая ОС - 32разрядная WinXP, т.к. задача тестовая - никакой реальной упаковки не требуется, при запуске распаковщик извлекает файл в указанную пользователем папку.

Автор: Kallikanzarid 10.12.2008, 14:06
Что, на производительность асма ты забил? Зачем опять гнешь свои 2кб? Блин, будь мужчиной уже  smile 

Автор: GoldFinch 10.12.2008, 15:01
Kallikanzarid, так или иначе, каким бы производительным твой код не был, я всегда могу извлечь код из твоего бинарника, оптимизировть и засунуть в свой. Там всегда будет что оптимизировать, и я хз о каком соревновании тут может идти речь.

Автор: Kallikanzarid 10.12.2008, 15:06
Слив засчитан  smile 

Автор: Mayk 10.12.2008, 15:21
Цитата(GoldFinch @  10.12.2008,  19:01 Найти цитируемый пост)
я всегда могу извлечь код из твоего бинарника, оптимизировть и засунуть в свой.

это равносильно заявлению "компилятор пишет асмовский код лучше чем я" кстати

Автор: mes 10.12.2008, 15:44
Цитата(GoldFinch @  10.12.2008,  15:01 Найти цитируемый пост)
Kallikanzarid, так или иначе, каким бы производительным твой код не был, я всегда могу извлечь код из твоего бинарника, оптимизировть и засунуть в свой. Там всегда будет что оптимизировать, и я хз о каком соревновании тут может идти речь. 

Да неблагодарное это дело, сравнивать языки без ориентировки на определенную задачу. Так же как например взять русский и английский. Имхо, у русского больше форм и возможностей выражения
- но это его преимущество является недостатком, при техническом применение. Английский же в данном аспекте более удобен.

Также cpp, c, asm разняться от абстрактности мысли к ее точному применению. Да на асме можно заточить алгоритм под конкретную архитектуру .. решенная эта же задача на си будет переносима, 
а на cpp к тому же даст гарантию проверки типов. Т.е отдаляясь от точности разъяснения алгоритма конкретной машины, мы приходим к тому что машина (компилятор) сама подгоняет и контролирует 
код, а результативный код удовлетворяет выдвинутым задачей требованиям (в одних случаях критичен размер, в других скорость, в третьих безопасность кода и длительная поддержа и расширение)

Тесты показывают что c/cpp не отстает от асма по скорости. Да по размеру бинарника асм выигрывает,  зато проигрывает в ых сферах с человеческим фактором..  
Ну а  скорость и размер для "потребительских" задач уже давно перестали быть решающим требованиями..

Я считаю что максимальный эффект можно добиться если правильно подобрать инструмент/ы к текущей задаче (прокопать  тунель под Ла-Маншем лопатой конечно геройство, но задача трудновыполнимая и не имеющая смысла), но также не надо забывать, что языки всего лишь инструмент, и основное зависит от того насколько им хорошо умеет пользоваться программист  е




Автор: Kallikanzarid 10.12.2008, 15:47
mes, тссс! Не порть знатный срачег.

Автор: GoldFinch 10.12.2008, 16:37
Цитата(mes @  10.12.2008,  15:44 Найти цитируемый пост)
языки всего лишь инструмент, и основное зависит от того насколько им хорошо умеет пользоваться программист

ага, так или иначе, подобное сравнение упирается не в сравнение производительности программы вручную написанной на асме против производительности программы написанной на ЯВУ, а в мастерство одно и другого программиста.
в конце концов компилятор ЯВУ  - инструмент и ничто не мешает взять автоматически сгенерированный им код и вручную доработать его до идеала.

Автор: mes 10.12.2008, 17:10
Цитата(GoldFinch @  10.12.2008,  16:37 Найти цитируемый пост)
инструмент и ничто не мешает взять автоматически сгенерированный им код и вручную доработать его до идеала. 

такой способ (если конечно ручная доводка необходимa) также присутствует в данной цитате :

Цитата(mes @  10.12.2008,  15:44 Найти цитируемый пост)
максимальный эффект можно добиться если правильно подобрать инструмент/ы

 smile 

Автор: GoldFinch 10.12.2008, 17:17
а всетаки программирование на асме ничуть не медленнее программирования на С++, даже быстрее с учетом времени создания нового проекта и компиляции. опять же на .ехешку в 1кб смотреть приятно
Код

include 'win32a.inc'
include 'hll.inc'
format PE GUI 4.0
section 'AllInOne' code readable writeable executable
IMPORTS KERNEL32.DLL, <ExitProcess,GetLastError,FormatMessageA>,\
        USER32.DLL,   <SetWindowPos,FindWindowA,MessageBoxA>
        psMsg dd ?
entry $
      FindWindowA("GcxPropertyPageSite.Window.1",0)
            test eax,eax
            jz .err
      SetWindowPos(eax,HWND_TOPMOST,0,0,0,0,SWP_SHOWWINDOW+SWP_NOSIZE)
            test eax,eax
            jz .err
      ExitProcess()
.err:
      GetLastError()
      FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER+FORMAT_MESSAGE_FROM_SYSTEM+FORMAT_MESSAGE_IGNORE_INSERTS,\
                        0,eax,0,psMsg,0,0)
      MessageBoxA(0,[psMsg],0,0)
      ExitProcess()

Автор: J0ker 10.12.2008, 17:19
Цитата(mes @  10.12.2008,  15:44 Найти цитируемый пост)
Тесты показывают что c/cpp не отстает от асма по скорости.

тесты показывают, что как только задача сталкивается с реальностью многоядерного процессора, то только гений может оптимизировать код лучше компилятора

Добавлено через 1 минуту и 24 секунды
Цитата(GoldFinch @  10.12.2008,  16:37 Найти цитируемый пост)
ничто не мешает взять автоматически сгенерированный им код и вручную доработать его до идеала

мешает, мешает
см. выше

Автор: GoldFinch 10.12.2008, 17:23
J0ker, здравый смысл подсказывает что кодогенератор твоего компилятора тоже люди писали, написать менее универсальный но более эффективный не проблема

Автор: mes 10.12.2008, 17:23
Цитата(GoldFinch @  10.12.2008,  17:17 Найти цитируемый пост)
а всетаки программирование на асме ничуть не медленнее программирования на С++, даже быстрее с учетом времени создания нового проекта и компиляции. опять же на .ехешку в 1кб смотреть приятно

если программа для  решения мелкой задачи то трудно оценить.. А вот например составить браузер или тот же самый компилятор ? думаю мало кто из программистов отважится затеять такой проект на асме , хотя "герои" безусловно есть )

Автор: J0ker 10.12.2008, 17:24
Цитата(GoldFinch @  10.12.2008,  17:17 Найти цитируемый пост)
а всетаки программирование на асме ничуть не медленнее программирования на С++, даже быстрее с учетом времени создания нового проекта и компиляции

издеваешься, да?  smile 

Автор: mes 10.12.2008, 17:28
Цитата(GoldFinch @  10.12.2008,  17:23 Найти цитируемый пост)
написать менее универсальный но более эффективный не проблема 

Да существует куча компиляторов, некоторые заточны под универсальность, другие под конкретную архитектуру и можно выбрать тот, который больше подходит smile 

Автор: J0ker 10.12.2008, 17:30
Цитата(GoldFinch @ 10.12.2008,  17:23)
J0ker, здравый смысл подсказывает что кодогенератор твоего компилятора тоже люди писали

только не в пример нам лучше знающие особенности процессоров - это во-первых
во-вторых, логика распараллеливания настолько сложна, что даже люди из во-первых не в состоянии оптимизировать более-менее сложный код - они для этого написали умную программу, которая это делает - она называется компилятор

Добавлено через 1 минуту и 18 секунд
Цитата(GoldFinch @  10.12.2008,  17:23 Найти цитируемый пост)
написать менее универсальный но более эффективный не проблема 

с первым согласен
со вторым нет - для более-менее сложного кода - см.выше

Добавлено через 9 минут и 18 секунд
я много раз сталкивался с подобными спорами
и если лет 10 назад еще можно было показать, что программа, написанная на ассемблере более производительна, то как только появились многоядерные процессоры, это стало практически невозможно - разборы полетов показали, что компилятор может раскидать инструкции так, что они хорошо параллелятся - при этом логика оказывается настолько сложна, что ни один человек не в состоянии такое написать, а якобы бессмысленные с т.з. человека операции (например замена одного оператора парой других, выполняющихся заведомо медленней) приводит к повышению производительности - что обусловлено опять-таки распараллеливанием

Автор: Kallikanzarid 10.12.2008, 17:47
Цитата

я много раз сталкивался с подобными спорами
и если лет 10 назад еще можно было показать, что программа, написанная на ассемблере более производительна, то как только появились многоядерные процессоры, это стало практически невозможно - разборы полетов показали, что компилятор может раскидать инструкции так, что они хорошо параллелятся - при этом логика оказывается настолько сложна, что ни один человек не в состоянии такое написать, а якобы бессмысленные с т.з. человека операции (например замена одного оператора парой других, выполняющихся заведомо медленней) приводит к повышению производительности - что обусловлено опять-таки распараллеливанием

Ты имел ввиду конвеерные суперскалярные процессоры? А то применительно к мультиядерности ты написал хню smile

Автор: J0ker 10.12.2008, 19:50
Цитата(Kallikanzarid @  10.12.2008,  17:47 Найти цитируемый пост)
Ты имел ввиду конвеерные суперскалярные процессоры? А то применительно к мультиядерности ты написал хню

о мля, точно, переклинило  smile 

Автор: GoldFinch 10.12.2008, 20:10
J0ker, береш справочник Агнера Фога, и пишешь код не хуже того что генерит компилятор. Компилятор хорош тем что избавляет от рутины за счет неидеальной кодогенерации и отсутствия средств управления кодогенерацией
Может там и будет офигенное распараллеливание, но вот идиотские неоптимальности типа 
push reg32 / fld dword [m32real] / fstp dword [esp]
вместо
push dword [m32real]
всеравно останутся

Автор: Kallikanzarid 10.12.2008, 20:15
GoldFinch, пользуясь случаем, еще раз предлагаю тебе второй раунд. Докажи, что асм-код для FP или целочисленных вычислительных методов и правда выполняется быстрее компилируемого. Все, что тебе нужно сделать - это выбрать адекватный алгоритм и написать ее реализацию, которая работала бы быстрее моей на С++.

Автор: GoldFinch 10.12.2008, 20:34
Kallikanzarid, выложи свой бинарник я его оптимизирую и "мой" код будет работать быстрее.
Если говорить о сравнении различных реализаций, то все упрется в то чье программерское мастерство лучше, так я и на С++ напишу код быстрее твоего ^^

Автор: mes 10.12.2008, 20:36
Цитата(GoldFinch @  10.12.2008,  20:34 Найти цитируемый пост)
так я и на С++ напишу код быстрее твоего

заочно оценили ?  чудеса  smile 

Автор: GoldFinch 10.12.2008, 20:41
mes, ага, с доверительной вероятностью 95%

Автор: Kallikanzarid 10.12.2008, 20:41
GoldFinch, нет уж - назвался груздем - полезай в кузов. Либо чисто на ассемблере - ты ведь его сторонник - либо чисто на С++. Во втором случае, ясное дело, будут беспристрастные судьи, которые будут получать исходники и батники, запускающие компилятор, и выдавать результаты; исходники друг от друга будем хранить в тайне. В любом случае, я уже сутки жду от тебя задачу.

Автор: GoldFinch 10.12.2008, 21:14
Kallikanzarid, так мы что тестировать будем? "С++ vs асм" или "Kallikanzarid vs GoldFinch"?

Автор: Kallikanzarid 10.12.2008, 21:16
Давай второе.

Автор: GoldFinch 10.12.2008, 21:39
я тоже суп както не очень.

вобщем я завтра вечером те тестовый алгоритм и методику измерения напишу

десятая страничка однако....

Автор: J0ker 10.12.2008, 22:13
Цитата(GoldFinch @  10.12.2008,  20:10 Найти цитируемый пост)
J0ker, береш справочник Агнера Фога, и пишешь код не хуже того что генерит компилятор.

yуууу
"береш справочник по шахматам и обыгрываеш Каспарова"  smile 

Цитата(GoldFinch @  10.12.2008,  20:10 Найти цитируемый пост)
Компилятор хорош тем что избавляет от рутины за счет неидеальной кодогенерации и отсутствия средств управления кодогенерацией

я вам уже показал, что "неидеальность" обычно вызвана непониманием - вы упорно игнорируете этот факт  smile 

Цитата(GoldFinch @  10.12.2008,  20:10 Найти цитируемый пост)
Может там и будет офигенное распараллеливание, но вот идиотские неоптимальности типа 
push reg32 / fld dword [m32real] / fstp dword [esp]
вместо
push dword [m32real]
всеравно останутся 

упрямство - достоинство сами знаете кого  smile 
я вам знаете что советую
напишите-ка на ассемблере вычислительный модуль BIONIC'а и запустите - а мы посмотрим, примет ли сервер ваши "оптимизированные" вычисления  smile 

Автор: GoldFinch 11.12.2008, 21:13
Kallikanzarid, вобщем я подумал-подумал, даже на форуме поспрашивал на каком алгоритме может загнуться С++ в отличие от асма, да только подходящего ответа не получил, да и сам ничего толкового не придумал... Что попроще и 100% сработает - неинтересно, а то что сложно  - самому долго писать. Пришлось придумать нормальную задачу, близкую к реальной.

Нужно написать функцию bool __stdcall Tick(float x);
Функция принимает на вход некореллированную последовательность равномерно распределенных вещественных чисел Xi, 0<=Xi<A<=1
Для i от 0 до N-1 параметр распределения A равен 1, для чисел с i от N до 2*N-1 параметр распределения A равен 0.5
Функция должна возвращать 1 при i<N+D и 0 при i>=N+D, где D - задержка срабатывания функции.
Производительность функции оценивается произведением времени работы функции T за одну итерацию на задержку срабатывания функции D, либо суммой времени выполнения D итераций, это значение должно быть минимально.
Допускается не более 5% ложных срабатываний (возврата 0 при i<N), причем N>100, первые 100 тактов ложные срабатывания не считаются.

Код функции следует оформить в виде DLL и сделать эту функцию экспортируемой, имя не важно, импортировать будем по ординалу.
В DllMain() можно инициализировать переменные, выделить память и проч.

Программа тестирования, одна и та же для всех длл, будет загружать длл, вызывать эту функцию и замерять ее время исполнения.

Примерный код программы тестирования:
Код

int main()
{
//переменные
bool (__stdcall *Tick)(float x); //указатель на функцию

unsigned int RandSeed = GetTickCount(); //ядро ГПСЧ
float x; //входное данное функции
bool y; //выходное данное функции
int i; //переменная цикла
int N=10000; //длительность этапов измерения

__int64 /*long long*/ Start; //счетчик тактов до вызова
__int64 /*long long*/ Fin; //счетчик тактов после вызова
int Latency=0; //искомая задержка срабатывания, в тактах

(FARPROC &) Tick = GetProcAddressA(
    LoadLibraryA("showdown.dll"), //имя длл можно брать и из командной строки
    0x80000001 //функция с ординалом 1
    );
//меняем приоритет процесса
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);

//начинаем 1й этап измерений - разгон функции
for (i=0;i<100;i++) //первые 100 итераций
{
    RandSeed = 134775813 * RandSeed + 1; //получаем новое число ГПСЧ
    x=RandSeed/4294967295.0; //случайное число от 0<=x<1
    (*Tick)(x);
};
//начинаем 2й этап измерений - отлов ложных срабатываний
for (i=0;i<N-100;i++) //итерации от 100 до N
{
    RandSeed = 134775813 * RandSeed + 1; //получаем новое число ГПСЧ
    x=RandSeed/4294967295.0; //случайное число от 0<=x<1
    y=(*Tick)(x);
    if(0==y)return -1; //возврат ошибки - ложное срабатывание
};
//начинаем 3й этап измерений - замер производительности
for (i=0;i<N;i++) //итерации от N до 2*N, или пока функция не сработает (вернет 0)
{
    RandSeed = 134775813 * RandSeed + 1; //получаем новое число ГПСЧ
    x=(RandSeed/2)/4294967295.0; //случайное число от 0<=x<0.5
    Sleep(1); //ждем следующего кванта времени
    __asm {
        cpuid //"чистим трубы" (U&V pipes ;))
        rdtsc //читаем счетчик тактов ЦПУ
        mov dword ptr [Start],eax //сохраняем в переменную младший dword
        mov dword ptr [Start+4],edx //сохраняем в переменную старший dword
    };
    y=(*Tick)(x);
    __asm {
        cpuid //"чистим трубы" (U&V pipes ;))
        rdtsc //читаем счетчик тактов ЦПУ
        mov dword ptr [Fin],eax //сохраняем в переменную младший dword
        mov dword ptr [Fin+4],edx //сохраняем в переменную старший dword
    };
    Latency = Latency + (Fin-Start);
    if(0==y)
    { //функция сработала
        return Latency; //возврат времени задержки
    };
};
return -2; //возврат ошибки - пропуск срабатывания
};
//Программа возвращает результат в системной переменной ERRORLEVEL (в тактах ЦПУ)

Размер бинарника, используемой виртуальной памяти неограничен, но будем считать что прога будет работать на компе с 512-1Гб ОЗУ


Что-то может следует откорректировать, чтото уточнить, в целом думаю задача получилась неплохая =)

Автор: Kallikanzarid 11.12.2008, 21:50
Уточни парочку моментов:
1) Речь идет о нормальном распределении случайных чисел?
2) Что именно должна делать функция? Как я понимаю, ее выходное значение зависит от того, какой по счету раз ее вызвали и совершенно не зависит от передаваемого аргумента? Или я неправильно понял?
3) Как функция получит значение N?

Автор: GoldFinch 11.12.2008, 22:22
1) о равномерном, но можно сделать и нормальным. 
Цитата(GoldFinch @  11.12.2008,  21:13 Найти цитируемый пост)
некореллированную последовательность равномерно распределенных вещественных чисел Xi

2) функция должна определить что параметры входной последовательности изменились и вместо 1 вернуть 0
например она должна вычислять матожидание или дисперсию
фактически ее выходное значение должно както зависеть от предидущих значений
Как именно зависеть - решать тебе. Чтобы хранить эти значения можно использовать глобальные переменные, массивы, буферы, что захочешь.
3) N и i ей знать не надо, только принимать входные числа Xi, както накапливать их и возвращать

Выглядит это так
Код

i   N-5  N-4  N-3  N-2  N-1  N    N+1  N+2  N+3  N+4  N+5
A   1    1    1    1    1    0.5  0.5  0.5  0.5  0.5  0.5
Xi  0.9  0.2  0.6  0.7  0.1  0.3  0.4  0.1  0.2  0    0.1
y   1    1    1    1    1    1    ?    ?    ?    0    0
                                  <--- D --->


Автор: J0ker 11.12.2008, 22:31
что-то мне мнится, что производительность в данной задаче будет упираться в алгоритм, а не в то, на чем он написан  smile 

Автор: GoldFinch 11.12.2008, 22:33
J0ker, ну Kallikanzarid же сказал что ему интереснее "Kallikanzarid vs GoldFinch" чем "С++ vs асм"...

Автор: J0ker 11.12.2008, 22:56
ну в таком случае мне не ясно, зачем вы нивелировали задачу 5-ю процентами - ИМХО скорость и качество определения параметра распределения должны входить в оценку результата умственного онанизма оппонентов  smile 

Автор: GoldFinch 11.12.2008, 23:00
J0ker, а как тогда оценку рассчитывать? тем более что если не задавать Pлс, то возможно будут решения с максимальным быстродействием и принципом "угадал\неугадал"

Автор: J0ker 11.12.2008, 23:06
Цитата(GoldFinch @  11.12.2008,  23:00 Найти цитируемый пост)
J0ker, а как тогда оценку рассчитывать?

ну так об этом надо и договариваться

Цитата(GoldFinch @  11.12.2008,  23:00 Найти цитируемый пост)
тем более что если не задавать Pлс, то возможно будут решения с максимальным быстродействием и принципом "угадал\неугадал" 

да, но качество тогда снизится вдвое, при этом в формуле должна участвовать задержка D - в этом случае такой алгоритм станет заведомо проигрышным

Автор: GoldFinch 11.12.2008, 23:19
J0ker, проще задать вероятность не менее 95% чем выдумывать сомнительные интегральные критерии

Автор: Kallikanzarid 12.12.2008, 07:30
GoldFinch, лучше взять нормальное распределение. И использовать не самодельную эвристику, а boost::random.

А вообще задача очень интересная  smile 

Автор: GoldFinch 12.12.2008, 08:59
Kallikanzarid, ок, а какие матожидания и дисперсии?
и по какому алгоритму нормальное распределение получать будем?

Автор: Kallikanzarid 12.12.2008, 12:29
Предлагаю матожидание - 0.70 и 0.25, а дисперсию - 0.3 и 0.15.
Для гененрации предлагаю взять хорошо известную библиотеку boost::random - http://www.boost.org/doc/libs/1_37_0/libs/random/index.html

Автор: GoldFinch 12.12.2008, 20:18
Цитата(Kallikanzarid @  12.12.2008,  12:29 Найти цитируемый пост)
Предлагаю матожидание - 0.70 и 0.25, а дисперсию - 0.3 и 0.15.

мм.... а почему именно такие числа? выглядит это несколько неудобно:
http://spreadsheets.google.com/pub?key=pneb3GWHrZ5iTmapONJT2ew&oid=1&output=image

впрочем, чтобы и нет...

мне библиотека boost::random, но если она действительно удобная, можно и ее применить

вот еще какое предложение... если учитывать что число итараций (N) до момента изменения параметров распределения мало, то возникает соблазн сделать в программе буфер чисел этак на 10000000 и писать всю входную последовательность в него, не заботясь о том что буфер может закончиться. Вот чтобы такого небыло, предлагаю считать N значительно большим размера любого буфера.

Автор: Kallikanzarid 12.12.2008, 20:37
boost::random можешь оценить сам - по ссылке есть туториал. А матожидания и дисперсии лучше и правда сделать подальше друг от друга  smile

Добавлено через 2 минуты и 53 секунды
Насчет N согласен, давай и правда сделаем его достаточно большим.

Автор: Ln78 12.12.2008, 20:48
Цитата(J0ker @  11.12.2008,  22:31 Найти цитируемый пост)
что-то мне мнится, что производительность в данной задаче будет упираться в алгоритм, а не в то, на чем он написан  


Цитата(GoldFinch @  11.12.2008,  22:33 Найти цитируемый пост)
J0ker, ну Kallikanzarid же сказал что ему интереснее "Kallikanzarid vs GoldFinch" чем "С++ vs асм"... 


Давно на форум не заходил, тут такие бойкие новички появились.

GoldFinch, а почему ты сам задачу ставишь? Это всё равно, как если бы, например, я предложил тебе такой вариант: давай я загадаю число, а потом с тобой посоревнуемся, кто его отгадает за меньшее число попыток. smile Просите J0ker'а, чтобы он вам независимо от вас задачу поставил.

Автор: Kallikanzarid 12.12.2008, 21:11
Ln78, если что, еще один раунд проведем. А вот судья, который будет принимать длл-ки и говорить результаты, нам не помешает.

Автор: J0ker 12.12.2008, 21:12
Цитата(Ln78 @  12.12.2008,  20:48 Найти цитируемый пост)
Просите J0ker'а, чтобы он вам независимо от вас задачу поставил. 

не, спасибо
у меня нет специального математического образования  smile 

Цитата(GoldFinch @  12.12.2008,  20:18 Найти цитируемый пост)
то возникает соблазн сделать в программе буфер чисел этак на 10000000 и писать всю входную последовательность в него

какой в этом смысл, если допустимая задержка 5%
предлагаю сделать расширяемый буфер, равный 10% от текущего i - ИМХО единственное логичное решение - распределение-то заранее известно

Автор: Kallikanzarid 12.12.2008, 21:13
GoldFinch, предлагаю также встроить в тестирующую программу опциональный индикатор прогресса.

Автор: GoldFinch 12.12.2008, 21:14
Ln78, а я вообще на этот форум не заходил, а тут зашел - а тут вот как интересно))))
Kallikanzarid сам попросил чтобы я поставил задачу, я ее и поставил. Впринципе я не против того чтобы задачу ставила 3я сторона, если конечно задача будет интересная.

К слову для меня эта задача достаточно сложная, т.к. я уже успел благополучно забыть статистику (если было что забывать %))

Kallikanzarid, да не вопрос, можно еще сразу сделать 100 запусков алгорима, циклом:
for(int nTests=0; nTests<100; nTests++)
{
hDll=LoadLibrary("showdown.dll");
... //i-й тест
FreeLibrary(hDll);
};

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)