В интернете можно найти описание проблем, связанных с использованием DMA для стандартной функции копирования данных из памяти в память, например тут:

Linux – DMA memcpy operation in Linux

Давайте попробуем разобраться, как можно использовать интерфейс к DMA для реализации стандартной операции копирования memcpy и есть ли в этом смысл.

Реализация memcpy в Линуксе через обращение к DMA контроллеру могла бы выглядеть вот так:

void memcpyWithDma (u16* dest, u16* src, size_t len)
{
    dma_cookie_t cookie = dma_async_memcpy_buf_to_buf(chan, dest, src, len);

    while (dma_async_is_tx_complete(chan, cookie, NULL, NULL) == DMA_IN_PROGRESS)
    {
       dma_sync_wait(chan, cookie);
    }
}

Это описание: Linux – DMA memcpy operation in Linux начинается с демонстрации кода, в котором измеряется и логируется время исполнения реализации копирования с использованием DMA и время исполнения такого же копирования с помощью функции memcpy().

Вот этот код:

void foo ()
{
    int index = 0;
    dma_cookie_t cookie;
    size_t len = 0x20000;

    ktime_t start, end, end1, end2, end3;
    s64 actual_time;    

    u16* dest;
    u16* src;

    dest = kmalloc(len, GFP_KERNEL);
    src = kmalloc(len, GFP_KERNEL);

    for (index = 0; index < len/2; index++)
    {
        dest[index] = 0xAA55;
        src[index] = 0xDEAD;
    }

    start = ktime_get();
    cookie = dma_async_memcpy_buf_to_buf(chan, dest, src, len);

    while (dma_async_is_tx_complete(chan, cookie, NULL, NULL) == DMA_IN_PROGRESS)
    {
       dma_sync_wait(chan, cookie);
    }
    end = ktime_get();
    actual_time = ktime_to_ns(ktime_sub(end, start));
    printk("Time taken for function() execution     dma: %lld\n",(long long)actual_time);   

    memset(dest, 0 , len);

    start = ktime_get();
    memcpy(dest, src, len);

    end = ktime_get();
    actual_time = ktime_to_ns(ktime_sub(end, start));
    printk("Time taken for function() execution non-dma: %lld\n",(long long)actual_time);
}

Наша memcpyWithDma() это копия инлайн кода обращения к DMA из этого примера, оформленная как С-функция.

Вопросы

Автор этого кода удивляется:

  1. что время копирования с обращениями к DMA оказывается больше чем время копирования старым дедовским способом с помощью функции memcpy();

  2. просит подтвердить что это корректный способ использования DMA функциональности.

  3. интересуется тем какие есть методы измерения нагрузки на процессор (производительности)

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

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

Что же отвечает эксперт.

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

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

2. Тем не менее существует фундаментальная разница между методом копирования посредством DMA и стандартным методом, который реализован в функции memcpy(). Эта разница заключается в том, что DMA копирование не предполагает прямого увеличения производительности за счет простого ускорения копирования. Есть два аспекта которые определяют фундаментальную (принципиальную) разницу этих двух методов копирования:

a. Использование DMA не изменяет состояние кэша (при том, что при использовании обычного старого memcpy кэш заполняется адресами памяти, участвующей в копировании)

b. DMA копирование выполняется внешним аппаратным модулем - контроллером и процессор остается свободным во время такого копирования, и может выполнять код, который не имеет отношения к копированию, хотя в нашей реализации memcpyWithDma() мы ни как не используем эту возможность. У нас все-таки выполняется код который СВЯЗАН с текущим копированием самым непосредственным образом:

    while (dma_async_is_tx_complete(chan, cookie, NULL, NULL) == DMA_IN_PROGRESS)
    {
       dma_sync_wait(chan, cookie);
    }

Здесь мы просто ждем завершения операции, при этом вызов dma_sync_wait() на самом деле, все таки, сэкономит нам производительность при определенных условиях. Если приложение, в котором вызывается эта функция, является многопоточным(multithreaded), этот вызов деактивирует текущий поток(thread), который выполнил этот вызов, и позволит исполняться другим потокам приложения параллельно с текущей, инициированной здесь, операцией копирования данных. Таким образом, учитывать время после вызова функции dma_sync_wait() до возврата из нее, как время копирования не корректно с точки зрения измерения времени использования процессора, хотя это время конечно должно учитываться с точки зрения длительности копирования данных. То есть данные могут копироваться дольше, но при этом процессор фактически не будет занят во время копирования. Вообще говоря, это ставит перед разработчиком достаточно сложную дилемму, что предпочесть: реальную скорость копирования или возможность параллельной работы процессора во время копирования.

3. В этом пункте эксперт говорит, что: «Учитывая содержание подпункта (a) из предыдущего пункта, бессмысленно использовать операции DMA для чего-либо меньшего, чем размер кэша процессора, то есть десятков мегабайт. Обычно это делается для быстрой обработки потока вне ЦП, т.е. перемещения данных, которые в любом случае были бы произведены / потреблены внешними устройствами, такими как быстрые сетевые карты, оборудование для потоковой передачи / захвата / кодирования видео и т.д.» Честно говоря я бы не стал так безапеляционно увязывать использование DMA с параметрами кэша процессора, потому что существуют процессоры, которые не имеют кэша, но уже используют DMA. Наверно тут важно обратить внимание, на то, что DMA обычно используется в связке с каким-то внешним устройством или встроенным переферийным юнитом специальной функции процессора.

4. В этом пункте эксперт говорит о том, что некорректно сравнивать синхронные и асинхронные операции с точки зрения абсолютного и универсального времени. Время может оцениваться по-разному с точки зрения разных аспектов работы и/или использования разных компонент системы. Речь идет примерно о том же, о чем я написал выше в контексте того является ваше приложение многопоточным (multithreaded) или нет. Плюс эксперт указывает на то, что многопоточные системы вносят случайную ошибку при таком способе измерения, который используется в примере, так как переключение потоков происходит случайным образом с точки зрения пользователя системных функций.

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

6. Измерение "тиков" для современных процессоров также в некотором роде бессмысленно, указывает эксперт, хотя вы можете использовать инструменты конкретного производителя процессоров, такие как Intel VTune. Я бы добавил, что измерение «тиков» для современных процессоров бессмысленно до тех пор, пока вы не выяснили с какой точностью воспроизводятся ваши результаты. Иногда это сделать достаточно просто, достаточно лишь собрать статистику по нескольким измерениям.

7. "Использование операций копирования DMA на уровне приложения довольно бессмысленно – по крайней мере, я не могу придумать ни одного сценария, имеющего практический смысл, когда это стоило бы затраченных усилий" – по мнению эксперта, и я с ним здесь абсолютно согласен. "Это не обязательно быстрее, и, что более важно, я серьезно сомневаюсь, что узким местом производительности вашего приложения является копирование данных в памяти. Чтобы это было так, вы, как правило, должны делать все остальное быстрее, чем обычное копирование данных в памяти, и я действительно не могу придумать ничего на уровне приложения, что было бы быстрее, чем memcpy", ведь любая операция процессора так или иначе требует доступа к памяти, а значит является по определению боле сложной операцией чем тривиальное копирование. "И если мы говорим о взаимодействии с каким-либо другим устройством обработки данных вне центрального процессора, то это автоматически не уровень приложения", это уровень драйверов или уровень модулей ядра системы.

8. Как правило, производительность копирования данных в памяти (из одной физической локации памяти в другую физическую локацию) ограничена скоростью работы памяти, т.е. тактовой частотой и таймингами. Вы не получите никакого чудесного повышения производительности по сравнению с обычным memcpy хотя бы потому, что memcpy, выполняемый на процессоре, достаточно скоростной, поскольку процессор обычно работает с тактовой частотой в 3x-5x-10x выше, чем память (чем шина доступа к памяти).

9. Дополнительно стоит отметить что DMA работает с памятью напрямую, минуя подсистему MMU и кэш. Это требует специального способа выделения памяти который описан в предыдущей статье Выделение памяти для DMA в Linux, а если вы после копирования собираетесь использовать скопированные данные из памяти которую, до этого использовал или собирается использовать DMA контроллер вы должны выполнить какие-то аппаратно-зависимые функции для синхронизации данных в памяти, с данными, которые процессор или DMA контроллер будет читать из кэш памяти. Это могут быть функции подобные следующим:

void ResetDataCache(void* address, int len); чтобы кэш «забыл» адреса указанной области и при следующем обращении выполнил чтение из физической памяти

void WriteBackDataCache(void* address, int len); чтобы гарантированно сохранить данные из кэш памяти в физическую память в момент исполнения этой функции.

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

Выводы

Наверно главное, что нужно вынести из этой статьи, это то что теоретически аналог функции memcpy реализованный через DMA может существовать, но с практической точки зрения он будет уступать по эффективности старой доброй, можно сказать классической реализации memcpy. Более того, такая реализация на основе DMA накладывает ряд ограничений и/или требований на способ выделения памяти, способ использования памяти до и после копирования. Фактически такая реализация всегда будет оставаться аппаратно-зависимой и навсегда станет проблемой пользовательского приложения.

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

Комментарии (44)


  1. interprise
    17.01.2024 06:51
    +9

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

    PS сама тема интересная


    1. rukhi7 Автор
      17.01.2024 06:51

      ну, наверно можно задать автору какой-нибудь вопрос, попросить какие-то подробности чтобы это проверить.


      1. monah_tuk
        17.01.2024 06:51

        Эта тема для меня близка, но вот читать было тяжело.


        1. rukhi7 Автор
          17.01.2024 06:51

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

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


  1. mmMike
    17.01.2024 06:51
    +1

    Эксперт говорит, что вопрос или вопросы не совсем корректные

    Не то слово "некорректны".
    Использование DMA для копирования память-память - это совершенно не понятный случай.
    DMA - это, например, писать из регистра АЦП данные в память (или любое подобное).

    Так что, пунктом 0 я бы (хоть и не претендую на эксперта) сказал бы "чувак ты не для того используешь DMA и просто не понимаешь спрашиваешь и это видно по вопросам."

    А все остальные ответы "эксперта" вроде бы в целом верные, при этом весьма обтекаемые, и прямого отношения к вопросу "в чем концептуальное не понимание темы у спрашивающего" просто не имеют.

    while (dma_async_is_tx_complete(chan, cookie, NULL, NULL) == DMA_IN_PROGRESS)

    Ждать окончания DMA операции по опросу - это еще более странное решение (ну разве что для демонстрации..).

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

    Условность все это..
    Для отладки логики/железа (конкретного железа) можно и не оформлять ПО как драйвер ядра.
    Драйвер - это, в основном, скрыть фичи конкретной железяки за общим API. Это не всегда нужно в частных случаях.


    1. NutsUnderline
      17.01.2024 06:51

      "Ждать окончания DMA операции по опросу " не совсем - процессор в это время может "выполнять" другие задачи, ну или хотя бы обработчики прерываний. Но прерывания прекрасно могут проходить и при "традиционном" memcpy

      " писать из регистра АЦП данные " - есть большая вероятность того что автора данного материала так никогда не делал. Ну и вообще если судить по контексту то в коментарии рассуждения переходят от линуксов на что то более низкоуровневое.


      1. rukhi7 Автор
        17.01.2024 06:51
        +1

        Но прерывания прекрасно могут проходить и при "традиционном" memcpy

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


        1. Yuri0128
          17.01.2024 06:51

          DMA (ну я так думаю :)...) используют ту же шину для доступа к ОЗУ, что и для доступа к программному коду в ОЗУ. Тут (а в одноядерных (? какой) часто кэша нету) без кэша будет явное замедление (если DMA приоритет выше). С кэшем не влияет.


          1. rukhi7 Автор
            17.01.2024 06:51

            Кэш привязан не к шине, кэш привязан к типу операций, в процессоре четко различаются операции по доступу к памяти программ и к памяти данных даже если они идут через одну шину (а в АРМах например даже физические шины разные). Соответственно там два разных кэша физически, кеш данных, кэш инструкций.


            1. ptr128
              17.01.2024 06:51

              в АРМах например даже физические шины разные

              Любая программа и есть данные. Разные шины для разных видов памяти, но не разной информации. Я не встречал CPU, где при рефлексии необходимо было копировать память, а не просто передать управление на неё.


              1. Yuri0128
                17.01.2024 06:51

                Думаю, что руки7 несколько неточно выразились или просто не поняли шинную структуру, скажем того же АРМ. Ибо в ARM7 фон Неймановская архитектура..... Такие вот дела.


                1. ptr128
                  17.01.2024 06:51

                  Так даже в случае Гарвардской архитектуры, например, в AVR, все равно есть возможность выполнять код из RAM.

                  Другое дело, что в Cortex-M7 есть Гарвардская архитектура кеша, с раздельными кешами для инструкций и данных. Но в дополнении к этому есть две области кеша, выделенные для доступа, как к данным, так и к инструкциям, что позволяет избежать копирования при рефлексии. Строго говоря, загрузка кода из внешнего устройства (например, флеш-карты) в память - это уже рефлексия, так как то, что было данными, в результате обработки загрузчиком превращается в исполняемый код.


                  1. Yuri0128
                    17.01.2024 06:51

                    Ну, вы упоминали все-же ARM, где до ARM9 была фон Неймановская. Ну и наличие MMU в тех-же Cortex никто не отменял.И данные в ОЗУ вдруг становятся потоком команд, если их запрашивает дешифратор (через кеш, кстати). Вот TCM там разный для данных и программ, - это да. Ну и M7 - все-же для embending-а.


                  1. rukhi7 Автор
                    17.01.2024 06:51

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

                    call func;

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

                    сохраняет текущий адрес в стек в памяти данных,

                    это не зависит от того какая у нас Гарвардская архитектура или Парижская или какая другая.

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


                    1. ptr128
                      17.01.2024 06:51

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

                      А я писал о рефлексии. И тут уже грань между данными и кодом оказывается полностью стерта. И для ее поддержки даже чисто Гарвардской архитектуры CPU поддерживают частично Фон-Неймановскую.

                      или Парижская

                      Впервые о такой слышу. Дайте ссылку на описание.


                      1. rukhi7 Автор
                        17.01.2024 06:51

                        или Парижская

                        вы совершенно правильно поняли, "Парижская архитектура" - это архитектура которой нет или "пока нет", то есть я хотел подчеркнуть, что то, что я там написал справедливо даже для архитектуры, которой "пока нет".

                        Указатель - это данные

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

                        И также про указатель, для кого-то указатель это данные, а для кого-то это адрес, по которому лежат какие-то данные.


                      1. ptr128
                        17.01.2024 06:51

                        "Парижская архитектура" - это архитектура которой нет или "пока нет", то есть я хотел подчеркнуть, что то, что я там написал справедливо даже для архитектуры, которой "пока нет".

                        Это называется подмена понятия, и является ключевым признаком демагогии.

                        по моему, это все таки зависит от контекста,

                        Еще раз повторю то, что Вы принципиально игнорируете: РЕФЛЕКСИЯ! Для CPU один и тот адрес в памяти с одним и тем же содержимым может быть как данными, так и кодом.


                      1. rukhi7 Автор
                        17.01.2024 06:51

                        Еще раз повторю то, что Вы принципиально игнорируете: РЕФЛЕКСИЯ! Для CPU один и тот адрес в памяти с одним и тем же содержимым может быть как данными, так и кодом.

                        я не игнорирую, я в общем-то согласен, поэтому не очень понимаю что тут обсуждать.

                        Единственное я бы не сужал так понимание о рефлексии, потому что оно все-таки гораздо шире, как мне кажется, и наверно не только мне:

                        Рефлексия (программирование)


                      1. ptr128
                        17.01.2024 06:51
                        -1

                        поэтому не очень понимаю что тут обсуждать

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

                        Где я сужаю? Я даже расширяю, по сравнению с Википедией, считая, что обработка исполняемого файла загрузчиком - тоже рефлексия. А уж мой любимый динамический SQL, CompileToAssembly в C# или запуск кода из RAM на AVR - это вообще классика.


                      1. rukhi7 Автор
                        17.01.2024 06:51
                        +1

                        запуск кода из RAM на AVR - это вообще классика.

                        честно говоря я такой возможности не помню, чтобы на AVR можно было выполнять код из РАМ, но мне такое не требовалось. Наверно я что-то пропустил.

                        Но то что в AVR ассемблере есть инструкция

                        LPM (Load from Program Memory)

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


                      1. ptr128
                        17.01.2024 06:51

                        чтобы на AVR можно было выполнять код из РАМ, но мне такое не требовалось. Наверно я что-то пропустил.

                        В AVR8 такой возможности не было. Она появилась в AVR32

                        Ну а для STM8L исполнение кода из RAM - вообще необходимость, так как в low power run mode иначе не попасть (4.7.1).


                      1. rukhi7 Автор
                        17.01.2024 06:51

                        Ну а для STM8L исполнение кода из RAM - вообще необходимость, так как в low power run mode иначе не попасть

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

                        У меня много раз возникало такое состояние! Я, собственно, и статьи писать начал поэтому. Кроме рефлексии еще есть двойственность как в квантовой физике, эфекты наблюдателя, замена рекурсии простым циклом, INonDelegatingUnknown, ... Разные еще есть супер-хитрые хитрости, осознание которых вдохновляет.

                        Вот здесь вот:

                        RTOS или не RTOS вот в чем вопрос 2, или Windows тоже RTOS?

                        например, я нашел то что мне тоже показалось проявлениями рефлексии.


                      1. Yuri0128
                        17.01.2024 06:51

                        вот это я понимаю, понимаю так: однажды увидев такую супер-хитрую, но красивую штуку, хочется разделить с кем-то свой восторг от этой интелектуальной красоты,

                        Так там это штатный метод минимизации потребления для батарейных устройств. Вполне себе описан в дейташите.


                      1. rukhi7 Автор
                        17.01.2024 06:51

                        Вполне себе описан в дейташите.

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


                      1. Yuri0128
                        17.01.2024 06:51

                        Ну а для STM8L исполнение кода из RAM

                        только прерываний тама нету..... В LPR


                    1. Yuri0128
                      17.01.2024 06:51

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

                      Точно? А, простите-извините, вы писали на ассемблере? Ибо у "абстрактного процессора" текущий программный счетчик пушится в стек а в него загружается адрес вызываемой подпрограммы. Где вы увидели указатель (или вы считаете програмный счетчик указателем? Что в какой-то мере правда, хотя это чисто регистр АЛУ).

                      И по "Парижской" - а раскажите, мне ну очень интересно.


            1. Yuri0128
              17.01.2024 06:51

              Кеш привязан к шине (в зависимости от архитектуры могут быть 2 и больше), шина(ы) привязана(ы) к шине ОЗУ. Шина ОЗУ одна. Есть, правда, двухпортовое ОЗУ, но малоиспользуемое в качестве основной. Шина DMA тоже привязана к шине памяти. Так что пофиг, все равно упираемся в доступ к шине ОЗУ. И с кешем (в пределах до половины думаю) при копировании будет 1 цикл доступа (и впотом фоновое копрование) и при работе DMA - 2 цикла и + необходимость обновления кеша. В процах без кеша сильно не так. Я чуток подетальнее пояснил свою точку зрения ибо ну нифига не понял сообщение руки7.


              1. rukhi7 Автор
                17.01.2024 06:51

                вот здесь вот можно схему с шинами посмотреть, для примера:

                Какие бывают Cortex-M7 ARM-ы, периферия, шины, память, … DMA

                я по ней работал, в том числе, если что.


                1. Yuri0128
                  17.01.2024 06:51

                  Ну... Я как-бы embender иногда.... В основном stm32**** , CortexM0/M0+/M1 реже CortexM3/M4, сейчас уже и M7. Сейчас RISC-V добавляю.


      1. RichardMerlock
        17.01.2024 06:51

        Может на STM32 делал. Авторы они такие...


      1. Sap_ru
        17.01.2024 06:51

        Но DMA в хорошо авария круто нагружает шину процессора. Плюс данные из кэша вымываются. И сам кэш тоже прилично нагружается. В результате смысла особого в этом нет.


    1. ptr128
      17.01.2024 06:51

      Использование DMA для копирования память-память - это совершенно не понятный случай. DMA - это, например, писать из регистра АЦП данные в память (или любое подобное).

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

      Отдельная история с ссNUMA, где, по сути, DMA операции инициируются аппаратно и для программы прозрачны.


      1. mmMike
        17.01.2024 06:51

        Оба CPU все равно работают с одним адресным пространством.
        Конечно можно придумать частный случай когда это понадобится (копирование памяти).

        Но в пример (на основе чего статья основана) - это точно "сову на глобус".


        1. ptr128
          17.01.2024 06:51

          Оба CPU все равно работают с одним адресным пространством.

          Пространство одно, но физически память у CPU разная (NUMA). Именно поэтому я и указал, что в: "ссNUMA, по сути, DMA операции инициируются аппаратно". То есть, там уже пошли через DMA, не загружая такими пересылками CPU.

          Ну и в случае CoW у нас наоборот. До записи в страницу виртуальные адреса страницы разные, а физически страница одна. Она будет скопирована только при попытке записи в неё. И если её не было в кеше CPU, то грузить её в кеш не имеет никакого смысла, раз все равно запись пойдет в скопированную страницу.


    1. rukhi7 Автор
      17.01.2024 06:51

      Использование DMA для копирования память-память - это совершенно не понятный случай.

      я хорошо помню что когда начал разбираться с конкретным DMA в конкретном АРМ-е, я начал с того что сделал копирование из памяти в память чтобы проверить, что я все правильно понял в настройках контроллера ДМА и данные действительно копируются.

      Потом есть некоторые девайсы которые сразу пишут в память, а не в регистры, чтобы выгребать эти данные вовремя, может понадобиться копирование память-память. Насколько я помню у нас в АРМе Ethernet контроллер имеет свое встроенное ДМА, он сразу пишет пакеты в ОЗУ. Ему может понадобиться внешнее ДМА чтобы расширить буферизацию, что-ли, хотя тоже натянутый пример получился,

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


    1. VBKesha
      17.01.2024 06:51
      +1

      Использование DMA для копирования память-память - это совершенно не понятный случай.

      Не всё итак однозначно. У меня был случай когда это был вполне понятный случай. Есть система на FPGA которая занимается вводом/выводом видео с разных хитрых интерфейсов. Одна из возможностей системы делать скриншоты. Для этого надо просто из куска памяти куда складываются видеодананные, скопировать эти самые данные в другой кусок, откуда их уже можно по медленному интерфейсу долго и мучительно пересылать дальше. Там вот процессор которые реализован в FPGA с этим ну никак не справится, а DMA память-память справляется ну отлично.


    1. Yuri0128
      17.01.2024 06:51

      Использование DMA для копирования память-память - это совершенно не понятный случай.

      Ну, а другие пользуют, хотя вам и не понятный. Пример: копирование данных из област данных приемного USB буфера в буфер для передачи по USART (буфер освобожден будет явно быстрее а проц при этом что-то другое сделает).

      Ждать окончания DMA операции по опросу

      тут согласен, - есть легкий идиотизм. Хотя он тут асинк, то есть проц переключится на обработку других потоков.


  1. NutsUnderline
    17.01.2024 06:51

    Ну и вообще так, если DMA не ускоряет то это означает что испортили хорошую вещь. По сути это аппаратно реализованный поток узко заточенный под копирование блоков данных, да еще без оверхеда на всякие сохранения стэка. Только надо продумать цепочку обработки. На микропроцессорных контроллерах это может быть прямо таки панацеей. Не говоря уж о старых добрых процах типа z80 где копирование блока данных было отдельным исскуством, просчитываемого до такта процессора


  1. Indemsys
    17.01.2024 06:51
    +1

    Тут нельзя забывать что шина DMA в SoC-ах обычно одна на всех. И её пытаются использовать одновременно многие - файловая система, системные шины типа I3C, PCI , мелкая периферия типа SPI, I2C, UART-ы, SDIO, дисплей проч.

    И разные потоки DMA имеют приоритеты.

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

    Кстати DMA могут сбоить с быстрой периферией и периферией без FIFO (об этом отдельно пишется в errata-х) и отладка надежного DMA особо сложный вопрос в разработке драйверов. Поэтому любая пересылка по DMA должна быть готова повторить или возобновить DMA в случае отказа или конфликта с другой периферией.


  1. vk6677
    17.01.2024 06:51
    +3

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


    1. Indemsys
      17.01.2024 06:51

      Логично предположить, что операционка жестко резервирует один канал DMA для юзера.
      Этот единственный канал используется всякий раз когда вызывается функция dma_async_memcpy_buf_to_buf

      Скорее всего у канала самый низкий приоритет и вызов функции dma_async_memcpy_buf_to_buf вызывает постановку запроса в очередь на DMA и ожидание в очереди. Т.е. очень затратный по времени процесс. Такой DMA может быть оправдан только если речь идет о мегабайтах пересылаемой информации.


  1. Hanabishi
    17.01.2024 06:51

    Тут нечего особо думать. Аппаратная реализация DMA и IOMMU может кардинально различаться у разных систем. И если у вас не embedded или вы не пишете под конкретную платформу/железку - просто забудьте. Оставьте эти оптимизации писателям драйверов.

    Та же реализация memcpy вполне может под капотом использовать DMA, где это действительно нужно. Люди, занимающиеся сопровождением платформ, ядра и драйверов, лучше вас знают где и что использовать.

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


  1. Paulus
    17.01.2024 06:51

    Как-то ни о чём статья.

    Можно? Да, можно.

    Нужно? От железа зависит. Помню программировал на старых AXIS чипах, так там DMA каналы повсюду можно было использовать, не только как ext<->RAM, но и как RAM<->RAM тоже. Примеры и рекомендации, когда такой memcpy лучше, были сразу в документации.


    1. Yuri0128
      17.01.2024 06:51

      старых AXIS чипах

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