Re[20]: КЫВТ GUI—надо быть проще
От: enji  
Дата: 18.05.12 21:19
Оценка:
Здравствуйте, Vamp, Вы писали:

E>>Кстати насчет кода — мне кажется, жить стало бы сильно веселей, если бы можно было взять указатель на член как просто указатель на функцию (+ this). Т.е. был бы встроенный тип данных, который бы содержал собственно указатель на функцию и указатель на объект

V>Ну, bind + mem_fun спасут отца русской демократии, нет?

Спасут конечно, но это виртуальный вызов + вызов по указателю на функцию-член (вообще говоря тормозной — при этом надо обработать разные варианты виртуальности). Если бы компилер получил реальную функцию в момент взятия адреса, накладных расходов было бы как при обычном вызове по указателю
Re[21]: КЫВТ GUI—надо быть проще
От: Vamp Россия  
Дата: 18.05.12 21:42
Оценка:
E>Спасут конечно, но это виртуальный вызов + вызов по указателю на функцию-член (вообще говоря тормозной — при этом надо обработать разные варианты виртуальности). Если бы компилер получил реальную функцию в момент взятия адреса, накладных расходов было бы как при обычном вызове по указателю
Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...
Да здравствует мыло душистое и веревка пушистая.
Re[22]: КЫВТ GUI—надо быть проще
От: Abyx Россия  
Дата: 18.05.12 23:11
Оценка: +2
Здравствуйте, Vamp, Вы писали:


E>>Спасут конечно, но это виртуальный вызов + вызов по указателю на функцию-член (вообще говоря тормозной — при этом надо обработать разные варианты виртуальности). Если бы компилер получил реальную функцию в момент взятия адреса, накладных расходов было бы как при обычном вызове по указателю

V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
V>А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...

цена виртуального вызова — отсутствие инлайна.
In Zen We Trust
Re[22]: КЫВТ GUI—надо быть проще
От: dilmah США  
Дата: 19.05.12 03:03
Оценка:
V>В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд.

гм.. 10 микросекунд это *Огромное* время для вызова функции. Seek time многих жестких дисков меньше 10 микросекунд.
Re[23]: КЫВТ GUI—надо быть проще
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.05.12 05:03
Оценка:
Здравствуйте, dilmah, Вы писали:

V>>В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд.

D>гм.. 10 микросекунд это *Огромное* время для вызова функции. Seek time многих жестких дисков меньше 10 микросекунд.

Ты шутишь. Seek time жёстких дисков — единицы *милли*секунд. То есть в 1000 раз больше. Вот открыл характеристики гигабайтников от Samsung и Seagate — 8.9мс и 9мс соответственно.

С другой стороны, оппонент тоже приводит странные цифры для сравнения: на актуальном сейчас железе, резолвинг одного значения из памяти, даже если она не загружена ни в какой из кэшей, это десятки *нано*секунд.
The God is real, unless declared integer.
Re[23]: КЫВТ GUI—надо быть проще
От: Erop Россия  
Дата: 19.05.12 05:06
Оценка:
Здравствуйте, Abyx, Вы писали:

A>цена виртуального вызова — отсутствие инлайна.


Эта цена от степении косвенности и кратности диспечерезации не зависит
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[22]: КЫВТ GUI—надо быть проще
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.05.12 05:16
Оценка:
Здравствуйте, Vamp, Вы писали:

V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?


А почему именно такая цифра для сравнения?
Нет, оно, конечно, ещё меньше. В случае виртуального вызова нужно:
1. Один дополнительный лукап в память — если она даже не в L2; посмотрев таблицу скоростей всяких DDR пишем — 18.75нс (DDR3-1333, CL=9, восьмое слово), это один раз за ХЗ сколько. Размазывая по срабатываниям кэша, подсчитаем за 2 нс (среднепотолочно по больнице).
2. Неизвестная задержка на том, что не может быть сделан inline, если точно не известен класс, к которому относится объект (а точное знание в таком случае может быть только в конструкторе). Она состоит из цены двух перезагрузок конвейера команд (на входе в функцию и выходе), можно каждую из них посчитать за 10 тактов при условии, что код уже в кэше, при 3GHz процессоре это в сумме 6нс. Может, она тоже кэшируется, не знаю.
3. Совсем неизвестная задержка на том, что массовый inline может увеличить объём кода настолько, что станет меньше полезного влезать в L1.

В сумме получается меньше 10 *нано*секунд. Что, в принципе, хорошо. Но если это в цикле с малым телом, то становится безумно дорого.

V>А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...


+2. Мне кажется, что кроме особо хитрых случаев вроде тех же быстрых циклов оно не заметно.
The God is real, unless declared integer.
Re[22]: КЫВТ GUI—надо быть проще
От: enji  
Дата: 19.05.12 09:38
Оценка:
Здравствуйте, Vamp, Вы писали:


V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?

10 мкс — это на каком-нить 11МГц 8-битнике, на десктопе — меньше
V>А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...

Это накладные расходы, которых можно было бы избежать с поддержкой компилятора, причем как я понимаю, реализовать это в компиляторе — не сложно.
Понятно, что function+bind/лябмды — универсальнее, но в простых случаях было бы быстрее, проще и меньше кода
Re[22]: КЫВТ GUI—надо быть проще
От: Evgeny.Panasyuk Россия  
Дата: 19.05.12 11:28
Оценка: 15 (3)
Здравствуйте, Vamp, Вы писали:

V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?


Я делал.
Виртуальные вызовы определённо медленней чем обычные, особенно учитывая тот факт, что обычные вызовы могут инлайнится.
Но, когда необходимо делать некоторый runtime выбор с помощью virtual, не честно просто сравнивать обычные вызовы с virtual. В таких сравнениях обычным вызовам должен предшествовать некоторый runtime выбор: if, switch, и т.п.

Код теста: http://ideone.com/Tjzne
Я сравниваю несколько случаев, которые зависят от параметра "Types count":

* virtual func — "Type count" определяет количество derived классов. Сложность O(1).
* switch — "Type count" определяет количество веток case. Сложность в моём случае is O(1) (я проверял ассемблерный код, но это может зависеть от компилятора).
* if-else O(N) — "Type count" определяет количество веток. if-else здесь в виде цепочки, что приводит к сложности O(N).
* if-else O(log(N)) — "Type count" определяет количество веток. if-else рекурсивно вложены, формируя двоичный поиск со сложностью O(ln(n)).
* static polymorphism — "Type count" определяет количество классов policy/strategy. Порядок вызовов жёстко задан, что приводит к сложности O(1). Здесь фактически не используется runtime выбор, но всё же это очень показательно в плане того, что может случится с inlined вызовами.

http://img856.imageshack.us/img856/6497/resultx64multipleseries.png
Результаты(для больших значений "Types count"):
static polymorphism < switch ~ virtual func < if-else O(log(N)) < if-else O(N)

Необходимо отметить, что в этих тестах вычисления настолько простые, что в случае static polymorphism они свёрнуты (после inlining) что привело к обратной зависимости времени на один вызов от "Type count".

Виртуальные вызовы в этом тесте сравнимы с главной альтернативой — switch.
Но, необходимо делать правильные выводы из результатов.
Например, используются циклы, поэтому vtables были в кэше. Но для очень random'ного execution path это не всегда верно. Также, варьируя количество параметров функций, можно получить другие результаты.
Также, вы можете получить совершенно другие результаты на другой платформе/компиляторе/настройках и т.п.

V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?


Если всё таки интересно "голое" сравнение virtual и обычного вызова, смотрите на графике результаты для "Types count"=1
Re[23]: КЫВТ GUI—надо быть проще
От: Evgeny.Panasyuk Россия  
Дата: 19.05.12 12:03
Оценка:
V>>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
EP>Если всё таки интересно "голое" сравнение virtual и обычного вызова, смотрите на графике результаты для "Types count"=1

точнее для чистоты эксперимента, нужно убрать BOOST_FORCEINLINE, и убедится что в ассеблерном коде стоит именно вызов а не inline.
Re[23]: КЫВТ GUI—надо быть проще
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 20.05.12 05:58
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Код теста: http://ideone.com/Tjzne


Попробовал то же на: FreeBSD/i386, "Athlon(tm) 64 X2 Dual Core Processor 4800+" (2.5GHz), gcc 4.6.4.
Boost 1.45.0. Define IDEONE_DOT_COM не отключал, иначе не собирается. Компилятору сказано -O2.

EP>http://img856.imageshack.us/img856/6497/resultx64multipleseries.png

EP>Результаты(для больших значений "Types count"):
EP>static polymorphism < switch ~ virtual func < if-else O(log(N)) < if-else O(N)

График не рисовал. В числах у меня так:
* static — 0 (разве что при types count=1 там видно 1.22)
* switch — 26-29ns
* virtual — 27-30ns
* оба if-else дают примерно одинаково по ~36ns. Но их значения сильно шатаются (плюс-минус 3ns).

Как-то всё это странно. Получается, что неважно, какой метод отработки варианта используется — важно, что требуется делать выбор. Но почему?
The God is real, unless declared integer.
Re[24]: КЫВТ GUI—надо быть проще
От: Evgeny.Panasyuk Россия  
Дата: 20.05.12 10:09
Оценка:
Здравствуйте, netch80, Вы писали:

EP>>Код теста: http://ideone.com/Tjzne

N>Попробовал то же на: FreeBSD/i386, "Athlon(tm) 64 X2 Dual Core Processor 4800+" (2.5GHz), gcc 4.6.4.
N>Boost 1.45.0. Define IDEONE_DOT_COM не отключал, иначе не собирается. Компилятору сказано -O2.

Я использовал Boost 1.49 , скорей всего дело в этом.

EP>>http://img856.imageshack.us/img856/6497/resultx64multipleseries.png

EP>>Результаты(для больших значений "Types count"):
EP>>static polymorphism < switch ~ virtual func < if-else O(log(N)) < if-else O(N)
N>График не рисовал. В числах у меня так:
N>* static — 0 (разве что при types count=1 там видно 1.22)
N>* switch — 26-29ns
N>* virtual — 27-30ns
N>* оба if-else дают примерно одинаково по ~36ns. Но их значения сильно шатаются (плюс-минус 3ns).
N>Как-то всё это странно. Получается, что неважно, какой метод отработки варианта используется — важно, что требуется делать выбор. Но почему?

Я предполагаю, что это связанно с branch misprediction ( http://en.wikipedia.org/wiki/Branch_predictor ). Когда процессор не знает какая будет следующая инструкция — плохо во всех случаях.
В исходнике, в секции Settings, есть выбор для dispatch_base::type.
При dispatch_base_regular результат получается отличный от dispatch_base_shuffle_indexed : http://img195.imageshack.us/img195/6497/resultx64multipleseries.png
Результаты(для больших значений "Types count"):
static polymorphism < if-else O(log(N)) < switch < virtual func < if-else O(N)

Как вы видите, "if-else O(log(N))" даже быстрее чем "switch O(1)".
Я предполагаю, что это как раз из-за branch prediction.
В этом случае происходит регулярная итерация по "Types count" — 1,2,3..N.
Для такого регулярного паттерна, branch predictor работает прекрасно.
Например, давайте рассмотрим паттерн кода "if-else O(log(N))":

for(int type=0;type!=N;++type)
{
    if(type>N/2) // first check
    {
        if(type>...) // second check
        {
            ...more recursive checks
        }
        else
        {
            ...more recursive checks
        }
    }
    else
    {
        if(type>...)
        {
            ...more recursive checks
        }
        else
        {
            ...more recursive checks
        }
    }
}

Как вы видите, для всех types<=N/2 выбор ветки в первой проверке один и тот же. Аналогичные выводы применимы рекурсивно ко вложенным проверкам. Значит это очень благоприятная ситуация для branch predicton.
Но для switch мой компилятор использовал indirect jump, что не привело к удачному branch prediction в большинстве случаев.

При dispatch_base_shuffle_indexed, такого регулярного паттерна нет, и branch predictor работает плохо во всех случаях.

Также важен ещё параметр "Types count" — для больших значений(при dispatch_base_shuffle_indexed) у virtual только один конкурент — switch (и то, когда реализован как O(1)).
Также важна реализация inderect call в конкретном процессоре.

V>>>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?

EP>>Если всё таки интересно "голое" сравнение virtual и обычного вызова, смотрите на графике результаты для "Types count"=1
EP>точнее для чистоты эксперимента, нужно убрать BOOST_FORCEINLINE, и убедится что в ассеблерном коде стоит именно вызов а не inline.

ещё точнее нужно использовать dispatch_base_regular вместо dispatch_base_shuffle_indexed, чтобы не было постороннего кода в замерах.
Re[21]: Пропертя
От: Piko  
Дата: 25.05.12 10:19
Оценка:
Здравствуйте, Ops, Вы писали:

P>>>>что не вычислимо?

P>>>>нельзя кастануть указатели разных типов к void* и вычислить разницу между ними?
P>>>>в смысле char*
E>>>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти...
P>>1. можете дать ссылку на стандарт? хотя бы приблизительно где об этом говорится, может ключевые слова.
P>>я нашёл только три слова содержащие "seg", и все были SIGSEGV
Ops>Там не сегмент памяти, там все строже:
Ops>

Ops>Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined.

5.7.6


Чтобы не было UB, можно использовать placement new: выделить char[sizeof(class_with_property)] и делать в него placement new для class_with_property.
После этого по-идеи вычитать указатели легально.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.