pipe读写前设置O_NOATIME
Linux下的pipe使用非常廣泛, shell本身就大量用pipe來粘合生產(chǎn)者和消費(fèi)者的. 我們的服務(wù)器程序通常會用pipe來做線程間的ipc通訊. 由于unix下的任何東西都是文件,只要是文件,在讀取的時候,,就會設(shè)置last access time, 所以pipe也不例外., 但是這個時間對我們沒有意義 如果pipe使用的非常頻繁的時候會碰到由于設(shè)置訪問時間導(dǎo)致的性能問題. 這個開銷遠(yuǎn)比pipe讀寫的本身開銷大. 相比文件讀寫的開銷, atime微不足道,但是對pipe來講就不同了.
這個事情是上次和多隆同學(xué)在把玩他的網(wǎng)絡(luò)框架的時候,無意發(fā)現(xiàn)的.
我們來分析下pipe的這部分代碼:
//pipe.c:L349
static ssize_t
pipe_read(struct kiocb *iocb, const struct iovec *_iov,
? ? ? ? ? ? ? ?unsigned long nr_segs, loff_t pos)
{
...
? ?if (ret > 0)
? ? ? ? file_accessed(filp);
? ? return ret;
}
我們可以看到在pipe讀的時候要設(shè)置 file_accessed時間的,接著:
//fs.h:L1761
extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry);
static inline void file_accessed(struct file *file)
{
? ? ? ? if (!(file->f_flags & O_NOATIME))
? ? ? ? ? ? ? ? touch_atime(file->f_path.mnt, file->f_path.dentry);
}
如果文件沒設(shè)置 O_NOATIME就真正動手設(shè)置atime,接著:
//inode.c:L1493
void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
{
? ? ? ? struct inode *inode = dentry->d_inode;
? ? ? ? struct timespec now;
?
? ? ? ? if (inode->i_flags & S_NOATIME)
? ? ? ? ? ? ? ? return;
? ? ? ? if (IS_NOATIME(inode))
? ? ? ? ? ? ? ? return;
? ? ? ? if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
? ? ? ? ? ? ? ? return;
?
? ? ? ? if (mnt->mnt_flags & MNT_NOATIME)
? ? ? ? ? ? ? ? return;
? ? ? ? if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
? ? ? ? ? ? ? ? return;
?
? ? ? ? now = current_fs_time(inode->i_sb);
?
? ? ? ? if (!relatime_need_update(mnt, inode, now))
? ? ? ? ? ? ? ? return;
?
? ? ? ? if (timespec_equal(&inode->i_atime, &now))
? ? ? ? ? ? ? ? return;
?
? ? ? ? if (mnt_want_write(mnt))
? ? ? ? ? ? ? ? return;
?
? ? ? ? inode->i_atime = now;
? ? ? ? mark_inode_dirty_sync(inode);
? ? ? ? mnt_drop_write(mnt);
}
我們可以看出上面的流程還是比較復(fù)雜的,開銷也很大.
我們來演示下:
Linux下pipe使用注意事項
https://blog.csdn.net/xiaofei0859/article/details/50601180
$ cat > pipe_test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/unistd.h>
?
static int fds[2];
static pthread_t rp;
?
static void *rp_entry(void *arg) {
? char c[1];
? while (1 == read(fds[0], c, 1)) {
? ? if (*c == 'Q') break;
? }
? fprintf(stderr, "pipe read ok\n");
? return NULL;
}
?
int main(int argc, char *argv[]) {
? long i, n;
? int rc;
? if (argc < 2) {
? ? fprintf(stderr, "usage: pipe_test NNNNNN\n");
? ? return -1;
? }
? n = atol(argv[1]);
? pipe(fds);
? //fcntl(fds[0], F_SETFL, O_NOATIME);
? pthread_create(&rp, NULL, rp_entry, NULL);
? fprintf(stderr, "pipe write %ld...", n);
? for (i = 0; i < n; i++) {
? ? write(fds[1], "A", 1);
? }
? write(fds[1], "Q", 1);
? fprintf(stderr, "ok\n");
? pthread_join(rp, NULL);
? close(fds[0]);
? close(fds[1]);
? return 0;
}
CTRL+D
$ gcc -D_GNU_SOURCE pipe_test.c -lpthread
$ sudo opcontrol --setup --vmlinux=/usr/lib/debug/lib/modules/2.6.18-164.el5/vmlinux
$ sudo opcontrol --init && sudo opcontrol --reset && sudo opcontrol --start
$ ./a.out 10000000
pipe write 10000000...ok
pipe read ok
$ sudo opcontrol --shutdown
$ opreport -l|less ? ? ? ? ? ?
samples ?% ? ? ? ?app name ? ? ? ? ? ? ? ? symbol name
378654 ? 92.7742 ?vmlinux ? ? ? ? ? ? ? ? ?.text.acpi_processor_idle
12978 ? ? 3.1797 ?vmlinux ? ? ? ? ? ? ? ? ?current_fs_time
2530 ? ? ?0.6199 ?vmlinux ? ? ? ? ? ? ? ? ?thread_return
2345 ? ? ?0.5745 ?vmlinux ? ? ? ? ? ? ? ? ?touch_atime
2253 ? ? ?0.5520 ?vmlinux ? ? ? ? ? ? ? ? ?.text.acpi_safe_halt
1597 ? ? ?0.3913 ?vmlinux ? ? ? ? ? ? ? ? ?timespec_trunc
1368 ? ? ?0.3352 ?vmlinux ? ? ? ? ? ? ? ? ?file_update_time
1253 ? ? ?0.3070 ?vmlinux ? ? ? ? ? ? ? ? ?__mark_inode_dirty
901 ? ? ? 0.2208 ?vmlinux ? ? ? ? ? ? ? ? ?pipe_writev
768 ? ? ? 0.1882 ?vmlinux ? ? ? ? ? ? ? ? ?__mutex_lock_slowpath
763 ? ? ? 0.1869 ?vmlinux ? ? ? ? ? ? ? ? ?try_to_wake_up
270 ? ? ? 0.0662 ?vmlinux ? ? ? ? ? ? ? ? ?copy_user_generic_unrolled
254 ? ? ? 0.0622 ?vmlinux ? ? ? ? ? ? ? ? ?acpi_set_register
254 ? ? ? 0.0622 ?vmlinux ? ? ? ? ? ? ? ? ?system_call
233 ? ? ? 0.0571 ?vmlinux ? ? ? ? ? ? ? ? ?pipe_readv
188 ? ? ? 0.0461 ?vmlinux ? ? ? ? ? ? ? ? ?dnotify_parent
167 ? ? ? 0.0409 ?vmlinux ? ? ? ? ? ? ? ? ?mutex_unlock
...
我們可以看到touch_atime的開銷很大,遠(yuǎn)比pipe的讀寫大.
這次把這行注釋去掉: fcntl(fds[0], F_SETFL, O_NOATIME); 指示pipe在讀的時候不更新atime,看下效果:
view sourceprint?
$ opreport -l|less
samples ?% ? ? ? ?app name ? ? ? ? ? ? ? ? symbol name
599018 ? 95.2466 ?vmlinux ? ? ? ? ? ? ? ? ?.text.acpi_processor_idle
4140 ? ? ?0.6583 ?vmlinux ? ? ? ? ? ? ? ? ?.text.acpi_safe_halt
3281 ? ? ?0.5217 ?vmlinux ? ? ? ? ? ? ? ? ?thread_return
2812 ? ? ?0.4471 ?vmlinux ? ? ? ? ? ? ? ? ?current_fs_time
2615 ? ? ?0.4158 ?vmlinux ? ? ? ? ? ? ? ? ?file_update_time
1790 ? ? ?0.2846 ?vmlinux ? ? ? ? ? ? ? ? ?__mutex_lock_slowpath
1657 ? ? ?0.2635 ?vmlinux ? ? ? ? ? ? ? ? ?timespec_trunc
1341 ? ? ?0.2132 ?vmlinux ? ? ? ? ? ? ? ? ?try_to_wake_up
1281 ? ? ?0.2037 ?vmlinux ? ? ? ? ? ? ? ? ?mutex_unlock
1080 ? ? ?0.1717 ?vmlinux ? ? ? ? ? ? ? ? ?mutex_lock
1001 ? ? ?0.1592 ?vmlinux ? ? ? ? ? ? ? ? ?pipe_readv
925 ? ? ? 0.1471 ?vmlinux ? ? ? ? ? ? ? ? ?pipe_writev
這下看不到touch_atime了,開銷省了,對于高性能服務(wù)器是很重要的.
小結(jié): 細(xì)節(jié)很重要,記得開文件open的時候設(shè)置O_NOATIME或者用fcntl搞定它.
祝玩得開心!
總結(jié)
以上是生活随笔為你收集整理的pipe读写前设置O_NOATIME的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 判断程序是否处于调试状态
- 下一篇: CFileDialog 打开多个目录下的