configure –prefix 和 make install DESTDIR= 还有make install prefix 什么区别

./configure –prefix=* 确定了程序会被包装到哪里,以及,程序将在什么位置搜寻运行需要用到的相关的文件。如果你在一台机器上编译,然后仍然在这台机器上运行,那使用configure –prefix就是你想要的了。 make install DESTDIR=* 把程序安装到一个临时用的目录,这个目录不是程序以后将要运行的目录。例如,这个功能被deb包的打包人员使用。打包人员使用此功能时,并不真正把程序安装到–prefix指定的目录下。因为他可能已经安装了不同的版本,他不想搞乱他的环境,或者他没有boot权限,没有办法把程序安装到/bin,/sbin之类目录。 –prefix=/usr,让程序运行时认为被安装在/usr,然后make install DESTDIR=debian/tmp则实际把程序安装到debian/tmp。 make install prefix=/foo/bar/baz 和 make install DESTDIR的区别在于,前者不会创建prefix后面指定的所有目录层级,而DESTDIR会。 例如: ./configure –prefix=usr/local && make && sudo make install prefix=/usr/local/stow/foo 会把程序安装在/usr/local/stow/bin目录下。 而: make install DESTDIR=/usr/local/stow/foo,则把程序安装在/usr/local/stow/foo/usr/local/bin下面。 copyright ykyi.net

January 6, 2014 · 1 min · kamus

让eclipse自动生成的注释的时间显示英文,不用中文.

这几天换成用eclipse在windows机器上编写代码,远程运行在linux上,并且在windows机器上远程调试。 新建一个C++类的时候,eclipse/CDT自动生成注释,注释的时间用了中文,并且用的注释风格也不是我想要的。 但我想全部用英文,这个如何解决了。在stackoverflow上找到了答案,并试验成功。 windows -> preferences -> c/c++ -> code style -> code template 在右边的注释模板中编辑File Comment,改成你想要的模式。比如我的: /***************** * ${file_name} * Author: ${user} * Created on: ${date} ******************/ 再在eclipse的安装目录上找到eclipse.ini文件,加入:-Duser.language=en_US 重启eclipse。现在${date}变量生产的日期就是全英文了。 copyright ykyi.net

December 9, 2013 · 1 min · kamus

如何从windows远程调试linux程序。

用gdb在远程linux机器上调试程序实在太不方便了。于是想到用eclipse的GUI调试。下面介绍如何从windows远程调试linux程序。 ...

December 4, 2013 · 1 min · kamus

昨天解决了tcpcopy的一个小却很重要的bug.

tcpcopy的基础函数有个bug,流量比较大的时候,内核buffer满了。send系统调用发不完用户缓冲中的数据才会出现。然后加入了tcpcopy的QQ群,和作者稍稍讨论了一点时间。问了关于写论文和tc_session.c过于复杂的问题。 (wangb) 10:00:55 https://github.com//tcpcopy/pull/162 (wangb) 10:01:04 The bug arises when send system call returns with part of data transfered and part of data still need to be sent again. (wangb) 10:01:13 常见于压力比较大的场合 (wangb) 10:02:14 当然如果系统参数设置好的话,这样的情况不常见。这也是为啥我这边无法重现的原因所在 (wangb) 10:02:46 当然昨天在开发gryphon,貌似遇到过一次 (wangb) 10:03:06 gryphon给的压力,有时候真不是一般快和大 siu1ooooooo(16236914) 10:03:14 我在tcpcopy上作二次开发。碰到了个bug,最后追踪到了 tc_socket_send函数。 siu1ooooooo(16236914) 10:03:52 流量比较大的时候,内核buffer满了。send系统调用发不完用户缓冲中的数据才会出现。 siu1ooooooo(16236914) 10:05:21 希望能贡献更多代码的。。但是tc_session.c这个模拟tcp状态机的代码太难看懂了。 (wangb) 10:05:49 有些bug,程序员自身很难发现,往往需要依赖于用户的反馈,当然有上面的bug提出,就更好了 tc_session.c这个模拟tcp状态机,其实不仅模拟tcp状态机,而为复杂的是模拟上层应用交互 光模拟tcp状态机,是远远不够的 siu1ooooooo(16236914) 10:07:27 有个想法, 把TCP的11个标准状态加入到tc_session中。可不可以做的。. (wangb) 10:09:13 数据是死的,但测试服务器是活的。应该可以吧,但加入可能会更复杂。tc_session.c这个会进一步改进的,代码需简化和功能需独立,使其易懂 siu1ooooooo(16236914) 10:09:31 🙂 (wangb) 10:10:33 2010~2012.5月,初步探索阶段;2012.5~2014.5,为进一步探索阶段 2014.5~以后,进一步优化 因为tcpcopy刚开始,开发人员是无法知道复杂的互联网的各种应用的特性的,只有积累到一定程度,才能进一步优化。与其说是开发,不如说是探索 siu1ooooooo(16236914) 10:12:10 期待工程paper siu1ooooooo(16236914) 10:12:43 tcpcopy稳定到了一个版本。先别加功能了。写paper吧 siu1ooooooo(16236914) 10:13:01 投中EI应该问题不大。 siu1ooooooo(16236914) 10:13:55 中了paper,贡献者会迅速增多。 wangb() 10:15:43 其实写过sigcomm论文,但被拒,说应该投USENIX ATC wangb() 10:16:18 I don’t think that the research contribution of the paper is a good match for Sigcomm. Perhaps it would be a better match for a more practice-oriented conference like USENIX ATC. siu1ooooooo(16236914) 10:16:50 后来呢 wangb() 10:17:05 确实,tcpcopy是基于实践的,从实践中摸索爬行的。后来我就先不写论文了 siu1ooooooo(16236914) 10:17:22 嗯。这是个工程实践性很强的探索啊 wangb() 10:17:27 要写论文,必须要有条件 siu1ooooooo(16236914) 10:17:45 喔。 wangb() 10:18:06 从交换机或者其它设备。镜像过来,这样测试系统和在线系统就没有关联,这样的论文是能够中USENIX ATC 的 wangb() 10:19:13 tcpcopy最高端的应用,就是在交换机,利用分光镜或者其它镜像设备,利用高性能硬件,把用户的请求数据包复制给测试系统,可惜我没有这样的条件 wangb() 10:19:38 要是有这样的条件,我肯定要写论文了 siu1ooooooo(16236914) 10:19:55 呃。。没怎么看懂 siu1ooooooo(16236914) 10:21:49 是说复制的流量要非常非常大才能中论文么 siu1ooooooo(16236914) 10:21:59 而非常大的流量需求硬件支持 wangb() 10:22:02 twitter梦想的测试环境,其实完全可以用我们的tcpcopy来实现。交换机上面不是有来来往往的数据包吗?在那上面把请求数据包镜像到测试系统,测试系统搭一个跟在线类似的完整系统,这样测试系统跟在线系统承受类似的压力 wangb() 10:22:17 高端大气,才能中论文 wangb() 10:22:48 屌丝环境,写论文,还不被批啊 siu1ooooooo(16236914) 10:23:14 呃。是 。。。明白了。。想起以前学校的事情,懂了。 wangb() 10:24:38 总之,tcpcopy值得你去研究,期望有更多接班人把思想传承下去,代码可以推掉重来 wangb() 10:25:10 只要tcp协议还存在,这个思想,应该是最先进的,无法再先进了 siu1ooooooo(16236914) 10:26:11 需要好多的开发时间啊。..嗯。先上班了啊。多谢wangbin…. wangb() 10:27:16 慢慢来,这方面反正国外没有人做 ...

November 20, 2013 · 1 min · kamus

为什么我的名字没有出现在github的contributor列表中.

为什么我没有出现在github.com的contributor列表中. 我提交了commit,但为什么我没有出现在贡献者列表中呢。有三个原因: 1. 检查你的commit中的邮箱信息,这个邮箱必须和你的github.com账号关联。怎么关联邮箱账号呢。先选择Account Setting, 在左边先Emails,于是就看到可以verify邮箱地址的页面了。关联邮箱地址后还有过一段时间,贡献者列表才会更新。 2. 如果工程的贡献者名单列表超过了100个。就不会显示100个以后的贡献者了。官方HELP中说这是为了性能的考量。我觉得是码农偷懒,必竟这个需求太小了。绝大多数工程不会超过100个贡献者,于是码农不想解决这个小问题。 3. 你的commit必须被提交到工程的默认分支上。如果提交到其它的分支上,你的名字就不会被显示。 为什么我没有出现在github.com的contributor列表中. 我提交了commit,但为什么我没有出现在贡献者列表中呢。有三个原因: 1. 检查你的commit中的邮箱信息,这个邮箱必须和你的github.com账号关联。怎么关联邮箱账号呢。先选择Account Setting, 在左边先Emails,于是就看到可以verify邮箱地址的页面了。关联邮箱地址后还有过一段时间,贡献者列表才会更新。 2. 如果工程的贡献者名单列表超过了100个。就不会显示100个以后的贡献者了。官方HELP中说这是为了性能的考量。我觉得是码农偷懒,必竟这个需求太小了。绝大多数工程不会超过100个贡献者,于是码农不想解决这个小问题。 3. 你的commit必须被提交到工程的默认分支上。如果提交到其它的分支上,你的名字就不会被显示。   copyright ykyi.net      

November 20, 2013 · 1 min · kamus

如何删掉github上的master分枝.

假设,代码已经被clone到了本地。第一步要做的就是创建一个新的分支,比如placeholder,然后用-D从本地删除master分支。 git branch placeholder git checkout placeholder git branch -D master 如果现在删除github上的master,会报错: ...

November 1, 2013 · 1 min · kamus

Tcpcopy初体验.

Tcpcopy 初体验 Tcpcopy是一个模拟真实流量的测试工具。它的工作基本思想是,从已经上线的服务器复制一份真实流量到测试服务器。Tcpcopy的代码开源,代码仓库放在https://github.com/wangbin579/tcpcopy。 经过初步学习,已成功在公司的测试机器上部署tcpcopy,并用简单的DEMO程序测试达到预期目的。 **1.**安装 因为作者写的安装介绍只提到最基本的信息,而测试环境各不一样,在我用的测试机的实际安装过程中碰到一些问题。这时问题在这里列出,以供后来者参考,以节省时间。测试机:10.12.194.199 ; 10.12.194.212 ; 10.12.194.214 。 1.1 需要额外安装的库: 需要在网站 www.netfilter.org 下载 libmnl, libnfnetlink, libnetfilter_queue 三个工程并安装。 安装顺序为 libmnl, libnfnetlink, libnetfilter_queue,因为第三个依赖第二个,第二个依赖第一个。安装方法是GNU工具的传统三板斧方式: ./configure ; make; make install。这三个工程生成三个.so库放置到/usr/local/lib,而我们用的操作系统环境并没有把该目录列在默认查找库文件的目录列表中,因此要编辑 /etc/ld.so.conf 文件,把目录/usr/local/lib 加入,再运行 ldconfig 更新ld链接程序使用的cache。 1.2 IP_Queue****和NFQueue内核模块: 这两个内核模块给在用户空间编写处理内核空间中传递网络数据包提供接口。它们的区别是IP_Queue是旧的实现,仅支持IPv4,NFQueue是新的实现。Tcpcopy工程依赖这两个模块之一。 Tcpcopy官方文档中多次提到tcpcopy在内核版本小于3.5时默认使用IP_Queue,并在使用例子中有一步操作: # modprobe ip_queue 这个操作是确保加载ip_queue模块到内核。 我们的测试环境的内核版本号是2.6.32,按照官方文档介绍,内核版本小于3.5,于是使用#modprobe ip_queue命令,结果报错显示我们使用的内核没有启用动态模块加载。 于是再用 # zcat /proc/config.gz 检查当前内核的配置,发现CONFIG_IP_NF_QUEUE is not set, 说明IP_Queue模块没有被buit-in,再查找NFQueue的配置项发现 CONFIG_NETFILTER_NETLINK_QUEUE=y。 所以,在我们的环境中,应该忽略官方文档中# modprobe ip_queue,我们的内核已经内建了比IPQueue更新的NFQueue****。 1.3 编译安装tcpcopy**:** 官方文档中把已经正常运行业务的服务器称为在线服务器(online server),把运行待测试用的服务器称为目标服务器(target server)。 在在线服务器端运行配置命令时务必指定 –enable-nfqueue,这是因为我们用的内核中只有NFQueue,如果不指定这个选项,编译出的tcpcopy不会运行成功,会在日志文件中报错:please make sure ip queue is running. # ./configure –enable-nfqueue –enable-pcap ...

August 26, 2013 · 1 min · kamus

virtualBox开机挂载windows分区,并把光盘镜源设为源

virtualBox开机挂载windows分区,并把光盘镜源设为源。 设置fstab文件。把windows的d,e,f盘分别开机挂载到了/misc/d /misc/e /misc/f 。/misc是自建的目录,是miscellany的缩写。 # cat /etc/fstab # /etc/fstab: static file system information. # Use ‘blkid’ to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # / was on /dev/sda1 during installation UUID=590c2b64-87b7-4f92-b32f-7133139be772 / ext4 errors=remount-ro 0 1 # swap was on /dev/sda5 during installation UUID=1e4e1188-d057-4210-99e7-6f2d1529db80 none swap sw 0 0 /dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0 D_DRIVE /misc/d vboxsf rw,auto 0 0 0 E_DRIVE /misc/e vboxsf rw,auto 0 0 0 F_DRIVE /misc/f vboxsf rw,auto 0 0 0 /misc/d/debian_ios/debian-7.1.0-amd64-DVD-1.iso /misc/a_iso udf,iso9660 user,loop,auto 0 0 /misc/d/debian_ios/debian-7.1.0-amd64-DVD-2.iso /misc/b_iso udf,iso9660 user,loop,auto 0 0 /misc/d/debian_ios/debian-7.1.0-amd64-DVD-3.iso /misc/c_iso udf,iso9660 user,loop,auto 0 0 ...

August 21, 2013 · 1 min · kamus

我的毕业论文.Linux桌面环境下内存去重技术的 研究与实现

把我的毕业论文放上来,直接从word复制,所以图片会丢失。 在这里可以下载原稿 www.ykyi.net/upload/Research_and_Implementation_of_Memory_Deduplication_in_the_Linux_Desktop_Environment.pdf 中山大学硕士学位论文 Linux桌面环境下内存去重技术的. based on KSM 研究与实现 Research and Implementation of Memory Deduplication in The Linux Desktop Environment 学位申请人: <td style="width:160px;"> <p> 周霄 </p> </td> 导师姓名及职称: <td style="width:160px;"> <p> 王常吉副教授 </p> </td>         论文原创性声明 本人郑重声明:所呈交的学位论文,是本人在导师的指导下,独立进行研究工作所取得的成果。除文中已经注明引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写过的作品成果。对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本人完全意识到本声明的法律结果由本人承担。   学位论文作者签名: 日期: 年  月  日       学位论文使用授权声明 本人完全了解中山大学有关保留、使用学位论文的规定,即:学校有权保留学位论文并向国家主管部门或其指定机构送交论文的电子版和纸质版;有权将学位论文用于非赢利目的的少量复制并允许论文进入学校图书馆、院系资料室被查阅;有权将学位论文的内容编入有关数据库进行检索;可以采用复印、缩印或其他方法保存学位论文;可以为存在馆际合作关系的兄弟高校用户提供文献传递服务和交换服务。 保密论文保密期满后,适用本声明。   学位论文作者签名:                       导师签名: 日期:  年  月  日                       日期:  年  月  日         论文题目: Linux桌面环境下内存去重技术的研究与实现 专业:软件工程  硕士生:周霄 指导教师:王常吉  摘  要 内存管理是操作系统中至关重要的部分。优秀的操作系统高效地管理有限的内存资源。Linux内核的内核同页合并(KSM)模块是在虚拟化兴起后为节省虚拟机使用的内存而发展的一种节约内存的技术。KSM通过合并相同内容页面的方式显著地降低了多个基于内核虚拟机(KVM)技术的虚拟机同时运行时系统使用的内存。实际上,KSM也能合并一般应用程序中的相同内容页面。但一般应用程序为了使用KSM技术合并内存,需要在源代码级别显式地调用相应的系统调用来告知KSM需要扫描的内存区域。对于一般用户来说,需要修改应用程序的源代码显然是一个太高的门槛。 本论文在认真研究了KSM模块的实现的基础上,增强了KSM的功能。新设计实现的KSM+使得用户可以不必修改应用程序的源代码就能利用KSM+合并相同内容的内存页面。另外原来的KSM算法依赖程序指定的内存区域有大量的重复内存页面,而实际上,一般应用程序并没有大量的重复内存。在重复内存非常少的情况下,对这些程序应用KSM技术非但不能降低内存使用,而且因为运行KSM本身所需内存而增加了内存开销。本论文针对这一点在KSM的算法上做了改进,减少了运行KSM+算法本身所消耗的内存。然后论文用Linux桌面下的常用应用程序验证了KSM+的实际效果,并构造了一个实验比较了KSM和KSM+。最后,为了了解应用程序的重复内存页面的特点,还编写了专门统计重复页面的内核模块,发现应用程序的重复页面的一些规律,为持续改进KSM+提供了依据。   关键词:KSM,重复内存合并 ,内存管理   Title: Research and Implementation of Memory Deduplication in The Linux Desktop Environment Major: Software Engineering Name: Zhou Xiao Supervisor: Wang Changji Abstract Memory management is one of the most important parts of the operating system. KSM (Kernel Samepage Merging) in Linux kernel is a kind of memory saving technology developed after the emerging of virtual machine. KSM can dramatically decrease the memory usage of the hypervisor running several virtual machines. Actually, KSM can also be applied to normal applications. But in order to use the KSM, application must explicitly evoke a system call in source code level to tell KSM the memory area where the KSM will scan. To normal users, modifying the source code is impossible at most of the time. Base on the full grasp of the implementation of KSM, a new implementation named KSM+ is created, which allows users to merge same-content pages on the specified applications without modifying corresponding source code. Moreover, the original KSM algorithm relies heavily on the specified area is rich in same-content pages, while normal applications have much less same-content pages compared to virtual machines. So, when KSM is applied to those applications, it is possible that memory usage will rise rather than decrease. To combat with this situation, KSM+ employs a new algorithm to decrease the memory usage for running itself. Several experiments prove that the KSM+ can be easily applied to specified applications and memory usage can be reduced. And a case is designed to compare the effect between KSM and KSM+, which shows KSM+ behaves better in deduplication when the same-content pages’ density is very low. At last, in order to inspect the characteristics of same-content pages from normal desktop applications, an ad-hoc kernel module is developed to do the statistics which supplies significant data for the further development of KSM+. Key Words: KSM, Deduplication, Memory Management   ...

August 20, 2013 · 6 min · kamus

epoll学习报告

 epoll学习报告                              kamuszhou 周霄 Jul/26/2013   这几天通读了内核中对epoll I/O模型的实现代码,结合网络上很多介绍epoll的文章,对epoll的实现原理已经很熟悉,下面谈谈我的几点体会。下文引用的内核代码来自3.9.6版本的内核,见URL:http://lxr.oss.org.cn/source/fs/eventpoll.c。   一. epoll的边沿触发(ET)的效率高于电平(LT)触发的效率     首先简单介绍一个背景:epoll实现中,把已经有事件发生的文件用一个双链表链接一起,这个双链表是在struct eventpoll结构中的rdllist域。用户空间调用epoll_wait(),陷入内核后就会立即检查这个双链表,如果链表中非空,就通过文件的poll()函数询问文件有无事件发生。如果有事件发生且是用户关心的,就会向用户空间报告,否则就睡眠。     epoll的实现代码中实际上只有两行代码与触发方式有关,如下图所示。  上图所示的代码运行的上下文情况是:用户加入到epoll中的某个文件,只要支持poll(),(可以是socket,FIFO,裸设备,whatever)有关心的事件到达(或可读,或可写,或报错),内核空间已经把发生的事件复制到了用户空间,但还没有从内核态返回用户空间。在返回用户空间之前代码检查用被epoll监视的这个文件是否是ET触发,如果不是(那就是LT),就把监视的文件重新放回就绪队列,下次epoll_wait()调用的时候会立即重新检查这个文件有否有事件到达。如果这文件的确有事件发生,则epoll_wait()报告给调用者。如果没有,而且其它被监视的文件也没有事件发生,则调用epoll_wait()的task就让出处理器,开始睡觉(TASK_INTERRUPTIBLE)。这段逻辑在static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, int maxevents, long timeout)中,第1494行。 如果监听的文件开启的是边沿触发(默认),则不会执行上图中的list_add_tail()逻辑。这就是边沿触发只会向用户报告一次,直到下一个关心事件发生才向用户空间报告的原因。 那么为什么ET触发效率高于LT触发呢?看一个例子,假如客户端监视一个TCP的Socket,服务端这时发来1M数据,客户端的主机网卡驱动缓存足够大,一次性接收到了所有1M数据。下面看两段客户端的接收伪代码(没有写read调用返回时socket被关闭的情况;另socket描述符fd被设为非阻塞)。    上图的代码使用了LT触发,这段代码依赖epoll_wait()通知还有数据可供读取。所以共调用了1024次epoll_wait(),1024次read(),共2048次系统调用才读完1M数据。   上图使用ET触发,epoll_wait()只报告一次,然后代码循环调用1024次read()读完数据,直到第1025次read()返回-1,出错码为EAGAIN(EAGAIN等于EWOULDBLOCK),于是代码知道已经接收完数据。一共只使用了1026次系统调用就读完了数据。 总结:即使使用电平触发也不要依赖epoll_wait()通知调用者到达事件,需要循环调用IO函数直到被通知EAGAIN,这样就把epoll_wait()的调用次数降到最低,仅管有可能在下次epoll_wait()时会有可能浪费一次文件的poll()调用,但这个很小的开销可以忽略。   二. 为什么epoll支持嵌套调用 读epoll的实现代码发现,一个epoll的文件描述符epfd可以嵌套的加入另一个epoll。这样有什么用呢? epoll的实现中“平等的”对待每个被监视的文件,它们维护在一棵红黑树之中,假如有十万个文件被监视,那么查找某个文件时就要在这十万个文件中查找。即使红黑树的查找效率是log(n),文件非常大时也是比较消耗时间的。 那么假如有这样一种情况,如果这十万个文件中只有1000个是活跃的,或者说这1000个文件优先级最高。那么则有一种优化方案是,创建两个epoll,第一个epoll(epfd0)监控100000 – 1000 个文件,第二个epoll (epfd1) 监控1000个高优先级文件以及epfd0。这样的好处是,大多数情况下epoll实现只在1001个元素的红黑树中查找,自然效率提高了。 总结:epoll的嵌套调用给开发者提供了一个在高并发环境下的优化方案。   三. epoll的效率一定比select/poll高吗。     答案是不一定。 Select的缺点大致有: 1. 内核中写死了最多只能监视1024个文件. 2. 每次调用select都要把关心的文件描述符和关心的文件件从一个用户空间的长长的数组拷贝到内核空间. 3. select若使得caller进程进入睡眠后,某个文件有事件到达此进程被唤醒,那么所有被监视的文件全部会被调用poll()询问“你有没有事件到达”,这是一个线性的时间复杂度。 epoll针对select的三个缺点的改进: 1. 监视的文件数由取决于系统中有多少低端内存(x86_64架构中的所有内存都是低端内存)。3.9.6版本的内核实现中,对于每个登录用户,最多使用系统中低端内存的4%用来创建监视用的数据结构。见第1951行代码。max_user_watches = (((si.totalram – si.totalhigh) / 25) << PAGE_SHIFT) / EP_ITEM_COST; 2. 用户只需要把关心的文件对应的数据结构在调用epoll_wait()前用epoll_ctl()一次性传入内存,以后调用epoll_wait()时不需要像select一样拷贝大量数据。 3. 当调用epoll_wait()的caller进程睡眠时,突然有事件到达,caller进程被唤醒,epoll_wait()返回用户空间,内核并不遍历没有监视的文件,而只报告在一个即短时间内发生的事件。下面更详细的描述这个场景,以监视tcp socket举例,大致是:某进程调用epoll_wait(),此时没有任何它关心的事件发生,于是caller进程进入睡眠。处理器调度了其它进程。数据到达时,当前进程被硬件中断,网卡驱动收到数据包,数据包在中断处理函数中被拷入内核,中断处理函数设置中断下半部(Half Bottom)。下半部被处理器调度,调用epoll实现代码注册的回调函数ep_poll_callback()。ep_poll_callback()函数唤醒之前的caller进程,caller进程重新获得CPU,从epoll实现的ep_poll()函数中恢复执行,在3.9.6内核中的第1564行: if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))。然后,内核代码开始收集已经就绪的文件和发生的事件,发回用户空间。只有从第一次回调函数ep_poll_callback()被驱动的代码调用(caller进程还在睡眠时执行的ep_poll_callback()算第一次)到epoll实现代码走到第586行关闭中断关闭中断的代码 spin_lock_irqsave(&ep->lock, flags);之间发生的事件才会被收集。     对于第3点,这是epoll的优点,但在某种情况下却会是epoll的缺点。网上很多比较poll, select, epoll性能的文章,没来得及仔细看,我个人认为结论是可靠的。结论引入了一个概念active-to-total ratio,设所有被监控的文件数是n,活跃的文件数是m,active-to-total比则是m/n,如果这个比非常高,比如大于0.7,则poll或select的性能要高过epoll,反之则epoll胜出。     对比前文对select的第3个缺点和epoll的改进点3的叙述可以解释这个原因。因为select在返回用户空间前又轮循了所有关心的文件,而这些文件又大部分是有事件发生的,所以select所做的工作并没有浪费,但epoll只收集了一小段时间中发生的事件,于是select较之epoll减少了用户空间和内核空间的频繁切换,从而让select的性能反超epoll。 那么如何改进呢?明白了以上的原因,那么就可以对epoll做出改进,理论上对于active-to-total比较高的应用环境下,可以在epoll的实现中加入与select做法相同逻辑,即退出前询问所有的监控文件,反正active-to-total比很高。或者更好的方案,用一个链表链接活跃的文件,在epoll返回用户空间前遍历这个链表,争取每一个epoll_wait()调用返回尽可能多的事件。   附:epoll的主要数据结构简介. epoll接口的主要数据结构有struct eventpoll,struct epitem,struct eppoll_entry。     在讲述这三个数据结构前先提一下struct file。Unix设计初期希望它的设计遵从“一切皆文件”的理念。在Linux内核中,每个抽象的文件对应一个内核struct file结构体。Struct file结构体中有一个void *private_data域。不同的文件类型会在private_data域中存放特定的信息。Struct file中另一个域f_op是函数指针的列表,它记录了对应该文件的操作。所有epoll文件的f_op都指向static const struct file_operations eventpoll_fops,因此可以代码判断一个文件是不是epoll如下: static inline int is_file_epoll(struct file *f) {          return f->f_op == &eventpoll_fops; }       每次成功调用epoll_create时就会创建一个struct file的结构体,和一个struct eventpoll。Struct file中的private_data指向struct eventpoll。eventpoll维护了这个epoll的重要信息。其中比较重要的几个字段有:一个循环列表struct list_head  rdllist链接了该epll中已经可以读写或者有出错的文件描述符。一个红黑树的根结点struct rb_root  rbr,eventpoll维护了一棵红黑树,树中的结点是struct epitem。 每个被加入到epoll中被关注的文件描述符都对应一个struct epitem结构体。所有加入到同一个epoll中对应的所有epitem都挂在红黑树上。该红黑树的根结构保存在struct eventpoll中。epitem中记录了对应的文件的文件描述符和文件指针。 struct eppoll_entry是用来挂接到设备文件中的结构体。设备驱动在得知自己可读或可写或有错误时通过这个结构体通知有事件发生。每个eppoll_entry都指向一个epitem,一个epitem可能对应多个eppoll_entry。eppoll_entry中的域wait_queue_t  wait就是被用来挂接到设备文件中的等待队列。设备文件通过wait可以拿到eppoll_entry,再通过eppoll_entry拿到epitem,再拿到eventpoll。    

August 7, 2013 · 1 min · kamus