Linux基础IO函数压力测试

Posted: 2010年6月10日星期四
做系统性能调优确实不好做,不仅要从算法上去解决,还有就是系统的一个库函数的IO能力到底怎么样,虽然有些资料提到,但到底差多少,心里还是没谱,下面是我做的一个linux系统的IO函数的处理效率的压力测试,各执行一百万次,看消耗的时间,详情请看代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/time.h>
#define LOOPNUM 1000000
#define IOSIZE 8

static double currtime(void){
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + (double)tv.tv_usec / (1000 * 1000);
}

int main(int argc, char *argv[]){
int i;
double stime, etime;

// open and close
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
int fd = open("TESTFILE", O_RDWR | O_CREAT, 00644);
close(fd);
}
etime = currtime() - stime;
printf("open&close: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// open and write and close
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
int fd = open("TESTFILE", O_RDWR | O_CREAT, 00644);
write(fd, "hogehoge", IOSIZE);
close(fd);
}
etime = currtime() - stime;
printf("open&write&close: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// open and read and close
char buf[256];
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
int fd = open("TESTFILE", O_RDWR | O_CREAT, 00644);
read(fd, buf, IOSIZE);
close(fd);
}
etime = currtime() - stime;
printf("open&read&close: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// lseek and write
int fd = open("TESTFILE", O_RDWR | O_CREAT, 00644);
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
lseek(fd, 0, SEEK_SET);
write(fd, "hogehoge", IOSIZE);
}
etime = currtime() - stime;
printf("lseek&write: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// lseek and read
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
lseek(fd, 0, SEEK_SET);
read(fd, buf, IOSIZE);
}
etime = currtime() - stime;
printf("lseek&read: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// pwrite
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
pwrite(fd, "hogehoge", IOSIZE, 0);
}
etime = currtime() - stime;
printf("pwrite: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// pwrite
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
pread(fd, buf, IOSIZE, 0);
}
etime = currtime() - stime;
printf("pread: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// mmap and output
void *map = mmap(NULL, IOSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
memcpy(map, "hogehoge", IOSIZE);
}
etime = currtime() - stime;
printf("mmap&output: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

// mmap and input
stime = currtime();
for(i = 0; i < LOOPNUM; i++){
memcpy(buf, map, IOSIZE);
}
etime = currtime() - stime;
printf("mmap&input: total=%.8f qps=%.0f\n", etime, LOOPNUM / etime);

munmap(map, IOSIZE);
close(fd);

return 0;
}



编译执行,在我笔记本上的执行结果如下:
open&close: total=2.59459996 qps=385416
open&write&close: total=4.47499609 qps=223464
open&read&close: total=3.04626703 qps=328271
lseek&write: total=1.35459495 qps=738228
lseek&read: total=0.51210380 qps=1952729
pwrite: total=1.15936184 qps=862543
pread: total=0.32837701 qps=3045280
mmap&output: total=0.00775003 qps=129031686
mmap&input: total=0.00818515 qps=122172497
从上面结果看,还是mmap速度快,跟其它的少一个数量级。

用C测试加减乘除压力测试

Posted: 2010年6月8日星期二
闲得无聊写了一个计算一百万次加减乘除所需要的时间,具体代码如下:

#include <stdio.h>
#include <sys/time.h>

#define MAX 1000000

static double currtime(void)
{
struct timeval tv;
if (gettimeofday(&tv, NULL) == -1) return 0.0;
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}

int main(int argc, char *argv[])
{
int i, j = 0;
double stime, etime;
stime = currtime();
for (i = 0; i < MAX; i++)
j += 0;
etime = currtime();
printf("%d time's plus exec time is:\t%f\n", MAX, etime - stime);

stime = currtime();
for (i = 0; i < MAX; i++)
j -= 0;
etime = currtime();
printf("%d time's subtracting exec time is:\t%f\n", MAX, etime - stime);

stime = currtime();
for (i = 0; i < MAX; i++)
j *= 1;
etime = currtime();
printf("%d time's multiplication exec time is:\t%f\n", MAX, etime - stime);

stime = currtime();
for (i = 0; i < MAX; i++)
j /= 1;
etime = currtime();
printf("%d time's division exec time is:\t%f\n", MAX, etime - stime);
return 0;
}

在我的笔记本上测试,测试出来的加减乘除执行一百万次所需要的时间基本差不多。

c语言获取今日,明日,昨日的方法

Posted: 2010年6月7日星期一
最近要处理大量的log,基本上按天保存log文件,这就牵涉到日期问题,本来采用shell写了一套程序,发现效率不是很高,所以改用c语言重新写了一份,下面是获取系统的今日日期和昨日的一个demo

#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
time_t t;
struct tm *m;

t = time(NULL) - 24 * 3600;
m = localtime(&t);
printf("Yesterday is: %d%.2d%.2d\n", m->tm_year + 1900, m->tm_mon + 1, m->tm_mday);

t = time(NULL);
m = localtime(&t);
printf("Today is: %d%.2d%.2d\n", m->tm_year + 1900, m->tm_mon + 1, m->tm_mday);


return 0;
}

nginx论坛防刷贴的实例

Posted: 2010年6月6日星期日
最近我的一个朋友跟我抱怨他的论坛被一群无聊的人在刷帖,问我有什么好的方法避免这种情况的发生,由于他使用的web服务器是nginx,我就利用web站点的访问log和nginx的目录访问权限规则写了个脚本,实现上面的功能,具体脚本的设计如下:
每5分钟探测当前这一个小时单IP的访问量,如果达到设置的上限,直接返回403错误页面给他,禁止他在接下来的一个小时的访问,并记录下他的ip,若在接下来的一个小时访问量正常,再智能的把他的站点的访问权限放开,允许他继续使用论坛,这样就拒绝了这群无聊的人,当然记得排除自己的ip地址。
附shell脚本实例

#!/bin/sh

LANG=UTF-8
onehourago=`date -d "1 hour ago" +%d\/%b\/%Y:%H`
now=`date +%d\/%b\/%Y:%H`
grep -v 1.1.1.1 /usr/local/nginx/logs/access.log | awk '/$onehourago/{++S[$1]}END{for (a in S) print a, S[a]}' | awk '{if($2>5000) print }' > /tmp/onehoureagodenyip
grep -v 1.1.1.1 /usr/local/nginx/logs/access.log | awk '/$now/{++S[$1]}END{for (a in S) print a, S[a]}' |awk '{if($2>5000) print }' > /tmp/nowdenyip
cat /tmp/onehoureagodenyip >> /tmp/nowdenyip
awk '{print $1}' /tmp/nowdenyip | sort |uniq > /tmp/denyip
cat /dev/null > /usr/local/nginx/conf/acl.conf
if [ ! -z /tmp/denyip ] ; then
for i in `cat /tmp/denyip`
do
echo "deny $i;" >> /usr/local/nginx/conf/acl.conf
done
fi
echo "allow all;" >> /usr/local/nginx/conf/acl.conf
echo "location ~ .*\.php?$ {
include /usr/local/nginx/conf/enable_php5.conf;
}" >> /usr/local/nginx/conf/acl.conf
kill -HUP `ps -ef |grep "nginx: master" |grep -v grep |awk '{print $2}'`

脚本说明:
先在nginx的主配置文件中server断中加入如下的内容:
location ^~ / {
include /usr/local/nginx/conf/acl.conf;
}
排除1.1.1.1的ip,同时当单IP一个小时的访问量达到5000次就屏蔽它(要是你的log中记录的东西不多的话,90%的用户单IP访问量一小时不可能有这么大)。

实时监控demo

Posted: 2010年5月22日星期六
最近写了一个实时服务器资源监控系统的demo,具体URL详见:http://60.29.244.76/live/live.html
目前能监控cpu,内存,load,网络连接状态,带宽。每2秒刷新一次,每条线都有开关,实现在动态显示,
Y轴随关闭的线,动态显示大小,每个点都有显示当前的实时状态的点,鼠标移动到相应的点能显示出来,如果闲更新太快,显示看不清楚,可以点击暂停,等你看清楚了可再点击开启实现再监控的功能。
目前只是一个demo程序,很多东西还没有,后期完善后,准备开源。

c实现数据字典批量替换文本内容

Posted: 2010年3月7日星期日
最近工作中需要大量替换log日志中的IP地址,使之显示ip对应的地区信息,于是用C写了个程序实现上述功能。
具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#define __USE_GNU //为使用strcasestr函数添加
#include <string.h>

void str_replace(char *buf, const char *pre, const char *aft)
{
char *p;
//不区分大小写
p = strcasestr(buf, pre);
if (p){
char *p_2 = p + strlen(pre);
str_replace(p_2, pre, aft);
memmove(p + strlen(aft), p_2, strlen(p_2)+1);
memcpy(p, aft, strlen(aft));
}
}

int main(int argc, char *argv[])
{
FILE *fp1, *fp2;
char buf1[1024] = {0},
buf2[1024] = {0},
id[20] = {0},
name[32] = {0};

if (argc != 3) {
printf("%s \n", argv[0]);
exit(-1);
}

fp1 = fopen(argv[1], "r");
if (fp1 == NULL) {
printf("Open file %s FAILE!", argv[1]);
exit(-1);
}

fp2 = fopen(argv[2], "r");
if (fp2 == NULL) {
printf("Open file %s FAILE!", argv[2]);
exit(-1);
}

while (fgets(buf1, sizeof(buf1), fp1)) {
fseek(fp2, 0, SEEK_SET);
while (fgets(buf2, sizeof(buf2), fp2)) {
sscanf(buf2, "%s %s", id, name);
str_replace(buf1, id, name);
}
printf("%s", buf1);
}

fclose(fp1);
fclose(fp2);

return 0;
}

编译:
gcc -o replace replace.c

使用:
./replace apache.log ip.txt
其中apahce.log文件可以为任何格式的文本文件,ip.txt文件具体格式如下所示:

1.1.1.1 北京电信
2.2.2.2 天津联通
3.3.3.3 广州移动

第一列为IP地址,第二列为ip地址对应的地区信息。
该工具同样适用于其它的类似替换,代码中已做了不区分大小写处理。

shell编程中文本处理中用到的几张图

Posted: 2009年11月10日星期二
在网上找到几个shell文本处理的几个常用命令的使用方法,觉得比较好,就贴在博客中,权当备忘,由于在google图片搜索出来的,不知道原载作者是谁,如知道,告诉我一声,加上原作者地址,下面的图直接看比较小,可以直接点击图,看大图,或者下载下来作为文件保存
正则表达式:

vi使用

sed使用

awk使用