Запрет обходится второй переменной: DOTNET_PreferredVectorBitWidth=512. С парой переменных W-2255 наконец показывает Count = 16, и Sum() пересаживается на zmm
если что, Vector<T> не использует avx512 исключительно в цельях совместимости со старым кодом, который мог бы полагать что под капотом либо 16 либо 32 байтовый вектор. Со временем это ограничение уберут.
PS: в LINQ особо не пытаются оптимизировать симдами всё что можно, скорее по принципу “если это немного кода и работает на всех платформах - берем”. потому что для every nanosecond matters надо брать TensorPrimitives.
У меня проф.деформация, я повидал слишком много очень плохого кода, авторы которого свято верили что делают благое дело микрооптимизируя код. в dotnet/runtime написали новую либу, 99% safe код. в одном узком месте просился Unsafe.As чтобы убрать оверхед от ковариантного каста. Угадайте из-за какого кода в итоге в этой библиотеки был официальный CVE? И это написано экспертами, теми кто все нюансы рантайма знает по долгу службы, а на деле чаще всего unsafe код пишется скучающими программистами которые борятся с imaginary scaling issues или ставят сами себе челенджы
(9) удаление проверок границ - популярная причина CVE когда девелопер думает что он самый умный оптимизируя на 2 наносекунды какой-то код от скуки
(10) тоже самое только со вкусом редковоспроизводимых багов из-за сломанной атомарности (джит мержит доступы к памяти там где это ничего не сломает сам)
(12) сериализация секретов со стека в паддинги и отправка по сети. десериализация untrusted input из массива байт - это прям хорошо известные CVE, внутри мсфт прям есть список забаненных либ которые такое делают
(13) там в статье написано что с этим не так
(16) опять ковбой-стайл удаление проверок границ, ну удачи вашему продакшну.
Дальше, на х64 спан занимает 16 байт, тогда как размер без паддинга - 12. Для единственного инстанса ок, но представим, что вы храните несколько ссылок на буферы в ref struct, которая кроме этого содержит и множество полей - вполне себе оверхед при передаче по значению.
тут вообще не понял что конкретно вы экономите на передаче спана vs byref+length. передача byref+length это как минимум - два 8 байтовых регистра
(19) “C# всё равно не позволяет обратиться к неинициализированной переменной.”
во-первых, вполне позволяет. во-вторых, неинициализированные переменные вполне классифицируются как memory safety issue в любом языке
короче у вас претензии в стиле “не мешайте мне стрелять в ногу”, а смысл статьи - криминализировать байтое*лю, как это сделано в раст, где за любой unsafe код насмехаются, а не “блин, ну ты крут конечно, понимаешь как под капотом всё работает”
Но что умеешь - за плечами не носить, как говорится. Лично я был бы рад, если бы в своё время имел возможность начитаться о всякого рода трюках чисто про запас - меньше пришлось бы тратить времени на “изобретения”, когда они реально понадобились.
Не понял что вы хотели сказать этим) Мой посыл в том что джит активно развивают, то что вчера надо было костылить сегодня уже работает как надо
loop unrolling много лет есть в JIT, но включается для совсем простых случаев. мало развернуть цикл, нужно еще что-то сделать с тем что получилось чтобы был какой-то профит с этого. А тут в дело вступает модель памяти которая не позволит легально что-то засимдовать в большинстве случаев.
Там, где нужно гарантированно избавиться от bounds checking - ref var, MemoryMarshal.Get*Reference + Unsafe.Add.
Это всё будет требовать unsafe {} контекст.
При желании, с их помощью можно соорудить цикл с обратным счётчиком и при этом “прямым” доступом к данным - экономим инструкции на загрузке предельного значения в регистр и сравнении счётчика с регистром.
Большинство обычного вида циклов не нуждаются в этом, jit вставит оптимальный код как есть
По поводу выравниваний - влияет очень сильно, мало того, что выравнивание это лотерея, так ещё и даже пару лишних байт в горячем цикле может как серьёзно замедлить, так и ускорить процесс.
Сильно зависит от платформы, но в целом на процентов 10-15% производительности можно расчитывать + стабилизация бенчей
Вы не внимательно прочитали мой комментарий. Если вы записываете гуид и читаете в потоках, то максимум что вам грозит - это прочтение гуида где только часть записалась, а остальное - нули/мусор. Возможно это приведет к ошибкам в логике программы - но это уже на совести программиста. Несинхранизированная запись юниона, в котором вы делаете Unsafe.As над shared слотом в зависимости от тэга может привести к крашу рантайма. Фактически, это UB для джита/рантайма.
Нет. Присвоение структурного поля никогда не приведет к крашу рантайма, там не будет атомарности как это и обещает модель памяти, но никаких крашей рантайма не будет. А здесь без синхронизации может возникнуть ситуация когда вызывается инстанс метод (или например поле) у объекта, которые еще не успел переключится в новый объект (или наоборот - объект уже новый, а тэг старый).
Никаким образом это не решает проблему. Представьте что у вас поле класса - юнион Pet pet. вы меняете значение этого поля с Cat на Dog. в каком порядке вы должны менять тэг и shared слот чтобы читающий это поле другой поток всё это увидел без потенциального краша рантайма?
Проблема ExplicitUnion в атомарности - вы должны и значение и тэг поменять атомарно, иначе это тайп-сефити баг потенциальный. А учитывая что больше чем 64 бита атомарно не поменять…
Думаю не надо объяснять что object и не-обджект в одном слоте вообще даже теоретически нельзя хранить в .NET
Имею право полагать, что до выхода Native AOT, возможности -p:PublishReadyToRun=true не было
Нет, не имеете. R2R был с самых первых версий .NET Core, до этого с нулевых (по-моему с .NET 2.0 или даже 1.1) был NGen - +/- тоже самое (чуть с другой философией, fragile). Какое-то время .NET Core даже поддерживал оба режиме - NGen и R2R.
В C# любая рекурсия (т.е. вызов функцией самой себя) требует O(n) памяти только для стека
Это не так, JIT компилятор где сможет, прекрасно расставляет тейл коллы сам (а в очень редких ситуациях может даже развернуть в цикл). tail. prefix который использует F# это больше как обязательное требование к рантайму, в духе "мне все равно как, сделай тут tail call, в случае если быстрый (имплицитный) тейл-колл нельзя вставить, джиту придется вставлять специальный хелпер колл от чего будет удар по перфу.
Я не думаю что есть хоть какие шансы на появление этого в синтаксисе C#, хз зачем вы его тут перечислили.
если что,
Vector<T>не использует avx512 исключительно в цельях совместимости со старым кодом, который мог бы полагать что под капотом либо 16 либо 32 байтовый вектор. Со временем это ограничение уберут.PS: в LINQ особо не пытаются оптимизировать симдами всё что можно, скорее по принципу “если это немного кода и работает на всех платформах - берем”. потому что для every nanosecond matters надо брать TensorPrimitives.
У меня проф.деформация, я повидал слишком много очень плохого кода, авторы которого свято верили что делают благое дело микрооптимизируя код. в dotnet/runtime написали новую либу, 99% safe код. в одном узком месте просился Unsafe.As чтобы убрать оверхед от ковариантного каста. Угадайте из-за какого кода в итоге в этой библиотеки был официальный CVE? И это написано экспертами, теми кто все нюансы рантайма знает по долгу службы, а на деле чаще всего unsafe код пишется скучающими программистами которые борятся с imaginary scaling issues или ставят сами себе челенджы
(9) удаление проверок границ - популярная причина CVE когда девелопер думает что он самый умный оптимизируя на 2 наносекунды какой-то код от скуки
(10) тоже самое только со вкусом редковоспроизводимых багов из-за сломанной атомарности (джит мержит доступы к памяти там где это ничего не сломает сам)
(12) сериализация секретов со стека в паддинги и отправка по сети. десериализация untrusted input из массива байт - это прям хорошо известные CVE, внутри мсфт прям есть список забаненных либ которые такое делают
(13) там в статье написано что с этим не так
(16) опять ковбой-стайл удаление проверок границ, ну удачи вашему продакшну.
тут вообще не понял что конкретно вы экономите на передаче спана vs byref+length. передача byref+length это как минимум - два 8 байтовых регистра
(19) “C# всё равно не позволяет обратиться к неинициализированной переменной.”
во-первых, вполне позволяет. во-вторых, неинициализированные переменные вполне классифицируются как memory safety issue в любом языке
короче у вас претензии в стиле “не мешайте мне стрелять в ногу”, а смысл статьи - криминализировать байтое*лю, как это сделано в раст, где за любой unsafe код насмехаются, а не “блин, ну ты крут конечно, понимаешь как под капотом всё работает”
даже интересно стало - с чем конкретно? :-) а то вроде исключительно база
Не понял что вы хотели сказать этим) Мой посыл в том что джит активно развивают, то что вчера надо было костылить сегодня уже работает как надо
loop unrolling много лет есть в JIT, но включается для совсем простых случаев. мало развернуть цикл, нужно еще что-то сделать с тем что получилось чтобы был какой-то профит с этого. А тут в дело вступает модель памяти которая не позволит легально что-то засимдовать в большинстве случаев.
Это всё будет требовать unsafe {} контекст.
Большинство обычного вида циклов не нуждаются в этом, jit вставит оптимальный код как есть
Сильно зависит от платформы, но в целом на процентов 10-15% производительности можно расчитывать + стабилизация бенчей
tl;dr: да, это перенос того же самого на уровень рантайма, просто с возможностью инлайнить и более точно знать какие локалсы надо перетаскивать
из примера выше:
где тут нет объектов?
Вы не внимательно прочитали мой комментарий. Если вы записываете гуид и читаете в потоках, то максимум что вам грозит - это прочтение гуида где только часть записалась, а остальное - нули/мусор. Возможно это приведет к ошибкам в логике программы - но это уже на совести программиста. Несинхранизированная запись юниона, в котором вы делаете Unsafe.As над shared слотом в зависимости от тэга может привести к крашу рантайма. Фактически, это UB для джита/рантайма.
Нет. Присвоение структурного поля никогда не приведет к крашу рантайма, там не будет атомарности как это и обещает модель памяти, но никаких крашей рантайма не будет. А здесь без синхронизации может возникнуть ситуация когда вызывается инстанс метод (или например поле) у объекта, которые еще не успел переключится в новый объект (или наоборот - объект уже новый, а тэг старый).
Никаким образом это не решает проблему. Представьте что у вас поле класса - юнион Pet pet. вы меняете значение этого поля с Cat на Dog. в каком порядке вы должны менять тэг и shared слот чтобы читающий это поле другой поток всё это увидел без потенциального краша рантайма?
Проблема ExplicitUnion в атомарности - вы должны и значение и тэг поменять атомарно, иначе это тайп-сефити баг потенциальный. А учитывая что больше чем 64 бита атомарно не поменять…
Думаю не надо объяснять что object и не-обджект в одном слоте вообще даже теоретически нельзя хранить в .NET
Нет, не имеете. R2R был с самых первых версий .NET Core, до этого с нулевых (по-моему с .NET 2.0 или даже 1.1) был NGen - +/- тоже самое (чуть с другой философией, fragile). Какое-то время .NET Core даже поддерживал оба режиме - NGen и R2R.
"Появилось понятие R2R"
очень странная статья, понятно что это ИИ, но как-будто какой-то устаревший, из 2023 - смесь бесполезных фактов + откровенно неверных утверждений, аля
или
наверное неверных утверждений еще больше, я вскольз глянул
Там скорее про то что большое кол-во public API начнут требовать unsafe{} контекст, т.к. они не безопасны. Остальное вокруг этого.
вот вам 2 примера https://godbolt.org/z/9ne5K5G16
Какую именно это меняет семантику и результат программы? наличие или нет StackOverflowException? это не семантика
Это не так, JIT компилятор где сможет, прекрасно расставляет тейл коллы сам (а в очень редких ситуациях может даже развернуть в цикл). tail. prefix который использует F# это больше как обязательное требование к рантайму, в духе "мне все равно как, сделай тут tail call, в случае если быстрый (имплицитный) тейл-колл нельзя вставить, джиту придется вставлять специальный хелпер колл от чего будет удар по перфу.
Я не думаю что есть хоть какие шансы на появление этого в синтаксисе C#, хз зачем вы его тут перечислили.