Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Вперед |
Приложение Г: Тесты распределителя памяти
Возможности динамического выделения памяти детально обсуждались ранее. Но в литературе и обсуждениях фигурируют самые разнообразные и противоречивые цифры и рекомендации по использованию (или не использованию) механизмов kmalloc(), vmalloc(), __get_free_pages(). Проделаем некоторые грубые оценки на различных компьютерах, с различными объёмами реальной RAM и с установленными Linux различных версий ядра. Для этого используем подготовленные тесты (архив mtest.tgz):
memmax.c :
#include <linux/module.h> #include <linux/slab.h> #include <linux/vmalloc.h> static int mode = 0; // выделение памяти: 0 - kmalloc(), 1 - __get_free_pages(), 2 - vmalloc() module_param( mode, int, S_IRUGO ); char *mfun[] = { "kmalloc", "__get_free_pages", "vmalloc" }; static int __init init( void ) { static char *kbuf; static unsigned long order, size; if( mode < 0 || mode > 2 ) { printk( KERN_ERR "illegal mode value\n" ); return -1; } for( size = PAGE_SIZE, order = 0; ; order++, size *= 2 ) { char msg[ 120 ]; sprintf( msg, "order=%2ld, pages=%6ld, size=%9ld - %s ", order, size / PAGE_SIZE, size, mfun[ mode ] ); switch( mode ) { case 0: kbuf = (char *)kmalloc( (size_t)size, GFP_KERNEL ); break; case 1: kbuf = (char *)__get_free_pages( GFP_KERNEL, order ); break; case 2: kbuf = (char *)vmalloc( size ); break; } strcat( msg, kbuf ? "OK\n" : "failed\n" ); printk( KERN_INFO "%s", msg ); if( !kbuf ) break; switch( mode ) { case 0: kfree( kbuf ); break; case 1: free_pages( (unsigned long)kbuf, order ); break; case 2: vfree( kbuf ); break; } } return -1; } module_init( init ); MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" ); MODULE_DESCRIPTION( "memory allocation size test" ); MODULE_LICENSE( "GPL v2" );
По 3-м экземплярам компьютеров с Linux указываются ниже перед результатами тестирования: а). версия ядра, б). объём установленной оперативной памяти.
$ uname -r
2.6.32.9-70.fc12.i686.PAE
$ cat /proc/meminfo | grep MemTotal
MemTotal: 2053828 kB
$ sudo insmod memmax.ko mode=0
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
order= 0, pages= 1, size= 4096 - kmalloc OK order= 1, pages= 2, size= 8192 - kmalloc OK order= 2, pages= 4, size= 16384 - kmalloc OK order= 3, pages= 8, size= 32768 - kmalloc OK order= 4, pages= 16, size= 65536 - kmalloc OK order= 5, pages= 32, size= 131072 - kmalloc OK order= 6, pages= 64, size= 262144 - kmalloc OK order= 7, pages= 128, size= 524288 - kmalloc OK order= 8, pages= 256, size= 1048576 - kmalloc OK order= 9, pages= 512, size= 2097152 - kmalloc OK order=10, pages= 1024, size= 4194304 - kmalloc OK order=11, pages= 2048, size= 8388608 - kmalloc failed
$ sudo insmod memmax.ko mode=1
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
order= 0, pages= 1, size= 4096 - __get_free_pages OK order= 1, pages= 2, size= 8192 - __get_free_pages OK order= 2, pages= 4, size= 16384 - __get_free_pages OK order= 3, pages= 8, size= 32768 - __get_free_pages OK order= 4, pages= 16, size= 65536 - __get_free_pages OK order= 5, pages= 32, size= 131072 - __get_free_pages OK order= 6, pages= 64, size= 262144 - __get_free_pages OK order= 7, pages= 128, size= 524288 - __get_free_pages OK order= 8, pages= 256, size= 1048576 - __get_free_pages OK order= 9, pages= 512, size= 2097152 - __get_free_pages OK order=10, pages= 1024, size= 4194304 - __get_free_pages OK order=11, pages= 2048, size= 8388608 - __get_free_pages failed
$ sudo insmod memmax.ko mode=2
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
order= 0, pages= 1, size= 4096 - vmalloc OK order= 1, pages= 2, size= 8192 - vmalloc OK order= 2, pages= 4, size= 16384 - vmalloc OK order= 3, pages= 8, size= 32768 - vmalloc OK order= 4, pages= 16, size= 65536 - vmalloc OK order= 5, pages= 32, size= 131072 - vmalloc OK order= 6, pages= 64, size= 262144 - vmalloc OK order= 7, pages= 128, size= 524288 - vmalloc OK order= 8, pages= 256, size= 1048576 - vmalloc OK order= 9, pages= 512, size= 2097152 - vmalloc OK order=10, pages= 1024, size= 4194304 - vmalloc OK order=11, pages= 2048, size= 8388608 - vmalloc OK order=12, pages= 4096, size=16777216 - vmalloc OK order=13, pages= 8192, size=33554432 - vmalloc OK order=14, pages= 16384, size=67108864 - vmalloc failed
$ uname -r
2.6.18-92.el5
$ cat /proc/meminfo | grep MemTotal
MemTotal: 255600 kB
$ sudo /sbin/insmod memmax.ko mode=0
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
EXT3-fs: mounted filesystem with ordered data mode. order= 0, pages= 1, size= 4096 - kmalloc OK order= 1, pages= 2, size= 8192 - kmalloc OK order= 2, pages= 4, size= 16384 - kmalloc OK order= 3, pages= 8, size= 32768 - kmalloc OK order= 4, pages= 16, size= 65536 - kmalloc OK order= 5, pages= 32, size= 131072 - kmalloc OK order= 6, pages= 64, size= 262144 - kmalloc failed
$ sudo /sbin/insmod memmax.ko mode=1
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
order= 0, pages= 1, size= 4096 - __get_free_pages OK order= 1, pages= 2, size= 8192 - __get_free_pages OK order= 2, pages= 4, size= 16384 - __get_free_pages OK order= 3, pages= 8, size= 32768 - __get_free_pages OK order= 4, pages= 16, size= 65536 - __get_free_pages OK order= 5, pages= 32, size= 131072 - __get_free_pages OK order= 6, pages= 64, size= 262144 - __get_free_pages OK order= 7, pages= 128, size= 524288 - __get_free_pages OK order= 8, pages= 256, size= 1048576 - __get_free_pages OK order= 9, pages= 512, size= 2097152 - __get_free_pages OK order=10, pages= 1024, size= 4194304 - __get_free_pages OK order=11, pages= 2048, size= 8388608 - __get_free_pages failed
$ sudo /sbin/insmod memmax.ko mode=2
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
order= 0, pages= 1, size= 4096 - vmalloc OK order= 1, pages= 2, size= 8192 - vmalloc OK order= 2, pages= 4, size= 16384 - vmalloc OK order= 3, pages= 8, size= 32768 - vmalloc OK order= 4, pages= 16, size= 65536 - vmalloc OK order= 5, pages= 32, size= 131072 - vmalloc OK order= 6, pages= 64, size= 262144 - vmalloc OK order= 7, pages= 128, size= 524288 - vmalloc OK order= 8, pages= 256, size= 1048576 - vmalloc OK order= 9, pages= 512, size= 2097152 - vmalloc OK order=10, pages= 1024, size= 4194304 - vmalloc OK order=11, pages= 2048, size= 8388608 - vmalloc OK order=12, pages= 4096, size=16777216 - vmalloc OK order=13, pages= 8192, size=33554432 - vmalloc OK order=14, pages= 16384, size=67108864 - vmalloc OK order=15, pages= 32768, size=134217728 - vmalloc OK order=16, pages= 65536, size=268435456 - vmalloc failed
$ uname -r
2.6.35.13-92.fc14.x86_64
$ cat /proc/meminfo | grep MemTotal
MemTotal: 4047192 kB
$ sudo /sbin/insmod memmax.ko mode=0
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
[1747955.216447] order= 0, pages= 1, size= 4096 - kmalloc OK [1747955.216452] order= 1, pages= 2, size= 8192 - kmalloc OK [1747955.216456] order= 2, pages= 4, size= 16384 - kmalloc OK [1747955.216460] order= 3, pages= 8, size= 32768 - kmalloc OK [1747955.216465] order= 4, pages= 16, size= 65536 - kmalloc OK [1747955.216469] order= 5, pages= 32, size= 131072 - kmalloc OK [1747955.216475] order= 6, pages= 64, size= 262144 - kmalloc OK [1747955.216481] order= 7, pages= 128, size= 524288 - kmalloc OK [1747955.216495] order= 8, pages= 256, size= 1048576 - kmalloc OK [1747955.216519] order= 9, pages= 512, size= 2097152 - kmalloc OK [1747955.325561] order=10, pages= 1024, size= 4194304 - kmalloc OK [1747955.325695] order=11, pages= 2048, size= 8388608 - kmalloc failed
$ sudo /sbin/insmod memmax.ko mode=1
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
[1748395.522702] order= 0, pages= 1, size= 4096 - __get_free_pages OK [1748395.522708] order= 1, pages= 2, size= 8192 - __get_free_pages OK [1748395.522712] order= 2, pages= 4, size= 16384 - __get_free_pages OK [1748395.522716] order= 3, pages= 8, size= 32768 - __get_free_pages OK [1748395.522720] order= 4, pages= 16, size= 65536 - __get_free_pages OK [1748395.522725] order= 5, pages= 32, size= 131072 - __get_free_pages OK [1748395.522730] order= 6, pages= 64, size= 262144 - __get_free_pages OK [1748395.522737] order= 7, pages= 128, size= 524288 - __get_free_pages OK [1748395.522745] order= 8, pages= 256, size= 1048576 - __get_free_pages OK [1748395.522759] order= 9, pages= 512, size= 2097152 - __get_free_pages OK [1748395.522777] order=10, pages= 1024, size= 4194304 - __get_free_pages OK [1748395.522788] order=11, pages= 2048, size= 8388608 - __get_free_pages failed
$ sudo /sbin/insmod memmax.ko mode=2
insmod: error inserting 'memmax.ko': -1 Operation not permitted
$ dmesg | tail -n100 | grep order
[1747830.678358] order= 0, pages= 1, size= 4096 - vmalloc OK [1747830.678445] order= 1, pages= 2, size= 8192 - vmalloc OK [1747830.678496] order= 2, pages= 4, size= 16384 - vmalloc OK [1747830.678552] order= 3, pages= 8, size= 32768 - vmalloc OK [1747830.678607] order= 4, pages= 16, size= 65536 - vmalloc OK [1747830.678667] order= 5, pages= 32, size= 131072 - vmalloc OK [1747830.678745] order= 6, pages= 64, size= 262144 - vmalloc OK [1747830.678848] order= 7, pages= 128, size= 524288 - vmalloc OK [1747830.679015] order= 8, pages= 256, size= 1048576 - vmalloc OK [1747830.679312] order= 9, pages= 512, size= 2097152 - vmalloc OK [1747830.679932] order=10, pages= 1024, size= 4194304 - vmalloc OK [1747830.681139] order=11, pages= 2048, size= 8388608 - vmalloc OK [1747830.683463] order=12, pages= 4096, size= 16777216 - vmalloc OK [1747830.688677] order=13, pages= 8192, size= 33554432 - vmalloc OK [1747830.697957] order=14, pages= 16384, size= 67108864 - vmalloc OK [1747830.712238] order=15, pages= 32768, size=134217728 - vmalloc OK [1747830.742639] order=16, pages= 65536, size=268435456 - vmalloc OK [1747830.810859] order=17, pages=131072, size=536870912 - vmalloc OK [1747831.040146] order=18, pages=262144, size=1073741824 - vmalloc OK [1747831.636957] order=19, pages=524288, size=2147483648 - vmalloc OK [1747831.784385] order=20, pages=1048576, size=4294967296 - vmalloc failed
Обратите внимание!: тест показывает не максимально возможный размер блока, который тот или иной механизм выделения памяти способен разместить (и такой тест несложно соорудить из показанного), а грубо оценивает блок, который уже нельзя разместить.
Следующая вещь, которая явно требует оценивания — это порядок временных затрат на выделение блока при использовании того или иного механизма. Код такого модуля-теста показан ниже:
memtim.c :
#include <linux/module.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <asm/msr.h> #include <linux/sched.h> static long size = 1000; module_param( size, long, 0 ); #define CYCLES 1024 // число циклов накопления static int __init init( void ) { int i; unsigned long order = 1, psize; unsigned long long calibr = 0; const char *mfun[] = { "kmalloc", "__get_free_pages", "vmalloc" }; for( psize = PAGE_SIZE; psize < size; order++, psize *= 2 ); printk( KERN_INFO "size = %ld order = %ld(%ld)\n", size, order, psize ); for( i = 0; i < CYCLES; i++ ) { // калибровка времени выполнения rdtscll() unsigned long long t1, t2; schedule(); // обеспечивает лучшую повторяемость rdtscll( t1 ); rdtscll( t2 ); calibr += ( t2 - t1 ); } calibr = calibr / CYCLES; printk( KERN_INFO "calibr=%lld\n", calibr ); for( i = 0; i < sizeof( mfun ) / sizeof( mfun[ 0 ] ); i++ ) { char *kbuf; char msg[ 120 ]; int j; unsigned long long suma = 0; sprintf( msg, "proc. cycles for allocate %s : ", mfun[ i ] ); for( j = 0; j < CYCLES; j++ ) { // циклы накопления измерений unsigned long long t1, t2; schedule(); // обеспечивает лучшую повторяемость rdtscll( t1 ); switch( i ) { case 0: kbuf = (char *)kmalloc( (size_t)size, GFP_KERNEL ); break; case 1: kbuf = (char *)__get_free_pages( GFP_KERNEL, order ); break; case 2: kbuf = (char *)vmalloc( size ); break; } if( !kbuf ) break; rdtscll( t2 ); suma += ( t2 - t1 - calibr ); switch( i ) { case 0: kfree( kbuf ); break; case 1: free_pages( (unsigned long)kbuf, order ); break; case 2: vfree( kbuf ); break; } } if( kbuf ) sprintf( ( msg + strlen( msg ) ), "%lld", ( suma / CYCLES ) ); else strcat( msg, "failed" ); printk( KERN_INFO "%s\n", msg ); } return -1; } module_init( init ); MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" ); MODULE_DESCRIPTION( "memory allocation speed test" ); MODULE_LICENSE( "GPL v2" );
Результаты этого теста я приведу только для одной системы, из-за их объёмности и громоздкости. Вы их можете повторить для своего компьютера и своей версии ядра:
$ uname -r
2.6.32.9-70.fc12.i686.PAE
$ sudo insmod ./memtim.ko
insmod: error inserting './memtim.ko': -1 Operation not permitted
$ dmesg | tail -n4
size = 1000 order = 1(4096) proc. cycles for allocate kmalloc : 146 proc. cycles for allocate __get_free_pages : 438 proc. cycles for allocate vmalloc : 210210
$ sudo insmod ./memtim.ko size=4096
insmod: error inserting './memtim.ko': -1 Operation not permitted
$ dmesg | tail -n4
size = 4096 order = 1(4096) proc. cycles for allocate kmalloc : 181 proc. cycles for allocate __get_free_pages : 877 proc. cycles for allocate vmalloc : 59626
$ sudo insmod ./memtim.ko size=65536
insmod: error inserting './memtim.ko': -1 Operation not permitted
$ dmesg | tail -n4
size = 65536 order = 5(65536) proc. cycles for allocate kmalloc : 1157 proc. cycles for allocate __get_free_pages : 940 proc. cycles for allocate vmalloc : 84129
$ sudo insmod ./memtim.ko size=262144
insmod: error inserting './memtim.ko': -1 Operation not permitted
$ dmesg | tail -n4
size = 262144 order = 7(262144) proc. cycles for allocate kmalloc : 2151 proc. cycles for allocate __get_free_pages : 2382 proc. cycles for allocate vmalloc : 52026
В последнем нашем эксперименте сделаем блок не кратным размеру страницы MMU (чуть-чуть урежем значение из предыдущего запуска):
$ sudo insmod ./memtim.ko size=262000
insmod: error inserting './memtim.ko': -1 Operation not permitted
$ dmesg | tail -n4
size = 262000 order = 7(262144) proc. cycles for allocate kmalloc : 8674 proc. cycles for allocate __get_free_pages : 4730 proc. cycles for allocate vmalloc : 55612
- видно, как __get_free_pages() и kmalloc() (что странно для последнего) «впадают в задумчивость», и в разы теряют производительность; практически не замечает этого изменения.
Можно заметить следующее:
- При распределении малых блоков разница kmalloc() и vmalloc() разительная, и составляет до 3-х порядков:
$ sudo insmod ./memtim.ko size=5
insmod: error inserting './memtim.ko': -1 Operation not permitted
$ dmesg | tail -n30 | grep -v audit
size = 5 order = 1(4096) proc. cycles for allocate kmalloc : 143 proc. cycles for allocate __get_free_pages : 890 proc. cycles for allocate vmalloc : 152552
- При увеличении размеров запрашиваемого блока различия нивелируются, и на больших объёмах не превышают порядка.
- В этих различиях нет ничего страшного, учитывая ту гибкость и диапазон, которые обеспечивает как раз vmalloc(), если только речь не идёт о быстром получении-удалении малых блоков в динамике.
Предыдущий раздел: | Оглавление | Следующий раздел: |
Приложение В: Пример - открытые VoIP PBX: Asterisk, FreeSwitch, и другие | Источники информации |