Pull to refresh
22
0.1
Алексей @AlexPublic

User

Send message

В статье же чётко описано, что это не совпадение, а однозначно следствие того, как была выбрана международная единица измерения длины (в каких-нибудь футах/секунда^2 или аршинах/секунда^2 цифры уже не сходятся).

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

Если уж говорить о g, как о константе, то надо апеллировать скорее к каким-то инженерным наукам, а не к физике. Вот в них частенько используют g как внесистемную единицу измерения ускорения. Скажем при расчёте допустимых перегрузок и т.п. А вот в физике это точно не является одной из фундаментальных констант. Хотя бы потому что для физиков это как минимум функция, а по хорошему вообще тензорное поле 2-го ранга. )))

Потому что согласно истории считать надо не от меридиана, а от маятника. А меридиан потом подогнали просто.

Соответственно для Марса один местный метр будет где-то 0,4 нашего (с учётом разницы в секундах). Ну и можно потом подогнать, что он равен 1/53 000 000 их меридиана.

И тогда местное g будет как раз в районе 9,88 в местных единицах.

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

Если автор «дорос» до такой «инновационной» технологии, как make и при этом параллельно активно использует различные скрипты на Python, то возможно ему стоило бы сделать следующий шаг в развитие и открыть для себя такие слова как Scons, Waf или вообще Bazel. С ними получился бы один простенький и логичный скрипт сборки, а не запутанный монстр, как в статье.
Зачем было использовать ESP32, главной фичей которого является интегрированный wifi (не используемый в данном проекте)? Можно было взять любой приличный МК со встроенным bluetooth (например те же популярные STM32) и избежать половины проблем из статьи.
Никаких особых оптимизаций в C++ мы не делали. Мы согласны с тем, что если покрутить правильные ручки у компилятора, то можно выжать совсем другие цифры.

Делать тесты производительности с C++ без хотя бы опции "-O3" — это уже довольно странная трата времени…

Лично я ожидал, что нативный код будет выполняться значительно быстрее Wasm. Но первые полученные результаты показали, что это не так. И это меня довольно сильно удивило. Планирую вернуться к этому бенчмарку позже.

И правильно что удивило — там точно что-то не так. )

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

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

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

Если у вас там видео воспроизводится, то можно посмотреть различные латентности, особенно в 4K и со сложными кодеками. )
Гарантий нет, но ведь всегда есть достаточно безопасные и предсказуемые кусочки программы, про которые что-то можно доказать.

Проблема в том, что на уровне машинных кодов невозможно получить гарантии. Потому как JIT компилятору неоткуда знать, что к данной ячейки памяти нет доступа у какого-то другого кода. Т.е. тот же C++ компилятор ещё может делать подобные выводы например по отсутствию ссылок (или операций взятия адреса) на данную переменную. А при просто потоке машинных кодов, обращающихся к каким-то произвольным участкам памяти, как гарантированно понять, что какой-то посторонний код (в худшем случае вообще в параллельном потоке — этого сейчас в WASM нет, но планируется в ближайшее время) не поправит данную ячейку памяти (которая потом используется как указатель)?

А браузеру вовсе не нужно с данной памятью работать. Учитывая, что в WebAssembly пока размер кучи ограничен 2^32, а процессоры у нас 64-битные, можно тупо нарезервировать страниц как раз на 2^32, но на реальные физические отобразить ровно столько, сколько заявлено в дескрипторе wasm-модуля (ну и по мере вызова grow_memory отображать дополнительные).

Ээээ что? Что значит браузеру не нужно с данной памятью работать? Ему не нужна вообще никакая память для своей личной работы или как? А если хоть какая-то нужна, то как её защитить от доступа из WASM модуля с помощью защиты страниц виртуальной памяти?

Вы хотите сказать, что clang берёт и сам генерит векторные инструкции? Мне казалось, что они всё-таки получаются в процессе работы самого LLVM. Учитывая, что с точки зрения меня, как разработчика приложений, формат wasm является всего лишь форматом обмена данными, мне всё равно, в какой там IR браузер разворачивает мой wasm-модуль и как его оптимизировать.

Ни в какой IR модули WASM в браузере не разворачивается. Формат wasm — это по сути и есть IR, представляющее собой ассемблерные инструкции некого виртуального процессора. Причём этот формат является чуть изменённой (упрощённой и с большей безопасностью) версией IR из LLVM. К сожалению векторные типы LLVM не вошли в первую версию WASM.

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

Не нехотят, а это единственное разумное решение. И собственно говоря уже все материалы (типы, инструкции) для реализации подготовлены: github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md. Но в текущий «стандарт» WASM это пока не входит.
Вот уж не знаю как. Я точно помню, как общался с сотрудниками Мозиллы и они мне говорили про багу в range analysis ещё в альфа-версии WebAssembly. Как минимум, нижняя граница определена в compile-time (в WebAssembly-модуле для heap необходимо указывать минимальный и максимальный размер хипа), а то, что указатель известен только в рантайме, ещё не значит, что его диапазон нельзя оценить с помощью статического анализа. Такое, например, реализовано в JVM для устранения проверки на выход за границу массива.

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

mprotect в POSIX. В Windows тоже был системный вызов, но я с ходу не вспомнил название.

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

Там есть всё необходимое. Вот как-то C-компиляторы делают это. А они, заметьте, никогда не оптимизируют непосредственно AST C. Т.е. они строят IR (промежуточное представление), которое как раз очень похоже на портабельный ассемблер, а потом уже находят в нём циклы, которые можно векторизовать. Для этого есть куча способов, есть много специализорованной литературы, которая рассказывает про это (вот даже последние редакции Dragon Book рассказывают про векторизацию), и есть ещё большая куча всяческих статей от авторов тех или иных компиляторов.

С учётом того, что в LLVM IR имеются векторные типы, это конечно очень большая загадка, как это делается. ))) Кстати, ещё забавный вопрос: интересно, как укладывается в это ваше видение факт работы OpenMP SIMD (у уже молчу про intrinsics)?

Полагаю, что статья автора как раз не про драйвера и ядра ОС.

Речь о том, что отказ от исключений уж точно не ведёт к потере производительности. )
Само собой. Например, хотя у нас в имеются специалисты с экспертным знанием C++, но для бэкенда наших сайтов используется вообще дико медленный Питон, потому как C++ нам тут просто не нужен — мы не Гугл или Яндекс. Однако все эти размышления не имеют никакого отношения к моему изначальному замечанию — там речь шла совсем о другом:

если у ребят получилась одинаковая производительность подобного алгоритма на JS, WASM (C++) и нативном C++, то практически гарантированно у них что-то очень не так в варианте нативного C++.
Мне кажется, что проверка на выход за границы heap-а в ряде случаев может убираться оптимизатором.

Каким это образом, если и значение указателя и значения границ определены только в рантайме?

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

Каким образом можно в рамках одного процесса закрыть некому коду доступ к какой-то области выделенной памяти?

Что касается SIMD, опять же, браузер может сам анализировать WASM и автоматом векторизовать его (для этого в WASM есть всё необходимое).

Нет там ничего необходимого. В будущем появится (соответствующие инструкции), но пока нет.

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

По крайней мере, LLVM ровно так и делает.

Ээээ что? Где это он так делает?

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

Хм, да это интересный момент. Я его не смотрел. Причём с учётом того, что итоговая машина всё же стековая, у WASM JIT'a в теории есть большое поле для оптимизации. А вот делается ли там сейчас что-то для этого или нет — не знаю. Хотя это не сложно посмотреть, т.к. исходники открыты.

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

С учётом того, что в наиболее требовательных к ресурсам приложениях (программирование различных МК, ядра ОС, дравейров и т.п.) как раз применяется режим C++ с отключёнными исключениями, то данная особенность если и влияет на производительность, то только положительно. )))
Все приложения разные, а JIT в браузерах творит чудеса.

Нет там никаких чудес. Каждый раз, когда я видел утверждения о равенстве быстродействия с C++, всё сводилось к кривому использованию последнего (собственно иначе и быть не может, т.к. тогда бы уже давно писали бы браузеры на js). Для схожего с использованным в статье для тестов алгоритмом у меня были следующие результаты (это усреднённое время в мс):

JS 15,6
C# 15,1
ASM.JS (из C++) 12,5
WASM из ASM.JS 11,4
Java 10,1
C# unsafe 8,9
WASM 8,6
D 7,2
C++ nosimd 4,4
C++ 1,5
Хорошая статья по WebAssembly. Единственное, чтобы я добавил, это что для сборки C++ кода в WASM не требуется обязательно Emscripten. Для собственно компиляции достаточно просто компилятора LLVM (естественно собранным с поддержкой WASM и Clang'ом). И именно его использует Emscripten внутри себя. А смысл проекта Emscripten не в генерации WASM (или даже asm.js, с чего всё начиналось), а в генерации JS обёрток, реализующих функциональность стандартных библиотек C++ через браузерное API. Т.е. без Emscripten (с чистым LLVM) не будет возможности даже для вызова функции типа printf (но при этом будет базовая возможность вызвать произвольную JS функцию из страницы, в которую загружен wasm модуль).

Да, ну и вот эта цитата:
Но когда включается оптимизация (зеленый столбик), мы получаем время, практически совпадающее с JS. И, забегая вперед, мы получаем аналогичные результаты в нативном коде, если скомпилируем С++, как нативное приложение.

означает, что у вас есть какие-то фундаментальные проблемы в вашем нативном C++ приложение. Т.е. мои тесты вполне подтверждают ваш результат, что WASM в данное время сравним по производительности с JS. Но при этом тот же C++ код скомпилированный в машинные коды всегда получается в разы быстрее. И на это есть две фундаментальные причины:
1. WASM с одной стороны предоставляет полный доступ к работе с указателями, а с другой должен гарантировать безопасное выполнение подобного кода внутри песочницы (у модуля не должно быть способа залезть в данные браузера или других модулей). Как следствие этого, IR код работы с памятью компилируется (при загрузке модуля в браузере) не в прямую инструкцию x86, а с дополнительной проверкой выхода за границы выделенной памяти. На активно работающем с памятью коде, это может давать просадку производительности х2 раза.
2. SIMD. В будущем в WASМ планируют завести поддержку SIMD инструкций, но пока этого нет. В JS этого нет тем более. А в любом приличном компиляторе C++ уже много лет как поддерживается автовекторизация циклов, которая может давать увеличение быстродействие вплоть до х7 раз (для самых подходящих циклов, но в коде графических фильтров изображений должно быть полно таких).

В общем не знаю где у вас там конкретные косяки с C++, но если у вас скомпилированное в машинные коды приложение исполняется столько же, сколько WASM и JS варианты, то эти косяки у вас однозначно есть.
Да, я вспомнил что в десятки раз — это касалось не openocd, а родной утилиты от STМ (называется ST-LINK Utility), которой я пользовался для прошивки до j-link.
Насколько софт JLink быстрее? Полагаю, что главным фактором, определяющим время прошивки, является всё же скорость соединения дебагера.

В десятки раз. На том же железе (но с другой прошивкой программатора).

Qt Creator поддерживает только openocd и st-util

Это не так. Qt Creator изначально поддерживает ровно один универсальный режим отладки — удалённый gdb. Плюс к этому там есть две дополнительные предустановки для st-link и openocd. Однако это всего лишь для удобства — можно без проблем настроить тот же openocd (который естественно реализуют gdb сервер) через общий универсальный режим (он в настройках Qt Creator называется «по умолчанию»).

Так что отладка через j-link (ПО, а в качестве железа служит обычный st-link, перепрошитый под j-link их официальной утилитой) у меня отлично работает из Qt Creator.

работа под линуксом — это два (хотя мб софт jlink тут тоже работает)

Есть и под винду и под линух и под мак.

openocd это универсальный комбайн, поддерживающий хоть stm32, stm8, отечественные кортексы — это три

Так j-link аналогично. И более того, там получается одно универсальное решение не только со стороны ПО, но и одно аппаратное решение для всех МК.

целый зоопарк отладчиков помимо jlink и stlink — это четыре

В данном сравнение это получается уже скорее минус, чем плюс. )))

ну и возможность лазить в сходники и делать любые фиксы — это пять.

А вот это да, я бы тоже предпочёл иметь открытые исходники ПО от Segger. Но боюсь в таком случае у них не вышло бы нормально зарабатывать… ))) Так что уж лучше качественное закрытoe ПО.
Из всего семейства Сortex-M вывода SWO нет лишь у M0/M0+ — поэтому решение прокатывает в большинстве случаев.

Ну вот например у нас из МК используются исключительно STM32F0, так что для нас это «лишь» является наоборот «всем». )))

Раньше вот даже не знал, что RTT уже c openocd скрестили, а теперь руки чешутся всё это дело проверить.

А зачем обязательно openocd использовать? Почему не попробовать более мощный j-link? Оно же даже без логирования и отладки намного удобнее, например хотя бы временем прошивки…
Semihosting — довольно медленный, RTT — завязан на программно-аппаратные решения Segger, USB — есть не в каждом микроконтроллере. Поэтому обычно, я отдаю предпочтение последним двум — использование UART и ITM.

SWO к сожалению тоже есть далеко не в каждом STM32. Ну а использование UART — это уже нагрузка на МК и использование периферии, т.е. уже не похоже на нормальный режим отладки. Так что на мой взгляд единственным универсальным и при этом эффективным способом логирования является технология типа Segger (там же на самом деле нет ничего такого секретного и проприетарного — просто периодическое чтения блока памяти через отладчик, можно самому легко написать, если есть желание).

Ну и кстати говоря, если уж говорить про непосредственно Segger, то их ПО (j-link, которое на мой взгляд на голову лучше openocd) спокойно работает с обычными st-link. Так что никакой привязки к их недешёвому железу нет.
Вы много сами-то в Китае производили и закупали?..

Ничего не производил, но много закупал.

А то у нас там, например, свой человек есть, и он настоятельно не рекомендует в принципе

Ну т.е. опыта закупок компонент в Китае у вас нет, правильно?

делать там партии размером меньше одной катушки — ни с точки зрения качества компонентов, ни с точки зрения качества монтажа (и да, в пробной партии в сотню штук изделий с компонентами 0201, сделанной в Китае, брака была половина, то же устройство, те же 100 штук, сделанные на метро Савёловская — 96 из 100 полностью исправны).

Ээээ что? Какое вообще отношение имеет заказ сборки плат в Китае к обсуждаемой теме (мелкосерийного производства плат в России)?

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

О, я смотрю очередное сильно аргументированное утверждение… )))

Какое отношение механическая загрузка компонент имеет к программированию?

Как только предложите, как без неё обойтись — сразу же все дружно решим, что никакого.

Ну так и без закупки и доставки компонент у поставщика тоже невозможно обойтись! Так что, включаем время на доставку в «программирование станка»?
Потому как со временем появится список надёжных поставщиков для каждого вида компонент

При нерегулярной покупке менее 10 тыс. компонентов? Не появится.

Сильное утверждение. ))) А как насчёт такой же сильной его аргументации?

Я прямо вижу, как вы за пару минут проходитесь по десятку-двум-трём лент с лупой, выписываете ориентацию компонентов в каждой из них и одним движением вписываете коррекцию угла поворота относительно экспортированного из CAD по лежащему там футпринту.

Это всё делается не при каждом изготовление платы, а при поступление заказанного компонента на склад. Причём делается даже в том случае, если в ближайшее время не намечено использование этого компонента — как раз чтобы потом, в самый нужный момент, не потребовалось измерять десятки компонент сразу. Хотя вообще говоря это простейшее дело (внести пару измерений в табличку в excel'е), но удобнее, когда этим занимается соответствующий человек в оптимальное время, а не разработчик в процессе изготовления прототипа платки.

Потом ещё секунд за тридцать ставите на станок два десятка катушек, десяток отрезков и пару поддонов.

А причём тут это вообще? Напомню, что в статье была фраза: "программирование расстановщика у вас займёт сильно больше времени, чем собственно расстановка". Какое отношение механическая загрузка компонент имеет к программированию? Или может тогда ещё доставку компонент от поставщика включим во время программирования? )))

Ну и за оставшиеся пять секунд проверяете, что он увидел и скорректировался по реперным точкам.

Вот собственно это и есть единственное действие (помимо загрузки файла, выданного CAD'ом) в управляющем ПО станка, которое действительно необходимо сделать. И да, оно занимает как раз несколько секунд.

Что для всех компонентов правильно указано место подачи. Что нижняя камера не ошибается ни на одном из компонентов, что верхняя камера правильно различает чёрные компоненты на чёрном фоне в поддонах…

Про компоненты уже написано выше.
Вы видимо никогда не работали с автоматическими установщиками компонентов. В теории, все просто — импортировал PnP файл из CAD-а и готово. На самом деле, это только 1% от всей работы по настройке (или как говорят — программированию) установщика и подготовке к запуску производства. Требуется как минимум разместить компоненты в машине (решить логичстическую задачу, зарядить катушки или заправить обрезки лент), прописать и проверить все координаты и высоты подбора, создать образы, проверить их и убедиться что машина распознает все компоненты с вероятностью более 95%. После чего нужно описать плату, описать реперные метки, проверить их распознавание. Под конец пройтись по placement файлу и убедиться, что все компоненты стоят на своих местах, а не со смещением, что повернуты они верно, катоды/аноды у диодов расположены верно и т.д. Вобщем, коллега olartamonov совершенно прав, иногда подумаешь стоит ли включать машину, или может паяльник в руки, пару часов и готово :-).


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

Information

Rating
2,348-th
Location
Москва, Москва и Московская обл., Россия
Registered
Activity