Автор Тема: Работа с големи буфери в ядрото  (Прочетена 5291 пъти)

Lord Bad

  • Напреднали
  • *****
  • Публикации: 1667
  • Distribution: Fedora 13
  • Window Manager: GNOME
  • Jedi Knight
    • Профил
Здравейте!
Имам сериозен проблем и се нуждая от помощ. Проблема е следния - работя по драйвер който да заделя големи буфери от линейна памет в ядрото и после ги прехвърля в user space-a, където потребителска програма го обработва. За да заделя толкова голям буфер използвам следната техника:
Ако имам 32М оперативна памет стартирам Линукс с boot arg mem=30M, за да запазя от употреба от страна на ядрото(и евентуална фрагментация) последните 2М. После в драйвера правя следното нещо:
Примерен код

    volatile void *remapped;
    unsigned long trial_size = 0x100000; // 1MB

    printk(KERN_INFO "Allocator module was loaded successfully!\n");
    
    remapped = ioremap(0xA1E00000, trial_size);

    if (!remapped)
      return -1;
    
    printk(KERN_INFO "Allocator module mapped memory successfully!\n");


На този етап аз имам указател към 1М блок от памет, която мога да си правя каквото си искам. Остава само да мапна същия физически адрес и в user space-a и да изчета съдържанието на буфера. За съжаление нямам идея как мотова може да стане, а без такъв начин от техниката не би имало особен смисъл...
Активен

Fuelled by Fedora 13 "Goddard"
====================================
Rock it!

sdr

  • Напреднали
  • *****
  • Публикации: 655
    • Профил
Работа с големи буфери в ядрото
« Отговор #1 -: Aug 08, 2006, 17:44 »
Моята добрата стара механична памет ми подсказа
splice незнам дали има нещо общо с тебе и твоя проблем но друго просто не се сетих '<img'> а доколкото знам кернелмемори-то никога не се свапва и ако сам не си я фрагментираш няма как да се фрагментира та...



Активен

  • Гост
Работа с големи буфери в ядрото
« Отговор #2 -: Aug 08, 2006, 17:47 »
Ъъъъъм, това е интересен въпрос, всъщност не е невъзможно.

Да предадеш pointer към данни от кърнълспейс към юзърспейс-а и оттам да си ги четеш естествено няма да стане, поради ред причини, едната от които е, че от гледна точка на юзърския процес, адресът от указателя сочи към съвсем различно място във физическата памет (не виждам как при многозадачна операционна система нещата да не стоят така).

Да приемем, че юзърския процес има съответните привилегии (уид0), единият сигурен начин да направиш това  е чрез /dev/mem (/dev/kmem сигурно щеше да върши перфектна работа, ама тц, не става така от доста време насам)). Вероятно може да се спретне друг трик, но наистина нямам идея.

Друг е въпроса, че не е нужно (а и вероятно е малко грубо) трансфера на данни да става по такъв начин - иначе начини колкото искаш - примерно сокети, copy_to_user() - последното вероятно е точно това, което ти трябва.

Между другото, какъв драйвер разработваш, че ти трябват такива обеми данни? Просто ми стана интересно...
Активен

  • Гост
Работа с големи буфери в ядрото
« Отговор #3 -: Aug 08, 2006, 17:53 »
а, да не забравя че можеш и през procfs, стига да те удовлетворява и да имаш желание...
Активен

  • Гост
Работа с големи буфери в ядрото
« Отговор #4 -: Aug 08, 2006, 19:57 »
Аааа сега погледнах и примерния код, защо го правиш с ioremap(), а не с kmalloc(), ако си сигурен че така и с този адрес няма да имаш проблеми при x86, при други архитектури не е гаранция предполагам..

Със сигурност copy_to_user() в твоят вариант, за tee/splice нямам идея, предполагам и това  е вариант, поне в по-новите ядра.

Performance-a важен ли е? Тогава разните procfs/pipe/socket глупости могат да се окажат спънка предполагам..
Активен

Lord Bad

  • Напреднали
  • *****
  • Публикации: 1667
  • Distribution: Fedora 13
  • Window Manager: GNOME
  • Jedi Knight
    • Профил
Работа с големи буфери в ядрото
« Отговор #5 -: Aug 09, 2006, 09:46 »
Ами значи архитектурата не е x86 въобще, а е АRM(PXA255). По принцип в момента драйвера има работеща версия която е с copy_to_user, но заради ограниченията на функцията това вкарва сериозно забавяне на производителността. За какво точно става дума - имам аз един(даже 2) CMOS сензора които правят снимки с доста голяма скорост, пращят ги на един ДСП процесор, той ги обработва и ги праща на АРМ-а. Взехме решение тук че ако работим с един голям буфер вместо с много малки вероятно ще си увеличим производиелността по следния начин. Maр-ваме колкото памет ни трябва от тази на АРМ-а с ioremap, пишем там картинките и после вместо да копираме този голям буфер в user space да се опитаме да map-нем и от там същия физически адрес и прочетем направо съдържанието на него, което ефективно ще ни спести адски много копиране... Само дето там ударих на камък - мисля си по настоящем да се опитам да направя това с mmap и /dev/mem наистина, но ако някой има по-добра идея ще се радвам да я чуя...
Активен

Fuelled by Fedora 13 "Goddard"
====================================
Rock it!

  • Гост
Работа с големи буфери в ядрото
« Отговор #6 -: Aug 09, 2006, 10:29 »
Хм, доколкото знам uClinux вероятно ще е добър вариант - разработван е специално за разни embedded джаджи и няма paging и address separation, което предполагам означава, че съвсем спокойно би могло потребителския процес да адресира "чужда" памет, въпреки че никога не съм си играл с това и не гарантирам, просто съм чел. Не знам дали ще свърши работа точно във вашия случай, но се надявам.

Апропо, през /dev/mem няма да постигнеш някакво особено подобрение в скоростта според мен, защото се минава през достатъчно много "утежняващи" моменти и в крайна сметка нищо чудно с copy_to_user да върви по-бързо.
Активен

  • Гост
Работа с големи буфери в ядрото
« Отговор #7 -: Aug 09, 2006, 10:41 »
Между другото като отвориш /dev/mem и mmap-неш част от съдържанието му (подобно нещо прави X-a за да пише директно в някакъв регион от паметта, заради графиката) - трябва да се замислиш дали това не прави нещо подобно на copy_to_user() - т.е "експорт-натата" чрез /dev физическа памет просто се копира в регион от физическата памет, заделен от потребителския процес. Тъй като това се извършва в userspace вероятно дори ще е по-бавно. Поне според мен, не съм някакъв експерт по ядрата и драйверите, така че питай все пак някой, който се занимава изключително с това, може и да има  някакъв хитър номер, който да свърши работа.
Активен

sdr

  • Напреднали
  • *****
  • Публикации: 655
    • Профил
Работа с големи буфери в ядрото
« Отговор #8 -: Aug 09, 2006, 11:13 »
Защо не завъртите нещата: suer land-a да алокира памет и да я подаде на кернела той да я локне и да си маже по нея Така ми се струва че ще е по-лесно
Активен

  • Гост
Работа с големи буфери в ядрото
« Отговор #9 -: Aug 09, 2006, 11:38 »
Защото идеята е нещата да вървят в обратната посока - камерите capture-ват изображения, драйвера в ядрото ги изчита от някакъв абсолютен адрес във физическата памет и трябва по някакъв начин да ги подаде към приложенията, които работят с тях, т.е не е идеята приложенията да подават информация към ядрото, а то към хардуера, просто характера на хардуера е такъв, на камерите надали нещо се подава освен може би някакви команди за инициализация..
Активен

  • Гост
Работа с големи буфери в ядрото
« Отговор #10 -: Aug 09, 2006, 11:50 »
Уф чакай, не съм разбрал добре, съжалявам.

Проблемът е че това няма да изключи момента с копирането, а и кодът бая ще се утежни. Значи драйвера в ядрото ще трябва да знае къде точно се намира заделената от процеса памет - нещо което няма да е толкова лесно, защото трябва да се правят сметки, да се гледат разни алокатори и т.н глупости. Нямам много идея за АRМ архитектурата и дали там съществува понятието swapping, но ако malloc-натата памет от процеса по някакъв начин влезе в swap-а ще стане доста мътна и кървава. При което въпреки всичко накрая ще трябва да се изкопира  съдържанието на паметта от адрес 0xA1E00000 върху мястото където е заделената памет от процеса и няма да има особено подобрение.
Активен

Lord Bad

  • Напреднали
  • *****
  • Публикации: 1667
  • Distribution: Fedora 13
  • Window Manager: GNOME
  • Jedi Knight
    • Профил
Работа с големи буфери в ядрото
« Отговор #11 -: Aug 09, 2006, 12:51 »
Аз тука направих следните неща междудругото - набих един 16 байтов низ в буфера от драйвера в цикъл така че да се запълни целия буфер и след това реших да проверя дали ще имам достъп както си мислех до буфера през /dev/mem. За целта написах набързо следната програмка:

Примерен код

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

int main(void)
{
   int mem_fd, i;
   char test_string[] = "0123456789abcde";
   volatile void *mapped;

   if ((mem_fd = open("/dev/mem", O_RDONLY)) < 0) {
      printf("\n\nProblem in opening /dev/mem");
      exit(-1);
   }

   mapped = mmap(0, 0x100000, PROT_READ | PROT_WRITE, MAP_FIXED, mem_fd, 0xA1E00000);

   if (!mapped)
      return -1;

   printf("Mmap mapped memory successfully!\n");

      for (i = 0; i < 0x100000; i += 16) {
      printf("Current i is : %d\n", i);
      if (strncmp((char *)(mapped) + i, test_string, 16)) {
         printf("Compare failure, i = %d!\n", i);
         printf("mapped : %s\n", (char *)mapped);
         break;
      }
    }

    munmap(0, 0xA1E00000);

   return 0;
   
}


Само дето веднага като я пусна(като root разбира се) следва това:
Цитат
-bash-2.05b# ./readmem
Mmap mapped memory successfully!
Current i is : 0
Segmentation fault

Някакви идеи - в гугъл една хубава и изчерпателна статия не мога да намеря за /dev/mem, ако не измисля нещо друго ще пробвай след малко и read от /dev/mem...
Активен

Fuelled by Fedora 13 "Goddard"
====================================
Rock it!

  • Гост
Работа с големи буфери в ядрото
« Отговор #12 -: Aug 09, 2006, 13:55 »
А ако пробваш просто да четеш файла, без да го мап-ваш в паметта (lseek/read) какво се случва, пак ли сегфолтва?

Мисля че съм чел за някакви дивотии свързани с mmap-ване на /dev/mem и някакви региони от паметта дето били маркирани от ядрото по начин, който не позволявал да може да се мап-ват в паметта, но нямам идея, ще се разтърся в гугъл-а да проверя..
Активен

Lord Bad

  • Напреднали
  • *****
  • Публикации: 1667
  • Distribution: Fedora 13
  • Window Manager: GNOME
  • Jedi Knight
    • Профил
Работа с големи буфери в ядрото
« Отговор #13 -: Aug 09, 2006, 16:09 »
Ами да пак нещо гърми но поне няма seg fault:
Примерен код
   charp = (char *)malloc(16);
   lseek(mem_fd, 0xA1E00000, SEEK_CUR);
   ret = read(mem_fd, charp, 16);

   printf("Ret is %d\n", ret);
   printf("Charp is %s\n", charp);

Цитат
-bash-2.05b# ./readmem
Ret is -1
Charp is

А очакваните стойности за ret и charp са съответно 16 и 0123456789abcde... Мама му, почна да ми лази по нервите сериозно това...
Активен

Fuelled by Fedora 13 "Goddard"
====================================
Rock it!

  • Гост
Работа с големи буфери в ядрото
« Отговор #14 -: Aug 09, 2006, 16:32 »
Ми недей да се нервираш, дай да видим защо четенето се дъни...

Цитат

#include <errno.h>
int ern;
...
ret = read(mem_fd, charp, 16);
if (ret <0 ) {ern=errno;printf ("We have error#%d",ern);}
...


Може би ще помогне да разберем какво става, защо не иска да чете...
Активен