Month: Saturday May 26th, 2012

Linux kernel学习-内存寻址

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/linux-kernel-learning-memory-addressing/ 近日在看 Understanding the Linux kernel(慢慢啃E文原版,以下简称 ULK),这本书虽然已经是第三版了,但它基于的 Linux kernel 版本却不是很新,现在 Linux kernel 都已经出到 3.4 版本了,这本书还是基于 2.6.11 的 kernel,不得不说 Linux kernel 的更迭速度太快了。 下面准备以我正在用的 2.6.34 版本的 kernel 为基础进行学习,这本书中不对应的地方我会尽量找到新 kernel 中的实现,并尽量自己做个了解,日后的相同日志如无意外也基于 2.6.34 版本 Linux kernel。 首先已完成第一章:Introduction(这一章没有 Linux kernel 代码),来到第二章 Memory Addressing,开始是介绍逻辑地址、线性地址、物理地址的对应关系,虽然之前用汇编写过 Linux 的 bootloader,用到过实模式和保护模式,但对 GDT、LDT 的概念并没有深入了解过。这一章开篇就介绍了 Intel 80X86 硬件上内存分段的实现,包括段选择子,段寄存器,段描述符。 1、段式内存管理: 每个内存段由 8 个字节的段描述符来表示段的特征。段描述符被存储在 GDT 或者 LDT 中。内存中 GDT 的地址和大小包含在 gdtr 控制寄存器中,LDT 的地址和大小包含在 ldtr 控制寄存器中。段寄存器的高 13 位为段描述符在 GDT 或者 LDT 中的索引,GDT 或者 LDT 结构中包含基地址、段长度等信息。通过检查指令地址和段长度并确定没有越界以及权限是否正确之后,由于 线性地址 = 段基指 + 偏移地址,GDT 或者 LDT 中的基地址加上指令中的偏移量就可以得到需要的线性地址。 备注:由于每个进程都可以有 LDT,而 GDT 只有一个,为满足需求 Intel 的做法是将 LDT 嵌套在 GDT 表中。 Linux kernel 中的内存分段: Linux中所有进程使用相同的段寄存器值,因此它们的线性地址集也是相同的,不管在用户模式还是内核模式,都可以使用相同的逻辑地址,32位 kernel下为 4G 的地址空间。 ULK 中介绍的 user code、user data、kernel code、kernel data 这四个段对应的段选择子的宏为:__USER_CS、__USER_DS、__KERNEL_CS、__KERNEL_DS,2.6.11 中这4个宏定义在 include/asm-i386/segment.h 头文件中,2.6.34 中已经挪到 arch/x86/include/asm/segment.h 里,因为 2.6.34 中 i386 和 x86_64 的代码已经尽可能的合并到 x86 目录中,而不像老版本的代码那样弄成两个目录。定义如下: 下面是 Linux kernel GDT 的实现: 由于 kernel 中每个内核需要有一个 GDT,因此就有一个 GDT table,ULK 中说的是存在 cpu_gdt_table 中,GDT 的地址和大小存在 cpu_gdt_descr 中,2.6.11 kernel 里都是放在 arch/i386/kernel/head.S,使用的地方: 到了 2.6.34 中已经改为: 可以看到 2.6.34 中去掉了原来的 cpu_gdt_table 变量(详见 kernel commit bf50467204b435421d8de33ad080fa46c6f3d50b),新增了一个 gdt_page 结构存放 GDT table,而且提供 get_cpu_gdt_table 函数取得某个 CPU 的 GDT。cpu_gdt_descr 也已去掉,新增了 desc_ptr 结构存放每个 CPU 的 GDT 信息,cpu_gdt_descr 也改为 early_gdt_descr。 看下简单看下新的切换 GDT 的实现: load_gdt 最终调用 lgdt 汇编指令。 2、页式内存管理: Intel 从 80386 开始支持页式内存管理,页单元将线性地址翻译为物理地址。当 CR0 控制寄存器中的 PG 位置为 1 时,启动分页管理功能,为 0 时,禁止分页管理功能,并且把线性地址作物理地址使用。 32 位线性地址的高 10 位为页表目录的下标(指向页表),中间 10 位为页表的下标(指向页面),低 12 位为该地址在页面(通常大小为 4 KB)中的偏移量,这样的二层寻址设计主要为了减少页表本身所占用的内存,由于页表目录和页表都为 10 位,因此都最多包含 1024 个项。正在使用的页表目录的物理地址存在 cr3 控制寄存器中。 在 32 位大小的页表目录(页表)的结构中,其高 20 位为页表(页面)基地址的高 20 位,其它的 flag 中包含一个 Present 标志,如果该值为 1,表示指向的页面或者页表在内存中,如果为 0,页单元会将线性地址存在 cr2 控制寄存器中,并产生异常号 14: page fault。 页表目录结构中另外有一个 Page Size 标志(页表结构没有此标志),如果设为 1,则页面大小可以为 2MB 或者 4MB,这样可以跳过页表转换,将 cr4 寄存器的 PSE 标志启用即可启用大页面支持,此时 32 位线程地址由高 10 位页表目录下标和低 22 位的偏移量。 为满足寻址超过 4GB 的需求,Intel 从 Pentium Pro 处理器开始,将处理器的地址引脚数量由原来的 32 个提升为 36 个,处理器的寻址空间也从 4GB 增到 64GB,并增加 PAE 页面机制(设置 cr4 寄存器的 PAE 标志启用):64G内存可以划分为 2^24 个页面,页表中的基地址由 20 位增为 24 位,页表结构的大小由 32 位增为 64 位,增加 PDDT 表从而使用三层寻址设计来解释 32 位的线性地址等等。PAE 机制稍显复杂,而且由于仍然使用 32 位线性地址,因此对于应用程序来说,仍然无法使用超过 4GB 的地址空间,64GB 只是对于 kernel 而言的。 顺带说下不同的 64 位架构下的页面寻址级别,见下表,可以看到常用的 x86_64 架构只用了 48 位的线性地址空间,但也达到了 256TB 咯 ^_^ 3、硬件cache: 由于现在 CPU 速度太快,频率已经动辄多少 GHz,而相对的 DRAM 内存频率就慢很多,而且 DRAM 由于设计上电容存在不可避免的漏电原因,DRAM 的数据只能保持很短的时间,必须隔一段时间就刷新一次,不刷新的话会造成存储的信息丢失;而 […]

STL中const_iterator、reverse_iterator转换为iterator

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/stl-const-reverse-iterator/ STL中的容器类(Container)一般提供了4个迭代器:iterator、const_iterator、reverse_iterator、const_reverse_iterator,对于 container<T> 而言,其中 const_iterator 相当于 const T *,const_iterator 指向的元素不能做修改操作。 STL 容器的 begin() 和 end() 默认都提供了 iterator 和 const_iterator 的迭代器,相应的 rbegin() 和 rend() 则也分别提供了 reverse_iterator 和 const_reverse_iterator 的迭代器用于从容器的尾端反向遍历。 最近写的代码中刚好要用到 const_iterator 迭代器,发现由于 STL 提供的一些容器操作函数像 insert、erase 的参数必须为 iterator,这时就不能用 const_iterator 做参数(不能直接转换),以下为个人经验结果。 1、const_iterator 转换为 iterator: iterator 可以隐式转换为 const_iterator,但反过来就不行,就算祭出强制类型转换的杀招应该也会编译报错,这是可以用折中的办法解决: vector<sss> v_test; vector<sss>::iterator i_test; vector<sss>::const_iterator c_test; … c_test = …. … i_test = v_test.begin(); advance(i_test, distance<vector<sss>::const_iterator>(i_test, c_test)); i_test 指向第一个元素,先通过 distance 得到 c_test 和 i_test 的偏移量,然后用 advance 将 i_test 往后移对应的偏移量即可。注意 distance 的模板类型必须为 const_iterator 类型,否则按照 STL 的默认类型推导,distance 中的 i_test 和 c_test 类型不同还是会出现编译报错。 当然如果你想偷懒简单点,也可以这样写,道理是一样的,这时类型推导就显得很好用了: i_test = v_test.begin() + (c_test - v_test.begin()); 2、reverse_iterator 转换为 iterator: 对于 reverse_iterator 可以调用 base() 得到 “与之对应” 的 iterator(与上面的环境一样): vector<sss> v_test; vector<sss>::iterator i_test; vector<sss>::reverse_iterator r_test; … r_test = …. … i_test = r_test.base(); 但需要注意的是由于 STL 的 begin() 和 end()、rbegin() 和 rend() 是两个半闭合的区间,end() 并不是最后一个元素,rend() 也不是第一个元素,因此 end() 和 rbegin()、rend() 和 begin() 之间都是差了一个元素的。我们来看看 STL 标准上 base() 的说明: The base iterator is an iterator of the same type as the one used to construct the reverse_iterator, but pointing to the element next to the one the reverse_iterator is currently pointing to (a reverse_iterator has always an offset of -1 with regards to its base iterator). 也就是 reverse_iterator 的 base() 返回的元素都是 reverse_iterator 所指向元素的下一个元素,这也是前面 “与之对应” 加引号的原因。因此在使用时要特别注意,例如如果要删除 reverse_iterator 指向的元素就需要这样(因为 erase 必须要 iterator 类型的参数): v_test.erase((++r_test).base()); 3、关于随机访问容器: STL 中随机访问容器是一个迭代器类型为随机访问迭代器的可逆容器,它提供常量缓冲时间来访问随机元素。而可逆容器是一个有双向迭代器的前向容器,它可以向后向后迭代通过容器。 常用到的顺序容器是将单一类型的元素聚集起来,然后根据位置来存储和访问这些元素。顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定。 平时经常用的 string、vector、deque 之类就是典型的随机访问容器,map、set、list 之类的就不是。 因此需要注意 STL 中的 sort 等函数的参数必须是随机访问迭代器,所以对 map、set、list 等容器是无效的。 以上为个人见解,有任何问题欢迎指正交流咯 ^_^。

最新可用Facebook hosts(2012.5.23)

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/fb-hosts-20120523/ 今天加班改完有问题的 perl 脚本之后,发现 Gmail 里有 Facebook 的邮件,打开链接发现之前一段时间都一直好用的 Facebook hosts 今天也挂了,又找到了最新的 hosts,已经经过测试,请通过 https 打开,Firefox 等浏览器中可以安装 HTTPS-Everywhere 等插件实现访问 Facebook 时自动用 https 方式打开。 为防止被 GFW 扫描并再次墙掉,就不直接贴出 hosts 内容了,请猛击下面的福利网址下载,替换你的 hosts 文件的对应项即可,小心扩散~~~ ^_^。 http://miseal.googlecode.com/files/fb-hosts

忧伤的父爱-法国动画电影《魔术师》

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/lillusionniste-film/ 今天看到的这部法国动画电影《魔术师》,这只是一部手绘风格与CG结合的二维动画,没有现在3D动画的华丽,甚至全片也没有几句台词,所以虽然是法语的片子,你也能不借助任何字幕看懂,但这种手绘却能将片子的淡雅忧伤表现的更好,片子中体现的对旧日的缅怀,欧洲的手绘风光都值得留恋。 主人公 Tatischeff(简称 Tati) 是一个老牌魔术师,表演的都是一些非常老套的魔术,像帽子里变兔子,手绢里藏花,变酒杯之类,无奈在电视等新媒体冲击下,人们更爱电视明星、摇滚歌星之类,主人公为了生计只能到处奔波。上面的海报里头两个片段就是魔术师在不同表演场合的场景,都几乎没有观众,在电影刚开始的片段里,最深刻的就是魔术师在幕后不断地等一个摇滚乐团反复疯狂表演之后才能登台,但等到他登台时,原本台下狂热的摇滚观众已经无影无踪转到场外继续追星,而台下只剩两三人影。 魔术师辗转到苏格兰一个小乡村酒馆表演时,受到了相对不错的欢迎。他也是在这遇到女主人公 - 酒馆的小女孩招待员 Alice,她以为魔术师的表演就是魔法,甚至想让魔术师用魔法修已经坏了的玩具。魔术师为 Alice 买了一双红色的新鞋,但是以变魔术的方式给他的,女孩在 Tati 离开时也偷偷跟了出来,并开始跟着 Tati 辗转来到爱丁堡。 在这个小乡村的一段里也有我最中意的一个场景之一,这种画一般的风格灰常吸引人滴: 来到大城市之后,女孩开始对城市的繁华世界向往,魔术师却要为了生计想尽办法赚钱,更为了以魔术的方式将女孩想要的新大衣、连衣裙、高跟鞋等 “变” 出来,他沦落到在化妆品内衣橱窗里通过表演魔术吸引顾客,在洗车公司里做夜间看守,Alice 则每天在他们租住的旅馆里,似乎仍在认为 Tati 给他的都是魔术赐予的。这是他们在一起时比较温馨的片段: 同一间旅馆里还有一个小丑,一个拿着道具的腹语表演者,3个杂技演员,都是同样的落魄潦倒,小丑甚至在 Alice 送汤给他之前差点自杀,腹语表演者最后则是以乞讨和醉酒度日。 Tati 觉得在橱窗里的魔术表演并不适合自己,而在这时,他无意发现 Alice 已经与旁边的一个小伙陷入热恋中,他明白这已经是需要自己离开的时候,他在山上将一直跟随他的兔子(一只从头到尾一直在咬人的兔子啊)放生,然后拿上行李乘上火车离开。而 Alice 在回到旅馆时只看到 Tati 留下的 “Magicians donot exist” 字条,Alice 看着字条,拿上行李箱关上灯,与恋人一起离开。而片尾的火车上,魔术师则在给邻座的小女孩变出笔之后,拿出一张婴儿照片看了看,影片就此结束。 幕后故事(这部分就完全摘录自时光网咯): 这是一部向法国最伟大的喜剧大师雅克·塔蒂(Jacques Tatischeff)致敬的片子,本片就拍自雅克·塔蒂创作于1956年但未曾拍摄的剧本。影片中主角的形象就来自塔蒂本人,你会发现和主人公的名字是一样的。原剧本被认为是写给他当时才十几岁的私生女海尔格(Helga Marie-Jeanne Schiel)的一封特殊的信。这个剧本一直没有被搬上荧幕,是因为塔蒂本人认为片子蕴含太多私人情绪,隐晦而且让人感到不愉快。塔蒂与妻子米谢琳·温特的女儿索菲(Sophie Tatischeff)认为除了他的父亲塔蒂先生没人可以更好的演绎出这个片子。因此 2000 年,索菲将这个剧本交给法国动画导演 Chomet 时,索菲提出一个让 Chomet 制作一个动画中的 Tati,她不希望任何人来演绎他的父亲。 片中有一个片刻就是 Tati 在街头发现在热恋中的 Alice,他就想躲起来,结果退出一堆衣服误进了一家电影院,电影院中放映的片刻就正是 雅克·塔蒂 本人的表演。 至于本片中为什么 Tati 会对素不相识的 Alice 这么溺宠,恐怕潜意识里,他把这个小姑娘当成是自己的女儿,那个他没有尽到父亲职责的女儿,片尾魔术师看到的照片应该就是他的女儿。 而对于 Alice,或许有一些网友认为她完全是一个爱慕虚荣的小“叛徒”或者小“白眼狼”,但在她眼里,Tati 似乎就是如魔术师般的父亲的存在。Tati 对 Alice 体现出来也只是最单纯的父爱,只不过这父爱在片尾 Tati 独自离开之后体现的格外忧伤。 有关 雅克·塔蒂 本人,请参考百科和 Wiki: http://en.wikipedia.org/wiki/Jacques_Tati 另外,这里是电影《魔术师》的官方网站,上面有 Tati 和 Alice 的手绘稿之类的好玩东西哦: http://www.lillusionniste-lefilm.com/ 这是我摘下的两张 Tati 和 Alice 的原始手绘图 ^_^:

未能看到整个森林-编程学习中所犯的错误

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/fail-to-see-the-big-picture/ 备注:本文根据 pongba 大哥的这篇E文文章翻译并结合自己体会总结而来,pongba 的E文原文请猛击这里: http://blog.csdn.net/pongba/article/details/2143245 人类的一个普遍的天性是容易被自己感兴趣的东西所吸引。 不论是本文要说的编程学习还是日常事务都是这样,包括美女之类(哈哈),这似乎是一个难以打破的公理。人类自文明开始以来就对非凡的自然现象下的本质非常好奇,我们渴望理解,渴望知道原因。人类天性就是用来解决问题的,我们热衷于解决问题,热衷于发现问题的本质。不过悲哀的是,我们也是问题的主要创造者。 具体说到编程学习这一块,pongba 的原文中用 interesting(感兴趣) 和 mundane(平凡普通的)这两个词来区分编程学习中的两类知识。 我们最开始学习编程时用到的最经典的 hello world 就是 interesting 的一种,看到自己敲的一段字符能让计算机打印出来 hello world 确实能激发我们的兴趣。这就是所谓的 Under the Hood,这是一个在英文技术文章里经常见到的词,原意是钻进魔术师的帐篷,屏住呼吸,瞪大眼睛,把那些奇妙的魔法看个通透,让自己的理解和技艺获得巨幅的提升,在IT界里就是深入理解的意思。 你在学会设计程序和了解程序能正确运行的原因之后,接下来你会做什么?你会继续写程序,发现你所用的编程语言的越来越多的细节。你会越来越了解你用的编程语言,能知道该语言能方便的做些什么,哪些不能很方便的实现。接下来各种语言的窍门就开始进入你的脑海,注意这些窍门最吸引人的地方在于能让你做到本来做不到的事情,能让你荷尔蒙迸发,让你很 happy。 从程序设计语言的角度来看,我们热衷于解决的问题往往是我们自己创造的。例如,最近有一种争论关于设计模式是语言中缺失的一种特性。首先我们创造一门程序设计语言,由于一些设计时没有预料到的缺点,在使用中发现了,我们使用包括设计模式在内的一些语言窍门来解决它。但随着时间推移,我们就会发现这些模式不但没有价值,反而变成一种沉重的负担,这时通常会把这些作为新特性加入到语言中。 通常我们在解决以前的语言造成的问题过程中,我们通常又会造成新的问题。例如,现在总有 DSL 和 GPL 的争论,注意这里的 GPL 不是 GPL 开放授权协议,而是 Gerneral-purpose Language(通用语言),DSL 是 Domain-specific Language(领域专用语言)。DSL在很多人心目中是“非程序员的编程语言”,其首要目的是使程序尽可能接近领域中遇到的问题,消除不必要的间接性和复杂性,而其最终受众一般不是普通的程序员。一方面,将领域专用的一些特性加入到语言中,对那些需要对特定领域编程的人来说会非常便利;而另一方面,它会限制语言的使用范围。相对于DSL,GPL的最大优势在于可以为理论上无限的应用领域服务。GPL最大的妥协在于当面对领域相关的问题时,它只相当于一个 second-class language,这是为什么微软要搞一个CLR(通用语言运行时,Common Language Runtime)运行环境,也是为什么 Martin Fowler 要倡导面向语言编程LOP(Language-oriented Programming)了。 因此,在这总结一下,我们创造了各种语言抽象概念以使语言更加易用,但周尔反复的是我们总是在解决一个问题时创造时另一个新的问题。由于我们的程序设计语言都存在着不可避免的缺陷,这样语言窍门之类的东西就会登堂入室,并偷走我们的关注点(原文如此,嘿嘿),这也是为什么市面上有如此多的编程语言技巧书,语言陷阱介绍之类的,而且销量似乎都甚好。你可以看看任何C++编程学习的推荐书列表中,都不乏这样的例子。 然而到底是什么导致我们在编程学习时如在一堆树木里迷失,而导致没有看到整个森林?为了什么我们要学习这些奇淫技巧呢?实际上我们不是真正的需要,但我们内心里趋向于学习这些技巧,因为像文章开头说的,我们天生就是问题解决者,我们喜欢解决问题,即使这些问题是我们自己创造的。但这些奇淫技巧实际上只要在真正需要时按需学习即可,我们被这些东西吸引的原因在于: 1、我们喜欢新事物,如果什么东西是新事物就很有趣; 2、我们喜欢赶时髦(jump on the bandwagon)。 这就引出人类的第二个普遍的天性:赶时髦,如果所有人都做一件事,那我无论如何也得做。 不光是一些公司或者团体使用这个策略引诱我们去赶时髦,我们还热衷于创造自己的潮流。每当有新的语言或者技巧出来的时候,我们总是欢呼雀跃,总是被这些新带来的特性的光晕笼罩,而忘了它实际包含的问题,我们总是把它当做是万能灵药,开始万般饥渴地学习它。程序员是一种聪明的动物(原谅我如此直白,哈哈),不过有时显得过于聪明。他们总是渴望于新的事物(在任何编程论坛上找一圈就能得到验证,你会发现成千上万的程序语言技术细节的问题,学习这些东西是永无止境的,但程序员就是如此地欲罢不能),就像野兽永远不能停止对于食物的饥渴一样。 下面说说程序员普遍不爱的平凡的东西,什么是大多数程序员不喜欢的东西? 大多数程序员不爱的东西包括:编程原则,从小的编码规则(例如:永远给变量起一个有意义的名字)到大的项目设计原则(例如:在写代码之前先写测试文档)都有,还有文档的编制之类的,这些都是比较乏味的,不会显得古怪有味道,显得没有挑战性,显得没有那么酷。我们无法向外界展示遵从一些愚蠢的规则是多么聪明的一件事。我们尤其钟爱的是写一些疯狂的技巧代码或使用一些耀眼的模式以使别人都不知道我们在做什么(或者每个人都知道我们在做什么)。 接下来是人类的第三个天性:自私的偏见,我们热爱我们所做的,或者我们是谁,我们讨厌与之对抗或相反的东西。 不管你是否愿意承认这点,我们都有过这个体验。当我们对某些语言或平台非常熟悉时,我们就容易产生自私的偏见,它会影响我们想学习和不想学习的东西。你应该可以在一些论坛上感受到关于编程语言的争论是如此普遍。我们总是被蒙蔽了双眼,没有看到自己所用的语言或平台上的缺点和其它语言上的优点。我们限制了学习新的语言的能力,从某种意义上来说,我们限制了自己的潜能。 翻译的总结: 一方面,大多数时候我们学的东西有点太多了。我们像飞蛾扑火般被新事物吸引,我们经常是在学习周围的人在学习的,或者是别人告诉我们要学习的。但如果我们抓牢了一些本质的知识,其它的东西就完全可以按需学习。别再沉迷于技术技巧,除非它是必备的或者你马上就要用到的。因为要学习的技术技巧总是无穷无尽的,你应该将你的时间花在更有用的东西上(学些本质知识,学习编程思想,或者学习另一门编程语言)。 但另一方面,我们学的东西又太少了。我们总是忽视看起来乏味但又非常重要的东西,例如以下观点(可能很多人都有过): 测试? --- 就像做爱前戴套一样不爽; 重构? --- 为什么要做这种不能带来新功能也不酷的东西; 防御式编程? --- 对不起,我知道自己在写什么; API设计? --- 拜托,我在写这么华丽的代码的时候去考虑别人怎么使用我的代码也太TMD难了; 新语言? --- 你是说我现在用的这个不够好?没看到我能随意折腾这门语言来实现我想做的? 这是我首次完整翻译别人写的E文文章,也加了一些自己的观点,希望读者和我都能在未来看到编程学习中的整个森林 ^_^,有任何错误欢迎指正咯。 参考: 1、DSL领域专用语言: http://en.wikipedia.org/wiki/Domain-specific_programming_language 2、LOP面向语言编程: http://en.wikipedia.org/wiki/Language-oriented_programming

page cache诊断控制工具 vmtouch 源代码分析

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/vmtouch-code-analysis/ vmtouch 是一个 portable 的 page cache 诊断和控制工具,可以查看文件或者设备中有多少在 page cache 中,知道之后对这些在 page cache 中的内存引用可以避免 page fault,支持将文件的内容从 page cache 逐出,同时还可以将文件手工 touch 到 page cache 中,支持 lock 文件部分区域到 memory 中防止被交换出去从而提高。 vmtouch 可以在 Linux、BSD 等系统上使用,在这下载编译: http://hoytech.com/vmtouch/ 今天简单看了下 vmtouch 的代码,发现还比较简单,自己写个类似的程序验证之后,将代码分析结果写下。vmtouch 的代码比较少,我只贴出最关键的一个函数 vmtouch_file(关键部分已经高亮显示),这个函数做 分析 page cache 使用、touch、lock 的操作,其它部分只是加了读了目录的遍历处理之类的。 稍微有点基础就可以看明白了,先 mmap 映射文件到当前进程,按 page size 对齐之后,调用 mincore 函数就可以得到文件中每一个 page 是否在 page cache 中,结果保存在 mincore_array 数组中,该数据中每个字节的第一位即表示是否在 page cache 中。 将文件内容逐出(指定 o_evict)出 page cache 是通过 posix_fadvise 函数调用 fadvise 系统调用来实现的(BSD通过 msync 实现,这个在 Linux 上没有效果)。fadvise 系统调用可以告诉 kernel 要操作的文件在接下来要干什么,kernel 可以提前做一些操作而提高性能,Linux kernel 里实现了以下几种控制方式: POSIX_FADV_NORMAL - 正常操作,对文件使用底层设备的默认 readahead 值; POSIX_FADV_SEQUENTIAL - 顺序I/O,对文件使用两倍的 readahead 值; POSIX_FADV_RANDOM - 随机I/O,禁用文件上的 readahead; POSIX_FADV_NOREUSE - 只使用一次 POSIX_FADV_WILLNEED - 很快需要使用,对文件使用非阻塞读到 page cache POSIX_FADV_DONTNEED - 不再需要使用文件,从 page cache 中逐出 posix_fadvise 加 POSIX_FADV_DONTNEED 参数就可以将文件从 page cache 中逐出,需要注意的是如果需要确保文件从 page cache 中逐出,还需要在调用 fadvise 之前用 fsync/fdatasync/sync_file_range 之类的函数将 dirty page 清理。 下面是我在 Linux 下用 posix_fadvise 的一个测试程序测试的结果: 从 free 命令的结果可以很明显的看到,dd 之后基本文件都在 page cache 中,fadvise 之后从 page cache 中正确逐出。 接着是 vmtouch 中的 touch 操作(指定 o_touch)就更简单了,对 mmap 到的地址直接遍历引用,不在 page cache 的内容会自动产生 page fault 到 page cache 中。 lock 内存(指定 o_lock)也则直接使用 mlock 函数来实现,mlock 对于对安全性和实时性有很高要求的程序非常有用,可以保证指定的文件区域在内存中,不被 swap 出去。 以上为个人分析结果,有任何问题欢迎指正咯 ^_^

RAID5布局方式介绍及对性能的影响

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/raid5-layout-performance 本文主要介绍 RAID5 内部的数据布局方式,不对 RAID5 的基本原理做过多介绍。磁盘阵列中的 RAID5 类型是通过 XOR 奇偶校验算法来实现阵列中的数据冗余的,可以允许在坏一块磁盘的情况下继续使用,虽然在正常使用过程中写的额外开销比读要多很多,但对于一般企业来说还是很不错的选择。 布局方式: RAID5的校验和信息是平均分布到 RAID5 的每个硬盘上的,实际使用中有以下4种分布方式: 1、左对称(Left-symmetric); 2、左不对称(Left-asymmetric); 3、右对称(Right-symmetric); 4、右不对称(Right-asymmetric) 说这几个名词肯定不好理解,下面是一个4个硬盘组成的 RAID5 内部数据和校验和(parity)在不同布局方式下的分布图(每一行表示是一个条带 stripe): RAID5 几种布局方式中的“左”、“右”表示校验和(也就是图中的红色的P)如何分布,如图中,“左”的校验和都是从最后一个磁盘开始,依次前推,“右”的校验和从第一个磁盘开始,依次后推。 “对称”、“不对称”标识数据(也就是图中的 D0、D1、D2…)的分布方式,“不对称”方式都是直接将数据按照磁盘的数据直接排下来的(图中的左不对称和右不对称的前后数据明显不对称),而“对称”方式则将每个 stripe 中的第一个数据放在校验和的后面,然后往后排列,需要时再绕回第一个磁盘,这样“对称”的数据排列方式就能始终按照磁盘的顺序依次下来。 性能影响: 在实际使用测试中,校验和的左右布局方式对 RAID5 性能没有太大影响。由于实际读写 RAID5 时命令时均匀发到每个磁盘上的,从图中也可以推断出“对称”方式在处理大块值的连续 I/O 读时有更好的性能,实际测试中对随机 I/O 性能也有提升。 需要注意的是上面所说的性能影响相对于 RAID5 中的磁盘个数以及 stripe 条带大小参数来说是比较细微的。 其它说明: 现在很多的RAID卡中都使用了 左不对称 这种 RAID5 布局方式,另外 Linux MD RAID、Windows动态磁盘(LDM)、Veritas Volume Manager(VxVM)等实现中都默认使用了 左不对称 方式。了解 RAID5 的布局方式对 RAID 的性能调试之类有一定帮助哦,HOHO。 除了 Linux MD RAID,其它 RAID5 实现中的布局方式似乎没见到可以让用户选择,Linux MD RAID 可以在使用 mdadm 命令创建时指定 --layout 参数指定布局方式,详细请参考 man mdadm。 如果上面还是看不明白,可以参考这些E文的说明,特别第一篇画的很详细: http://www.accs.com/p_and_p/RAID/LinuxRAID.html http://www.z-a-recovery.com/art-raid5-variations.htm http://sfdoccentral.symantec.com/sf/5.0MP3/solaris/html/vxvm_admin/ch01s04s09s03.htm

刚迷上screen就不得不马上移情tmux

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/terminal-screen-and-tmux 一个星期之前调试代码时用上 GNU screen,这个多终端模拟器,对我而言很大程度上摆脱了调试时必须开N个 SecureCRT 远程登录标签的郁闷,而且很多 Linux 发行版上都已经自带 screen 包,直接安装即可,也可以在这下载自己编译: http://www.gnu.org/software/screen/ screen 的快捷键操作非常简单(文本模式下的 Linux 必须要N多快捷键的说),安装之后,在一个终端里运行 screen 命令就可以启动,可以在一个终端里再创建新的 shell,使用快捷键在不同的 shell 之间切换,使用 screen 的 detach shell 可实现更好的后台任务处理,用起来还是比较 happy,无奈 GNU screen 也有一些缺陷: 1、不支持在一个 shell window 里再拆分子窗口,也就是像 vim 的多窗口编辑效果; 2、对 xterm 终端支持一般; 3、不能自己根据启动 screen 时的窗口大小调节新 shell 的大小,这个小郁闷; …… 今天看到一哥们分享的 tmux 终端复用工具,立马感觉我要不淡定的移情了,在此下载: http://sourceforge.net/projects/tmux/ tmux 对比 screen 的优点:单个 shell window 拆分很强大,移动切换 shell pane 很强大,完美支持 xterm 终端和集成原 shell 大小,BSD license,命名 shell window,OOO,受不了先上图: 图中是我实际使用的一个环境,pane 0 查看 man 帮助,pane 1 修改代码,pane 2 命令操作,pane 3 监控系统。 tmux 的快捷键和 screen 的有点类似,只是初始快捷键改为了 Ctrl+B: Ctrl-B-C :创建新窗口; Ctrl-B-D :detach窗口,和 screen 的类似; Ctrl-B-”  :将当前窗口拆分为上下两行; Ctrl-B-%:将当前窗口拆分为左右两列; Ctrl-B-上下左右:切换 shell pane …… 具体请看 man tmux,果断强烈推荐了,tmux现在除了不是在每个 Linux 发行版中默认就附带这点似乎没有什么相比 screen 的缺点了(不过我还是下到了编译好的 RHEL6 上的 RPM 包,哈哈)。 tmux得在以后使用时继续研究咯,screen暂时抛弃,玩的开心~~~ ^_^

WordPress友言近期评论Widget更新(v1.1)

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/wordpress-uyan-recent-comment-widget-v1-1 前两天写了一个友言近期评论的 WordPress Widget,初步测试还能用,但多次进行刷新,会出现不能正常登录之类的问题(Failed to authentication with uyan.cc、Invalid comments data from uyan.cc 之类的报错),而且原来每次都需要登录友言的后台管理严重影响速度,我也比较怕怕这样不断发请求会导致友言把我的脚本和博客给封掉,嘿嘿。 由于友言没有公开 API 给我等码农来调用,因此今天又花了点时间做了一些改进,弄了个 1.1 版本,原介绍文章在这: https://zohead.com/archives/wordpress-uyan-recent-comment-widget/ 1.1版本更新说明: 1、登录友言后台管理,得到近期评论等地方增加错误处理,如果服务端返回的 JSON 数据不对则报错 2、减少 PHP 本身的 error message 输出 3、将得到近期评论的功能分离为一个函数单独调用 4、登录成功之后保存得到的 cookies 到同目录下的 uyan_cookie.php 文件中方便下次直接使用,而无需再重复登录,如果 cookie 过期下次获取评论时失败则再重新登录 5、发查询近期评论请求时增加友言本身的管理地址作为 referer 此次增加了一个 uyan_cookie.php 文件用于保存 cookie,从下面的链接下载解压缩之后,请将此文件也上传到同一目录中(不上传的话 PHP 可能会报 require_once 出错),此文件默认为空,详细代码就不贴了,直接在下面下载查看吧。友言 的登录邮箱、密码、域名之类的修改请参考原始的介绍文章了。 这个是 1.1 版本的下载地址: http://miseal.googlecode.com/files/uyan_comments_v1.1.zip 当前的通过临时文件保存 cookie 方式应该还有改进空间,有任何问题欢迎指正咯 ^_^

PHP实现WordPress友言近期评论Widget

本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/wordpress-uyan-recent-comment-widget/ 现在有很多人都使用 WordPress 来搭建自己的博客系统,其中有一些是像我这样使用 友言 这个社交评论插件来替代系统原始的评论框的,友言 评论框插件对一些主流的社交网站支持比较好,很是推荐,友言官网: http://uyan.cc/ 之前我写过一个修改 友言 插件实现完美与 WordPress Mobile Pack 插件配合实现移动版博客的文章,在这里仅供参考: https://zohead.com/archives/modify-plugin-wordpress-mobile-pack/ 但现在发现还是有一点不足,由于使用了友言评论框替代 WordPress 本身的,导致 WordPress 的 ”近期评论“ Widget(小工具)显示不了,因此小折腾一个晚上,靠着还依稀记得的 PHP 编程经历,写了一个简单的显示 友言 近期评论的 WordPress Widget,先看效果图(本博客右侧就有 ^_^): 原理及代码: 实现原理比较简单,先用工具分析 友言 评论的后台登录和评论显示之类的 HTTP 包信息,然后用 PHP 的 fsockopen 来自己发送 GET、POST 请求实现在 WordPress 上列举显示已经存在的友言评论(备注:默认只显示已经经过审核的评论)。 由于中间有几步 GET 和 POST 请求,就找了个现成的 post-to-host 这个很小的 PHP 脚本来发 GET 和 POST 请求,下载地址: http://code.google.com/p/post-to-host/ 下面是主程序 uyan_comments.php 的代码: 代码本身比较简单,有些 PHP 基础就可以看懂了,把 uyan_comments.php 文件最上面的 $email、$password、$domain、$maxcomments 改为实际的 友言 后台管理的登录邮箱、密码、你的域名、显示的最多评论数(备注:默认为10条,如果改为小于0的值则不限制显示的评论条数),就可以使用了。你应该已经发现这个 uyan_comments.php 其实和 WordPress 没太大关系,完全也可以直接单独使用。 需要注意的是为了避免使用明文密码而可能导致的问题(安全第一 ^_^),上面的 $password 是 友言 后台管理时实际用到的加密过的密码。这个加密过的密码可以通过 Firefox 的 Live HTTP headers 插件之类的抓取 HTTP 协议头的插件或工具来得到。 得到友言的加密登录密码: 下面以 Firefox 的 Live HTTP headers 插件为例说明如何得到 友言 的实际加密的密码,打开 Live HTTP headers,该插件会自动开始抓取,然后用正确的邮箱和密码登录 友言 的后台管理,停止 Live HTTP headers 的抓取,在输出里就能找到地址为如下格式的 GET 请求,请求参数中就有加密的密码: http://uyan.cc/index.php/youyan_login/userAutoLoginCrossDomain?callback=jsonpxxxxxxx&email=xxxxx@xxxxx.com&loginPassword=xxxxxxxxxxxxxxxxx&rem=1&domain=xxx.com 其中的 email 段就是登录邮箱,loginPassword 段即为加密的密码,保存下该密码,修改 uyan_comments.php 文件中的 $email 和 $password 值。 Live HTTP headers 的抓取截图如下所示(后面的未显示完整): 如何加入 WordPress Widget 列表中: 你如果有真正实现一个 WordPress Widget 的心思,可以用本代码加上 WordPress 的 register_widget 之类的接口来实现。无奈我是一个超级懒人,懒人就有懒人的办法,下面介绍的就是懒人的办法,哈哈。 首先下载本文最下面下载链接中的 post_to_host.php 和 uyan_comments.php,将 uyan_comments.php 中对应的 登录邮箱、密码、域名 改掉(参考上面),将这两个文件上传到 WordPress 根目录中(位置也可以自己修改),然后给 WordPress 安装 PHP Code Widget 插件,这是一个通用 Widget,添加之后,可以自行添加 文本、HTML、PHP 代码等,比较方便,插件地址: http://wordpress.org/extend/plugins/php-code-widget/ 安装之后,在 WordPress 管理后台的 外观 - 小工具 里就能看到名为 “PHP Code”  的小工具,将其托至右侧的 “第一小工具区域”,输入自定义的标题,然后加入以下代码保存即可(如果上传的位置不在 WordPress 根目录那请自行修改): 重新访问 WordPress,如果上面的 登录邮箱、密码、域名 设定都正确的话,应该就可以出现类似上面效果图的评论列表。 不足和改进: 1、uyan_comments.php 每次访问时都需要登录 友言 管理后台,请求评论列表,因此速度会有些影响,这个有空再改进了。 2、由于需要在 Web服务器中使用 PHP 的 fsockopen 来发 GET、POST 请求得到评论列表,因此可能对 WordPress 博客的访问速度造成一些影响,如果 PHP 空间在国内还可以,像我这样空间在国外的就稍微悲剧点了,所以建议安装 WP Super Cache WordPress 之类的插件来实现更好的缓存加速,将影响尽量降低。 下载地址(115网盘): http://115.com/file/beezjk3b 写博客好累,准备休息,HOHO,本文件为个人作品,有任何问题欢迎指正。 ^_^