Pull to refresh

Comments 94

Можно было дизассемблировать ещё то что делали компиляторы и сравнить в чем разница между ними и вашим кодом.
Статья переводная…
То есть нельзя было дизассемблировать то, что делали компиляторы и сравнить в чем разница между ними и кодом автора?
Я дизассемблировал и сравнил. Главное отличие в том, что компиляторы разворачивают несколько итераций рекурсии, т.е. функция sortRoutine получается в пять экранов длиной.
Почему вы решили, что это в компетенции переводчика? Перевести технический текст, буду слегка в теме, это одно, а добавить что-то новое в перевод — совсем другое. Тоесть да, нельзя было.
Почему вы решили, что я решил, что это в компетенции переводчика. Как нельзя, если tyomitch это сделал.
quicksort ориентирован на работу с памятью, в любом случае код упирается в скорость работы процессора с памятью. А если взять какой-нибудь вычислительный алгоритм и попытаться обогнать компилятор?
Что-нибудь такое, где вклад памяти небольшой, а нагрузка идет в основном на вычислительные блоки.
эмм… что-то, где дико нагружаются два-три регистра процессора, без памяти?) AES, возможно
Ну например да. 10 (кажется) раундов AES для каждого блока или 80 раундов SHA-1. С другой стороны криптография вообще плохо ложится на обычные ALU.

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

Понятно, что работа с памятью будет в любом случае. Ну пусть её будет не 75% как в случае quicksort, а хотя бы процентов 20.
С диффурами все еще хуже. Основное время будет тратиться на решение больших матриц, которые, как правило, очень разрежены и храняться в CRS формате. Скрость доступа к памяти будет основным ограничивающим фактором, даже если вы помассажируете матрицу всякими reordering алгоритмами…
Напомнило старую историю, как схлестнулись адепты ассемблера с адептами оптимизирующих компиляторов. И решили посоревноваться. В качестве задачи взяли вычисление миллионного, кажется, числа Фибоначчи (а может, миллиардного — не суть, в любом случае нужна длинная арифметика, а работы с памятью немного).
И тут пришёл какой-то чувак, написавший решение не через суммирование F[n+1] = F[n]+F[n-1], а через возведение матрицы ((1,1),(0,1)) в степень. Чуть ли не на бейсике. И, соответственно, порвавший всех.
И тут пришёл какой-то чувак, написавший решение не через суммирование F[n+1] = F[n]+F[n-1], а через возведение матрицы ((1,1),(0,1)) в степень. Чуть ли не на бейсике. И, соответственно, порвавший всех.

И получил фигню, потому что такое возведение считает не то? Ибо возведение такой матрицы в степень n даст ((1,n),(0,1)).

Как нам говорит википедия (https://en.wikipedia.org/wiki/Fibonacci_number), правильная матрица ((1,1),(1,0)). Соответственно, для вычисления F[N] нам достаточно быстрого возведения матриц в степень. Очевидно, что существует алгоритм с логарифмической сложностью. Таким образом алгоритмы с меньшей эффективностью для достаточно большого N покажут результат хуже.


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

Очевидно что за o(logN) возвести в N-ю степень нельзя, т.к. O(logN) операций уйдет только на чтение показателя.
И получил фигню, потому что такое возведение считает не то? Ибо возведение такой матрицы в степень n даст ((1,n),(0,1)).

Попробуйте ловить суть, а не цепляться к мелочам.
Существует алгоритм со сложностью O(log N) — это факт, а то, что с индексами ошибка — это не критично, любой умеющий думать человек её тут же поправит.

Попробуйте не использовать ad hominem. Я писал «алгоритм» быстрого возведения в степень (не для матриц, в другом кольце), но сути это не меняет.


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

Угу (насчёт матрицы я писал по памяти и поленился проверить)
Единственное — из-за длинной арифметики там вроде не O(log(n)), а поболее получалось (но и алгоритмы «в лоб» тоже были не O(n)).
N-е число Фибоначчи состоит из (с точностью до константы) N разрядов.
Сложение двух N-разрядных чисел делается за (опять же с точностью до константы) N операций, так что реализация через сложение потребует O((1 + 2) + (2 + 3) +… + (N — 1 + N)) = O(N^2) операций.

Если делать умножение длинных чисел наивным способом (за квадрат от числа разрядов), то нам понадобится O(1^2 + 2^2 + 4^2 +… + (N/2)^2) = O(N^2) операций. Правда константа получается куда лучше.
Ну и если делать более интеллектуальное длинное умножение, то и асимтотика получится лучше.

Забавно, 18 лет прошло, да и сети той (фидо) уже давно нет.
А ту устроенную мной развлекуху люди еще помнят.
PS. Работы с памятью там как раз много, это вообще основное. Числа длинные (килобайты и десятки килобайт), вам нужно пословно, с переносами, их складывать. Я, например, сопроцессором складывал, там внутре есть/был хитрый режим 80-битных целых, до которого можно только из ассемблера дотянуться. Но вы понимаете, что даже в этом случае на 1 операцию сложения, которая вообще плевая, приходится две операции чтения и одна — записи.
О да, до эпохи многоядерных процессоров часто использовал этот трюк с плавающей запятой. Тогда это была магия — на халяву еще один процессор, да по 64-80 бит операции.
А дотягивался я до туда ни из какого не ассемблера, а из Фортрана.
хитрый режим 80-битных целых

Расскажите поподробнее, в документации по x87 такого нет. Есть только режим 64-битных целых (=extended без мантиссы) и режим BCD-чисел (72 бита + знак), который имеет более узкий диапазон, чем int64.

Раньше, когда сопроцессор был именно отдельным процессором, наверное, можно было параллельно что-нибудь считать на CPU, пока FPU выполняет вычисление. Потому же сопроцессор стал частью CPU. Жалко, я не застал этого момента: первый компьютер сопроцессора ещё не имел, второй — уже не имел.
и режим BCD-чисел (72 бита + знак), который имеет более узкий диапазон, чем int64

Но int64 будет за две операции вычисляться — add и adc.
Да, точно, 72 бит BCD. Запамятовал уже.
Там трюк в том, что в конце работы результат нужно вывести в ascii. Для числа длиной десятки килобайт перевод из двоичной формы в десятичную оказывается достаточно медленной операцией (нужно делить, хотя бы и сдвигами, но всё равно).
У меня есть просьба: выложите не только исходники, но и бинарники, чтобы я мог сравнить с другими компиляторами (MSVC2015 и ICL17).
UFO just landed and posted this here
Делал достаточно простую задачу по наложению двух восьмибитных FullHD-кадров друг на друга (YUV+YUVA=YUV), с использованием SIMD. Ассемблерная функция в C-программе.

Даже на AVX дает прирост больше чем в 50% при рандомной альфа-маске.
Возможно, я не идеально знаю ключи для оптимизации, компилил при помощи gcc -O3

На AVX2 ассемблер еще быстрее.
Я уже не говорю про то, что он отрабатывает ЗНАЧИТЕЛЬНО быстрее, если в маске у нас 16 следующих друг за другом 0x00 или 0xFF (полностью прозрачный или полностью непрозрачный фрейм), что очень актуально при наложении эффектов типа логотипа.
А если использовать Eigen или другие готовые решения для работы с массивами чисел?
Тогда не было необходимости и достаточного скилла на это всё)
Спасибо за наводку, обязательно буду иметь в виду, как дойдут руки — проверю на деле.
и -Ofast, и -O2, и -O3

Лучший результат, которого удалось добиться на том проце (вроде бы, был i3 low power 3 поколения), был 3.2мс, против которого ассемблер выдавал меньше 2мс.

Цифры помню, остальное — увы, уже нет. Надо будет освежить
-pipe -O2 -march=native -mtune=native -fomit-frame-pointer -mfpmath=sse -mavx2 -ftree-vectorize -funroll-loops
Скажу так. Есть у меня в коде одна задача, когда мне нужно было отрисовать в текстуру пиксели с хитрым блендингом (пусть вас не смущает слово «текстура», задача чисто CPU-шная, никаких ускорителей в работе не используется).
Ну так вот. Я написал код на ассемблере с использованием SSE2. Вроде быстро.
Но потом я переписывал это код на AMD64 и решил отказаться от ассемблера. Переписал на интринсики. При чем вообще не заморачивался на скорость. Писал грубо, без каких-либо оптимизаций. Там присутствовали конструкции вида:
_mm_storeu_si128( ( __m128i * )dst_argb, _mm_packus_epi16( _mm_add_epi16( 
  _mm_mulhi_epu16( _mm_shuffle_epi8( t4, pta1 ), _mm_shuffle_epi8( tt5, a1l ) ), 
    _mm_mulhi_epu16( _mm_shuffle_epi8( tt5, a1r ), t6 ) ),
      _mm_add_epi16( _mm_mulhi_epu16( _mm_shuffle_epi8( t4, pta2 ), _mm_shuffle_epi8( tt5, a2l )),         _mm_mulhi_epu16( _mm_shuffle_epi8( tt5, a2r ), t6 ) ) ) );

Ну т.е. многоэтажные вызовы интринсиков. И каков результат? А результат таков, что этот код стал работать быстрее того, что был на голом ассемблере. Так что компиляторы нынче действительно очень хороши. Смысла в ассемблере очень мало.
Ради забавы тут кое что ваял и интринсики и вправду оказались быстрее и удобнее. И как я не бился, ассемблерный код всегда вызывался (не инлайнился).
Да ну, интринсики — это уже тоже ручная оптимизация. Можно считать, что это тот же ассемблер, только чуть более универсальный.
А главное — можно писать одинаковый код для х86 и х64.
Если бы. Отойти подальше от конкретной архитектуры и уже нужен другой код. Те же x86 инструкции у разных интеловских атомов очень отличаются от не атомов и тот же код, что оптимально работал на хасвеле совсем не оптимален на атомах.
В такое случае попробуйте Gentoo.

Никто не будет писать отдельный код для каждого процессора, за очень редким исключением. Обычно вполне устраивает существенное ускорение программы за счёт использования векторных инструкций.
Хотите сказать, что компилятор с теми -march=native -mtune=native для генту перепишет ваши интринсики? Нет, конечно, он может только другие инструкции сгенерить, но лэйаут тот же останется, а для конкректной архитектуры лэйаут не менее важен. Собственно в обработке изображений и видео можно наблюдать подход с получением CPUID в рантайме и выбором подходящей под процессор оптимизированной функции. Да и на ассемблере все, интринсики в этом не встречал, потому что хз что там компилятор в очередной новой версии начнет оптимизировать, а ассемблер таким и останется, ассемблер надежнее.
Мне кажется что в этой статье есть заблуждение. Когда говорят что компилятор C++ «лучше, выше, быстрее» имеют в виду не конеретный код, работающий с конкретными типами, как в примере приведенном в статье, а имеют в виду гораздо более общие случаи.
А приведенном коде (который кстати совсем не а C++), производится работа по сортировке массивов заданного типа, и именно это дает возможность переписать этот код на ассемблере с выигрыщем в произовдительности и (возможно) свободном от ошибок. А теперь представьте что у вас эти Item разные, имееют разные китерии сравнениия, да и вообще у вас не Item а например Peoples, или еще чтото… На C — вы будете пытаться это обобщить через void* и предикаты (и имеете шанс запутаться), на asm вы уже запутаетесь в косвенной адресации и предикатах, шаблонные же алгоритмы на C++ сгенирируют за вас вполне корректный код, который работает по фиксированным отступам в пямяти, со знанием размеров объектов и членов, именно по тому что КОМПИЛЯТОР ЗНАЕТ ТИП и именно это поможет быть этому коду оптимальным.

Забавно смотреть бенчи без описания окружения… Тем более в разных окружениях (здесь явно интересны результаты под разные процессоры и с разными опциями оптимизации).


Да и алгоритм тут не самый обычный (редко исполняется). В 80% случаев в коде идут простые переборы, хэши и вычисления, там уже можно использовать SIMD etc.

Вот тут, кстати, можно прямо на сайте скомпилировать сишный код разными компиляторами и посмотреть, что на выходе.
В наличии GCC, CLANG, ICC(Intel Compiler) разных версий. Так же архитектуры x86, x64, ARM, MIPS, MSP, PowerPC. MSVC на бета части только. Помимо С++ есть Rust, D и Go.
Вообще тесты на 99 мс — это фигня ибо очень мало. Надо хоть секунд 10 делать для равномерности.
Для интереса прогнал на своей системе:
  • sort_cpp_recurse (GCC) занимает 64мс
  • sort_cpp_recurse (clang) занимает 62мс
  • sort_asm_recurse занимает 60мс (и потребовало некоторое время на адаптацию к линуксовому ABI)
  • std::sort занимает 55мс

Отсюда вывод: чем выпендриваться и писать на ассемблере, лучше взять готовый, переносимый, отлаженный код на C++
Кроме того, большое сомнение вызывает методология эксперимента (сравнивать самый быстрый из ста прогонов, и игнорировать все остальные).
Если сравнивать результат по всем ста прогонам вместе, то sort_cpp_recurse (clang) даже слегка обгоняет sort_asm_recurse.
>сравнивать самый быстрый из ста прогонов, и игнорировать все остальные
Слышал такое мнение, что окружение в котором запускается процесс не может заставить его выполняться быстрее. Т.е. если у вас есть 4-е запуска программы с разным временем выполнения, то тот, у которого это время меньше ближе всего к реальному времени исполнения, т.к. ему меньше всего «мешали»
Здесь-то разница по времени между разными прогонами не из-за «внешних помех», а из-за того, что массив заполняется по-разному. Для каких-то вариантов начальных данных ассемблерное решение обгоняет сишное, для каких-то — наоборот, так что умелой подгонкой условий эксперимента можно получить любой нужный результат.
Абсолютно с вами согласен. Есть разные вариации методологии, но чаще делают что то вроде (P+N+2*B) прогонов. P- количество прогонов «на прогрев», B — число лучших и худших прогонов, которые мы выкинем.
И время на один прогон определяем как T\N, где T — общее время за вычетом P «прогревных» прогонов, B лучших и B худших. Так можно минимизировать ошибки и убрать джиттер во времени максимальным образом.
Стоит отметить, что std::sort — это не просто quicksort, это (насколько мне известно) интроспективная сортировка, т.е. комбинация из quicksort, heapsort и insertion sort. Вывод такой можно сделать: начинайте выпендриваться с алгоритмов, а не с ассемблера)
народ в интернете иногда может говорить нечто, совсем не соответствующее действительности.

Как вы мягко перевели. :)

Такие синтетические тесты типа: "Берем функцию, пишем на C и на ассемблере", совершенно не демонстрируют преимущества ассемблера. Я всегда утверждал, что сравнивать надо реальные, законченные программы, которые делают что то разумное и полезное.


Дело в том, что человек не пишет код на ассемблере так как пишет его на ЯВУ. Некоторые вещи, которые на ассемблере просты и логичны, на C такими не являются. Поэтому, неоптимизированные программы на ассемблере всегда получаются намного быстрее чем неоптимизированные программы на C/C++. Мои тесты (а я проводил такие несколько раз) показывают от 5 до 80 раз большее быстродействие ассемблерных программ.


Далее, если сделать несколько итерации оптимизации, программа на C/C++ можно довести до примерно 20..50% медленнее, чем та же программа на ассемблере. Но только если код на ассемблере известен.


В итоге, код на C получается совершенно нечитаемым, а код на ассемблере вполне читаемым.


Но какая часть программ оптимизируют так глубоко? И как поддерживается так глубоко оптимизированная программа?

Писать на ассемблере «разумную, полезную, законченную программу» целиком — это пальба из БАК-а по воробьям. В реальной жизни никто так делать не будет, так что такие тесты совершенно ничего не доказывают.
В реальной жизни никто так делать не будет, так что такие тесты совершенно ничего не доказывают.

Никто? Ведь я именно так и делаю. И знаю многих, которые так делают. И поэтому такие тесты многое доказывают.

А можно посмотреть пример большой современной программы написанной вами на ассемблере?

Можно конечно — и мою и не мою.


Не моя: RWASA — современный веб сервер, с TLS, быстрее nginx-а. Автор: Jeff Marrison из Австралии.


Моя: AsmBB — Простой форумный движок. Хорошо масштабируем, благодаря использования FastCGI протокола. (И FastCGI фреймворк к нем, которой можно использовать для других веб приложении).

UFO just landed and posted this here

Писать с нуля, конечно можно, но зачем? Это то же самое если писать с нуля на C (без libc и других библиотек). На ассемблере есть библиотеки, и повторное использование кода никто не запрещал. А когда пишешь все на ассемблере и соблюдаешь правила структурного программирования, то код постепенно накопляется и писать становится все легче и легче.


У меня почти весь этот код собран в библиотеке FreshLib, которая разрабатывается как часть и основа Fresh IDE. Там многое чего есть — от обработка строк и масивов, до OOP библиотека графического интерфейса (неокончена).


Поэтому, такие небольшие проекты как AsmBB пишутся быстро и приятно. Правда, несколько медленнее (примерно на 50%) чем на PHP, но и результат несравнимо лучше. Можно посмотреть история версии насчет реальные сроки разработки до v1.0;

UFO just landed and posted this here
а 24 часа на php можно написать немаленький проект, причём он будет с БД, кешированием, email-рассылками, полноценным логированием, и т.д.

Это так, только потому что некто уже все это написал и не за 24 часа, а намного медленнее.


То же самое и на ассемблере. Теперь каждый может взять мои исходники и за 24 часа написать чего нибудь, которое работает на FastCGI. Или например — парсер markdown можно написать за 10 минут. Как? А просто — его уже есть в FreshLib библиотеке.


А если что нибудь все еще не написано, то некто должен потратить некоторое время и не 24 часа.

UFO just landed and posted this here

Ну я же говорил о 1.5 раза, не знаю откуда x2 взялось. :D


А почему не работают на ассемблере? Это просто. Потому что пока действовал закон Мура, писать даже на 50% медленнее было смерти подобно. Всех учили писать быстро плохой код, ведь экспоненциальный прогресс исправить медленный код, а кто первый встанет, тому и тапочки.


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

UFO just landed and posted this here
Опять таки — почти всегда всё упирается в БД.

А что мешает написать БД на ассемблере? Вот, веб сервер уже написали и он быстрее самых быстрых серверов на C.


Разработка на нём — не в 2, и не в полтора, а в десятки раз медленнее и сложнее чем на языках высокого уровня.

Это только если программист не знает ассемблер, а знает ЯВУ. Если программист на одинаковом уровне знает ассемблер и ЯВУ, то мои тесты показывают совсем не в десятки раз медленнее, а именно в 1.5, ну пусть будет в 2 раза медленнее. Я ссылку давал наверх к таймлайне.

UFO just landed and posted this here
Ну так вот как раз таки БД — вероятно и будет смысл написать на ассемблере.

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

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

А кто вам сказал, что nginx — самый быстрый веб-вервер на С? Изначально у него была задача быть эффективным по памяти, про скорость там ничего нет.
А кто вам сказал, что nginx — самый быстрый веб-вервер на С? Изначально у него была задача быть эффективным по памяти, про скорость там ничего нет.

Ну, не знаю, так говорят. Я сам бенчмарки не ставлю.


Но RWASA также эффективнее по памяти. Да и все программы на ассемблере будут пожалуй лучше по памяти, чем эквивалентная программа на ЯВУ.


Потому что в ассемблере контролируется все на самом низком уровне.

Давайте ещё затронем тему HighLoad, где люди лезут напрямую в буфер сетевой карты, а не пользуются системными вызовами.
рано или поздно писать все на ассемблере станет выгодным. Кстати, оно уже и так выгодно
Можете про это подробнее?
Угу. Возьмем, например, файл source/post.asm.
sqlSelectConst text "select ? as slug, ? as caption, ? as source, ? as ticket, ? as tags"
sqlGetQuote   text "select U.nick, P.content from Posts P left join Users U on U.id = P.userID where P.id = ?"
sqlInsertPost text "insert into Posts ( ThreadID, UserID, PostTime, Content, ReadCount) values (?, ?, strftime('%s','now'), ?, 0)"

Все SQL запросы писать руками?

xor     eax, eax
mov     [.fPreview], eax
mov     [.slug], eax
mov     [.source], eax
mov     [.caption], eax
mov     [.tags], eax
mov     [.ticket], eax
mov     [.stmt], eax
mov     [.stmt2], eax

И обнуление переменых писать руками?

stdcall StrNew
mov     edi, eax
...
stdcall StrDel, eax

И создавать и удалять тоже все надо руками?

stdcall StrCat, [esi+TSpecialParams.page_title], "Posting in: "
stdcall StrCat, [esi+TSpecialParams.page_title], [.caption]

И вместо $page_title = "Posting in: " . $caption надо писать вот эту портянку? Или может копипастить из другого аналогичного места?

Да банально на все вот это уйдет несравнимо больше времени, чем если писать на PHP. Потому что на PHP тут вообще почти ничего писать не надо. Кода будет меньше даже не в 1.5 раза, а раза в 3-4.

Далее в целом по коду.

    cmp     [esi+TSpecialParams.thread], 0
    je      .perm_ok
    mov     eax, permPost

.perm_ok:
    or      eax, permAdmin

Ага, система проверки доступа захардкожена прямо здесь же. Какой там RBAC, битовых флагов хватит.

    test    eax, eax
    jz      .title_ok

.title_ok:
    ...
    test    eax, eax
    jz      .tags_ok
    
tags_ok:
    ...

Вместо if-ов или цикла куча условных goto на три экрана.

stdcall StrByteUtf8, [.caption], 512

Какие-то магические константы. Наверно размер буфера. А может максимальная длина в символах. Кто его знает.

cinvoke sqlitePrepare_v2, [hMainDatabase], sqlGetThreadInfo, -1, eax, 0

Константа sqlGetThreadInfo где-то в другом месте находится, надо догадаться поискать ее в файле showthread.asm.

mov     [.source], eax          ; [.source] should be 0 at this point!!!

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

; check the ticket
        stdcall CheckTicket, [.ticket], [esi+TSpecialParams.session]
        jc      .error_bad_ticket
        
; begin transaction!
        lea     eax, [.stmt]
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlBegin, sqlBegin.length, eax, 0
        cinvoke sqliteStep, [.stmt]        

Бизнес-логика тоже тут же, в контроллере обработки запроса. Правильно, зачем ее выносить, запутаемся же потом. И работу с БД сюда же поместим.

В общем, так даже на PHP уже не пишут, а вы про ассемблер.
Кода будет меньше даже не в 1.5 раза, а раза в 3-4.

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


Бизнес-логика тоже тут же, в контроллере обработки запроса. Правильно, зачем ее выносить, запутаемся же потом. И работу с БД сюда же поместим.

Все что находится в файле source/post.asm это только "бизнес логика" — запись в БГ, очередной постинг юзера. Конечно те процедуры вызываются как результат запроса POST, но сам запрос обрабатывается в другом месте.


Константа sqlGetThreadInfo где-то в другом месте находится, надо догадаться поискать ее в файле showthread.asm.

Ну не знаю, можно и погадать, конечно, но не лучше ли спросить у IDE? — Оно всегда знает где какая константа находится.

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

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


Все что находится в файле source/post.asm это только "бизнес логика"

Я понял, что post здесь не связан с HTTP-методом POST. В терминологии MVC, которая используется в PHP-фреймворках, post.asm это контроллер обработки запроса на создание сущности "Post". Бизнес-логика — это поведение сущности (в данном случае при ее создании). У вас она перемешана с редиректами и sql-запросами. Например, я хочу создавать post автоматически при некотором событии, как это сделать? Если я просто вызову PostUserMessage, то в случае ошибки он прервет текущий бизнес-процесс и сделает redirect на другую веб-страницу. А если я MySQL хочу использовать, вместо SQLite?


Ну не знаю, можно и погадать, конечно, но не лучше ли спросить у IDE?

Суть не столько в том, что IDE ее найдет, сколько в том, что это глобальный объект, находящийся даже не в конфиге, а где-то в специфичном файле. Это мне надо следить за порядком подключения файлов? И если я в другом файле определю константу с тем же именем, будет ошибка компиляции? С переменной hMainDatabase аналогично.

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

Нет, не так. Программист не машинистка. Он прежде всего придумывает код, а потом пишет. А код на ассемблере придумывается быстрее если считать строк. Просто потому что эти строки придумываются одновременно по нескольких.


А если я MySQL хочу использовать, вместо SQLite?

В этом проекте, нельзя использовать другая БД кроме SQLite. Это не потому что на ассемблере, а потому что я так решил на стадия проектирования программы Если нужно было, то сделал бы по другому.

Нет, не так. Программист не машинистка.

Вот при увеличении размера кода он превращается в машинистку. На обдумывание остается меньше времени. К тому же при написании на ассемблере утомляемость больше, так как надо больше состояния держать в памяти — регистры, стек, глобальные переменные.


А код на ассемблере придумывается быстрее если считать строк. Просто потому что эти строки придумываются одновременно по нескольких.

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


В этом проекте, нельзя использовать другая БД кроме SQLite

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

Откровенно говоря, несмотря на то, что я согласен с вами по многим позициям, но здесь, в конце, вы уже придираетесь — здесь идет смешение спора о «асм вс ЯВУ» и спор о концепциях архитектуры. Можно взять PHP и на нем написать «сполшняком», что-то ненастраиваемое и невстариваемое, со смешением бизнес-логики и всего остального. Негоже отказывать такому приложению в звании «большой современный проект» — проект современный = написан сегодня, а не сто лет назад. Большой? Да, LOC много. Пассаж о том, что оно не современное, т.к. написано не по современный канонам — натяжка кмк.

Возможно, просто когда такой же код приводится в статьях про проекты на PHP, в комментах намекают на PHP4 и на то, какой сейчас год.

В этом проекте, нельзя использовать другая БД кроме SQLite. Это не потому что на ассемблере, а потому что я так решил на стадия проектирования программы

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

Я не спорю, что в качестве хобби написать веб-сервер с форумным движком можно хоть на Алголе, хоть на Brainfuck. Но к написанию «разумных, полезных (кому-то, кроме самого автора), законченных программ» всё это отношения не имеет.
Но к написанию «разумных, полезных (кому-то, кроме самого автора), законченных программ» всё это отношения не имеет.

Весь домен flatassembler.net сейчас хостится на сервер RWASA. Никакие проблемы не возникали с момента перемещения. Даже стало лучше — раньше были проблемы с https, теперь уже нет. Раньше были проблемы с производительности. Теперь уже нет.


AsmBB, совершенно работающая система малого форума, на которой можно организовать форум. И он будет "просто работать". Инсталляция отнимает 5 минут. Поддержки не требуется. Хостинг будет стоит наверное вдвое меньше, чем такой же форум на PHP. Уязвимостей нет. Скрипт-киды не прорвутся. (Кстати, знаете как умер wasm.ru?)

А как?

Поймите, чудак-человек — вам говорят о том, что если вы захотите содержать не относительно небольшой портал, а реально «проходимое» место, потребуется более мощная БД. А подключить ее — ой, так просто не получится. В то время, как те же пхпшники просто подключат другую базу, фреймворк воспользуется другими заглушками для работы с ней — и все. Им не придется переписывать все. Да это может и вовсе не SQL база данных быть — все равно.
UFO just landed and posted this here
А почему такая железая уверенность в отсутствии уязвимостей?

Потому что проще код, меньше уязвимостей. У ассемблерного кода намного меньше слоев и зависимостей. Поэтому и уязвимостей меньше.


Конечно нет программы без бага. Но репорты свободно принимаются. Если найдете уязвимость или баг, то сможете увидеть как быстро она исчезнет. Потому что код на ассемблере поддерживается просто и быстро. :P

Я понял, что post здесь не связан с HTTP-методом POST. В терминологии MVC, которая используется в PHP-фреймворках, post.asm это контроллер обработки запроса на создание сущности "Post". Бизнес-логика — это поведение сущности (в данном случае при ее создании). У вас она перемешана с редиректами и sql-запросами. Например, я хочу создавать post автоматически при некотором событии, как это сделать? Если я просто вызову PostUserMessage, то в случае ошибки он прервет текущий бизнес-процесс и сделает redirect на другую веб-страницу. А если я MySQL хочу использовать, вместо SQLite?

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


Ведь хорошо я написал код или нет, это дело десятое. Примеры плохого кода на ЯВУ тоже хватает. Да и я не претендую на гениального программиста.


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


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


А то что надо вручную делать деталей, которые ЯВУ делают за вас, это ведь то, что делает ассемблер лучше чем ЯВУ. Кстати, это тоже вопрос выбора. Можно и так и иначе. Современные ассемблеры очень гибкие системы программирования. Это я выбрал писать деталей вручную и концентрироваться на деталях, потому что это улучшает эффективность кода.


Кстати есть и такой метод программирования, посредством естественного интеллекта — там и ЯВУ знать не нужно. Сформулируется задание человеческим языком и подается, вместе с некоторым количеством денежных знаков естественному интеллекту. После некоторого срока, на выходе получается работающая программа.

Тут важно понять, что ассемблер дает не меньше возможностей, а больше. Хотите например писать на ООП — пожалуйста. Хотите другую парадигму — делайте, язык вам не помешает…
А то что надо вручную делать деталей, которые ЯВУ делают за вас, это ведь то, что делает ассемблер лучше чем ЯВУ. Кстати, это тоже вопрос выбора. Можно и так и иначе

А еще лучше — писать просто вставками на ассемблере там, где это реально надо.
За плюсы не скажу. Но, по многолетнему опыту, на Delphi код по скорости почти догоняет ассемблер. 1-2% что я видел. Если без simd, конечно. Simd может дать выигрыш. Еще большее ускорение дает распараллеливание медленных частей по ядрам, что обычно относительно просто делается.
На новых — не знаю, а у 7ки было много бесполезного жонглирования регистрами. Вроде такого:

mov ebx, [ebp + 8]
mov eax, [ebx + 32]

mov ebx, [ebp + 8]

т.е. он чуть плоховато чувствовал, когда регистр не становился «грязным».
Самое интересное, что это жонглирование почти никак не сказывается на скорости. Я проверял. Разница, по скорости, как я писал — несколько процентов.
Если это неответственный участок кода — да. А так лишнее обращение к памяти не может быть бесплатным, особенно если в промежутке кеш вымывается.
Вангую хорошее попадание в кэш. Потому и разница в скорости мизерная.
Если важен каждый процент производительности, то все таки на ассемблере, можно попробовать потягаться с компиляторм — спланировать код по переходам, спаривать инструкции по исполнительным юнитам, выравнивать их по адресу в памяти, расставлять префечи, раскручивать циклы, вычислять на lea, использовать минимальные по длине инструкции и т.д. Это очень кропотливая работа, но если речь идет о коде для крупных заказчиков, то имеет смысл использовать асм. Но если перфоманс не настолько критичен, как время на разработку и компилятор при этом сообщает, что векторизовал написанный код, то можно оставлять и на С, А еще можно грамотно прагмы компилятора использовать для оптимизации.

И код будет быстро работать на одной микроархитектуре, но запросто может оказаться хуже сишного без оптимизаций на другой.

Ну да, это минус ассемблера, под каждый набор инструкций и даже иногда под микроархитектуру код нужен свой. Но опять же, это если код прям супер критичный типа Фурье или gzip сжатия или с ограничениями по размеру. А так, в большинстве случаев, даже у нас, в x86 performance ориентированой библиотеке используются интринсики в последнее время. Те 10% производительности от ассемблера, зачастую не стоят затрат на разработку и главное поддержку в будущем, но за некоторыми исключениями.
Половина этих оптимизаций компилятором gcc/msvc делается.
Помимо уже упомянутых ограничений, есть еще такая проблема: в большинстве проектов сейчас код меняется так быстро, что не успеваешь только оптимизировать. Как только оптимизировал, код становится или ненужен, или требования меняются так, что правки сводят эффект от оптимизации на нет.

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

Кроме того, неоптимизированный код подстегивает продажи нового оборудования. Win-win situation! Шутка. :)
Все же надо понимать, что меняется код проектов, т.е. бизнес-логика, а на ассемблере пишут библиотеки, т.е. базовые алгоритмы вроде той же сортировки. Они не меняются так быстро.
Sign up to leave a comment.

Articles