birdwatcher: (Dore: Ogre)
[personal profile] birdwatcher
В программировании различают run time и compile time. То, что известно компилятору в compile time, следует тогда же и делать; тогда программа будет работать быстрее. Например, полиморфный вызов виртуальной функции происходит медленнее, чем вызов статической: ее адрес надо сначала найти в vtable.

Между тем, значительное количество проектов, формально являющихся объектно-ориентированными, используют полиморфизм в следующем урезанном виде. Пусть, например, мы моделируем солнечную систему. В начале работы программа читает конфигурационный файл и инстанциирует из него некоторое количество объектов, имплементирующих бизнес-логику Солнца, Земли, Луны, планет, американских разведывательных спутников и проч. Все они являются потомками абстрактного класса Небесное Тело. После этого новые объекты больше не создаются, а существующие не уничтожаются; движок только полиморфно вызывает у каждого из них по очереди функцию "сделать следующий ход", пока не будет достигнут конец вселенной или не будет нажата комбинация клавиш Ctrl-C.

Легко видеть, что полиморфизм тут используется только для удобства организации и расширения кода путем добавления все новых и новых небесных тел, а также потому, что людей, пишущих код именно таким образом, легче нанять. Конкретно, после того, как конфигурационный файл прочитан и все необходимые объекты инстанциированы, адреса виртуальных функций, специфичных для каждого конкретного указателя-на-небесное-тело, оказываются навсегда известными. В такой ситуации естественнее различать compile time, run time before reading config, и run time after reading config.

Соотвественно, пропатченный рантайм C++ должен, по окончании чтения конфига, пройтись по коду, найти в нем все поиски виртуальных функций в vtable, и хардкоднуть на их место известные к тому времени адреса в памяти.

Date: 2012-06-08 01:37 am (UTC)
From: [identity profile] dmpogo.livejournal.com
Я сомневаюсь что в задачах подобных солнечной системе вызов функций и есть то узкое место определяющее скорость вычислений

Date: 2012-06-08 01:42 am (UTC)
From: [identity profile] krl-pgh.livejournal.com
Заголовок хороший, такие приятно игнорировать.

Date: 2012-06-08 01:53 am (UTC)
From: [identity profile] glocka.livejournal.com
Хе-хе, а весь выигрыш будет съеден другими vtables, отвечающими за распараллеливание и контроль за здоровьем железа.

Date: 2012-06-08 03:22 am (UTC)

Date: 2012-06-08 03:34 am (UTC)
From: [identity profile] birdwatcher.livejournal.com
Сложности с распараллеливанием - это та проблема, которую хочется иметь.

Date: 2012-06-08 06:18 am (UTC)
From: [identity profile] morfizm.livejournal.com
Предлагаю простое решение, требующее лишь слегка изменить формат конфига.
Итак, для начала - файл конфига будет расширение cpp. (Дальше, надеюсь, и так понятно =))

Date: 2012-06-08 07:44 am (UTC)
From: [identity profile] dmpogo.livejournal.com
Что нам этот внешний цикл ? Это внутренний цикл, для каждого тела по остальным телам, что существеннен.

Date: 2012-06-08 07:58 am (UTC)
From: [identity profile] dmpogo.livejournal.com
нет, внешний конечно есть, только все время программа проводит не в нем.

Date: 2012-06-08 10:11 am (UTC)
From: [identity profile] birdwatcher.livejournal.com
Тогда нельзя будет никого нанять, или каждому нанятому надо будет по году объяснять, как делать. С точки зрения программиста и его существующих практик решение должно быть прозрачным.

Date: 2012-06-08 10:14 am (UTC)
From: [identity profile] birdwatcher.livejournal.com
Это тоже было бы весьма полезно. В ту же кучу - очень неудобно, что сейчас конструкция if (0) {...} исчезает из окончательного кода целиком, а if (x) {...}, где x прочитан из конфига и равен нулю - нет.

Date: 2012-06-08 10:45 am (UTC)
From: [identity profile] birdwatcher.livejournal.com
Дык я же написал, как сделать с минимальным импактом. Нужен новый модификатор типа: const_after_having_read_config.

Date: 2012-06-08 05:49 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Мне кажется любой C++ программист сделает именованную константу в коде вместо конфига, если он знает, что в рантайме оно не будет меняться. Но это в случае, если изменения в конфиг будет вносить C++ программист. Если же изменения будут вносить другие люди, то мы либо платим performance'ом за гибкость, либо вручную имплементируем оптимизацию. Вашу оптимизацию вполне можно имплементировать вручную для конкретного случая.

Вопрос - должен ли это делать компилятор?
Может быть. А может быть и нет. Надо weigh benefits against costs. SMC может вызвать разные CPU caching/parallelization issues, это надо делать аккуратно. Кроме того, ваш конкретный use case не кажется достаточно общим. Если бы runtime умел с точностью определять life span of objects, он мог бы временно заменять виртуальные вызовы на статические, или даже на jump'ы. Но это по сложности уже близко к тому, чтобы, скажем, уметь распознавать неэффективные алгоритмы, и на лету заменять их на более эффективные. Если мы столько работы отдаём компилятору, то это перестаёт пахнуть C++-ом :) Фишка C++-а в том, что на нём пишут люди, которые хорошо понимают, как оно будет работать, и даже если есть оптимизации, программист знает про них, и специально пишет код в рассчёте на них.

Date: 2012-06-08 05:51 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Вспомнился prefetch из Windows. Windows собирает статистику, в какой последовательности обычно грузятся странички из EXE/DLL, и время от времени сортирует их на диске так, чтобы это было последовательное чтение. (Вы знали об этой фиче?).

Date: 2012-06-08 05:54 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Я выше пишу чуть подробнее - нужен новый модификатор const и еще один проход опттимизатора с его учетом после чтения конфига.

Date: 2012-06-08 05:54 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Вот уж не знал.

Date: 2012-06-08 07:04 pm (UTC)

Date: 2012-06-08 10:23 pm (UTC)
From: [identity profile] akor168.livejournal.com
Есть такой анекдот: "А ты умеешь играть на скрипке?" - "Не знаю, может и умею, ни разу не пробовал"

Также и здесь - вдруг случайно окажешься специалистом по рентгеновской кристаллографии.

Date: 2012-06-08 11:04 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Бьерн Страуструп. Дизайн и эволюция языка C++, или Как я родил ёжика.
Андрей Александреску. Современное проектирование на С++, или Как я выебал ёжика.

Date: 2012-06-09 09:40 am (UTC)
From: [identity profile] vi-z.livejournal.com
Польностью согласен. С++ должен стать Явой с JIT.

Date: 2012-06-17 12:53 am (UTC)
From: [identity profile] bobehobi.livejournal.com
Интересно, а C++ программисты слышали, что кроме наследования есть еще и агрегация как способ композиции?

Date: 2012-06-17 12:00 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Аггрегирование неизвестно чего не работает быстрее, чем вызов неизвестно какой функции.

Date: 2012-06-20 01:56 pm (UTC)
From: [identity profile] bobehobi.livejournal.com
Именно поэтому агрегацию нужно включить в это обсуждение.

Date: 2012-06-20 02:23 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Включайте, я слушаю.

Date: 2012-06-20 02:28 pm (UTC)
From: [identity profile] bobehobi.livejournal.com
Нет, это я слушаю (я же не программист): например, 1) pure virtual functions –– они требуют обращения к vtables? 2) может ли компилятор так соптимизировать, например if или case, чтобы это было быстрее чем обращение к vtable?

Date: 2012-06-20 02:36 pm (UTC)
From: [identity profile] birdwatcher.livejournal.com
Фундаментально, проблема заключается в том, что неизвестно заранее, какую функцию вызывать. Это становится известным только после чтения конфига. К тому времени программа уже давно скомпилирована и должна оставаться неизменной до следующей перекомпиляции. В такой парадигме ничего поделать нельзя, хоть аггрегируй, хоть наследуй.

Date: 2012-06-20 04:46 pm (UTC)
From: [identity profile] bobehobi.livejournal.com
Т.е. слив защитан?