Перейти до основного вмісту

Модель пам’яті.

У Neat фреймворку середовище виконання обробляє велику кількість байтів — закодовані відеокадри, декодовані площини YUV, вхідні тензори FP32, квантовані тайли INT8, зображення для тимчасового зберігання MLA. Виконання цього без чітко визначеної моделі пам’яті означало б копіювання на кожному етапі. На цій сторінці пояснюється, як фреймворк уникає цих копіювань.

Трійка буферів: (buffer_id, paddr, vaddr)

Кожен буфер, з яким працює фреймворк, ідентифікується за трьома параметрами:

  • buffer_id — стабільне ціле число, яке використовується середовищем виконання для відстеження життєвого циклу буфера (кількість посилань, власність сегмента).
  • paddr — фізична адреса, яка використовується IOMMU для буфера. Апаратне забезпечення MLA / EV74 / DMA використовує цю адресу.
  • vaddr — віртуальна адреса, область пам’яті, доступна для програми. Процесор використовує цю адресу для доступу до даних.

Завдяки використанню потрійного буфера, до нього можна отримати доступ з будь-якої сторони (ЦП або прискорювач) без копіювання даних. Єдиний блок пам’яті з’являється в обох таблицях сторінок ядра (щоб програмне забезпечення могло його зчитувати) і таблицях сторінок IOMMU (щоб апаратне забезпечення могло здійснювати прямий доступ до пам’яті).

Під час передачі даних між етапами передається саме потрійний буфер, а не окремі байти.

Сегменти

Буфери створюються з іменованих сегментів. Сегмент — це суміжний регіон пам’яті, який підтримується певним алокатором (DMA-BUF, CMA, ION, звичайна купа) і містить метадані про те, хто має до нього доступ: лише ЦП, лише MLA, обидва, тощо. Під час виконання (runtime) обирається відповідний сегмент для кожного буфера, виходячи з того, які етапи обробки даних використовуватимуть його.

Приклади:

  • nv12_decode сегмент містить декодований YUV-потік із H.264, який може бути зчитаний процесором для діагностичних цілей і зчитаний IOMMU для вузла зміни розміру.
  • mla_input сегмент містить тесельований тензор, який передається в MLA — лише апаратне забезпечення MLA зчитує його; для доступу з боку ЦП потрібне явне відображення.
  • Сегмент model_output містить тензори FP32 після детеселяції — вони доступні для читання процесором, тому застосунок може їх отримати.

Tensor містить свій сегмент разом із потрійною структурою, тому фреймворк знає, чи є допустимим доступ до даних/зміна даних із коду, що виконується на ЦП.

Узгодженість кешу

MLA, EV74 і CPU мають власні кеші. Коли один модуль записує дані в буфер, а інший їх зчитує, система вставляє виклики для очищення/анулювання кешу на межі між модулями. Код програми не повинен про це турбуватися — це обробляється на рівні сегментів, коли буфери передаються між етапами.

Єдине місце, де код програми має враховувати це: під час відображення TensorBuffer для безпосереднього читання або запису даних процесором (CPU) за допомогою Mapping. Система вставляє відповідний виклик для анулювання (для читання) або очищення (для запису) під час видалення відображення. Див. MapMode та TensorBuffer::map().

Реалізація концепції «нульового копіювання» на практиці.

Типовий конвеєр для здійснення висновків:

file → demux → H.264 decode → resize → preproc → MLA → postproc → app

Без використання механізму «нульового копіювання» потрібно сім копій. Завдяки використанню потрійного буфера та сегментів, їх кількість зводиться до нуля — на кожному етапі передається (buffer_id, paddr, vaddr), і наступний етап працює безпосередньо з цими даними.

Планувальник у рамках системи відповідає за вибір сегментів таким чином, щоб послідовні етапи могли використовувати спільні дані. Якщо два сусідні етапи мають несумісні вимоги до сегментів, планувальник вставляє Transfer ConversionKind і фіксує це в активному ConversionTraceCollector. Зверніть увагу на це — це єдині місця, де фактично відбувається переміщення байтів у середовищі виконання.

Джерела зображень для камери та адаптивна пам’ять.

Кадри з камери надходять через стек платформи, тому тип їхньої пам’яті залежить від встановленого ядра, драйвера та шляху до libcamerasrc. CameraInput спочатку запитує пам’ять пристрою/SiMaAI без копіювання. Його приватний міст пропонує стандартний пул через GST_QUERY_ALLOCATION; пул виділяє перевірені площини з одного згорнутого виділення SiMaAI та експортує їх як DMA-буфери. libcamerasrc імпортує ці DMA-буфери в ISP, а міст розпаковує те саме згорнуте виділення для наступних етапів CVU/MLA.

Коли стек камери надає лише буфери OS/libcamera і ввімкнено allow_cpu_fallback, Neat вставляє приватний міст пам’яті камери. Міст копіює кожен кадр у пул SiMaAI, додає очікувані метадані та передає цей буфер для попередньої обробки CVU, керованої моделлю. Ця копія є мостом сумісності; зміна розміру, перетворення кольору, нормалізація, квантування та теселяція все ще повинні виконуватися на CVU/EV74.

Не додавайте загальнодоступний OsToSima, videoconvert або videoscale етап лише для того, щоб забезпечити роботу вхідного потоку з MIPI-камери. Використовуйте CameraInput і дозвольте шляху джерела керувати адаптацією пам’яті.

Пов’язані типи

  • TensorBuffer — контейнер, що містить трійку буферів.
  • Segment — дескриптор сегмента.
  • Mapping — дескриптор відображення RAII для безпосереднього доступу до ЦП.
  • MemoryContract — спосіб, яким вузол надає перевагу при розподілі пам’яті.
  • ConversionKind::Transfer — єдиний тип конвертації, який копіює дані між сегментами.

Для подальшого ознайомлення

  • «Тензори та буфери» — §0.10, §18, §19, §20 розділів детального аналізу проєкту.
  • «ABI TensorBuffer» — розділ 20 детального аналізу проєкту.