Доступ к памяти после ioremap очень медленный - PullRequest
3 голосов
/ 15 декабря 2010

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

Я резервирую память во время загрузки, используя параметр ядра memmap=2G$1G. Затем, в функции __init драйвера, я ioremap часть этой памяти, и инициализировать ее для известного значения. Я также ввел некоторый код для измерения времени:

#define RESERVED_REGION_SIZE    (1 * 1024 * 1024 * 1024)   // 1GB
#define RESERVED_REGION_OFFSET  (1 * 1024 * 1024 * 1024)   // 1GB

static int __init memdrv_init(void)
{
    struct timeval t1, t2;
    printk(KERN_INFO "[memdriver] init\n");

    // Remap reserved physical memory (that we grabbed at boot time)
    do_gettimeofday( &t1 );
    reservedBlock = ioremap( RESERVED_REGION_OFFSET, RESERVED_REGION_SIZE );
    do_gettimeofday( &t2 );
    printk( KERN_ERR "[memdriver] ioremap() took %d usec\n", usec_diff( &t2, &t1 ) );

    // Set the memory to a known value
    do_gettimeofday( &t1 );
    memset( reservedBlock, 0xAB, RESERVED_REGION_SIZE );
    do_gettimeofday( &t2 );
    printk( KERN_ERR "[memdriver] memset() took %d usec\n", usec_diff( &t2, &t1 ) );

    // Register the character device
    ...

    return 0;
}

Я загружаю драйвер и проверяю dmesg. Сообщает:

[memdriver] init
[memdriver] ioremap() took 76268 usec
[memdriver] memset() took 12622779 usec

Это 12,6 секунды для memset. Это означает, что memset работает со скоростью 81 МБ / с . С какой стати это так медленно?

Это ядро ​​2.6.34 в Fedora 13 и система x86_64.

EDIT:

Цель этой схемы - взять часть физической памяти и сделать ее доступной как для устройства PCI (через шину / физический адрес памяти), так и для приложения в пространстве пользователя (через вызов mmap, поддерживаемый водитель). Устройство PCI будет постоянно заполнять эту память данными, а приложение из пользовательского пространства будет их считывать. Если ioremap - плохой способ сделать это (как предложил Бен ниже), я открыт для других предложений, которые позволят мне получить любой большой кусок памяти, к которому могут напрямую обращаться как аппаратные, так и программные средства. Я, вероятно, также могу обойтись меньшим буфером.


См. Мое возможное решение ниже.

Ответы [ 4 ]

4 голосов
/ 15 декабря 2010

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

Вы, вероятно, хотите kmalloc или vmalloc. обычный справочный материал материалы объяснят возможности каждого из них.

2 голосов
/ 15 декабря 2010

Я не думаю, что ioremap() это то, что вы хотите там.Вы должны получать доступ только к результату (то, что вы называете reservedBlock) с помощью readb, readl, writeb, memcpy_toio и т. Д. Даже не гарантируется, что возврат фактически сопоставлен (хотя он, очевидно, находится наПлатформа).Я предполагаю, что регион отображается без кэширования (подходит для регистров ввода-вывода), что приводит к ужасной производительности.

1 голос
/ 17 октября 2012

Я попытался сделать огромные резервы памяти с помощью memmap

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

при запросе резервирования 128 ГБ памяти, начиная с 64 ГБ. вы видите следующее в / proc / vmallocinfo

0xffffc9001f3a8000-0xffffc9201f3a9000 137438957568 0xffffffffa00831c9 phys=1000000000 ioremap

Таким образом, адресное пространство начинается с 0xffffc9001f3a8000 (который слишком велик).

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

Итак, затраченное время связано в основном с преобразованием адресного пространства и загрузкой не кешируемой страницы.

1 голос
/ 29 марта 2012

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

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

...