на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Мониторинг виртуальной памяти в ОС Linux
урнал событий:

29305: anon page @b7ee1fa0 (R)

29305: fsync(0)

29305: anon page @b7f22d4e (R) - страничные отказы в сегменте кода libc.so

29305: anon page @b7ee2000 (R)

29305: anon page @b7e85180 (R)

29305: anon page @b7e86330 (R)

29305: anon page @b7f1f680 (R)

29305: anon page @b7ef6470 (R)

29305: anon page @b7e83140 (R)

29305: anon page @b7e82370 (R)

29305: anon page @b7e87de0 (R)

29305: brk(00000000)

29305: brk -> 134520832 (0804a000)

29305: brk(0806e000)

29305: brk -> 134668288 (0806e000) - malloc выделил 144 кб

29305: anon page @0804a004 (W) - здесь malloc заносит метки в начало и конец выделенного региона

29305: anon page @0804d00c (W)

29305: fsync(1)

29305: anon page @0804b000 (R) - сбои при обращении к страницам из цикла

29305: anon page @0804c000 (R)

29305: fsync(2)

29305: brk(0806b000) - free возвращает часть памяти

29305: brk -> 134656000 (0806b000)

29305: fsync(0) - `дальнейшие циклы уже не выделяют памяти

29305: fsync(1)

29305: fsync(2)

В приведенном примере видно, что при выделении 12К памяти malloc() выделяет изначально гораздо бОльший объем (144К), однако реально эти страницы из физической памяти не выделяеются, и при обращениях к ним происходят страничные отказы. В первую и последнюю страницу выделенной секции malloc заносит свои метки (сбой происходит на операции записи).

2) Выделяем подряд блоки по 4 страницы (не освобождая), обращаясь ко всем страницам:

21049: brk(00000000)

21049: brk -> (0804a000)

21049: brk(0806e000)

21049: brk -> (0806e000) - выделение первого блока, malloc выделяет 144 кб

21049: anon page @0804a004 (W)

21049: anon page @0804d00c (W) - запись меток

21049: fsync(1)

21049: anon page @0804b000 (R)

21049: anon page @0804c000 (R) - обращение к выделенной области

21049: fsync(2)

21049: fsync(0)

21049: anon page @08050014 (W) - выделение следующих 12 кб (запись метки)

21049: fsync(1)

21049: anon page @0804e000 (R)

21049: anon page @0804f000 (R) - обращения к выделенной области

21049: fsync(2)

21049: brk(0808f000) - очередной вызов malloc(), расширяем сегмент данных

21049: brk -> 134803456 (0808f000)

21049: anon page @0806e064 (W)

21049: fsync(1)

21049: fsync -> -22 (ffffffea)

21049: anon page @0806c000 (R)

21049: anon page @0806d000 (R)

Таким образом, видно, что malloc выделяет память блоками по 128 с небольшим кб при помощи вызова brk(). Рассмотрим, что происходит при увеличении размера запроса.

3) Запрашиваем последовательно 4, 8, 12, 16К, и т.д., обращаясь в цикле ко всем страницам. При этом, как только размер выделения превышает 128К, malloc выделяет память уже не из области сегмента данных программы (расширяемого вызововм brk()), а при помощи mmap(), после чего free() его освобождает последующим munmap():

789: mmap (00000000, 139264, rw-, PRIVATE | ANON, fd -1, @f019a000)

789: mmap -> -1210519552 (b7d8f000)

789: anon page @b7d8f004 (W)

789: fsync(1)

789: anon page @b7d90000 (R)

789: anon page @b7db0000 (R)

789: fsync(2)

789: munmap (b7d8f000, 139264)

789: munmap -> 0 (00000000)

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

3) Третий пример запрашивает память куда большими блоками, увеличивающимися по 100 Мб. При отключенном overcommit'e память быстро заканчивается, и очередной mmap возвращает ENOMEM:

1536: mmap (00000000, 629149696, rw-, PRIVATE | ANON)

1536: mmap -> -12 (fffffff4)

1536: anon page @b7e06de0 (R)

1536: brk(00000000)

1536: brk -> 134520832 (0804a000)

1536: brk(2d86b000)

1536: brk -> 134520832 (0804a000)

1536: mmap (00000000, 629280768, rw-, PRIVATE | ANON)

1536: mmap -> -12 (fffffff4)

1536: mmap (00000000, 2097152, rw-, PRIVATE | ANON)

1536: mmap -> -1212555264 (b7b9e000)

1536: munmap (b7b9e000, 401408)

1536: munmap -> 0 (00000000)

1536: munmap (b7d00000, 647168)

1536: munmap -> 0 (00000000)

1536: anon page @b7c00008 (W)

1536: mmap (00000000, 629149696, rw-, PRIVATE | ANON)

1536: mmap -> -12 (fffffff4)

Библиотека libc при этом пытается сначала выделить ту же память при помощи вызова brk(), затем снова при помощи вызова mmap(), но уже несколько меньший объем, однако и эти вызовы проходят неудачно.

4) Включим overcommit. Теперь, пока программа не обращается ко всем страницам из выделенного региона, а лишь к некоторым (не расходуя при этом всю физическую память), выполнение проходит нормально, и вызов mmap() успешно выделяет блоки памяти, значительно превыщающие объем свободной оперативной памяти (порядка 600 M):

2515: mmap (00000000, 996151296, rw-, PRIVATE | ANON)

2515: mmap -> 2089299968 (7c883000)

2515: anon page @7c883004 (W)

2515: fsync(1)

2515: anon page @8b603008 (R)

2515: anon page @9a383008 (R)

2515: anon page @a9103008 (R)

2515: fsync(2)

2515: munmap (7c883000, 996151296)

2515: munmap -> 0 (00000000)

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

5) При попытке попытаться обратиться ко всем страницам из выделенного региона, очень скоро память исчерпывается и возникает ситуация, называемая OOM - Out Of Memory. В этом случае ядро вызывает функцию oom_kill(), которая выбирает процесс-жертву для уничтожения, основываясь на расходах памяти, времени работы, приоритете и т.п., и убивает выбранный процесс, с целью освободить память. При этом в журнал отладочных сообщений ядра выдается уведомление о том, что сработал oom_kill:

kernel: kwin invoked oom-killer: gfp_mask=0x201d2, order=0, oomkillad

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

19225: anon page @b7418bb0 (R)

19225: anon page @b7602893 (R)

19225: swapfile page @0ae1507c (R)

19225: swapfile page @0d8cb0e6 (R)

19225: swapfile page @0af146b0 (R)

7) Системные вызовы mlock()/mlockall() делают невыгружаемой определенную страницу виртуальной памяти процесса или все его страницы - текущие и / или выделенные в будущем, в зависимости от передаваемых в вызов mlockall() флагов.

Сделаем в начале выполнения программы невыгружемыми все страницы, выделяемые в будущем, после чего выделяем блоки по 12 кб (не освобождая):

13749: brk(00000000)

13749: brk -> 134520832 (0804a000)

13749: brk(0806e000)

13749: anon page @0804a000 (W)

13749: anon page @0806c000 (W)

13749: anon page @0806d000 (W)

13749: brk -> 134668288 (0806e000)

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

Таким образом, можно сделать следующие выводы:

1. При выделении памяти ядро не выделяет сразу все физические страницы (если в mmap() не был передан флаг MAP POPULATE или страницы процесса не были заблокированы в физической памяти вызовами mlock[all]() - в этих случаях страницы всего региона подгружаются сразу)

2. Для выделения небольших объемов памяти библиотека libc расширяет сегмент данных программы вызовом brk(), для запросов, бОльших 128К - использует mmap().

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

В рамках данной работы были исследованы вопросы, связанные с разработкой драйверов под OS Linux, работой ядра Linux с виртуальной памятью и перехватом системных вызовов.

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

Было произведено исследование механизма выделения памяти в ядре Linux и библиотеке libс, исследована технология overcommit.

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

Список использованной литературы

Jonathan Corbet. Linux Device Drivers, 3rd Edition.

Роберт Лав. Разработка ядра Linux, 2-е издание.

Peter Salzman. The Linux Kernel Module Programming Guide, 3rd Edition.

Клаудия Родригес. Азбука ядра Linux.

Исходники ядра и документация к ним.

Приложения

Код драйвера

mmon.c

/*

* Main module and entry point of memmon.

*/

#include <linux/module.h>

#include <linux/moduleparam.h>

#include <linux/kernel.h>

#include <linux/proc_fs.h>

#include «common.h»

#include «watch-pids.h»

#include «mm-fault.h»

#include «events.h»

#include «syscalls.h»

/*** Internal data ***/

/*

* procfs directory entry

*/

struct proc_dir_entry *procdir = NULL;

/*

* Init entry point

*/

static int __init init(void)

{

int ret = - EBUSY;

procdir = proc_mkdir (PROCDIR, NULL);

if (! procdir)

goto out;

if (! init_watch_pids())

goto out_procdir;

if (! init_events())

goto out_watch_pids;

if (! capture_syscalls())

goto out_events;

capture_mmfault();

return 0;

out_events:

fini_events();

out_watch_pids:

fini_watch_pids();

out_procdir:

remove_proc_entry (PROCDIR, NULL);

out:

return ret;

}

module_init(init);

/*

* Exit point

*/

static void __exit exit(void)

{

release_mmfault();

restore_syscalls();

fini_events();

fini_watch_pids();

remove_proc_entry (PROCDIR, NULL);

}

module_exit(exit);

/*** Module info ***/

MODULE_LICENSE («GPL»);

MODULE_AUTHOR («Ivan Korotkov»);

MODULE_DESCRIPTION («Linux Virtual Memory Monitor»);

events.h

/*

* Events ringbuffer.

*/

#ifndef MEMMON_EVENTS_H

#define MEMMON_EVENTS_H

/* Filename in procfs directory */

#define EVENTS_ENTRY «events»

/* Types of events */

enum memmon_event_type

{

NOTUSED = 0, /* to prevent treating zero-filled region as event struct */

MMAP2,

MUNMAP,

MREMAP,

MLOCK,

MUNLOCK,

MLOCKALL,

MUNLOCKALL,

BRK,

FSYNC,

ANON_PF,

SWAP_PF,

FILE_PF,

SYSCALLRET

};

/*

* Struct describing each event

*/

struct memmon_event

{

/* Type */

enum memmon_event_type type;

/* Caller PID */

pid_t pid;

/* Per-type data */

union

{

struct

{

void __user *start;

size_t len;

} munmap;

struct

{

void __user *start;

size_t len;

unsigned long prot, flags;

unsigned long fd, off;

} mmap2;

struct

{

void __user *start[2];

size_t len[2];

unsigned flags;

} mremap;

struct

{

void __user *start;

size_t len;

} mlock, munlock;

struct

{

unsigned long flags;

} mlockall;

struct

{

void __user *addr;

} brk;

struct

{

int fd;

} fsync;

struct

{

void __user *addr;

int write;

} pagefault;

struct

{

char *callname;

long ret;

} callret;

};

};

#define NEVENTS (EVENTS_BUFLEN/sizeof (struct memmon_event))

/*

* Initializes event ringbuffer & creates /proc entry

*/

int init_events(void);

/*

* Destroys ringbuffer & removes /proc entry

*/

void fini_events(void);

/*

* Adds events to ringbuffer tail

*/

void put_event (const struct memmon_event *ev);

#endif // MEMMON_EVENTS_H

events.c

/*

* Events ringbuffer.

*/

#include <linux/module.h>

#include <linux/moduleparam.h>

#include <linux/kernel.h>

#include <linux/seq_file.h>

#include <linux/proc_fs.h>

#include <linux/poll.h>

#include <linux/mman.h>

#include «common.h»

#include «events.h»

/*** Forward declarations ***/

static int events_open (struct inode *i, struct file *filp);

static unsigned events_poll (struct file *filp, struct poll_table_struct *pt);

static void *events_seqstart (struct seq_file *m, loff_t *pos);

static void events_seqstop (struct seq_file *m, void *p);

static void *events_seqnext (struct seq_file *m, void *p, loff_t *pos);

static int events_seqprint (struct seq_file *m, void *p);

/* Default ringbuffer size */

#define EVENTS_BUFLEN (32*1024)

/* Min ringbuffer size */

#define MIN_EVENTS_BUFLEN (8*1024)

/*** Module parameters ***/

/* Actual ringbuffer size */

static int buflen = EVENTS_BUFLEN;

module_param (buflen, int, 0444);

/*** File operations ***/

static const struct file_operations events_fops =

{

owner = THIS_MODULE,

open = events_open,

read = seq_read,

release = seq_release,

poll = events_poll

};

static const struct seq_operations events_seqop =

{

start = events_seqstart,

stop = events_seqstop,

next = events_seqnext,

show = events_seqprint

};

/*** Internal data ***/

/* Ringbuffer */

static struct memmon_event *events;

/* Last entry left in ringbuffer

* (where 1st read should begin) */

static int ev_start;

/* Current write position */

Страницы: 1, 2, 3, 4



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