闲来无聊,想自己重写一些Command line tools,于是就先瞄准了cp。
写得也比较简陋,只能复制一个文件,主要是想先看看和系统实现的cp在性能上有多大差距。
写完之后,运行测试,复制同一个1KB文件1000次,复制一个11.5MB文件10次,和复制一个550MB的文件一次。 (文件大小均按1000进制计算)
测试环境及编译优化选项
MacBook Pro 13' Mid 2012
8GB DDR3 1333MHz
120GB SSD
编译器是Apple LLVM 6.0
优化开关-Os
于是还是先贴上测试结果(单位为秒),再附上源代码。
Result
测试项 |
系统 |
Mine |
1KB (1000) |
2.068 |
2.660 |
11.5MB (10) |
3.027 |
2.212 |
550MB (1) |
6.293 |
6.209 |
下面就附上源代码,肯定还有很多需要改进的地方,比如在复制小文件的时候,明显效率略低。也许应该把default_buf_size的值再改小一点?
Code
//
// main.c
// cp
//
// Created by Ryza 14-7-23.
// Copyright (c) 2014年 Ryza. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <string.h>
#define min(x,y) ( x>y?y:x )
int main(int argc, const char * argv[]) {
if (argc != 3) {
exit(EXIT_FAILURE);
}else{
struct stat buf;
stat(argv[1], &buf);
if (S_ISDIR(buf.st_mode)) {
perror("Could't copy dir");
exit(EXIT_FAILURE);
}
//先取得文件的类型和存取的权限
int from = open(argv[1], O_RDONLY, S_IROTH);
int to = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, buf.st_mode);
//保留原来的存取权限
#define default_buf_size 8192 * 4
#define max_buf_size 8192 * 16
//设置默认和最大缓冲区大小
#define magic_number 88
#define split_size (80 * default_buf_size)
// 80 is another magic number
long long bufsize = default_buf_size;
if (buf.st_size > split_size) {
bufsize = min(buf.st_size / magic_number,max_buf_size);
}
//找一个合适的缓冲大小
char *filebuf = (char *)malloc(bufsize);
ssize_t readcount;
while (( readcount = read(from, filebuf, bufsize) ) > 0) {
if (write(to, filebuf, readcount) != readcount) {
perror("Could't write whole file");
}
}
//复制文件
memset(filebuf, 0, bufsize);
//清空文件
free(filebuf);
exit(EXIT_SUCCESS);
}
}
后记,将改成了8192之后,复制1KB的文件1000次仍然需要2.632秒,不知道怎么继续优化了。也许要mmap?