随笔-15  评论-10  文章-1  trackbacks-0
  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 阅读(1220) | 评论 (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 阅读(942) | 评论 (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 阅读(366) | 评论 (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 阅读(553) | 评论 (1)编辑 收藏
  2007年9月29日
     摘要:   阅读全文
posted @ 2007-09-29 17:24 hzb 阅读(425) | 评论 (2)编辑 收藏
  2007年9月25日
     摘要:   阅读全文
posted @ 2007-09-25 16:49 hzb 阅读(1031) | 评论 (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 阅读(259) | 评论 (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 阅读(1208) | 评论 (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 阅读(923) | 评论 (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 阅读(302) | 评论 (1)编辑 收藏
仅列出标题  下一页