Титла: Динамичен kernel tunning?
Публикувано от: gat3way в Oct 31, 2006, 18:50
От известно време насам се чудя дали това е добра идея? За какво точно говоря? Представете си следната програмка: 1) През равни интервали от време в продължение на известен брой цикли събира информация за работата на системата (loadavg, buffers/cache, swap/mem usage, sockets/fds, etc). 2) Прост алгоритъм който вади средно аритметично, средно отклонение, максимално отклонение, амплитуда (разликата между най-високата и най-ниската стойност в периода) 3) На база някакви критерии в зависимост от горните стойности променя различни kernel tunnables така че да се осигури по-добър responsiveness, по-рационално I/O спрямо наличната памет, по-малко разхищение на памет (не ни трябват раздути буфери и структури когато не ги ползваме), ако щете донякъде защита от добре известни локални DoS (като например форкбомби, отваряне на голям брой сокети или файлове за малко време и т.н). Що се отнася до тунинговането на производителността според мен има смисъл в зависимост от ситуацията човек динамично да променя неща като vfs_cache_pressure, swappiness, readahead буфери за блоковите устройства и т.н. 4) goto 1 Всъщност написах една кратка "първоначална" версия на програмка, която реализира нещо подобно. Естествено, доста далеч е от целта, най-малкото доста неща трябва да се допроверят и тестват, особено тези свързани с точка 3. Мисълта ми е: според вас има ли смисъл от динамично тунинговане на тези параметри или ако човек работи през цялото време с дефолтните или някакви собствени, цялостната картинка ще е по-добра? Знам че тестването на практическата файда от нещо такова е доста сложна занимавка от друга страна, иначе тестовете щях да си ги направя сам и нямаше да питам за чужди мнения  От друга страна знам, че за да промениш някои параметри така че нещата да се наредят най-добре изисква да си баба Ванга и да знаеш какво ще се случи на машината известно време напред. Примерно хубаво е да имаш много dentry/inode кеш на машината принципно, но ако от това се възползва единствено updatedb едва ли ще го викаш през 5 минути за да си индексираш файловите системи  П.П. за момента иначе съм донякъде горд с това дето го сътворих...когато изкуствено предизвикам ситуация в която се налага машината да суоп-ва, откривам някакъв смисъл от цялата работа. Иначе не се усеща никаква разлика 
Титла: Динамичен kernel tunning?
Публикувано от: ZEN в Nov 01, 2006, 11:52
Приветствам тази идея... от години си играя да оптимизирам /според възможностите си, които не са кой знае какви/... затова ще се радвам /предполагам и други/ да публикуваш някакви резултати... или решения. Успех
Титла: Динамичен kernel tunning?
Публикувано от: gat3way в Nov 02, 2006, 11:25
Такам...досега какъв напредък имам: 1) vfs_cache_pressure се регулира динамично според тенденциите на нарастване на buffers/cached (не е много правилно, но примерно при updatedb или du -hs / сработва успешно в посока inode/dentry cache. При големи обеми резервирана памет за периода става обратното -> pagecache) 2) dirty cache expire/writeback се регулира динамично в зависимост от това колко памет е заета и колко се е освободила при записването й върху диска, така че да се избягва от една страна прекалено честото генериране на I/O и прекалено много заетата памет от друга 3) Параметрите на IO scheduler-a се тунинговат в зависимост от това колко писане/четене има за периода (работи засега само с anticipatory scheduling алгоритъма) 4) Регулиране на swappiness в случай че сме навлезли в суоп-а и в зависимост от тенденцията loadavg да расте/намалява - така се повишава responsiveness-a на системата 5) page-cluster се променя динамично в зависимост от това колко се суоп-ва: това с цел да се подобри swap I/O performance-a 6) Ако продължително време няма почти никакъв swapin/swapout, има свободна рам и въпреки всичко в суопа стоят разни работи, целият swap се flush-ва (swapoff -a;swapon -a). Това е защото VM мениджмънта на линукс на моменти е малко тъп и ако има нещо в суоп-а и въпреки че има свободна РАМ има тенденцията да продължава да тъпче глупости в суоп-а 7) file-max, threads-max се регулират в зависимост от отворените файлови дескриптори / броят на процесите. Това с цел да се смекчат последствията от forkbomb-и или някаква бъгавиня дето отваря изведнъж много файлове. От това няма кой знае какъв смисъл като се замисля, отделно дето понякога създава проблеми - вероятно ще го разкарам. 8) Големината на буферите за мрежови операции (rmem_max/default, wmem_max/default) се коригират в зависимост от нарастването/намаляването на входящият/изходящият трафик. За съжаление понякога и тук има слаби моменти. 9) Големината на read-ahead буферите за блоковите устройства се коригират в зависимост от тенденцията за нарастване на операциите на четене от тях (леко грубо и недодялано). Какво мисля да реализирам още? 1) Тунинговане на TCP параметри - много бих искал, въпреки че ще е огромна работа 2) Коригиране на netdev_max_backlog за да не се дропят пакети в дадени ситуации - това няма да е много сложно 3) Дали не може да се направи нещо свързано със балансирането на interrupts? Обаче там нещата стават доста сложни и трябва бая да се помисли върху логиката. Най-малкото значение има и архитектурата, и броя процесори и т.н 4) Разни ACPI занимавки - с тях пък така или иначе не съм особено запознат и трябва да почета доста преди това 5) Дали не може да се вземат предвид разни данни от lmsensors, cpufreq? Смисълът от нещо такова обаче е доста противоречив. Съмнително е също дали мога да го реализирам като хората  В най-скоро време ще кача кода на глупостта, която съм сътворил, в момента е доста грозен и неподреден и без коментари и ме е срам  Не е кой знае какво иначе - около 1000 реда на C, байнърито е доста леко - към 30кб, верно malloc-ва повечко памет, но не кой знае колко много. Освен това бавно и неусетно някъде leak-ва (не тече кой знае колко силно де  ) и още не съм го хванал къде. Та това е progress report-a засега 
Титла: Динамичен kernel tunning?
Публикувано от: ZEN в Nov 02, 2006, 16:44
Продължавай в същия дух със сигурност ще съм ти първия бета тестер 
Титла: Динамичен kernel tunning?
Публикувано от: senser в Nov 02, 2006, 19:13
интересно ми е къде може да се намери/прочете подробна информация за параметрите, които подлежат на тунинговане и може да се разпредели работата по отделните компоненти и алгоритми - доста работа си е за сам човек  иначе поздравления за начинанието 
Титла: Динамичен kernel tunning?
Публикувано от: gat3way в Nov 02, 2006, 21:00
/usr/src/`uname -r`/Documentation Относително сносна документация, но на моменти има мъгляви твърдения и се налага да прегледаш и конкретния код и да се опиташ да разкриеш замисъла. Има разни уики-та с полезни насоки, както и lwn.net, kerneltrap.net. Ако ти възникне по-конкретен въпрос, google намира доста уеб-архиви на LKML, където обаче нерядко говорят и глупости  И измежду другото попадаш на доста забавни спорове между типове като Ханс Райзер или Йорг Шилинг и разните там архигурута - kernel devs:) А, да, и на един хърватски сайт се опитват да документират /proc tunnables. http://linux.inet.hr/proc_filesystem.html . Определено не може да се каже че е много пълна документацията, но това което има е събрано удобно на едно място където лесно се търси. 2.6 променливите принципно са доста по-зле документирани от тия от 2.4, ама сега нещата и без това са се усложнили немалко...procfs започва да става някаква промита история, има и /sys, много хора пък си дефинират ioctls или други механизми и си пишат userspace библиотеки (cpufreq примерно са тръгнали в тази насока). Така че няма някакво удобно място наедно, налага се повече собствен research в някои случаи 
Титла: Динамичен kernel tunning?
Публикувано от: zeridon в Nov 03, 2006, 12:29
Като цяло и аз съм за бета тестер и то най вече в областта на I/O i Mem usage. Понеже това най яко ми къса нервите.
Титла: Динамичен kernel tunning?
Публикувано от: kennedy в Nov 03, 2006, 12:37
Сякаш в миналото съм срещал подобен проект ...
Титла: Динамичен kernel tunning?
Публикувано от: gat3way в Nov 03, 2006, 15:36
Ето ви примерния сорс (грозен, бъглив, недодялан) засега: Цитат | #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <sys/time.h> #include <sys/resource.h>
// Defines, Data structures, global vars #define MAX_DATA 100 #define SLEEP_TIME 2 #define AFTER 3
#define TODO_VFS_CACHE_INC 1 #define TODO_VFS_CACHE_DEC 2 #define TODO_DIRTY_INC 3 #define TODO_DIRTY_DEC 4 #define TODO_REBALANCE_READ 5 #define TODO_REBALANCE_WRITE 6 #define TODO_READAHEAD_UP 7 #define TODO_READAHEAD_DOWN 8 #define TODO_SWAPPINESS_UP 9 #define TODO_SWAPPINESS_DOWN 10 #define TODO_SWAPPINESS_ONE 11 #define TODO_PAGECLUSTER_UP 12 #define TODO_PAGECLUSTER_NORM 13 #define TODO_FLUSH_SWAP 14 #define TODO_CHECK_FILENR 15 #define TODO_RECVBUF_UP 16 #define TODO_RECVBUF_DOWN 17 #define TODO_SENDBUF_UP 18 #define TODO_SENDBUF_DOWN 19
// system-data struct struct tcinfo { int id; float loadavg; int memused; int memmax; int memuse; int buffers; int cached; int swapcached; int swapused; int swapmax; int swapuse; int dirty; int writeback; int uswap; int ioread; int iowrite; int recv; int send; };
// statistics struct struct tcstat { float loadavg[3]; int memused[3]; int memmax[3]; int memuse[4]; int buffers[4]; int cached[3]; int swapcached[3]; int swapused[3]; int swapmax[3]; int swapuse[3]; int dirty[3]; int writeback[3]; int uswap[3]; long ioread[3]; long iowrite[3]; int recv[4]; int send[4]; };
// vars struct tcinfo cia[MAX_DATA]; struct tcstat cst; int cindex; // read over write marker int sched=0; // Read-ahead, marker int read_ahb=1; char *ulog="/var/log/tune.log";
// recover after X passes int vfsd_after=0; int vfsu_after=0; int recu_after=0; int recd_after=0; int senu_after=0; int send_after=0;
// Log into file void logme(char *data) { FILE *fd; fd=fopen(ulog,"a+"); fputs(data,fd); fclose(fd); } // Get system data void getdata(int time) { FILE *fd; char *buf; char *buf1; char *buf2; char *buf3; char *buf4; int t1,t2; long tt1,tt2; float l;
for (cindex=1;cindex<=time;cindex++) { cia[cindex].id=cindex; // Parse networking stats buf=malloc(300); fd=fopen("/proc/net/snmp","r"); fgets(buf,300,fd); fgets(buf,300,fd); fclose(fd); buf1=strtok_r(buf," ",&buf4); for (t1=1;t1<=9;t1++) buf1=strtok_r(NULL," ",&buf4); l=strtod(buf1,NULL); cia[cindex].recv=l; buf1=strtok_r(NULL," ",&buf4); l=strtod(buf1,NULL); cia[cindex].send=l; free(buf);
// Parse loadavg data buf=malloc(100); fd=fopen("/proc/loadavg","r"); fgets(buf,100,fd); buf1=strtok(buf," "); l=strtod(buf1,NULL); cia[cindex].loadavg=l; free(buf); // Parse meminfo stats buf=malloc(300); //memleakshit buf4=buf; fd=fopen("/proc/meminfo","r"); fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); t1=strtod(buf1,NULL); fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); t2=strtod(buf1,NULL); cia[cindex].memused=((t1-t2)*100/t1); cia[cindex].memuse=t2; cia[cindex].memmax=t1; // Buffers fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); cia[cindex].buffers=strtod(buf1,NULL);
// Cached fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); cia[cindex].cached=strtod(buf1,NULL);
// SwapCached fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); cia[cindex].swapcached=strtod(buf1,NULL); // Jumpto.. for (t1=1;t1<=6;t1++) fgets(buf,300,fd); // Parse swapinfo fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); t1=strtod(buf1,NULL); fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); t2=strtod(buf1,NULL); cia[cindex].swapused=((t1-t2)*100/t1); cia[cindex].swapuse=t2; cia[cindex].swapmax=t1; // Dirty, writeback fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); cia[cindex].dirty=strtod(buf1,NULL); fgets(buf,300,fd); buf1=strtok_r(buf,":",&buf2); buf1=strtok_r(NULL,":",&buf2); cia[cindex].writeback=strtod(buf1,NULL); // Close it, free it.. fclose(fd); free(buf); // Get I/O stats, the dumbest way  fd=fopen("/proc/diskstats","r"); tt1=0;tt2=0; while (feof(fd)==0) { buf=malloc(200); if (fgets(buf,200,fd)!=NULL) { buf1=strtok_r(buf," ",&buf2); buf1=strtok_r(NULL," ",&buf2); buf1=strtok_r(NULL," ",&buf2); buf1=strtok_r(NULL," ",&buf2); tt1=tt1+(strtol(buf1,NULL,0)/100); buf1=strtok_r(NULL," ",&buf2); buf1=strtok_r(NULL," ",&buf2); buf1=strtok_r(NULL," ",&buf2); tt2=tt2+(strtol(buf1,NULL,0)/100); } free(buf);
} fclose(fd); cia[cindex].ioread=tt1; cia[cindex].iowrite=tt2;
// Sleep... sleep(SLEEP_TIME); } }
// Analyze data: some stats analysis void analyze_data() { int a,b; int mean,mxdev,mndev; float mmean,mmxdev,mmndev;
// Network stats prepare cst.send[4]=cst.send[3]; cst.recv[4]=cst.recv[3]; mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].recv; if (mxdev<abs(cia[a].recv-cia[a-1].recv)) mxdev=abs(cia[a].recv-cia[a-1].recv); mndev=mndev+cia[a].recv-cia[a-1].recv; } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("recv: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev,m ndev); cst.recv[1]=mean;cst.recv[2]=mxdev;cst.recv[3]=mndev;
mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].send; if (mxdev<abs(cia[a].send-cia[a-1].send)) mxdev=abs(cia[a].send-cia[a-1].send); mndev=mndev+abs(cia[a].send-cia[a-1].send); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("send: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev,m ndev); cst.send[1]=mean;cst.send[2]=mxdev;cst.send[3]=mndev;
// Loadavg stats parse mmean=0;mmxdev=0;mmndev=0; for (a=2;a!=cindex;a++) { mmean=mmean+cia[a].loadavg; if (mmxdev<fabsf(cia[a].loadavg-cia[a-1].loadavg)) mmxdev=fabsf(cia[a].loadavg-cia[a-1].loadavg); mmndev=mmndev+fabsf(cia[a].loadavg-cia[a-1].loadavg); } mmean=mmean/(cindex-2); mmndev=mmndev/(cindex-2); // printf("loadavg: Average:%.2f percent Max_deviation:%.2f Mean_deviation:%.2f\n",mm ean,mmxdev,mmndev); cst.loadavg[1]=mmean;cst.loadavg[2]=mmxdev;cst.loadavg[3]=mmndev;
// Memory Usage stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].memused; if (mxdev<abs(cia[a].memused-cia[a-1].memused)) mxdev=abs(cia[a].memused-cia[a-1].memused); mndev=mndev+abs(cia[a].memused-cia[a-1].memused); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("Memusage: Average:%d percent Max_deviation:%d Mean_deviation:%d\n",mean,mx dev,mndev); cst.memused[1]=mean;cst.memused[2]=mxdev;cst.memused[3]=mndev;
// Memory use stats mean=0;mxdev=0;mndev=0; cst.memuse[4]=cst.memuse[3]; for (a=2;a!=cindex;a++) { mean=mean+cia[a].memuse; if (mxdev<abs(cia[a].memuse-cia[a-1].memuse)) mxdev=abs(cia[a].memuse-cia[a-1].memuse); mndev=mndev+(cia[a].memuse-cia[a-1].memuse); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("Memuse: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev ,mndev); cst.memuse[1]=mean;cst.memuse[2]=mxdev;cst.memuse[3]=mndev;
// Buffers stats cst.buffers[4]=cst.buffers[3]; mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].buffers; if (mxdev<abs(cia[a].buffers-cia[a-1].buffers)) mxdev=abs(cia[a].buffers-cia[a-1].buffers); mndev=mndev+(cia[a].buffers-cia[a-1].buffers); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("buffers: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxde v,mndev); cst.buffers[1]=mean;cst.buffers[2]=mxdev;cst.buffers[3]=mndev;
// Cached stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].cached; if (mxdev<abs(cia[a].cached-cia[a-1].cached)) mxdev=abs(cia[a].cached-cia[a-1].cached); mndev=mndev+abs(cia[a].cached-cia[a-1].cached); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("cached: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev ,mndev); cst.cached[1]=mean;cst.cached[2]=mxdev;cst.cached[3]=mndev;
// swapcached stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].swapcached; if (mxdev<abs(cia[a].swapcached-cia[a-1].swapcached)) mxdev=abs(cia[a].swapcached-cia[a-1].swapcached); mndev=mndev+abs(cia[a].swapcached-cia[a-1].swapcached); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("swapcached: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,m xdev,mndev);
cst.swapcached[1]=mean;cst.swapcached[2]=mxdev;cst.swapcached[3]=mndev;
// Swap Usage stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].swapused; if (mxdev<abs(cia[a].swapused-cia[a-1].swapused)) mxdev=abs(cia[a].swapused-cia[a-1].swapused); mndev=mndev+abs(cia[a].swapused-cia[a-1].swapused); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("swapusage: Average:%d percent Max_deviation:%d Mean_deviation:%d\n",mean,m xdev,mndev); cst.swapused[1]=mean;cst.swapused[2]=mxdev;cst.swapused[3]=mndev;
// swap use stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].swapuse; if (mxdev<abs(cia[a].swapuse-cia[a-1].swapuse)) mxdev=abs(cia[a].swapuse-cia[a-1].swapuse); mndev=mndev+abs(cia[a].swapuse-cia[a-1].swapuse); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("swapuse: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev,mndev); cst.swapuse[1]=mean;cst.swapuse[2]=mxdev;cst.swapuse[3]=mndev;
// dirty stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].dirty; if (mxdev<abs(cia[a].dirty-cia[a-1].dirty)) mxdev=abs(cia[a].dirty-cia[a-1].dirty); mndev=mndev+abs(cia[a].dirty-cia[a-1].dirty); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("dirty: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev, mndev); cst.dirty[1]=mean;cst.dirty[2]=mxdev;cst.dirty[3]=mndev;
// writeback stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].writeback; if (mxdev<abs(cia[a].writeback-cia[a-1].writeback)) mxdev=abs(cia[a].writeback-cia[a-1].writeback); mndev=mndev+abs(cia[a].writeback-cia[a-1].writeback); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("writeback: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mx dev,mndev);
cst.writeback[1]=mean;cst.writeback[2]=mxdev;cst.writeback[3]=mndev;
// ioread stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].ioread; if (mxdev<abs(cia[a].ioread-cia[a-1].ioread)) mxdev=abs(cia[a].ioread-cia[a-1].ioread); mndev=mndev+abs(cia[a].ioread-cia[a-1].ioread); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("ioread: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxdev ,mndev); cst.ioread[1]=mean;cst.ioread[2]=mxdev;cst.ioread[3]=mndev;
// iowrite stats mean=0;mxdev=0;mndev=0; for (a=2;a!=cindex;a++) { mean=mean+cia[a].iowrite; if (mxdev<abs(cia[a].iowrite-cia[a-1].iowrite)) mxdev=abs(cia[a].iowrite-cia[a-1].iowrite); mndev=mndev+abs(cia[a].iowrite-cia[a-1].iowrite); } mean=mean/(cindex-2); mndev=mndev/cindex; // printf("iowrite: Average:%d kb Max_deviation:%dkb Mean_deviation:%dkb\n",mean,mxde v,mndev); cst.iowrite[1]=mean;cst.iowrite[2]=mxdev;cst.iowrite[3]=mndev;
}
// The funny part: react accordingly void makescript(int TODO) { char *str=malloc(100); FILE *fd; char *buff=malloc(100); int value;
// Re-balance IO scheduller void rebalance() { if (sched>0) { sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/read_expire|awk '{print \"echo %d > \"$1}'`\"",(sched)*125*2); system(str); sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/read_batch_expire|awk ' {print \"echo %d > \"$1}'`\"",(sched)*125); system(str); sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/write_expire|awk '{prin t \"echo %d > \"$1}'`\"",(sched)*125); system(str); sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/write_batch_expire|awk '{print \"echo %d > \"$1}'`\"",(sched)*125*4); system(str); } else if (sched<0) { sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/read_expire|awk '{print \"echo %d > \"$1}'`\"",((0-sched)+1)*125); system(str); sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/read_batch_expire|awk ' {print \"echo %d > \"$1}'`\"",((0-sched)+1)*125*4); system(str); sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/write_expire|awk '{prin t \"echo %d > \"$1}'`\"",(1-sched)*125*4); system(str); sprintf(str,"sh -c \"`ls /sys/block/*/queue/iosched/write_batch_expire|awk '{print \"echo %d > \"$1}'`\"",(1-sched)*125); system(str); } }
// Resize readahead buffer void resizerabuffer() { sprintf(str,"sh -c \"`ls /sys/block/*/queue/read_ahead_kb|awk '{print \"ech o %d > \"$1}'`\"",(read_ahb)*128); system(str); }
// Set maximum FDs void filenr() { char *buf1; int i,j;
// buff=malloc(300); fd=fopen("/proc/sys/fs/file-nr","r"); fgets(buff,300,fd); fclose(fd); buf1=strtok(buff," "); i=strtod(buf1,NULL); fd=fopen("/proc/sys/fs/file-max","r"); fgets(buff,300,fd); fclose(fd); j=strtod(buff,NULL); if ((j-i) < 10000) { j=j+10000; logme("Tune FS: Raise maximum file handles...\n"); sprintf(buff,"echo %d > /proc/sys/fs/file-max",j); system(buff); }
if ((j-i) > 20000) { j=j-10000; logme("Tune FS: Don't need so much available file handles...\n"); sprintf(buff,"echo %d > /proc/sys/fs/file-max",j); system(buff); }
}
switch (TODO) {
// Increase vfs_cache_pressure case TODO_VFS_CACHE_INC: { logme("Tune VM: Increase VFS cache pressure -> pagecache..\n"); fd=fopen("/proc/sys/vm/vfs_cache_pressure","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value+10; sprintf(str,"echo %d > /proc/sys/vm/vfs_cache_pressure",value); system(str); if ((vfsu_after==0)&&(vfsd_after!=1)) vfsu_after=AFTER;
} break;
//decrease vfs_cache_pressure case TODO_VFS_CACHE_DEC: { logme("Tune VM: Decrease VFS cache pressure -> inode/dentry cache...\n"); fd=fopen("/proc/sys/vm/vfs_cache_pressure","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value-10; sprintf(str,"echo %d > /proc/sys/vm/vfs_cache_pressure",value); system(str); if ((vfsd_after==0) && (vfsu_after!=1)) vfsd_after=AFTER; } break;
// Increase dirty expire time case TODO_DIRTY_INC: { logme("Tune VM: Increase dirty cache expire time..\n"); fd=fopen("/proc/sys/vm/dirty_expire_centisecs","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value+500; sprintf(str,"echo %i > /proc/sys/vm/dirty_expire_centisecs",value); system(str); fd=fopen("/proc/sys/vm/dirty_writeback_centisecs","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value+500; sprintf(str,"echo %i > /proc/sys/vm/dirty_writeback_centisecs",value); system(str); } break;
// Decrease dirty expire time case TODO_DIRTY_DEC: { fd=fopen("/proc/sys/vm/dirty_expire_centisecs","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); if (value>=1000) {value=value-500;logme("Tune VM: Decrease dirty cache expir e time..\n");} sprintf(str,"echo %i > /proc/sys/vm/dirty_expire_centisecs",value); system(str); fd=fopen("/proc/sys/vm/dirty_writeback_centisecs","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); if (value>=500) {value=value-500;} sprintf(str,"echo %i > /proc/sys/vm/dirty_writeback_centisecs",value); system(str); } break;
// Rebalance iosched - we have more reads case TODO_REBALANCE_READ: { if (sched>-2) {sched=sched-1; logme("Tune IOsched: Peak reads,rebalancing..\n"); rebalance(); } } break;
// Rebalance iosched - we have more writes case TODO_REBALANCE_WRITE: { if (sched<2) { sched=sched+1; logme("Tune IOsched: Peak writes,rebalancing..\n"); rebalance(); } } break;
// Increase swappiness case TODO_SWAPPINESS_UP: { fd=fopen("/proc/sys/vm/swappiness","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); if (value<=90) {logme("Tune VM: Increase swappiness, don't need better responsiveness now..\n");va lue=value+10;} sprintf(str,"echo %i > /proc/sys/vm/swappiness",value); system(str); } break;
// Decrease swappiness case TODO_SWAPPINESS_DOWN: { fd=fopen("/proc/sys/vm/swappiness","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); if (value>=30) {logme("Tune VM: Decrease swappiness, we want better responsiveness now...\n");valu e=value-30;} else if ((value>10)&&(value<30)) {logme("Tune VM: Decrease swappiness, we want better responsiveness now...\n");value=10;} sprintf(str,"echo %i > /proc/sys/vm/swappiness",value); system(str); } break;
// (Almost) no swappiness case TODO_SWAPPINESS_ONE: { value=10; logme("Tune VM: Set swappiness at minimum, we don't need swapping now...\n"); sprintf(str,"echo %i > /proc/sys/vm/swappiness",value); system(str); } break;
// Increase page-cluster case TODO_PAGECLUSTER_UP: { fd=fopen("/proc/sys/vm/page-cluster","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); logme("Tune VM: Increase page-cluster for better swap I/O performance..\n");value=v alue+1; sprintf(str,"echo %i > /proc/sys/vm/page-cluster",value); system(str); } break; // Normalize page-cluster case TODO_PAGECLUSTER_NORM: { fd=fopen("/proc/sys/vm/page-cluster","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); if (value!=3) { logme("Tune VM: Return page-cluster to its normal value..\n");value=3; sprintf(str,"echo %i > /proc/sys/vm/page-cluster",value); system(str); } } break;
// Bye-bye swap... case TODO_FLUSH_SWAP: { logme("Tune VM: It's a good time to flush all your swap...\n");value=3; sprintf(str,"swapoff -a;swapon -a",value); system(str); } break;
// Increase readahead buffers case TODO_READAHEAD_UP: { if (read_ahb<20) { logme("Tune IO: Increase read-ahead buffers size...\n"); read_ahb=read_ahb+1; resizerabuffer(); } } break;
// Decrease readahead buffers case TODO_READAHEAD_DOWN: { if (read_ahb>1) { logme("Tune IO: Decrease read-ahead buffers size...\n"); read_ahb=read_ahb-1; resizerabuffer(); } } break;
// Check file-nr against file-max case TODO_CHECK_FILENR: { filenr(); } break;
// Increase receive network buffers size.. case TODO_RECVBUF_UP: { fd=fopen("/proc/sys/net/core/rmem_max","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); logme("Tune NET: Increase receive network buffers size..\n");value=value+20000; sprintf(str,"echo %i > /proc/sys/net/core/rmem_max",value); system(str); fd=fopen("/proc/sys/net/core/rmem_default","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value+20000; sprintf(str,"echo %i > /proc/sys/net/core/rmem_default",value); system(str); if ((recu_after==0)&&(recd_after!=1)) recu_after=AFTER;
} break;
// Decrease receive network buffers.. case TODO_RECVBUF_DOWN: { fd=fopen("/proc/sys/net/core/rmem_max","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); logme("Tune NET: Decrease receive network buffers size..\n");value=value-20000;
sprintf(str,"echo %i > /proc/sys/net/core/rmem_max",value); system(str); fd=fopen("/proc/sys/net/core/rmem_default","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value-20000; sprintf(str,"echo %i > /proc/sys/net/core/rmem_default",value); system(str); if ((recd_after==0)&&(recu_after!=1)) recd_after=AFTER; } break;
// Increase send network buffers size.. case TODO_SENDBUF_UP: { fd=fopen("/proc/sys/net/core/wmem_max","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); logme("Tune NET: Increase send network buffers size..\n");value=value+20000; sprintf(str,"echo %i > /proc/sys/net/core/wmem_max",value); system(str); fd=fopen("/proc/sys/net/core/wmem_default","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value+20000; sprintf(str,"echo %i > /proc/sys/net/core/wmem_default",value); system(str); if ((senu_after==0)&&(send_after!=1)) senu_after=AFTER; } break;
// Decrease receive network buffers.. case TODO_SENDBUF_DOWN: { fd=fopen("/proc/sys/net/core/wmem_max","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); logme("Tune NET: Decrease send network buffers size..\n");value=value-20000; sprintf(str,"echo %i > /proc/sys/net/core/wmem_max",value); system(str); fd=fopen("/proc/sys/net/core/wmem_default","r"); fgets(buff,100,fd); value=strtod(buff,NULL); fclose(fd); value=value-20000; sprintf(str,"echo %i > /proc/sys/net/core/wmem_default",value); system(str); if ((send_after==0)&&(senu_after!=1)) send_after=AFTER;
} break; } free(buff);free(str); }
// Teh Delphi Oracle: void givemyadvice() {
/* Must not: - Rely on absolute ratios (value_X more than X), only relative (value_X more than N*value_Y) - Keep it eventually unbalanced */ if ( (cst.buffers[3]>cst.buffers[4]+1) && ((cst.buffers[3]+cst.buffers[4])>0) && (cst.memuse[4]>cst.memuse[3]) ){makescript(TODO_VFS_CACHE_INC);} else if ((cst.buffers[3]<cst.buffers[4]+1) && ((cst.buffers[3]+cst.buffers[4])<0) && (cst.memuse[4]<cst.memuse[3]) ) {makescript(TODO_VFS_CACHE_DEC);} if (3*cst.dirty[2]<cst.dirty[1]) {makescript(TODO_DIRTY_DEC);} if (cst.dirty[1]<cst.dirty[2]) {makescript(TODO_DIRTY_INC);} if (cst.ioread[2]>cst.iowrite[2]) {makescript(TODO_REBALANCE_READ);} else if (cst.iowrite[2]>3*cst.ioread[2]) {makescript(TODO_REBALANCE_WRITE);} if (cst.swapuse[1]==0) {makescript(TODO_SWAPPINESS_ONE);} if ((cst.loadavg[2]>0.05)&& (cst.swapused[1]>0)) {makescript(TODO_SWAPPINESS_DOWN);} if ((cst.loadavg[2]<=0.05) && (cst.swapused[1]>0)){makescript(TODO_SWAPPINESS_UP);} if (cst.swapuse[2]>0) {makescript(TODO_PAGECLUSTER_UP);} else {makescript(TODO_PAGECLUSTER_NORM);} if ( (cst.swapcached[1]>0) && (cst.swapuse[2]==0) && (cst.swapuse[3]==0) && (cst.loadav g[3]<0.01)) {makescript(TODO_FLUSH_SWAP);} if (cst.ioread[3]<1) {makescript(TODO_READAHEAD_DOWN);} if (cst.ioread[3]<1) {makescript(TODO_READAHEAD_DOWN);} if (cst.ioread[2]>5*(cst.ioread[3]+1)) {makescript(TODO_READAHEAD_UP);} if ((cst.recv[3]>35*cst.recv[4]+1) && (cst.recv[3]+cst.recv[4]>0)) {makescript(TODO_RECVBUF_UP);} if ((cst.recv[4]>35*cst.recv[3]+1) && (cst.recv[3]+cst.recv[4]<0)) {makescript(TODO_RECVBUF_DOWN);} if ((cst.send[3]>35*cst.send[4]+1) && (cst.send[3]+cst.send[4]>0)) {makescript(TODO_SENDBUF_UP);} if ((cst.send[4]>35*cst.send[3]+1) && (cst.send[3]+cst.send[4]<0)) {makescript(TODO_SENDBUF_DOWN);}
if (vfsu_after>0) vfsu_after=vfsu_after-1; if (vfsd_after>0) vfsd_after=vfsd_after-1; if (recu_after>0) recu_after=recu_after-1; if (recd_after>0) recd_after=recd_after-1; if (senu_after>0) senu_after=senu_after-1; if (send_after>0) send_after=send_after-1; // These are mandatory
// Deprecate! // makescript(TODO_CHECK_FILENR); if (vfsu_after==1) makescript(TODO_VFS_CACHE_DEC); if (vfsd_after==1) makescript(TODO_VFS_CACHE_INC); if (recu_after==1) makescript(TODO_RECVBUF_DOWN); if (recd_after==1) makescript(TODO_RECVBUF_UP); if (senu_after==1) makescript(TODO_SENDBUF_DOWN); if (send_after==1) makescript(TODO_SENDBUF_UP);
}
// Here we are now, entertain us.. int main() { struct rlimit *rlm;
cst.send[3]=0; cst.memuse[3]=0; cst.recv[3]=0; cst.buffers[3]=0; cst.cached[3]=0; logme("***dktune started***\n"); // DO NOT FALL VICTIM TO STUPID RESTRICTIONS!!! rlm->rlim_cur=5000; rlm->rlim_max=30000; setrlimit(RLIMIT_NOFILE,rlm);
printf("Dynamic kernel tunning wannabe\nBy Milen Rangelov <mrangelov_@_globul_._bg>\n\nDaemonizing...\n");
// Detach from tty.. if ((fork())!=0) exit(0); setsid(); if ((fork())!=0) exit(0);
// Main Loop while (cindex!=-2) { getdata(10); analyze_data(); givemyadvice(); } return 0; }
|
Преди някой да почне да критикува: да, знам, не се пише код така, не се парсват стрингове така, не е хубаво толкова много system() да се ползва (съжалявам, набързо така ми е по-лесно), sprintf() хич не е безопасно да се ползва по тоя каруцарски начин и т.н и т.н..
За логиката на това в givemyadvice() и въобще за алгоритъма като цяло също вероятно ще си извадите извода че е дело на психично-болен индивид, няма да се обидя 
Не ви съветвам да го тествате засега все пак, това е само примерен код, за който засега единствено гарантирам че няма сработи като хората 
И откъде тези съотношения на базата на които си правя разни изводи: на базата на тестове на две машинки, т.е въобще не са меродавни и има доста да се преработват 
Титла: Динамичен kernel tunning?
Публикувано от: kennedy в Jan 17, 2007, 10:46
|