Обновить
8K+
35
Леонид@SLenik

TeamLead/.NET Developer

27
Рейтинг
14
Подписчики
Отправить сообщение

Даже на x86 тема аппаратного ускорения имеет свои особенности. К сожалению, соответствующая статья у меня до сих пор в черновиках - и опубликовать её сейчас не могу. Единственное что могу назвать из общеизвестного: в справочном центре требование использовать видеоадаптер Intel не старше 2016 года появилось не на пустом месте. На всех доступных нам версия драйверов Intel мы не могли создать более дюжины рабочих контекстов декодирования (на каждый видеопоток нужен был контекст). То есть контекстов-то можно было создать сколько угодно, они создавались без ошибок, но только первая дюжина работала как надо - при передаче в остальные данных для декодирования на выходе всегда был массив пустых пикселей.

Про ARM: в 2024 году у меня на работе было несколько тестовых устройств, где мы пытались запустить наше приложение с аппаратным ускорением декодирования и отрисовки видео. На всех устройствах (это были и платы, и “распотрошенные” приставки) стоял Armbian.

Аппаратное декодирование видео есть на многих SoC, не только на Rockchip, на котором его было проще всего запустить (так как есть достаточно популярный репозиторий-форк ffmpeg). При этом для других SoC решения тоже, помнится, были. Точно помню, что с корректно собранным ffmpeg у нас заработало аппаратное декодирование на SoC Amlogic. И была информация, что на SoC Allwinner через VAAPI запустить его также можно.

А вот где мы тогда застряли - это аппаратная прорисовка. То есть это быстрый вывод декодированного видео на подключенный к устройству экран. И вот тут, действительно, только у Rockchip rk3588 (у нас была плата Orange Pi 5 Plus) вывод сработал (причём удалось это через API Vulkan). Для других же плат мы бились с OpenGL/OpenGL ES - но я перешел в другую компанию до окончания этого процесса, поэтому о результатах не в курсе.

Видимо мне просто не повезло.

У меня с до сих пор остался купленный в конце нулевых ASRock ION 330HT-BD (Atom 330 + NVidia ION + 2x2Гб DDR2 SODIMM), для которого я в свое время сделал простенькую систему охлаждения на основе низкооборотного вентилятора 120мм. Один тонкий вентилятор работал сильно лучше, чем две встроенные в него “шумелки”; судя по датчикам температура выше 60 не поднималась ни на ЦП, ни на ГП. Изначально устройство при установленной Windows 7 позволяло комфортно смотреть фильмы в разрешении до FullHD включительно.

Однако в 2020 году я сначала поставил на него Windows 10, а затем заменил ОС на Ubuntu (кажется 18.04 lts). И на обеих версиях уже не смог заставить нормально работать продукт, который в то время разрабатывал (приложение для видеонаблюдения). Компьютер даже одну камеру в HD не тянул, всё время начинал тормозить при декодировании =(( И это при активном аппаратном ускорении и отсутствии b-frame в видеопотоке (и да, я проверял что ускорение активировано и работает). При этом нагрузка ЦП периодами скакала до 100%.

А потом ещё выяснилось, что фактическая скорость сети на Ubuntu почему-то составляла лишь ~ 1Мбит/c (мерял в браузере speedtest-ом при выключенных других приложениях). Может там была проблема с драйверами, может что-то ещё потребляло ресурсы. Но после этого опыта со старенькими Atom-ами я уже не связывался.

Дело в том, что устройства с поддержкой usb-otg часто могут и заряжаться, и передавать данные одновременно. Я с этим познакомился ещё при работе с 7" планшетом Dell (точно уже не помню модель) на процессоре Intel Atom.

При покупке телефона я специально смотрел, чтобы в прошивке был упомянут usb-otg. И чутьё не подвело. С купленным на сдачу usb-хабом за 300р с “поддержкой power delivery”:

мой телефон успешно заряжается.

Правда, только при подключении хаба к зарядке кабелем USB-A (тестер показывает, что в таком случае через кабель от зарядки к хабу идет ток 5В). Подключив же хаб к кабелем к зарядке с USB-C ток вообще не идет. Видимо, хаб “настолько недорогой”, что не умеет принимать ничего, кроме 5В (ну или не умеет в связке именно с моим телефоном).

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

А в чём конкретно вы видите разницу затрат по времени с x86?

И там, и там нужен был бы Linux (иначе более 1Гб памяти съелось бы просто на ядро + периферию). И там, и там надо было бы поставить ОС, провести первичную настройку.

На x86 могло понадобиться доставить драйвера (в отличие от сборки PostmarketOS). В моём же случае чуть потребовалось времени на поиск рабочего Mi Unlock.

Единственное видимое мною существенное отличие - потеря недели на ожидание разблокировки. Но я спокойно положил телефон на неделю. И занимался другими делами. В перерывах попивая чай =))

Ну и так, для полноты картины: цены на компоненты x86 (в частности, на оперативную память) сейчас такие, что даже думать в эту сторону страшно…

Баловство

Скорее любопытство. И чуточку баловства - почему бы и нет =)

Возьмите нетбук типа eepc

Eee PC точно не подошёл бы. Беглый поиск подсказал, что самым производительным чипом в этой серии был Intel Atom D525, который при TDP 15Вт в 6-8 раз слабее установленного в Xiaomi Redmi Note 9 Pro Snapdragon-а (если верить синтетическим тестам), и также (в разы) слабее SoC в роутере.

А в телефоне, между прочим, ещё и флеш-память на 128Гб…

Дельный совет, спасибо! Через некоторое время надо будет сделать отдельный комментарий (или приписку к статье) с описанием всех альтернатив, что порекомендовало сообщество.

класть старый телефон с литиевой батареей на вечную зарядку куда-нибудь в шкаф или на чердак

Полностью согласен. Поэтому нигде в статье и не описан план размещения телефона ни в шкафу, ни на чердаке =)

Приветствую! В самом начале я рассматривал покупку платы. Сейчас бегло поискал: конкретно ваша стоит от 4 тысяч и имеет на борту всего 1Гб RAM. А тут получилось в 6 раз больше и за ту же цену.

Может быть это связано с циклами заряда-разряда, перепадами температуры или общим качеством аккумулятора? У меня на старом ноутбуке, где стояло ограничение зарядки до 80% и который без зарядки я почти не использовал, за 4 года работы на нём по 8+ часов износ аккумулятора составил лишь 6%.

А на недорогом кнопочном телефоне (резервном) аккум. вздулся уже через год.

ЗЫ. Уверен, где-нибудь на Хабре найдётся статья, подробно объясняющая эту механику…

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

А локальные домены — ну это уже перебор (С)

Для доступа к агенту злоумышленнику как минимум потребуется пароль от моего компьютера)

Спасибо за комментарий!

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

Но моем случае при наступлении бас-фактора на помощь как раз llm wiki и придет. Ведь она хранит информацию о структуре сети, а также о моих действиях с ней!

Любой член моей семьи сможет задать вопрос агенту “а как получить доступ к роутеру” - и агент ответит. И поможет разобраться.

Так что бас-фактор учтён)

Официальная документация Microsoft явно транслирует, что при перечислении элементов порядок их возврата не определён, цитирую:

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey,TValue> structure representing a value and its key. The order in which the items are returned is undefined.

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

Огромное спасибо за подробный разбор!

ЗЫ. Правда, в production-приложениях на это завязываться все же опасно. Это внутренняя "кухня" .NET и она может измениться в любой момент. Та же реализация сортировки в .NET несколько раз переписывалась...

По второму пункту: а вы не могли бы подсказать откуда информация?

Я посмотрел в свежих исходниках .NET на github (тэг v10.0.0, файлы /src/libraries/System.Linq/src/System/Linq/ToCollection.cs и src/System/Collections/Generic/Dictionary.cs) - там словарь всё ещё работает на основе хэш-таблицы. И порядок добавления в неё элементов не будет сохраняться.

и чтобы гарантировать порядок написали тесты проверяющие сортировку переговорок

UPD: очень интересно как выглядит проверка сохранения порядка следования элементов в Dictionary.

Большое спасибо за статью! Правда некоторые моменты немного смущают.

  1. Не совсем обычно, что для оценки сложности вы используете θ-нотацию вместо более распространённой О. Цитирую:

Таким образом для θ(n) встреч всех участников получаем θ(n * log(n)) времени и θ(n) памяти, что почти не отличимо от линейной обработки по типу обычного маппинга.

Тета-оценка ограничивает время как сверху, так и снизу. Однако метод List.Sort, использованный в коде построения busyIntervals, может отработать и за линейное время - если последовательность частично (или полностью) отсортирована.
Поэтому тета-оценка, кажется, тут не очень применима.

  1. Финальный код тоже не совсем обычен:

return rooms.Where(room => roomsIntervals.ContainsKey(room.Email))
   .OrderBy(room => Math.Abs(userFloor.Value - room.GetFloorNumber()))
   .ToDictionary(room => room.Email, room => roomsIntervals[room.Email]);

Дело в том, что преобразование результата в Dictionary<K, V> по сути "уничтожит" сортировку по удалённости комнат с предыдущего шага.

И пара моментов по тексту статьи:

В параллелях генерируются GUIDы, что дает уникальность.

Вообще говоря, реализация метода Guid.NewGuid() зависит от операционной системы:

  • в Windows Guid создаётся силами native-библиотеки ole32.dll (метод CoCreateGuid) (исходный код .NET 9). На rsdn есть древняя статья, в которой препарировали реализацию CoCreateGuid того времени. И обнаружили там достаточно предсказуемые данные.

  • в Linux же Guid может создаться как через вызов криптографического генератора случайных чисел, так и обычного (снова исходный код .NET 9).

Вывод 1: считать сгенерированные данным кодом Guid-ы случайными можно только в определённом окружении.

Далее этот массив байт подвергается криптохэшированию, что дает полную непохожесть наборов байт (а исходные GUIDы похожи друг на друга, хоть и отличаются).

Любая функция хэширования обладает свойством детерминированности. То есть при передаче ей одного и того же значения она будет возвращать один и тот же результат. Посчитайте хоть один раз, хоть миллион любую функцию хэша от Guid.Parse("be6296a3-fc24-4f58-a450-a874a333f8cd") - результат всегда будет одним и тем же.

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

Вывод 2: реализованное хэширование не увеличит "случайность" в ваших исходных данных - поэтому его можно вообще удалить из кода.

UPD: увидел комментарий

SHA512 дает нужную максимальную длину итоговых строк.

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

Или сразу генерировать нужное количество байт через упомянутый выше System.Security.Cryptography.RandomNumberGenerator

Спасибо за статью!

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

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

Ой зря вы реальный токен бота оставили и в картинках, и в текстах...

Один из вариантов пути, которым автор мог прийти к текущему коду при изучении EF Core

  1. Загуглить как пользоваться EF Core - вылез бы overview

  2. Увидеть там ТОЧНО ТАКИЕ ЖЕ примеры с using-ом контекста. Использовать их и на их основе писать статью.

А теперь давайте сравним этот код - и код из примера в другом разделе Get started with ASP.NET Core MVC

Случайно заметим, что _context там создаётся не в начале метода - а в конструкторе контроллера.

И тут можно было бы попытаться начать искать информацию в чём разница, может быть вообще стоит один контекст на всё время работы программы сделать? Ищем информацию о времени жизни контекста - находим DbContext Lifetime, Configuration, and Initialization. Перепишем вывод из этой статьи - один контекст на один UnitOfWork...

Вот так, постепенно, и можно собрать информацию на статью - максимально полное описание.

Давайте всё же сделаем скидку на то, что это первая статья.

А я буду держать кулачки за то, чтобы автор продолжил свою работу по изучению интересных ему тем - и с каждым новым разом разборы получались чуть глубже ;)

Приветствую!

В целом пока что не сталкивались. Но как резервное средство всегда есть разметка HTML, которую можно встраивать в markdown-документы.

Информация

В рейтинге
295-й
Зарегистрирован
Активность

Специализация

Специалист
C#
.NET
Git