Информация об изменениях

Сообщение Re[49]: MS забило на дотнет. Питону - да, сишарпу - нет? от 09.09.2021 15:13

Изменено 09.09.2021 15:42 vdimas

Re[49]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:

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

S>Как и всё — кладётся в стек.

Каким образом?
Это в модели .Net VM два независимых стека — стек данных и стек возвратов.
К тому же, стек данных волшебный, с безразмерными ячейками.

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

Работает оно так:
internal struct S1 {
    public long l1, l2, l3;

    public static S1 Create() => new S1();

    public static void Create(out S1 result) {
        result = new S1();
    }
}

Оба метода Create эквиваленты в железе, т.е. в обоих случаях как аргумент будет подана ссылка на участок памяти, куда вернуть результат.
Например, в архитектуре x64 fastcall, эта ссылка в обоих случаях будет подана через RCX.


S>Вот, текущее состояние экспериментов

S>https://github.com/evilguest/atropos/blob/main/Atropos/BranchNode.cs#L37
S>К сожалению, ожидаемый инлайнинг this[] в https://github.com/evilguest/atropos/blob/main/Atropos/BranchNode.cs#L28 не происходит, несмотря на то, что T — это struct тип, точно известный в момент JIT

FindChild — тяжелый метод в смысле сложности операций.
Несколько арифметических операций приравниваются к одной операции сравнения в плане сложности, а у тебя весь метод — бесконечные сравнения.

Можно попробовать заменить childIndex_X на inplace массив и сделать линейный поиск в цикле.
Я когда-то экспериментировал, примерно до 20-30 элементов линейный поиск быстрее бинарного.
Скорее всего это связано с предсказателем переходов процессора.

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

Заодно тело метода станет маленьким, вероятность инлайна вырастет.


S>Опять же в доке сказано, что из разных потоков работать с зокетами нельзя.


Это клиентскому кому нельзя.
Прерывания от сетевой карты всё-равно асинхронные, исполняются с т.з. потоков в другом потоке, и в момент обнаружения и забора новых пакетов данных при очередном вызове со стороны юзверя унутре без синхронизации никак. Хотя, синхронизация может быть выполнена на lock-free алгоритмах, но знать бы достоверно...


S>Так что явно там нет никаких примитивов синхронизации.


Там нет синхронизации публичного АПИ.
Это не то же самое, что межпоточная перекачка данных.

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

Здесь примерно такая же схема — прерывание выполняется в некоем "случайном" аппаратном потоке в контексте ядра, обработчик прерывания должен покласть новые пакеты в межпоточную очередь.


V>>Выглядит так, что у тебя своеобразные представления как о возможностях AOT, так и о возможностях hot-spot оптимизаций.

S>У меня своеобразные представления о том, как что должно работать.

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


V>>Вручную писаный сериализатор будет оптимизирован и в АОТ,

S>Каким образом? На основании чего АОТ будет выполнять спекулятивный инлайнинг?

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


V>>Например, "выпрямлять" в памяти банальный List<T>.

S>Что значит "выпрямлять"? Он же уже и так прямой.

Он дважды косвенный.


V>>Статистика в основном нужна для определения мест, где требуется оптимизация.

S>Мы ходим по кругу. Ну вот мы увидели, что у нас в горячем цикле вызывается _serializer.Serialize(dataReader, stringBuilder).
S>Дальше что? Это косвенный вызов по интерфейсу.

Тебя интересует нынешнее положение дел или будущее гипотетическое?
В нынешнем состоянии джит делает те же оптимизации, какие сделал бы и АОТ, только ограничен по времени.

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

И вот эта проверка — "природный" ограничитель возможности технологии спекулятивной оптимизации.


V>>В рекордсете из 1001 элемента первые 1000 будут прочитаны без оптимизации.

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

Схема рекордсета каждый раз создаётся с 0-ля, это будут другие экземпляры схемы с другими экземплярами абстрактных дескрипторов полей.


S>А АОТ так и оставит косвенный вызов через VMT.


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


V>>И даже если схемы будут те же — это будут другие экземпляры схем, вот в чём прикол.

S>При чём тут экземпляры? Речь о коде методов, т.е. о содержимом VMT.

Первый VMT — это абстракция от провайдера БД.
Прошли.
Далее у нас массив абстрактных дескрипторов полей, вторая VMT.
Полей десяток-другой, допустим.
Для каждого поля надо убедиться, что тип дескриптора тот же.

А оно точно будет эффективнее предложенной мною схемы вызова ф-ии-маппера по указателю на метод?

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


V>>В случае DataReader в нынешнем виде не прокатит — слишком большая иерархия объектов, всю её проверять на соответствие текущему хот-спот-коду будет накладней получаемых от хот-спот плюшек.

S>И удивительным образом, Java ухитряется сворачивать вполне себе прикладной код в приемлемый x86/x64.

Я не помню, чтобы она что-то там сворачивала, когда абстрактные объекты состоят из десятков других абстрактных объектов.
Мы тут однажды серьезно бодались с коллегой '.' (ник такой), он приводил примеры — они примитивнейшие все.


V>>Тогда проверка соответствия лейаута объекта будет сводиться к проверке только ссылок на метаинформацию столбцов рекодрсета, где эти столбцы ссылаются на одни и те же статические-заготовленные конвертеры.

S>И даже такую конструкцию способен улучшить хотспот.

Убрать самый первый VMT.
Вот это он может, угу.


V>>Т.е. сравни — проверить только равенство ссылок в объекте верхнего уровня или рекурсивно пройтись по кучерявым объектам, проверяя равенство всех полей всех дочерних элементов.

V>>Счётчик сложности в последнем случае скажет "извините, в другой раз".
S>Вот это уже интересный вопрос. Всё зависит от того, сколько у нас реальных типов используется внутри тела цикла.

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

А в моей схеме на указателях на мемберы все дескрипторы полей любых типов имеют один и тот же тип (или как миниму не абстрактны).
А для полей одинакового типа и вовсе будет один и тот же экземпляр дескриптора.


V>>Я показал устройство таблицы конвертеров в сообщении, на которое уже давал ссылку.

V>>Читабельность и поддерживаемость (то бишь расширяемость) прекрасная.
V>>А в варианте с новыми указателями на ф-ии — еще и максимально-эффективная, т.е. даже, грубо, на асме или IL быстрее не сделаешь.
S>Навскидку не видно, благодаря чему это будет быстрее вызова через интерфейс — ведь в реальности у нас будет не просто вызов по указателю. Сначала надо будет достать по указателю таблицу функций (рукопашный аналог VMT)

Ну да, просто минус одна косвенность.
Если сделать дескрипторы структурами (всё-равно в массивах хранятся) — минус две косвенности.
Если сделать часть массива inplace (как в std::string) — будет минус три косвенности.


S>Вот то-то и оно. Так что вы итоге мы обсуждаем гипотетический АОТ vs гипотетичексий хотспот.

S>В моей идеальной картине мира они сосуществуют: то есть АОТ работает заранее, возможно, с применением PGO. Как опциональный компонент, призванный улучшить время холодного старта.
S>А затем в дело вступает хотспот, который докомпилирует динамический код (если такой появится), и использует рантайм статистику для дальнейших оптимизаций уже и так неплохого кода.

После качественного AOT стираются типы.
Я не представляю, как у нас должна будет работать спекулятивная оптимизация в этом случае.
Это надо держать два варианта кода в бинарнике: скомпиллированный через АОТ и исходный IL.


V>>Даже существующий полноценный доступен только для iOS на основе mono (ХЗ какого он там качества).

V>>А виндовые UWP-приложения на .Net Core UWP компиляются серверами магазина Windows под сетку устройств, тот код публично недоступен.
S>Так нам же не исходники АОТ нужны.

Так он никак не доступен, если я правильно понимаю ситуацию.
А то, что доступно — это другие опенсорсные проекты в разной степени готовности.

Т.е., на прямо сейчас нельзя дать отмашку, мол, АОТ для .Net Core готово, пользуйтесь.
Насколько я понимаю, в некоторой степени будет готов AOT для webasm с выходом .Net 6.0.


V>>Я помню обратное — ты так и не прошёл понимание про повторно-используемые "кубики" при построении плана запроса.

S>Я привёл пример "плана запроса" и просил показать, какие его запчасти можно повторно использовать для альтернативных планов того же запроса, или каких-то других запросов.
V>>Псевдокод давался.
S>Да, мной.

При желании можно будет вернуться и продолжить или создать тему-продолжение.
Обсуждение то было достаточно забавным, на мой взгляд.
Хорошо раскрыло уровень рассмотрения происходящего в БД с т.з. ведущих базоводов этого сайта, для меня было откровением, что настолько с высоты птичьего полёта на это смотрят.

Я еще там же высказался — это значит, что курс проектировани СУБД те коллеги не проходили.
(не путать с проектированием БД в конкретной СУБД)

Например, взять тебя.
Ты более-менее разбираешься в возможностях самой БД, т.е. в её основной функциональности.
Более-менее разбираешься в том, как база хранит данные (хотя, почему-то считал это чуть ли не откровением для MSSQL, хотя такой же принцип используют почти все ISAM-базы еще с конца 80-х, кроме хранилищ на DBF-файлах, которые у нас были слишком популярны из-за FoxPor и 1C). Т.е., как по мне, вот эти эксурсы в то, как база хранит данные, да еще выдаваемые за откровение — это всё сильно засоряло обсуждение информацией ни о чём.

Но основное, что обсуждалось — это то, что находится м/у данными и "публичной" функциональностью, т.е. в какой вид компиллируются, собсно, запросы и как исполняются на уровне железа — тут у тебя чёрная дыра.

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

Опять же — ограничения.
Разумеется, базы могут обслуживать произвольные сценарии и произвольные запросы.
Но для анализа придумали т.н. "исторические данные" и OLAP.

А боевое приложение магазина-склада или биржи — это набор хорошо формулируемых ограничений.
По правилам инженерии, чем больше ограничений, тем проще.
"База вообще" и "база, к которой обращается одно специально разработанное приложение" — две большие разницы.
Во втором случае кол-во join-ов может быть до смешного малым, например, в случае кеширования справочных данных приложением.

И рассуждения как раз шли в направлении того, сколько реальных вариантов запросов (за минусом параметров к ним) породит конкретное приложение.
Сколько потенциальных планов породит такой запрос, с учётом отброшенных заведомо неудачных не в рантайме, а еще на этапе компиляции.
Сколько запросов будут иметь общие части, например, в одном запросе where Field1=A, а в другом where Field1=A AND Field2=B.
Например, в обоих случаях может получиться так, что лучшим вариантом будет сканить по Field1, бо по этому полю стоит более выгодный индекс (больше уникальных значений в индексе и распределение строк по индексу более равномерное). Это пример той самой "склейки" генерируемой функциональности, где план второго запроса целиком включает план первого — вот что имелось ввиду под "экономией", т.е. имелось ввиду повторное использование.

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


V>>Для статических еще в момент компиляции известны наличествующие индексы.

S>Для любых. Дело не в динамике, а в количестве сочетаний.

Это соломинка для утопающих, а не аргумент.
Для произвольного анализа данных существует OLAP — используйте инструменты по назначению, как грится.

А для 99% применений БД (торговля и учёт ТМЦ, финансы/бухгалтерия, биржи, банковский опердень) — у нас операции сводятся к приходу-расходу-остаткам и сбоку те самые "справочные данные", составляющие большинство таблиц (но не большинство записей, ес-но).

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


V>>Поэтому, комбинаторика будет только по различиям в статистике, где для многих типов индексов, которые я обозвал enum (разновидность справочных данных эдакого системного плана, т.е. которые жестко привязаны к версии приложения) — статистика известна на момент компиляции. То бишь, кол-во уникальных значений в индексе, характер этих значений (подряд или разрежёнными "островками" и т.д.).

S>В реальной системе таких "индексов" пренебрежимо мало.

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

Для банка аналогично.


S>Ну, так это известный трюк, связанный не столько с хотспотом, сколько с отсутствием value-типов. А иногда — и с тем, что мы хотим получить автовекторизацию, которая не работает в случае int a; int b; int c.


В плюсах работает, значит и в джите потенциально может работать.
И для векторизации надо хранить в одном массиве подряд, а не в 3-х.


V>>Вытягивают её ручками, помогая хот-споту.

S>Ну, по честному это применяется только в том случае, если перформанс прямо очень важен, а себестоимость разработки — нет. А обычные гражданские приложения, написанные идиоматическим образом, работают приемлемо быстро.

Разве что запускаются неприёмлимо долго.
И тормозят первые секунды.

Не от хорошей же жизни Андроид перешёл на AOT, а iOS отродясь бочку катила на скриптовые технологии, даже запретив Flash.


V>>Сам понимаешь, поддерживаемость ТАКОГО кода ни идёт ни в какое сравнение с предложенной мною микро-оптимизацией на основе таблицы диспетчеризации конвертеров.

S>Да, с этим я не спорю. Именно поэтому мне CLR нравится больше, чем JVM.

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

И я приветсвую тот факт, что в .Net Core набежали суровые нейтивные ребята и стали диктовать свои условия, что нынешний дотнет уже не узнать.
Плохо, что так много времени было упущено, конечно...
Re[49]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:

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

S>Как и всё — кладётся в стек.

Каким образом?
Это в модели .Net VM два независимых стека — стек данных и стек возвратов.
К тому же, стек данных волшебный, с безразмерными ячейками.

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

Работает оно так:
internal struct S1 {
    public long l1, l2, l3;

    public static S1 Create() => new S1();

    public static void Create(out S1 result) {
        result = new S1();
    }
}

Оба метода Create эквиваленты в железе, т.е. в обоих случаях как аргумент будет подана ссылка на участок памяти, куда вернуть результат.
Например, в архитектуре x64 fastcall, эта ссылка в обоих случаях будет подана через RCX.


S>Вот, текущее состояние экспериментов

S>https://github.com/evilguest/atropos/blob/main/Atropos/BranchNode.cs#L37
S>К сожалению, ожидаемый инлайнинг this[] в https://github.com/evilguest/atropos/blob/main/Atropos/BranchNode.cs#L28 не происходит, несмотря на то, что T — это struct тип, точно известный в момент JIT

FindChild — тяжелый метод в смысле сложности операций.
Несколько арифметических операций приравниваются к одной операции сравнения в плане сложности, а у тебя весь метод — бесконечные сравнения.

Можно попробовать заменить childIndex_X на inplace массив и сделать линейный поиск в цикле.
Я когда-то экспериментировал, примерно до 20-30 элементов линейный поиск быстрее бинарного.
Скорее всего это связано с предсказателем переходов процессора.

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

Заодно тело метода станет маленьким, вероятность инлайна вырастет.


S>Опять же в доке сказано, что из разных потоков работать с зокетами нельзя.


Это клиентскому кому нельзя.
Прерывания от сетевой карты всё-равно асинхронные, исполняются с т.з. потоков в другом потоке, и в момент обнаружения и забора новых пакетов данных при очередном вызове со стороны юзверя унутре без синхронизации никак. Хотя, синхронизация может быть выполнена на lock-free алгоритмах, но знать бы достоверно...


S>Так что явно там нет никаких примитивов синхронизации.


Там нет синхронизации публичного АПИ.
Это не то же самое, что межпоточная перекачка данных.

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

Здесь примерно такая же схема — прерывание выполняется в некоем "случайном" аппаратном потоке в контексте ядра, обработчик прерывания должен покласть новые пакеты в межпоточную очередь.


V>>Выглядит так, что у тебя своеобразные представления как о возможностях AOT, так и о возможностях hot-spot оптимизаций.

S>У меня своеобразные представления о том, как что должно работать.

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


V>>Вручную писаный сериализатор будет оптимизирован и в АОТ,

S>Каким образом? На основании чего АОТ будет выполнять спекулятивный инлайнинг?

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


V>>Например, "выпрямлять" в памяти банальный List<T>.

S>Что значит "выпрямлять"? Он же уже и так прямой.

Он дважды косвенный.


V>>Статистика в основном нужна для определения мест, где требуется оптимизация.

S>Мы ходим по кругу. Ну вот мы увидели, что у нас в горячем цикле вызывается _serializer.Serialize(dataReader, stringBuilder).
S>Дальше что? Это косвенный вызов по интерфейсу.

Тебя интересует нынешнее положение дел или будущее гипотетическое?
В нынешнем состоянии джит делает те же оптимизации, какие сделал бы и АОТ, только ограничен по времени.

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

И вот эта проверка — "природный" ограничитель возможности технологии спекулятивной оптимизации.


V>>В рекордсете из 1001 элемента первые 1000 будут прочитаны без оптимизации.

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

Схема рекордсета каждый раз создаётся с 0-ля, это будут другие экземпляры схемы с другими экземплярами абстрактных дескрипторов полей.


S>А АОТ так и оставит косвенный вызов через VMT.


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


V>>И даже если схемы будут те же — это будут другие экземпляры схем, вот в чём прикол.

S>При чём тут экземпляры? Речь о коде методов, т.е. о содержимом VMT.

Первый VMT — это абстракция от провайдера БД.
Прошли.
Далее у нас массив абстрактных дескрипторов полей, вторая VMT.
Полей десяток-другой, допустим.
Для каждого поля надо убедиться, что тип дескриптора тот же.

А оно точно будет эффективнее предложенной мною схемы вызова ф-ии-маппера по указателю на метод?

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


V>>В случае DataReader в нынешнем виде не прокатит — слишком большая иерархия объектов, всю её проверять на соответствие текущему хот-спот-коду будет накладней получаемых от хот-спот плюшек.

S>И удивительным образом, Java ухитряется сворачивать вполне себе прикладной код в приемлемый x86/x64.

Я не помню, чтобы она что-то там сворачивала, когда абстрактные объекты состоят из десятков других абстрактных объектов.
Мы тут однажды серьезно бодались с коллегой '.' (ник такой), он приводил примеры — они примитивнейшие все.


V>>Тогда проверка соответствия лейаута объекта будет сводиться к проверке только ссылок на метаинформацию столбцов рекодрсета, где эти столбцы ссылаются на одни и те же статические-заготовленные конвертеры.

S>И даже такую конструкцию способен улучшить хотспот.

Убрать самый первый VMT.
Вот это он может, угу.


V>>Т.е. сравни — проверить только равенство ссылок в объекте верхнего уровня или рекурсивно пройтись по кучерявым объектам, проверяя равенство всех полей всех дочерних элементов.

V>>Счётчик сложности в последнем случае скажет "извините, в другой раз".
S>Вот это уже интересный вопрос. Всё зависит от того, сколько у нас реальных типов используется внутри тела цикла.

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

А в моей схеме на указателях на мемберы все дескрипторы полей любых типов имеют один и тот же тип (или как миниму не абстрактны).
А для полей одинакового типа и вовсе будет один и тот же экземпляр дескриптора.


V>>Я показал устройство таблицы конвертеров в сообщении, на которое уже давал ссылку.

V>>Читабельность и поддерживаемость (то бишь расширяемость) прекрасная.
V>>А в варианте с новыми указателями на ф-ии — еще и максимально-эффективная, т.е. даже, грубо, на асме или IL быстрее не сделаешь.
S>Навскидку не видно, благодаря чему это будет быстрее вызова через интерфейс — ведь в реальности у нас будет не просто вызов по указателю. Сначала надо будет достать по указателю таблицу функций (рукопашный аналог VMT)

Ну да, просто минус одна косвенность.
Если сделать дескрипторы структурами (всё-равно в массивах хранятся) — минус две косвенности.
Если сделать часть массива inplace (как в std::string) — будет минус три косвенности.


S>Вот то-то и оно. Так что вы итоге мы обсуждаем гипотетический АОТ vs гипотетичексий хотспот.

S>В моей идеальной картине мира они сосуществуют: то есть АОТ работает заранее, возможно, с применением PGO. Как опциональный компонент, призванный улучшить время холодного старта.
S>А затем в дело вступает хотспот, который докомпилирует динамический код (если такой появится), и использует рантайм статистику для дальнейших оптимизаций уже и так неплохого кода.

После качественного AOT стираются типы.
Я не представляю, как у нас должна будет работать спекулятивная оптимизация в этом случае.
Это надо держать два варианта кода в бинарнике: скомпиллированный через АОТ и исходный IL.


V>>Даже существующий полноценный доступен только для iOS на основе mono (ХЗ какого он там качества).

V>>А виндовые UWP-приложения на .Net Core UWP компиляются серверами магазина Windows под сетку устройств, тот код публично недоступен.
S>Так нам же не исходники АОТ нужны.

Так он никак не доступен, если я правильно понимаю ситуацию.
А то, что доступно — это другие опенсорсные проекты в разной степени готовности.

Т.е., на прямо сейчас нельзя дать отмашку, мол, АОТ для .Net Core готово, пользуйтесь.
Насколько я понимаю, в некоторой степени будет готов AOT для webasm с выходом .Net 6.0.


V>>Я помню обратное — ты так и не прошёл понимание про повторно-используемые "кубики" при построении плана запроса.

S>Я привёл пример "плана запроса" и просил показать, какие его запчасти можно повторно использовать для альтернативных планов того же запроса, или каких-то других запросов.
V>>Псевдокод давался.
S>Да, мной.

При желании можно будет вернуться и продолжить или создать тему-продолжение.
Обсуждение то было достаточно забавным, на мой взгляд.
Хорошо раскрыло уровень рассмотрения происходящего в БД с т.з. ведущих базоводов этого сайта, для меня было откровением, что настолько с высоты птичьего полёта на это смотрят.

Я еще там же высказался — это значит, что курс проектировани СУБД те коллеги не проходили.
(не путать с проектированием БД в конкретной СУБД)

Например, взять тебя.
Ты более-менее разбираешься в возможностях самой БД, т.е. в её основной функциональности.
Более-менее разбираешься в том, как база хранит данные (хотя, почему-то считал это чуть ли не откровением для MSSQL, хотя такой же принцип используют почти все ISAM-базы еще с конца 80-х, кроме хранилищ на DBF-файлах, которые у нас были слишком популярны из-за FoxPor и 1C). Т.е., как по мне, вот эти эксурсы в то, как база хранит данные, да еще выдаваемые за откровение — это всё сильно засоряло обсуждение информацией ни о чём.

Но основное, что обсуждалось — это то, что находится м/у данными и "публичной" функциональностью, т.е. в какой вид компиллируются, собсно, запросы и как исполняются на уровне железа — тут у тебя чёрная дыра.

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

Опять же — ограничения.
Разумеется, базы могут обслуживать произвольные сценарии и произвольные запросы.
Но для анализа придумали т.н. "исторические данные" и OLAP.

А боевое приложение магазина-склада или биржи — это набор хорошо формулируемых ограничений.
По правилам инженерии, чем больше ограничений, тем проще.
"База вообще" и "база, к которой обращается одно специально разработанное приложение" — две большие разницы.
Во втором случае кол-во join-ов может быть до смешного малым, например, в случае кеширования справочных данных приложением.

И рассуждения как раз шли в направлении того, сколько реальных вариантов запросов (за минусом параметров к ним) породит конкретное приложение.
Сколько потенциальных планов породит такой запрос, с учётом отброшенных заведомо неудачных не в рантайме, а еще на этапе компиляции.
Сколько запросов будут иметь общие части, например, в одном запросе where Field1=A, а в другом where Field1=A AND Field2=B.
Например, в обоих случаях может получиться так, что лучшим вариантом будет сканить по Field1, бо по этому полю стоит более выгодный индекс (больше уникальных значений в индексе и распределение строк по индексу более равномерное). Это пример той самой "склейки" генерируемой функциональности, где план второго запроса целиком включает план первого — вот что имелось ввиду под "экономией", т.е. имелось ввиду повторное использование.

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


V>>Для статических еще в момент компиляции известны наличествующие индексы.

S>Для любых. Дело не в динамике, а в количестве сочетаний.

Это соломинка для утопающих, а не аргумент.
Для произвольного анализа данных существует OLAP — используйте инструменты по назначению, как грится.

А для 99% применений БД (торговля и учёт ТМЦ, финансы/бухгалтерия, биржи, банковский опердень) — у нас операции сводятся к приходу-расходу-остаткам и сбоку те самые "справочные данные", составляющие большинство таблиц (но не большинство записей, ес-но).

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


V>>Поэтому, комбинаторика будет только по различиям в статистике, где для многих типов индексов, которые я обозвал enum (разновидность справочных данных эдакого системного плана, т.е. которые жестко привязаны к версии приложения) — статистика известна на момент компиляции. То бишь, кол-во уникальных значений в индексе, характер этих значений (подряд или разрежёнными "островками" и т.д.).

S>В реальной системе таких "индексов" пренебрежимо мало.

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

Для банка аналогично.


S>Ну, так это известный трюк, связанный не столько с хотспотом, сколько с отсутствием value-типов. А иногда — и с тем, что мы хотим получить автовекторизацию, которая не работает в случае int a; int b; int c.


В плюсах работает, значит и в джите потенциально может работать.
И для векторизации надо хранить в одном массиве подряд, а не в 3-х.


V>>Вытягивают её ручками, помогая хот-споту.

S>Ну, по честному это применяется только в том случае, если перформанс прямо очень важен, а себестоимость разработки — нет. А обычные гражданские приложения, написанные идиоматическим образом, работают приемлемо быстро.

Разве что запускаются неприёмлимо долго.
И тормозят первые секунды.

Не от хорошей же жизни Андроид перешёл на AOT, а iOS отродясь бочку катила на скриптовые технологии, даже запретив Flash.


V>>Сам понимаешь, поддерживаемость ТАКОГО кода ни идёт ни в какое сравнение с предложенной мною микро-оптимизацией на основе таблицы диспетчеризации конвертеров.

S>Да, с этим я не спорю. Именно поэтому мне CLR нравится больше, чем JVM.

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

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