Pull to refresh

Comments 97

Эх, оптимизация… Как же её не хватает в современном мире интерпритируемых («Управляемых») языков…
Если отказаться от «управляемых» языков, то очень быстро окажешься в мире встраиваемых систем и низкоуровневого программирования, где до сих пор главенствуют C (просто С) и ассемблер. И хватает простора для безумных оптимизаций.
Приятно читать такие статьи. Еще приятнее осознавать, что подобные «хаки» уже использовались в твоих решениях. К счастью сегодня в большинстве случаев можно не считать такты (и не экономит байты XOR'я указатели). Впрочем, это умение всегда оказывается востребованным в самый неожиданный момент. И владеть им очень даже полезно.
Благодаря Ардуине и прочим микроконтроллерам — такие специфические знания по-прежнему популярны (более-менее).
Боюсь тут мы с Вами по разные стороны баррикад. С моей колокольни именно Arduino первой обесценила умение «мыслить оптимальным кодом на ассемблере». А когда выяснилось что для более-менее серьезных задач это все же необходимо подоспел STM32, который позволил «не думать оптимально» дальше.
В итоге если раньше меня звали на проект с фразой «Мы хотим того и этого. Что тебе надо для того чтобы сделать?», то теперь всегда одно и то же «У нас STM32, а молодой и перспективный предшественник слился». И уж поверьте на слово, «молодой и перспективный» в подавляющем большинстве случаев совсем не горел желанием «оптимально мыслить на ассемблере». Скорее ему хотелось «нагородить фичь и выполнить все хотелки руководства». И пока получалось — работал. А как перестало… зовут меня.
Конечно, глупо винить в таком раскладе Arduino или STM32. Но и признавать их полную непричастность я тоже отказываюсь.
Ну да… Ардуину я зря упомянул. Тут надо STM32F103 + HAL, хотябы, упомянуть. Или STM8…
У меня был один из любимых «хаков» в программе на ассемблере
проверить один регистр, например на нуль — т.е. сформировать соответствующий флаг в регисте состояния (например флаг Z-нуля, на допустимый тайм-аут выполнения текущего цикла), а другой командой проверить ещё какой то регистр, но командой не изменяющей первый флаг, а устанавливающий/сбрасывающий другой флаг (наприме флаг переноса Carry), И финальной командой или остаться в цикле или выйти из него по результату командой перехода анализирующей оба флага (знаковые, безнаковые… переходы)

P.S. Вот, такие и ещё «моменты», хотелось бы видеть в учебниках применения ассемблера… :)
Ммм… А нужен ли здесь ассемблер? Насколько я знаю любой более-менее уважающий себя компилятор C умеет (и с радостью проделывает подобное) на уровнях оптимизации больше «none».

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

Ну и спуск на уровень ассемблера… Это тема отдельного разговора. И, конечно, это всегда компромис. Другое дело, что работа со встраиваемыми системами это всегда бесконечный день сурка. Каждая новая железка начинается с написания того, что уже было написано неоднократно ранее. Та сама ситуация, против которой всегда выступает так любимый прикладным сообществом лозунг «не повторяйся» (DRY code). Но… Каждая новая итерация приносит чуть больше понимания и делает код чуть быстрее и чуть более качественным. Очень медленный процесс. Фундаментальные изменения крайне редки. С другой стороны, этот самый лозунг «не повторяйся» больно бьёт прикладников порождаю «технический долг» и прочий «Legacy Code». Так что своя порция «счастья» есть везде.

Потому мой обычный принцип состоит в том, что если не нравится итоговый ассеблерный код — правь алгоритмы на C. И только если это невозможно спускайся ниже. Другое дело, что понять что именно не нравится и определиться с тем надо ли спускаться можно только понимая ассемблер и зная как именно один код преобразуется в другой (и как на этот процесс можно влиять). Но это наш кактус — кактус embedder'щиков. И мы его потихоньку грызём.
Ну ладно Ардуино с кучей С++ абстракций над GPIO, а с STM32 что не так?
Так и с Ардуино проблем нет. AVR классный чип с отличным набором инструкций и превосходной документацией. Он очень на многое способен.

Что до STM32, то у меня к нему вопросы исключительно по качеству документации. Кто реально пытался с ним работать на уровне «шуршать по регистрам» тот знает о чем речь. Частенько приходилось заглядывать в библиотеку или HAL и натыкаться на странные вещи типа важной не задокументированной последовательности инициализации периферии.

Впрочем, возможно уже поправили. И документацию и чипы. Просто лет 5 назад это настолько взбесило, что зарекся с этим чипом писать на уровне регистров. А современный HAL, наконец позволяющий делать нормальные callback'и, конечно, красив. И, самое главное, под капотом имеет довольно не плохой код. Совсем не чета старой Standard Peripheral Library.

Впрочем, низкий порок вхождения генерирует проблемы. Что на Ардуино, что на STM32. Пока эти проблемы не выходят за рамки DIY — проблем нет. Но обнаружить хм… дурно пахнущий код… в промышленном изделии (крайне плохо) работающим тысячами и раскиданным по всей территории России… А самое главное потом его полностью переписать и понять что STM32 не недостаточен (как считалось) а избыточен (как получилось)… И если б это единичная история… Потому с моей колокольни это одного поля ягоды.

Впрочем, упаси меня бог запрещать кухонные ножи, топоры или автомобили только по той причине, что они могут убить. Потому отвечаю на Ваш вопрос так — проблема не в конкретных чипах. Проблема в людях, которые эти конкретные чипы используют. И если Atmel (теперь Microchip) несколько дистанцируется от Arduino, то ST Microelectronics всячески способствует увеличению таких «специалистов». Для них это хорошо. Для рынка, пожалуй, тоже неплохо. Но кто сказал что моя оценка обязана совпадать с рыночной?
И если Atmel (теперь Microchip) несколько дистанцируется от Arduino, то ST Microelectronics всячески способствует увеличению таких «специалистов».

а много ли ардуинщиков знает, что «у неё внутре неонка atmel»?
Ну а ST просто захватывает рынок. И переводит его из «элитарного» в утилитарное. 30 лет назад слово микроконтроллер знали, условно, единицы. 20 — уметь что-то сделать на МК было крутостью. 10 лет назад это стало обычным в узких кругах, и элитарным в среде школьников благодаря ардуине. сейчас не освоить ардуину — стыд и позор, а STM хочет занять ее место для всех слоев — от школоты, использующих вместо ардуины — нуклео или блупилл (да, ftitzing и вот это всё), включая середнячков, которые знают, что такое принципиальная схема, и которым кубик просто сильно экономит время, и заканчивая такими, как Вы, профессионалами. И у STM это получается.
Наверное мне стоит благодарить ST Microelectronics за то, что без работы я не сижу. Но, предельно честно, это не та работа которой хочется заниматься. Хочется разрабатывать и рождать не костыльные решения (и это моя основная работа уже много лет), а приходится подтирать сопли за теми, кто переоценил свои силы в плане освоения STM32 (и это тоже многолетняя подработка).

И, слушайте, откуда взялось «элитарное», «утилитарное»? Это чья оценка? По мне или ты профессионал и делаешь продукт или… не профессионал и не делаешь. Во всяком случае за деньги. Я же не бросаюсь учиться оперировать на мышах и соседских собаках и не кричу что это «элитарное» умение должно быть продвинуто в массы и стать «утилитарным».

Резюмируя скажу так. Я бы предпочел жить без подработки. Но это тема политэкономии, а не техники. Потому простите, но… Я завязываю.
Выдавать глобальные идеи — это удовольствие; искать сволочные маленькие ошибки — вот настоящая работа. (Фредерик Брукс-мл)
Между «профессионал» и «не профессионал» — широкий спектр. У некоторых это целая жизнь.
«элитарное» — это доступное немногим. «утилитарное» — доступное всем. Жизнь постоянно переносить элитарность в утилитарность, в т.ч. и в профессиях. В начале прошлого века «шофер» был крутой дядька в кожаной куртке и очках, ездящий на настоящей автомашинеЭ с замасленными руками и жутко умный (ибо еще и чинил свою машину). Сейчас шофером может быть даже слабоумная «блондинка». Редкое и особенное стало распространенным и обычным.
Даешь атомный реактор в широкие массы! Раньше электричеством занимался только головастый Фарадей, а теперь любой дошкольник может не просто замкнуть электрическую сеть включая свет в туалете, так ещё и способен обуздать полупроводники банальным нажатием кнопки на планшете. Было б смешно, если б не было так грустно.

Ваш пример в шофером — сущая провокация. Даже в извозчики брали не всех. Нужно было пройти обучение и подтвердить квалификацию. В частности и по знанию ПДД. Извозчик почти всегда должен был иметь навыки конюха (и, отчасти, ветеринара). Ранние шоферы — не просто водители, они еще и автомеханики. А нередко еще и автоконструкторы. Куда там любой современной блондинке до старого шофера. Как и до шеф-повара. Механически повторять рецепты на кухне (даже немного разнообразя их количеством специй) совсем не то же самое, что придумать реально новое блюдо. Да и дать мужу или ребенку парацетамольчик, чтоб сбить температуру блондинка может. И то в зависимости от степени «блондинистости» — а то ведь только после подсказки провизора из аптеки (по сути варианта блондинки с медицинским уклоном).

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

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

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

Так что я не готов согласиться с тем, что «Жизнь постоянно переносить элитарность в утилитарность». Нет, она просто постоянно расширяет границы утилитарности. Вселенная расширяется, энтропия возрастает…

А цитата хороша. Впрочем… Вреден я. Ведь и здесь не соглашусь. Выдавать глобальные идеи — это политика, популизм, научная фантастика или что-то им близкое. А вот реализовывать глобальные идеи, получая удовольствие от устранения мелких сволочных ошибок — это уже работа мечты. К счастью у меня такая вот уже 20 лет как есть. И, надеюсь, еще хотя бы 25 продержаться.

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


ST Microelectronics всячески способствует увеличению таких «специалистов».

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

Давайте так. Научить программиста в ВУЗе невозможно. Сколько б минусов я не словил за столь категоричное высказывание. Любого программиста делает в первую очередь опыт практической работы. Я не говорю что базовые знания бесполезны. Нет. Но я утверждаю — выпускник ВУЗа это полуфабрикат. Его еще готовить и готовить. При чем в любой отрасли. Невозможно подготовить специалиста по базам данных. По веб-технологиям. По ИИ. Ну и токовый специалист по встраиваемым системам это плод длительной работы. Сначала с наставником, потом самостоятельной, потом обучения. Да, умение передавать знание не менее важно, чем умение получать. Рассказывая, объясняя и обосновывая почему так сам глубже понимаешь вопрос и пересматриваешь свои подходы. Возможно, я не прав. Но мне кажется что это касается вообще любой сферы. Учителя, врачи, токари, слесари, плиточники, монтажники…

Теперь чем же мне не нравится ST Microelectronics. Да всем нравится. Кроме одного. Она выдает микроскопы и не объясняет как ими пользоваться. В итоге в неподготовленных руках они безоговорочно превращаются в молотки. И ладно б так. Почему б и не забить саморез микроскопом, раз микроскоп доступен и саморезов навалом? Но беда в том, что люди заколотившие саморез становятся абсолютно уверенны в том, что только так и можно. Более того — как все неофиты они искренне и с достойную лучшего применения рвением пытаются доказать всему оставшемуся миру свою правоту. Вот именно за это я и не люблю ST Microelectronics. Atmel (Microchip), Sharp, Maxim, NXP — да фактически все уделяют внимание в первую очередь документации и базовой поддержки средствами разработки. Справедливо полагая что код напишут знающие люди (и напишут так хорошо, как только смогут). STM же выдает странный полуфабрикат. Который превратится в едва съедобное в руках неопытного разработчика, и во что-то более или менее похожее на правильный результат в руках опытного специалиста.

Я поправлюсь. Я видел очень классный код работающий на STM. Но беда в том, что таких проектов подавляющее меньшинство. Нужна определенная смелость для того чтобы все же пробраться через огрехи документации и доделать нижний слой. К счастью на хабре такие присутствуют. Чтоб ненароком кого не обидеть не стану называть никого. Но видел я и такие статьи. И скажу честно — слегка завидовал. Меня на такое не хватило. Впрочем, там в основном плюсы были. А это несколько не мой профиль.
Ардуина — вряд ли. там тупокод цветет и пахнет.
а контроллеры вообще- да, хотя сейчас «историю одного байта» повторять никто не будет — проще взять контроллер на несколько центов дороже, с вдвое большей памятью.
В «история одного байта» все же условия были несколько экстримальные: есть МК который утвержден и под него уже все готово и нужно было впихнуть фичу, про которую заказчик забыл.
UFO just landed and posted this here
И это печально… Теперь найти интересную работу, где надо напрягать мозги, стало крайне проблематично.
… и опять я со своими уточнениями. Работы такой навалом. Проблема не в работе. Проблема в том, что оплачивать ее адекватно не хотят. Как правило бюджет съеден на этапе обрастания фичами. Но увы, это практически невозможно исправить.

В большинстве случаев конечный пользователь не хочет платить на скорость, он хочет платить за функционал. Так что это не проблема, просто IT даёт то, на что есть спрос.


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


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

Я за то, чтоб был McDonald's. Но я категорически против того, чтоб был ТОЛЬКО McDonald's. Я хочу хоть иногда отдохнуть в Метрополе. И сильно расстроюсь если закроют сильно любимые Питерские кафехи Север. Больше того — суши бары, азиатская кухня, и все остальное тоже вкусно и интересно.

Но времена складывается ощущение что я единственный кому интересно хоть что-то кроме Макдака. А вот это уже страшно.
Можно, например, пойти работать в NASA и попробовать добавить новую фичу в прошивку Вояджеров.
Да оставьте вы эти статьи в покое — они для людей для которых это просто хобби. В то же время есть и статьи для «хардкорщиков». Но первых гораздо больше, вот и статей таких появляется больше.
Ну вот я «мигал светодиодом» недавно на esp32. Это был единичный и практически одноразовый девайс. Я взял платку, которая была под рукой, спаял пяток проводов своей криворукой пайкой, набросал пару десятков кода в ardiuno ide. На все про все ушло пол часа времени. Зачем мне лезть в дебри, если это для меня лишь хобби. Я отдыхаю а не работаю (хотя этот девайс мне нужен был для работы, но повторюсь, он был не серийный и одноразовый).
Помню времена, когда для ускорения работы кода в программу вставлял многочисленные ассемблерные вставки (в т.ч. для отрисовки на экране, вывода графических файлов, обмена с внешними устройствами и пр., чтобы экономить процессорные ресурсы), да еще старался сильно оптимизировать программный код (чтобы уложиться в объем небольшого ОЗУ). А сейчас — все увеличивающиеся мощности компьютеров, ОЗУ и дисковое пространство, ООП, визуальное программирование, фреймворки и пр. попросту убивают искусство программирования; и современные программы реально пожирают ресурсы компьютеров.
Искусство программирования убито кроссплатформенностью. Теперь нужно либо для каждой из платформ придумывать собственный набор трюков и хаков, фактически написав одну и ту же программу столько раз, сколько она поддерживает платформ. Либо же использовать фреймворки и создавать как можно более предсказуемый код, чтоб он работал везде.
И ситуация изменится не раньше, чем рынок полностью монополизируется единственной платформой. В этом плане есть некоторая надежда на интенсивное развитие WebAssembly и сдыхание всех альтернативных браузеров в пользу одного-единственного.
То есть, конечно, если такое случится, то негативных эффектов будет масса. Но вот возможности оптимизации возрастут колоссально, вплоть до написания байт-кода вручную.
Искусство программирования убито кроссплатформенностью...

Это не совсем так. Есть множество хаков мало зависящих от конкретного процессора или системы команд. Хотя, конечно, часть правды в этом есть. Но в коце-концов тот же Unix придумывался в первую очередь ради переносимости. Но это не мешает оптимизировать и ядро (на конкретной железке) и прикладное ПО (как под железку, так и кроссплатформенно).
UFO just landed and posted this here
В современном мире все еще есть сферы, где считают байтики и такты. Как в качестве хобби (демосцена) так и во вполне практических целях (ААА-геймдев и прочие рендереры, кодеки, майнинг и т.д.).
И людей, что таким занимаются, поди на порядок больше, чем 30 лет назад. Просто доля их в общем числе программистов упала на тот же порядок или два. Но когда будет под это задача, любители хардкорной оптимизации найдутся.
Тут скорее проблема именно с задачами, где такая оптимизация будет экономически оправданной.

Сейчас появились беспроводные VR с относительно слабым железом (можно выделяться картинкой) и облачный гейминг развивается (чем больше игр сможет, тем выгоднее). Вот где нужна исключительная производительность.

Ooopss… Похоже ошибся уровнем. Извиняюсь.
… современные программы реально пожирают ресурсы компьютеров ...

А Вы современный программист? Вот только честно и для себя.
Я когда-то решил, что мне не интересно прикладное программирование. Вот совсем. И решил остаться на самом низком уровне. Пусть и менее востребовано, пусть и денег здесь меньше — за то я четко знаю как каждый оператор моей программы влияет на бег электронов внутри изделия. И на этом уровне все осталось как раньше. Те самые бешенные хотелки в процессе реализации выжимают все даже из таких монстров как STM32, а неуемные аппетиты прикладного ПО не дают расслабиться и на уровне ядер операционной системы. И загрузку быструю все хотят — загрузчик неизбежное зло, а потому должен быть максимально эффективным.
Другое дело, что мало кто желает идти этим путем. Было бы интересно добавить в эту (и ей подобные статьи) опрос — кто насколько понял написанное. Думаю при честных ответах едва ли половину осилили. Букв много. Буквы такие, которые требуют знания «внутреннего мира» процессора. Хотя по сути просто описана давно известная оптимизация.
А искусство убить невозможно. Оно так или иначе неистребимо. Другое дело, что в живописи тоже были свои эпохи. Импрессионисты не примут Авангард, но и те и другие будут посланы далеко в лес художниками эпохи Возрождения. Так что главное выбрать путь и идти по нему. По возможности не навязывая окружающим своего мнения. Временами даже полезно узнать, что там нового в соседском лагере (и где мы это уже видели).
Помню, как-то переписывал все свои ассемблерные вставки обратно на С++, т.к:
1. Код не компилировался на другую архитектуру.
2. Когда я писал этот код, он и правда был быстрее того, что генерил компилятор того времени для тех процессоров. Но с тех пор сменилось уже не одно поколение процессоров и версий компиляторов, и современный компилятор уже давно генерил для новых процессоров более быстрый код, в чем я убедился переписав его на С.
Ассемблер — это не ядерная бомба. Это скальпель. А у хирургического вмешательства всегда есть единственное показание — без него жизнь по угрозой. Потому если без него МОЖНО обойтись, то без него НУЖНО обойтись.
А вопрос написания кроссплатформенного кода сильно шире ассемблерных вставок. В общем случае наиболее справедливый ответ выглядит как «вы просто не умеете их готовить». Впрочем — еще раз повторюсь — это всегда хирургия. И великое искусство всегда ровно в том, чтоб с одной стороны не впадать в гомеопатию, с другой не скатываться до хирургии. И уж подавно не доводить до необходимости хирургического лечения избыточным увлечением гомеопатией.

Даже на встраиваемых 1МГц нынче встретишь нечасто. И уж тем более нечасто там бывают задачи о плавной отрисовке тайлов в реалтайме. Поэтому запилить туда python и запульнуть скрипт на сотню строчек, который опрашивает данные очередной "погодной станции" — норм. А читать посты о том, как кто-то запустил эмулятор ZX-Spectrum на двухдолларовом программаторе-"свистке" — уже вызывает "аах!"

Именно что полезно уметь и держать в арсенале. А заодно — знать, как оно там под капотом шевелится. От встраиваемых систем недалеко (качественно) до какого-нибудь core-i9; покуда там больше "количества".
Ардуина хороша высокоуровневостью и и предлагаемым другим подходом: чтобы просто помигать светодиодом пару раз в секунду не нужно лезть в ассемблер!
(если задача состоит именно в этом — скрипт-ардуидди парой строчек, скопипащенных с какого-нибудь форума/stackoverflow решит такую задачу гораздо быстрее гуру ассемблера). Но досадно, что дальше, порой, дело не идёт. И причина этому — сама ардуина. Она, во-первых, слишком быстрая, чтобы заметить недостатки высокоуровневых языков. Во-вторых, в её родной экосистеме программируется всё же на Си, который компилируется, и тем самым оставляет место по сути лишь для безумных оптимизаций (покуда все разумные уже сделал компилятор).


В этом плане тот же ZX Spectrum гораздо больше провоцирует к исследованиям: сам как ардуино (запустил — и вот тебе бейсик!), но при этом более-менее серьёзные программы на бейсике с какой-то числодробительной математикой уже ЗАМЕТНО тормозят, и при этом под рукой куча программ, написанных на некоих "машинных кодах", которые те же задачи выполняют плавно и быстро. Оп-па, челлендж! Надо разобраться!
Да и встроенное руководство их упоминает, и даже приводит пример простейшей программы, причём в НУЖНОМ месте — в самом конце, когда бейсик уже освоен


LD BC, 99
RET

хм… непонятные буковки… Интересно!

Если отказаться от «управляемых» языков, то очень быстро окажешься в мире встраиваемых систем и низкоуровневого программирования
Это хорошо или плохо, на ваш взгляд?
молоток — это хорошо или плохо? :-)
Я не уверен, что понял вопрос.

На сегодня это факт. Я склонен считать, что любая сложившая и самоподдерживающая ситуация — это хорошо. Раз получается довольно четкое разделение на «системщиков» и «прикладников» значит так (и только так) и нужно. И пока взаимопроникновения не происходит — значит и не должно происходить. Потому отвечу так — на мой взгляд это факт. И все. Без оценок.

Подход с «подсчетом байт» почти наверняка никогда не придет в прикладное программирование. Прикладное программирование всеми силами от него убегало и нет ни одной причины, по которой ему бы захотелось вернуться к таким сложностям. Да, мы понимаем цену, которую приходится платить за такие удобства. Но ведь платим. Значит всех все устраивает. И конечного потребителя, и разработчика прикладного ПО, и разработчика инструментальных средств. Не вижу причин считать такую ситуацию плохой.

На другом фронте «системное ПО». Как бы много не было байт и тактов, но они конечны. И сильно нужны прикладной части. Потому позволить себе бесконтрольно их использовать просто нельзя. Нравится это кому-то или нет. Потому и приходится опускаться и отказываться от «управляемых» языков. Да, это не столь востребовано. Очевидно — прикладников надо в разы больше. Да, это не так хорошо оплачивается. Да, даже производители чипов не сильно заботятся о «низкоуровневой» части доверяя ее OpenSource Community. Но по факту именно такой подход позволяет поддерживать критически необходимый уровень системных программистов. Не истребляя их как класс, не заморачиваясь их специальной подготовкой, но и не оставаясь без низкоуровневых разработчиков. Не вижу причин считать такую ситуацию плохой.

А вот свою личную оценку всей отрасли целиком, прикладной и системной составляющей в частности я, пожалуй, попридержу. Но она не будет сильно отличаться от озвученной.
На том же Z80 (ZX-Spectrum, к примеру) двух стековых регистров не было. Но никто не мешал, скажем, читать через POP из памяти, а писать в фиксированный адрес ячейки, что бы без всяких ++. Да, процедуру нужно было разворачивать «руками» для каждой ячейки экрана. Благо, что их было не так много. Зато максимально быстро, на Z80 быстрее сделать было нельзя.

На спектруме в целом всё более "теплично".
Возьмём условно частоту 7Мгц и экран размером 7Кб (так легче прикидывать). Это сразу даёт возможность возиться над каждым байтом по 1000 тактов, чтобы обновлять картинку раз в секунду. Делим на "жёсткий реалтайм" того времени (25 кадров/сек) — 40 тактов. Берём реальную частоту (половина от 7МГц) — 20 тактов. И если учесть, что экран всё же 6,75К, и цветовые байты на каждый чих обновлять не надо — даже чуть больше. Так что даже в этих условиях вроде всё получается без всяких безумных оптимизаций (тот же LDIR насколько помню кушал 17 тактов на байт). Плюс, никто не думал о простое процессора (а сколько он кушает в HALT до следующего прерывания, по сравнению с тем, если мы вместо этого будем что-то считать). Ну и 25fps — тоже жёстко, да и цвета всё равно будут прыгать по 8 строчек и портить визуальное впечатление. А раз идеала всё равно не получится — можно и тут понизить и освободить ресурсы для логики.

Насчёт оптимизаций — LDIR был медленнее кучи LDI. А обновить все 6.75кб экранной памяти между прерываниями от кадровой развёртки (50к/с на телевизоре и, соответственно, спектруме) не хватало времени даже при помощи LDI, так что приходилось идти на ухищрения типа обновления только части экрана, занятой активными спрайтами и, соответственно, полностью статичным фоном в игре (Dizzy) или использования не всего экрана, а к примеру, верхних двух третей (Elite) или даже средней трети (демоверсия чего-то похожего на Doom). Ну и особенности адресации видеопамяти тоже доставляли, но к этому уже можно было привыкнуть и использовать для относительно быстрого вывода спрайтов с точностью до знакоместа.

50fps там никто особо не ждал (и реально заметных глазу поводов стремиться к этому не было). Да и прерывания на два-три тика можно просто запретить. Или заменить обработчик своим собственным, легковесным (чтобы пошустрее всё проверил и вернулся). Но в целом да, сделать половину/две трети экрана чёрными и там не рисовать вообще — тоже вариант. Но мне кажется, это уже шаги в сторону Agile. Сделать хоть как-то быстрее, но на пол-экрана, и уже завоёвывать рынок. Против "сделать плавно и гладко на весь экран, но + пол-года разработки безумных оптимизаций"

LDIR — это 21 такт на байт, а через стек можно почти вдвое быстрее.
На ZX не 7 МГц, а вдвое меньше, и LDIR 21 такт на байт. И в игровом рендере нельзя обойтись просто линейным копированием байт, одна только обвязка кадра может занять сравнимое с копированием врем, не говоря про наложение спрайтов по маске.

Про вдвое меньше я прямо в комментарии и написал, просто вы не дочитали.
И цель была, в общем-то, просто прикинуть рамки выше которых точно не прыгнуть.

Трудно построить реалистичные прикидки на изначально очень неточных данных. Это довольно странная идея, сначала завысить-занизить параметры, потом как-то поделить. Поэтому у вас получилось, что легко получить хороший фреймрейт без креативных оптимизаций. Но в реальности это было далеко не так. В реальности была медленная память, снег, порча стека, пропуск прерываний, ради 25 FPS был код типа pop de:ld (hl),e:inc l:ld(hl),d:dec l, т.е. чтение стеком и вывод змейкой с оптимизацией перехода 256-байтных границ (~16 тактов на байт), и многое другое.

Про подобное определение рамок вспоминаются статьи из 90-х о невозможности полноэкранной прокрутки текста в 50 FPS, там тоже считали примерно так же. Но фактически она таки возможна, что и было многократно реализовано чуть позже.
Особенно весело было в Ghosts'n'Goblins под ZX Spectrum 48K:
loop:
ld bc,7
add hl,bc
ld sp,hl
add hl,bc
pop de
pop bc; вот этими словами будем рисовать одну строку
ld sp,hl
exx
pop de
pop bc; а вот этими соседнюю
ld sp,hl; вот сюда будем рисовать строку
push bc/de *14; некая комбинация слов (например, небо и потом текстура земли)
inc h
ld sp,hl; а вот сюда соседнюю
inc h
exx
push bc/de *14; аналогично
dec a
jr nz,loop

С вариациями (там несколько таких циклов).
И дизайн игры подчиняется этому техническому решению, чтобы было быстро.
На спектруме часто заполняли все регистровые пары из стека, потом меняли указатель стека на буфер экрана и pushили их туда. Для этого даже использовали второй набор регистров, чтобы реже менять указатель стека.
На моей памяти одна демка на спектруме устанавливала адрес стека на начало экранной памяти 16384 и пушила туда картинку. Это позволяло получить чуть-ли не полноценную анимацию… Вспомнил название — «Lyra 128»
www.youtube.com/watch?v=EpQ94LmXaSQ&lc=Ugi2Y8idS0jnhngCoAEC

Меня тогда удивила как быстро она работает и я полез поковырять ассемблерный код.
На моей памяти одна демка на спектруме устанавливала адрес стека на начало экранной памяти 16384

Ошибочка. При добавлении чего-либо в стек изменение регистра SP (указателя на вершину стека) происходит в сторону уменьшения.

В случае ZX Spectrum, если требовался вывод только пикселов без изменения атрибутов, то указывалось на #5800 (начало области атрибутов) и далее PUSH'илось на экран до #4000.
Точно, вы правы. Уже забыл детали архитектуры. Но простительно, уже 25 лет не трогал спектрум :)
Вы, очевидно, просто не представляете, сколько оптимизаций в движке JS V8, например. Все эти ваши разворачивания циклов или вынос переменной в регистр прост покурят рядышком, не отсвечивая.
А что толку с этих оптимизаций, если куча веб-программистов на форумах спрашивают, нужны ли им знания алгоритмов?
Это не оптимизация, это бит-жонглирование…
Главное не делать оптимизацию ради оптимизации. Хотя и парадигма «у нас дофига процессорной мощности и памяти» иногда излишне развращает. Была такая игра Арк — выживалка с динозаврами, она удивительным образом тормозила даже на мощных системах. А затем выяснилось, что она целиком построена на одних блюпринтах анриал энжина.
«Была»? А сейчас что с ней? Перестала следить за новостями. Неужели наконец оптимизировали?
Нет, конечно. Но ушли кудато в сторону от динозавров, полностью сосредоточившись на Sci-Fi составляющей.
Требования прежние: 1080Ti + i7-7700 + 16GB Ram = 40-50FPS с просадками до 5-10 в городах…

ну, что значит "иногда"… Она всегда развращает, если поддаваться!

Рассказываю свою историю. Я писал лабиринтную стрелялку с возможностью прыжка/полета типа Марио. То есть перемещение персонажа не попадало под сетку спрайтов, что должно было дать уступ с которого можно упасть, стены в-пол кирпича итд.
Вопрос в том — а как проверить недетерменированную позицию на столкновение с препятствием и как считать повреждения от монстров?

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

Аналогично действовали и монстры — они перемещались во внутрь спрайта персонажа и если их спрайт получал искажения внутри этой рамки (два вектора скоростей давали 8 пикселей по горизонтали, минус 2 на рамки — 6 пикселей для маневров), то наносилось повреждение.

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

Кроме того надо было добавить и звуковые эффекты. Но там я нашел недокументированный мапхак — если быстро менять палитру при отрисовки спрайтов, то это вызывает колебание динамика но визуально совершенно незаметно, если только не забыть вернуть палитру после отрисовки в исходное состояние.

Вот что из этого вышло: www.youtube.com/watch?v=zs2HA6eQY88
Счастливое время, когда можно было потратить пару дней времени на оптимизацию. Сейчас так не получается — время жизни стало куда дороже, а железо — дешевле. Хотя удовольствие от того, что удалось ускорить расчет или запихнуть алгоритм в тесную память контроллера — ничего уже не заменит :(
Как только программист сам начинает пользоваться результатами своей работы, а не получает премию за досрочно закрытые таски — взгляд на вещи меняется ;)
При этом хорошие игры начали создаваться намного медленнее. Если на разработку игры уровня Battletoads под NES в те времена уходило около года, а Battle of Olympus вообще был создан тремя людьми за полгода, то сейчас по-настоящему хорошую игру за год уже не сделать.
Мало того, после выхода ещё года два будут выходить патчи, потому что системы усложнились настолько, что добиться стабильной работы кода на всех пользовательских устройствах сразу попросту невозможно.
Вы не правы, раньше просто это необходимо было делать практически везде, чтобы хоть как-то шелелилось. А сейчас те задачи, где это необходимо, просто не доезжают до СНГ.

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

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

Благодаря этому, такие формы могут заменять бумажные даже в условном кофейном ларьке, куда раньше было слишком дорого внедрять что либо т.к. сильно много времени требовалось на разработку софта с заданным набором требований (либо слишком редкие и дорогие разработчики, которые могли бы сделать такую форму на С++/asm с той же скоростью, с которой сделает современный джун на JS с фреймворками).
Рассказываю свою историю. Я писал лабиринтную стрелялку с возможностью прыжка/полета типа Марио. То есть перемещение персонажа не попадало под сетку спрайтов, что должно было дать уступ с которого можно упасть, стены в-пол кирпича итд.
Вопрос в том — а как проверить недетерменированную позицию на столкновение с препятствием и как считать повреждения от монстров?

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

Аналогично действовали и монстры — они перемещались во внутрь спрайта персонажа и если их спрайт получал искажения внутри этой рамки (два вектора скоростей давали 8 пикселей по горизонтали, минус 2 на рамки — 6 пикселей для маневров), то наносилось повреждение.

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

Кроме того надо было добавить и звуковые эффекты. Но там я нашел недокументированный мапхак — если быстро менять палитру при отрисовки спрайтов, то это вызывает колебание динамика но визуально совершенно незаметно, если только не забыть вернуть палитру после отрисовки в исходное состояние.

Вот что из этого вышло: www.youtube.com/watch?v=zs2HA6eQY88
Могу рассказать свою недавнюю историю. Считал спектры в Октаве беря экспортированные в .csv текстовые двоичные данные. В какой-то момент понял, что считаются раздражающе медленно и, главное, сильно медленее чем в предыдущем проекте. Натравив профайлер (великая вещь!) обнаружил, что большую часть времени скрипт проводит внутри октавовской функции bin2dec() (которая реализована как any2dec(param,2) и служебных функций копирования строк. Переписал функцию руками — ускорилось на порядок. Заинлайнил функцию преобразования в основной скрипт — еще процентов на 30%.
Это к слову об эффективности стандартных библиотек и своих велосипедов.
А как вам такое, перепаять в EC-1843 (советский аналог IMB совместимых) «тактовый герератор» с 4Гц до 8 или 9, точно уже не помню.
Вывести отдельно на платке оба эти генератоы с переключателем, плату сам травил, брал соляную кислоту и у мамы таблетки «гидроперита» (использовали для окраски волос).
Звал друзей в гости и показывал разницу между дефолтом и моим хаком.
93 год (никаких интернетов и гайдов, только советы «борадатых дядек инженеров»), 15 лет :) когда все паял, руки ОЧЕНЬ дрожали, это была дорогая техника, очень боялся поломать.

Я в те годы только сумел пропатчить boot-сектор для EC-1841 на дискетке так, чтобы дисковод переходил в 80-дорожечный режим из 40-дорожечного, так что у меня даже загрузочная дискета имела размер 720 кб.

Кнопка «турбо» в ЕС варианте :))

Отличная история! Браво!
Сколько сил тратилось на поиски "правильных" ассемблерных команд, использования арифметики с int вместо float.

Подобные игры со стеком применялись при выводе спрайтов в стратегии «Черный ворон» 1997года на ZX-SPECTRUM. Я этот алгоритм когда то оттуда вытащил, когда стало интересно как эта игра успевает так быстро отрисовать спрайты.
Копирование через стек применялось любым писателем демо для Спекки задолго до Чёрного Ворона.
Точно такая же идея с копированием байтовых пар стеком, в том числе с точно такими же решениями проблем порчи стека прерываниями и разного порядка байт, широко применялась в зарубежном и особенно в отечественном софте для ZX Spectrum. Также были и варианты, типа пар ld hl,NNNN:push hl (храним данные прямо в команде).
Это был идеальный хак!
За исключением варианта прерывания в момент копирования последнего тайла, когда запись данный может вылететь за экранное пространство… Но ведь этого никто не увидить, а старые компы… Что ж, они порой висли по загадочным причинам… :)

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

Можно конечно. Но это очень старый комп. Фиг его знает какая там карта памяти, могло впритык к области видеопамяти что-то быть. Могло и не быть.
Правильным решением тут было бы отключать прерывания на момент копирования, но. Это могло бы искажать генерируемый звук. Или в принципе невозможно в этом компьютере.

Моим последним шагом в исследовании деталей Z-80 на спектруме было измерение времени исполнения недокументированных команд.
У меня был Profi с 1024К памяти. Верхняя страница переключаемая, нижняя — ПЗУ (обычно), вторая — экран. Самая стабильная — третья (с 16К до 32К).
Размножал туда нужную команду, ждал прерывания и после него запускал. По следующему прерыванию (20ms) смотрел, докуда дошагал регистр PC. Взяв за эталон NOP, который должен занимать минимум (4 такта), 16Кб ему хватало, чтобы следующее прерывание возникло в пределах одной страницы, ну разве что с хвостиком (3,5Мгц/50 = 70К тактов, а в 16К NOP-ов 65,5К тактов, т.е. за одно прерывание, если забить память до верху одной командой мы никак не дошагаем).
Реальность идеи проверял на известных (документированных) командах и табличке с тактами. И вот там возникли вопросы… Потому что полученные метрики внезапно не соответствовали табличке. Вкратце, наблюдаемое количество команд в пределах одного прерывания для 8-тактовых оказалось не в точности вдвое меньше 4-тактовых. И даже не плюс/минус команда. Расхождение было в целом в пределах 20%, что очень удивило (вроде всё кажется очень детерминистично, а тут внезапно такой непорядок!

refresh памяти. Есть быстрые страницы и медленные (которые адресуются аппаратно вместе с видео контроллером.). Если читать ищ медденной страницы хотят оба — процессор приостанааливается. Если все страницы быстрые (пентагон, атм) то различия начинают проявляться в турбе. А в желтом скорпионе, емнип, даже бещ турбы все команды выравнивались до четного числа тактов. Тоже из-за его видноконтроллера

Медленная — до 32К. Выше быстрая. Там и проверял.

не знаю особенностей профи, но даже в фирменных 128 страницы делились не так и по-разному. Ниже 32 это только zx48 и его клоны, даже пнтагон48 имел всю памятт быстрой.

Ну вот я тоже слышал (а с интернетом в те времена было ещё туго), что первые 16К оперативки — небыстрые, поскольку доступ разделяется с выводом видео. Чтобы не гадать, так это или нет в профи — просто взял начиная с 32К, чтобы не было сомнений.
(а самая верхняя страница — переключаемая. Не знаю, влияет ли это хоть как-то на скорость, но чтобы исключить сомнения остаётся только третья, с 32 до 48К адресов)

Тормозят не окна памяти, а именно страницы. Т.е. если на компьютере с раздельными полями включить тормозящую экранную страницу в #c000, она будет тормозить и наверху тоже. При этом набор медленных и быстрых страниц на разных оригинальных моделях по нумерации разный. В Profi же, насколько я знаю, не было медленной памяти, по крайней мере в версии 3 и позже, и при желании развёртку можно было переделать на Pentagon'овскую.

С Пентагоном не встречался (только слышал про него). В те годы не было алиэкспресса и даже озона, приходилось везде ходить ногами и проверять, что есть в наличии. В наших краях был ATM-Turbo, продавался от готовых вариантов до голого куска текстолита. А потом всё понемногу пошло на убыль, и Profi я взял, кажется, в 1995-м, когда уже даже у нас в далёком замкадье массовым компьютером был 286, а в компьютерных фирмах можно было свободно купить 486 и позже пентиум.


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

UFO just landed and posted this here
Декранч и перенос данных стеком и сейчас пригождается в дебрях STM32.
Тот же FIR декранчем и стеком отбивает по 60% быстродействия. Да и авторы официальных библиотек считают по 8 сэмплов за цикл, а не по 1. Жива еще старая школа.
Моя история увеличения… только не производительности, а плотности печати картинки на матричном принтере. У папы на работе был дос, кто-то принес програмку печатающую, скажем, девушек в определенном виде. Я дизасемблировал эту программку чтобы понять как она распаковует графические файлы. Помню возился долго ибо было видно, что прога была скомпилирована с языка высокого уровня. Я написал свой вариант на асме + ноухау: печатал одной иголкой вместо девяти. Скорость упала в 9 раз, зато плотность печати возросла и напечатанные картинки были просто супер
Как говаривал мой друг — Прочитал, как стакан водки хлопнул! Отлично!
Если сработает прерывание, то повреждение произойдёт там, куда указывает S — на экране. Повреждение сохранится только до перерисовки следующего кадра

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

Это прекрасно!

Огромное спасибо за статью и перевод!!! Очень интересно написано. И результат отличный!

Данная статья — лишнее подтверждение, что надо читать документацию, господа. И чем внимательнее, тем продуктивнее вы будете. Если кто подумал, что тут про оптимизацию, то это не совсем так. Ибо улучшение результата состоялось благодаря архитектуре конкретного железа, а не оптимизации самого кода в универсальном его понятии.
Лет 10 назад делали контроллер управления аквариумом на платформе ATMEGA32.
Софт автор писал на BASIC — получилось весьма неплохо, я сам потом пару поделок на этом басике сделал — очень приятная штука и ASMа совсем не хотелось, при всей моей любви к нему и ностальгии.

Был у меня в лихие 90е PC 486dx2-66. И какой-то тетрис под DOS. У ПК была кнопка “turbo”, которая переключала частоту ЦП 33/66MHz. Что позволяло снизить скорость падения фигурок тетриса вдвое. Таким же образом можно было замедлить еще несколько игр.

Есть русскоязычный журнал Downgrade, в нём попадаются похожие статьи; в частности, в Downgrade №28 (страница 34) и Downgrade №29 мои статьи про историю ассемблерных оптимизаций на БК 0010.

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

Как минимум, чтобы анимация у этих спрайтов могла работать. Но еще может быть, что все эти оптимизации были нужны только для тех спрайтов, которые перерисовывать приходилось полностью.
Мы в своё время (~91-92 год), на очень прогрессивной в то время IBM PC XT двигали для таких фокусов указатель на видеопамять. Получался очень хороший и плавный скроллинг.
«Затем я наткнулся на PSHS. «Push registers on the hardware stack» («push-регистры аппаратного стека»).»

Это не совсем так переводится. Правильный перевод — «Поместить регистры в аппаратный стек». Подозреваю, что никакого понятия «push-регистры» в этом процессоре не существует.
Sign up to leave a comment.

Articles