Доступен ли Linux DMA механизм копирования mem-to-mem для пользовательского пространства?

У меня есть приложение Linux, которое обычно (50-100 раз в секунду) должно запоминать несколько мегабайт (10+) данных. Часто это не проблема, но мы начали видеть доказательства того, что это может потреблять слишком много пропускной способности нашего процессора. Текущие измерения показывают, что мы перемещаемся примерно на 1 Гбайт / с.

Мне известно о возможностях dma в ядре, и я вижу небольшую документацию, в которой говорится о создании собственных драйверов для больших копий памяти, именно по этой причине .. Но похоже, что кто-то уже создал для этого общий API. Я ошибся? DMA - это функция только ядра?

Я должен уточнить, это для архитектуры Intel X86, а не встраиваемой.

5
Yeraze 10 Май 2014 в 15:05

2 ответа

Лучший ответ
  • API Linux для DMA не позволяет передавать память в память. Это только для связи между устройствами и памятью. За подробностями обращайтесь к Documentation/DMA-API.txt.

  • На аппаратном уровне контроллер DMA x86 не позволяет передавать память в память. Это обсуждалось здесь: DMA-перенос RAM-to-RAM

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

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

9
Community 23 Май 2017 в 12:10

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

Копирование при записи значительно сэкономит вам, если ваши данные настолько велики, что эти вызовы memcpy могут навредить:

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

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

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

#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

int main() {
  // Once:
  int fd = shm_open("/cowalloc", O_RDWR|O_CREAT, 0600);
  shm_unlink("/cowalloc");
  ftruncate(fd, 1024); // This is the size of the COW regiona
  char *master = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

  strcpy(master, "hello world, this is a demonstration of COW behaviour in Linux");

  // Per thread:
  char *thread = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE, fd, 0);

  // Demo
  printf("Master: %s\nThread: %s\n", master, thread);
  printf("\nChanging in thread:\n");
  strcpy(thread, "This is a private change");
  printf("Master: %s\nThread: %s\n", master, thread);

  return 0;
}

Основная идея здесь заключается в том, что вы выполняете всю глобальную настройку данных (предположительно, загрузку с диска / сети или вычисление) один раз с помощью MAP_SHARED. Затем вы можете снова вызвать mmap с тем же дескриптором файла, чтобы сделать дополнительные частные сопоставления для каждого из ваших потоков, которые, по вашему мнению, могут нуждаться в записи в локальную копию.

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

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

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

3
Flexo 11 Май 2014 в 20:18