2008年4月23日
定位IOWait高的一些方法和工具:
在Linux性能分析时经常使用的工具包括:top, iostat, vmstat等
IOWait高的一些处理方法
1、检查RAID的状态,比如是否正在重建或者没有初始化
2、替换操作系统的内核,最好使用发行版标准的Linux kernel,因为有比较多的补丁
3、检查/proc/sys/vm下面是否可以优化
4、是否使用了文件系统,文件系统是否有优化的选项,比如在RAID5上采用xfs文件系统时,
可以调节一些参数优化性能
5、客户端程序是否产生了过大的压力,比如磁盘的读写性能只有10MB/s,每个线程的读写
速度为5MB/s,那么如果读写线程数为20的话,无疑会造成IOWait过高
6、查看进程状态
ps -eo pid,user,wchan=WIDE-WCHAN-COLUMN -o s,cmd|awk ' $4 ~ /D/ {print $0}'
lsof -p $pid
7、使用block_dump
/etc/init.d/syslog stop
echo 1 > /proc/sys/vm/block_dump
sleep 60
dmesg | awk '/(READ|WRITE|dirtied)/ {process[$1]++} END {for (x in process) \
print process[x],x}' |sort -nr |awk '{print $2 " " $1}' | \
head -n 10
echo 0 > /proc/sys/vm/block_dump
/etc/init.d/syslog start
posted @
2008-04-23 14:06 hzb 阅读(1370) |
评论 (0) |
编辑 收藏
2008年4月22日
例子1 - 调用外部命令,然后检查外部命令的返回值
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int error = system("ps -ef");
printf("Outer program return value: %d\n", WEXITSTATUS(error));
return 0;
}
调用外部程序例子2
例子2 - 调用外部命令,并获得外部命令屏幕输出内容
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char buffer[4096];
int main(int argc, char** argv)
{
FILE *fp;
int status;
char *cmd = "ps";
fp = popen(cmd, "r");
if (fp == NULL)
return -1;
memset(buffer, 0, sizeof(buffer));
/*逐行再打印出来*/
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s\n", buffer);
}
pclose(fp);
return 0;
}
posted @
2008-04-22 17:57 hzb 阅读(1052) |
评论 (0) |
编辑 收藏
2007年10月30日
sysfs中有事件通知机制,我找了下,发现有下面的代码可用
#include <sys/select.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
/**
* Compilation : gcc inotify.c -o inotify -O2 -Wall -W -Werror -ansi -pedantic
**/
int fd, wd;
void sigint_handler(int signum)
{
(void) signum;
/* Nous ne surveillons plus ce fichier/répertoire */
if (inotify_rm_watch(fd, wd)) {
perror("inotify_rm_watch");
exit(EXIT_FAILURE);
}
/* Fermeture du descripteur de fichier obtenu lors de l'initialisation d'inotify */
if (close(fd) < 0) {
perror("close");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void afficher_masque(int mask)
{
printf("Event : ");
if (mask & IN_ACCESS)
printf("IN_ACCESS");
if (mask & IN_MODIFY)
printf("IN_MODIFY");
if (mask & IN_ATTRIB)
printf("IN_ATTRIB");
if (mask & IN_CLOSE)
printf("IN_CLOSE");
if (mask & IN_OPEN)
printf("IN_OPEN");
if (mask & IN_MOVED_FROM)
printf("IN_MOVED_FROM");
if (mask & IN_MOVED_TO)
printf("IN_MOVED_TO");
if (mask & IN_MOVE_SELF)
printf("IN_MOVE_SELF");
if (mask & IN_DELETE)
printf("IN_DELETE");
if (mask & IN_CREATE)
printf("IN_CREATE");
if (mask & IN_DELETE_SELF)
printf("IN_DELETE_SELF");
if (mask & IN_UNMOUNT)
printf("IN_UNMOUNT");
if (mask & IN_Q_OVERFLOW)
printf("IN_Q_OVERFLOW");
if (mask & IN_IGNORED)
printf("IN_IGNORED");
if (mask & IN_ISDIR)
printf("IN_ISDIR");
else
printf("(file)");
}
int main(int argc, char *argv[])
{
size_t r;
fd_set fds;
char buffer[8192];
struct inotify_event *event;
if (argc != 2) {
fprintf(stderr, "usage : %s file or directory to monitor\n", argv[0]);
return EXIT_FAILURE;
}
/* Initialisation d'inotify */
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
return EXIT_FAILURE;
}
/* Surveillance du fichier/répertoire passé en paramètre
* On accepte tous les évènements possibles */
wd = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS);
if (wd < 0) {
perror("inotify_add_watch");
return EXIT_FAILURE;
}
printf("Monitoring : '%s' (number = %d)\n", argv[1], wd);
/* Capture de SIGINT (Ctrl + C) */
signal(SIGINT, sigint_handler);
while (1) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (select(fd + 1, &fds, NULL, NULL, 0) <= 0) {
continue;
}
/* Obtention des informations sur l'évènement qui vient de se produire */
r = read(fd, buffer, sizeof(buffer));
if (r <= 0) {
perror("read");
return EXIT_FAILURE;
}
event = (struct inotify_event *) buffer;
printf("Monitored file n°%d\t", event->wd);
afficher_masque(event->mask);
if (event->len) {
printf("\tObject : %s", event->name);
}
printf("\n");
/* Gedit act strangly, reload the file if we get an IN_DELETE_SELF event.
if (event->mask & IN_DELETE_SELF) {
printf("Reloding watch");
inotify_rm_watch(fd, wd);
wd = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS);
if (wd < 0) {
perror("inotify_add_watch");
return EXIT_FAILURE;
}*/
}
return EXIT_FAILURE;
}
文档看:linux/Documentation/filesystem/inotify.txt
posted @
2007-10-30 11:51 hzb 阅读(489) |
评论 (0) |
编辑 收藏
2007年10月25日
mdadm使用了md驱动,lvm使用了dm驱动。通常我们都是使用mdadm创建各种级别的RAID,然后再通过lvm创建pv,vg和lv,lv是最后用户可以看到的“逻辑盘”。实际上,mdadm和lvm完全可以被替代,目前有evms已经这样做了。下面是mdadm的一些命令:
1、创建md
mdadm -C /dev/md0 -l5 -n3 /dev/sd{a,b,c} --assume-clean
上面命令创建一个由3个scsi盘组成的raid5阵列,注意,如果没有使用--assume-clean参数的话,创建完
md后,系统会自动帮你重建阵列
2、删除阵列
mdadm -S /dev/md0 '停止阵列
mdadm --zero-superblock /dev/sd{a,b,c} '清除超级块信息
检查了md的代码,觉得挺可惜的是,没有把一个创建出来的md块设备删除的代码,出了在md_exit(即模块退出时才删除md块设备)
3、监控阵列
下面是使用c程序监控
//app.c
#include <stdio.h>
int main(int argc, const char* argv[])
{
int i;
for (i=0; i<argc; i++)
printf("argv[i]=%s\n", argv[i]);
return 0;
}
gcc -o app app.c
mdadm --monitor -p app --scan &
4、删除/添加阵列磁盘
mdadm /dev/md0 -a /dev/sda -f /dev/sdb -r /dev/sdb
posted @
2007-10-25 17:30 hzb 阅读(787) |
评论 (1) |
编辑 收藏
2007年6月16日
最近发现一处spinlock误用的案例,大概情况是这样的:
有一个链表,中断程序和内核线程都需要去访问,代码中采用了spinlock
对链表进行保护,使用的下面的函数,
spin_lock()
spin_unlock()
导致现象是,在繁忙操作这个表的时候,随机出现kernel bug的提示,然后系统死掉,定位为spinlock使用有误,原因是上述的函数只是禁止了抢占,但是没有关中断,所以正确的应该是使用下面的函数代替,
spin_lock_irqsave()
spin_unlock_irqrestore()
posted @
2007-06-16 00:08 hzb 阅读(380) |
评论 (0) |
编辑 收藏
2007年3月9日
1、struct socket表示一个BSD Socket,BSD Socket是一个编程模型,可以看成是一套比较固定的函数接口;
2、struct sock是传输层的struct socket。一个sock在逻辑上应该包含:
(1)N个链表,用于存储发送数据和接受到的数据;
(2)代表传输层、网络层和链路层的函数指针集。这里的一个函数指针集对应的应该就是一个编程模型,比如UDP模型或TCP模型。
3、TCP的特点:面向连接,基于流
TCP
这种方式中,底层应该维护了一个复杂的state
machine和N个链表以保证数据的不丢失。由于TCP基于流,所以就存在自动组报问题。比如你的发送缓冲设为2 bytes,你发送了2条1
byte的消息,接受端只收到1条2bytes的消息,于是接受端需要自己解析消息。
4、 UDP的特点:没有连接,基于消息。
坏处是消息可能丢失,但是接收端不需要自己解析消息。
5、SCTP的特点:面向连接,基于消息
posted @
2007-03-09 01:01 hzb 阅读(1595) |
评论 (1) |
编辑 收藏
2007年1月28日
有多个子模块,他们都各自提供了自己的Makefile文件。
我推荐的一种组织方式是:
比如有工程A,B,C
我的Makefile组织方式是
~~~~~~~~~~~~~~
./Makefile (总Makefile)
./A/Makefile (子Makefile)
./B/Makefile (子Makefile)
./C/Makefile (子Makefile)
总Makefile的实现
~~~~~~~~~
# include sub makefile
include A/Makefile
include B/Makefile
include C/Makefile
# define grobal vars
DBG_TARGETS =debug_a \
debug_b \
debug_c
REL_TARGETS =release_a \
release_b \
release_c
CLN_TARGETS =clean_a \
clean_b \
clean_c
# define targets
debug : $(DBG_TARGETS)
release : $(REL_TARGETS)
clean : $(CLN_TARGETS)
子Makefile的实现
~~~~~~~~~
# define targets of a
debug :
echo "build debug version of a"
release :
echo "build release version a"
clean :
echo "clean a"
这种组织方式的好处
~~~~~~~~~~~~
1)简单,每个子模块只维护自己的Makefile文件,只需要提供
预定义好的target即可
2)target可重用,比如我可以通过make release_a获得a模块
的release版本
posted @
2007-01-28 14:09 hzb 阅读(1166) |
评论 (1) |
编辑 收藏
2007年1月27日
最近在linux内核态下编写、调试代码,一点心得是:
1、kgdb比较难使用(环境比较难搭建,常死机),但是偶尔用一下还是挺不错的
大致情况是:使用kgdb调时需要有2台主机,需要编译一份打了kgdb补丁的内核(具体看相关资料)
2、使用printk还是比较方便的,
日志一般是被打印到/var/log/messages中(当然这个是可以配置的)
比较喜欢的命令是
tail -f /var/log/messages |grep xxx
demsg -c
vi /var/log/messages
3、用户态下通过字符设备调用ioctl获取调试信息。这种情况下一般是程序设计阶段就已经有考虑到
4、通过/proc或/sysfs导出和设置属性的方式。使用这种方式可以直接通过shell脚本跟内核交互。
可以参考:
1) Documentation/kobject.txt
2) http://www.linux.it/~rubini/docs/sysfs/sysfs.html
posted @
2007-01-27 01:56 hzb 阅读(401) |
评论 (1) |
编辑 收藏