Главная страница


ru.linux

 
 - RU.LINUX ---------------------------------------------------------------------
 From : Andrey Rudyavsky                     2:5030/163.28  31 May 2002  12:37:42
 To : Konstantin Tereschenko
 Subject : Эффективна ли pабота с памятью в Linux?
 -------------------------------------------------------------------------------- 
 
 
 29 May 30 13:27, Konstantin Tereschenko wrote to All:
 
  KT> 3. Hасколько вообще эффективна pабота с памятью в Linux?
 
 === Cut ===
                         Как Linux работает с памятью
 
 Случилось мне однажды поинтересоваться как же ядро работает с самым дорогим
 что у него есть, с памятью. Первые попытки  разобраться с налету что и как
 ни к чему не привели. е все так просто как хотелось бы. Отовсюду торчат
 концы, вроде все ясно, но как связать их воедино...
 
 Возникла мысль обратиться к прошлому , чтобы по крайней мере разобраться
 как все это развивалось (версия 0.1). Это помогло понять и современное
 ядро. В дальнейшем речь пойдет о ядрах серии 2.2 об изменениях в 2.4 будет
 сообщено особо.
 
 е буду углубляться в тонкости функционирования защищенного режима
 процессора об этом написаны целые фолианты. Посмотрим только самую суть.
 
 Итак, в овнове всего лежат страницы памяти. В ядре они описываются
 структурой mem_map_t.
 
 typedef struct page {
         /* these must be first (free area handling) */
         struct page *next;
         struct page *prev;
         struct inode *inode;
         unsigned long offset;
         struct page *next_hash;
         atomic_t count;
         unsigned long flags;    /* atomic flags, some possibly updated
 asynchronously */
         struct wait_queue *wait;
         struct page **pprev_hash;
         struct buffer_head * buffers;
 } mem_map_t;
 
 Уже тут наблюдается навороченность. Множество всяких ссылок. Все они
 используются . Одна страница может находиться в разных списках , например и
 всписке страниц в страничном кеше и в списке страниц относящихся к
 отображенному в память файлу (inode).В структуре описывающей последний
 можно найти и обратную ссылку,что очень удобно.
 
 Все страницы адресуются глобальным указателем mem_map
 
 mem_map_t * mem_map
 
 Адресация страниц порисходит очень хитро. Если раньше в структуре  page
 было отдельное поле указывающее на физический адрес (map_nr), то теперь он
 вычисляется
 
 static inline unsigned long page_address(struct page * page)
 {
         return PAGE_OFFSET + PAGE_SIZE * (page - mem_map);
 }
 
 Свободные страницы  хранятся в особой структуре free_area
 
 static struct free_area_struct free_area[NR_MEM_TYPES][NR_MEM_LISTS];
 
 , где первое поле отвечает за тип области : Ядра, Пользователя, DMA и.т.д.
 И обрабатываются по очень хитрому алгоритму.
 
 Страницы делятся на свободные непрерывные обрасти размера 2 в степени x
 умноженной на размер страницы ( (2^x)*PAGE_SIZE ). Области одного размера
 лежат в одной области массива.
 
 ....
 |------
 |Свободные Страницы размера PAGE_SIZE*4 ---> список свободных областей
 |------
 |Свободные Страницы размера PAGE_SIZE*2 ---> список свободных областей
 |------
 |Свободные Страницы размера PAGE_SIZE  ---> список свободных областей
 |------
 
 Выделяет страницу функция get_free_pages(order).  Она выделяет  страницы
 составляющие область размера PAGE_SIZE*(2^order). Ищется область
 соответствующего размера или больше. Если есть только область большего
 размера то она делится  на несколько маленьких и берется нужный кусок. Если
 свободных страниц недостаточно, то некоторые будут сброшены в область
 подкачки и процесс выделенения начнется снова.
 
 Возвращает страницу функция free_pages(struct page, order). Высвобождает
 страницы начинающиеся с page размера PAGE_SIZE*(2^order). Область
 возвращается в массив свободных обрастей  в соответствующую позицию и после
 этого происходит попытка объединить несколько областей для создания одной
 большего размера.
 
 Отсутствие страницы в памяти обрабатыватся ядром особо.  Страница может или
 вообще отсутствовать или находиться в области подкачки.
 
 Вот собственно и вся базовая работа с реальными страницами.Самое время
 вспомнить, что процесс работает все-каки с виртуальными адресами, а не с
 физическими. Преобразование происходит посредством вичислений, используя
 таблицы дескрипторов, и каталоги таблиц. Linux поддерживает 3 уровня
 таблиц: каталог таблиц первого уровня (PGD - Page Table Directory),каталог
 таблиц второго уровня (PMD - Medium Page Table Diractory), и наконец
 таблица дескрипторов (PTE - Page Table Entry). Реально конкректным
 процессором могут поддерживаться не все уровни, но запас позволяет
 поддерживать больше возможных архитектур (Intel имеет 2 уровня таблиц, а
 Alpha - целых 3 ). Преобразование виртуального адреса в физический
 происходит соответственно в 3 этапа. Берется указатель PGD, имеющийся в
 структуре описывающий каждый процесс, преобразуется в указатель записи PMD,
 а последний преобразуется в указатель в таблице дескрипторов PTE. И наконец
 к реальному адресу указывающему на начало страницы прибавляют смещение от
 ее начала.
 
         page_dir = pgd_offset(vma->vm_mm, address);
         if (pgd_none(*page_dir))
                 return;
         if (pgd_bad(*page_dir)) {
                 printk("bad page table directory entry %p:[%lx]\n",
 page_dir, pgd_val(*page_dir));
                 pgd_clear(page_dir);
                 return;
         }
         page_middle = pmd_offset(page_dir, address);
         if (pmd_none(*page_middle))
                 return;
         if (pmd_bad(*page_middle)) {
                 printk("bad page table directory entry %p:[%lx]\n",
 page_dir, pgd_val(*page_dir));
                 pmd_clear(page_middle);
                 return;
         }
         page_table = pte_offset(page_middle, address);
 
 Вообще-то все данные об используемой процессом памяти помещаются в
 структуре mm_struct
 
 struct mm_struct {
         struct vm_area_struct *mmap;            /* Список отображенных
 областей  */
         struct vm_area_struct *mmap_avl;        /* Те же области но уже в
 виде дерева для более быстрого поиска*/
         struct vm_area_struct *mmap_cache;      /* Последняя найденная
 область*/
         pgd_t * pgd;
 /*Каталог таблиц*/
         atomic_t count;
         int map_count;                          /* Количество областей*/
         struct semaphore mmap_sem;
         unsigned long context;
         unsigned long start_code, end_code, start_data, end_data;
         unsigned long start_brk, brk, start_stack;
         unsigned long arg_start, arg_end, env_start, env_end;
         unsigned long rss, total_vm, locked_vm;
         unsigned long def_flags;
         unsigned long cpu_vm_mask;
         unsigned long swap_cnt; /* number of pages to swap on next pass */
         unsigned long swap_address;
         /*
          * This is an architecture-specific pointer: the portable
          * part of Linux does not know about any segments.
          */
         void * segments;
 };
 Сразу замечаем, что помимо вполне понятных указателей на начало данных
 (start_code, end_code ...) кода и стека есть указатели на данные
 отображенных файлов (mmap). Это надо сказать особенность Linux - тащить в
 себя все что только можно. Может быть это и хорошо, но с другой стороны так
 разбазариваться памятью (вспомним еще буфера ввода/вывода при файловой
 системе, которые тоже будут кушать все новую память пока она есть) Данный
 подход может негативно отразиться на стабильности системы, ведь для запуска
 какого-то жизненно необходимого процесса может потребоваться время на
 освобождение лишних кешей. Простенькая проверка на потерю свободной памяти:
 введите команду "cat /dev/mem >/image " и посмотрите сколько свободной
 памяти после этого осталось. Если вам это не нравится, то обратите взгляд
 на функцию invalidate_inode_pages(* struct_inode), освобождающую страничный
 кэш для данного файла.
 При любом открытии файла, он сразу же отображается в память и добавляется в
 страничный кэш. Реальный же запрос на отображение файла только возвращает
 адрес на уже скешированные страницы.
 а уровне процесса работа может вестить как со страницами напямую, так и
 через абстрактную структуру vm_area_struct
 struct vm_area_struct {
         struct mm_struct * vm_mm;       /* VM area parameters */
         unsigned long vm_start;
         unsigned long vm_end;
 
         /* linked list of VM areas per task, sorted by address */
         struct vm_area_struct *vm_next;
 
         pgprot_t vm_page_prot;
         unsigned short vm_flags;
 
         /* AVL tree of VM areas per task, sorted by address */
         short vm_avl_height;
         struct vm_area_struct * vm_avl_left;
         struct vm_area_struct * vm_avl_right;
 
         /* For areas with inode, the list inode->i_mmap, for shm areas,
          * the list of attaches, otherwise unused.
          */
         struct vm_area_struct *vm_next_share;
         struct vm_area_struct **vm_pprev_share;
 
         struct vm_operations_struct * vm_ops;
         unsigned long vm_offset;
         struct file * vm_file;
         unsigned long vm_pte;                   /* shared mem */
 };
 
 struct vm_operations_struct {
         void (*open)(struct vm_area_struct * area);
         void (*close)(struct vm_area_struct * area);
         void (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
         void (*protect)(struct vm_area_struct *area, unsigned long, size_t,
 unsigned int newprot);
         int (*sync)(struct vm_area_struct *area, unsigned long, size_t,
 unsigned int flags);
         void (*advise)(struct vm_area_struct *area, unsigned long, size_t,
 unsigned int advise);
         unsigned long (*nopage)(struct vm_area_struct * area, unsigned long
 address, int write_access);
         unsigned long (*wppage)(struct vm_area_struct * area, unsigned long
 address,
                 unsigned long page);
         int (*swapout)(struct vm_area_struct *, struct page *);
         pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned
 long);
 };
 
 Идея данной структуры возникла из идеи виртуальной файловой системы,
 поэтому все операции над виртуальными областями абстрактны и могут быть
 специфичными для разных типов памяти, например при отображении файлов
 операции чтения одни а при отображении памяти (через файл /dev/mem )
 совершенно другие. Первоначально vm_area_struct появилась для обеспечения
 нужд отображения, но постепенно распространяется и на другие области.
 
 Что делать, когда требуется получить новую область памяти. Есть целых 3
 способа.
 
 1. Уже знакомый get_free_page()
 2. kmalloc - Простенькая (по возможностям, но отнюдь не коду) процедура с
 большими ограничениями по выделению новых областей и по их размеру.
 3. vmalloc - Мощная процедура, работающая с виртуальной памятью, может
 выделять большие объемы памяти.
 
 С каждой из двух процедур в ядре связаны еще по списку свободных/занятых
 областей, что еще больше усложняет понимание работы с памятью. (vmlist
 для    vmalloc, kmem_cash для kmalloc)
 
 Что же в 2.4.
 
 Добавлена поддержка новой архитектуры памяти NUMA. В противовес
 классической UMA память делится на зоны с разным временем доступа к каждой
 из них . Это очень полезно и для кластерных решений. В связи с этим
 появились новые обертки на функции и найти суть стало еще сложнее.
 Появилась также поддержка памяти до 64Гб.
 Раньше для всех  файловых систем был один generic_file_read и
 generic_file_mmap в связи с тотальным засасыванием всего подряд в память
 при чтении (различия делались уже только на уровне inode->readpage). Теперь
 появился и generic_file_write. В общем еще пара таких generic и прощай
 виртуальная файловая система.
 
 о посмотрим - увидим. Ведь Linux развивается очень быстро и не всегда
 предсказуемо.
 Stanislav Ievlev.
 === Cut ===
 
  KT>  + Origin: -=Easy Fido=- (2:5061/5.34)
 
      Всего наилучшего!(Whole Best!)    Andrey
 
 --- GoldED/2 3.0.1
  * Origin: -> Back A. G. <- (2:5030/163.28,/1082.48,/269.30) (2:5030/163.28)
 
 

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

 Тема:    Автор:    Дата:  
 Эффективна ли pабота с памятью в Linux?   Konstantin Tereschenko   29 May 2002 13:27:42 
 Re: Эффективна ли pабота с памятью в Linux?   Ilya Anfimov   30 May 2002 11:53:06 
 Эффективна ли pабота с памятью в Linux?   Konstantin Tereschenko   31 May 2001 15:00:02 
 Re: Эффективна ли pабота с памятью в Linux?   Vladimir Bormotov   03 Jun 2002 10:38:56 
 Эффективна ли pабота с памятью в Linux?   Konstantin Tereschenko   04 Jun 2001 13:36:27 
 Re: Эффективна ли pабота с памятью в Linux?   Vladimir Bormotov   05 Jun 2002 12:37:54 
 Re: Эффективна ли pабота с памятью в Linux?   Ilya Anfimov   03 Jun 2002 15:27:51 
 Эффективна ли pабота с памятью в Linux?   Gennady Krasnoshlyk   30 May 2002 11:41:40 
 Re: Эффективна ли pабота с памятью в Linux?   Stanislav Protassov   30 May 2002 15:58:33 
 Эффективна ли pабота с памятью в Linux?   Evgeny Vetrov   30 May 2002 17:43:04 
 Re: Эффективна ли pабота с памятью в Linux?   Leschinsky Oleg   30 May 2002 22:39:55 
 Эффективна ли pабота с памятью в Linux?   Evgeny Vetrov   31 May 2002 08:32:47 
 Re: Эффективна ли pабота с памятью в Linux?   Leschinsky Oleg   31 May 2002 12:59:36 
 Re: Эффективна ли pабота с памятью в Linux?   Vladimir Bormotov   01 Jun 2002 04:04:51 
 Re: Эффективна ли pабота с памятью в Linux?   Alexey Shaposhnikov   30 May 2002 17:35:08 
 Эффективна ли pабота с памятью в Linux?   Konstantin Tereschenko   31 May 2001 15:10:07 
 Re: Эффективна ли pабота с памятью в Linux?   Vladimir Mosgalin   04 Jun 2002 00:33:45 
 Эффективна ли pабота с памятью в Linux?   Konstantin Tereschenko   04 Jun 2001 14:04:38 
 Эффективна ли pабота с памятью в Linux?   Andrey Rudyavsky   31 May 2002 12:37:42 
 Re: Эффективна ли pабота с памятью в Linux?   Victor Wagner   03 Jun 2002 09:38:52 
 Re: Эффективна ли pабота с памятью в Linux?   Vladimir Bormotov   03 Jun 2002 10:28:37 
 Эффективна ли pабота с памятью в Linux?   Konstantin Tereschenko   04 Jun 2001 12:53:18 
 Re: Эффективна ли pабота с памятью в Linux?   Victor Wagner   05 Jun 2002 14:31:58 
Архивное /ru.linux/39503cf76eca.html, оценка 2 из 5, голосов 10
Яндекс.Метрика
Valid HTML 4.01 Transitional