直秋's profilewaiting 4......what?PhotosBlogListsMore ![]() | Help |
|
waiting 4......what?i saw you came to me, like my angel January 30 Popcount Problem: 求二进制数中1的个数 (上)一、问题描述:求一个N位整数x的二进制表示中1的个数,越快越好。 据说这是道很常见的面试题。原题是说如何在常量时间内算出32位整数的二进制表示中1的个数。实际上这么问是有漏洞的,因为按照最笨的方法,一个一个数,也不过32次,当然是常量时间。但如果你这么告诉面试官,十有八九会被骂白痴。因为大家一般都会认为32次实际上是O(N)的做法。所以这么问可能会更好一些,求一个N位整数x的二进制表示中1的个数,越快越好。 实际上这个问题叫做Hamming weight[1],或者叫做population count以及pop count。看到Hamming大家基本上可以恍然大悟一下了,这玩意可以用来计算海明距离。另外在信息论、编码学等也有很多应用。 对于这个问题的解法,Google一下popcount 或者count bits 1会有一大把。基本上无非是三大类,直观的挨个数O(N),分治法O(lgN),查表法O(1)。但实际上对于这种问题,单单考虑时间复杂度意义不大。尤其是在问题规模较小的情况下,比如说32位整数或者64位整数。比方说,对于查表法,如果查找表太大导致程序运行时不得不访存,这个开销可能要比前两种方法都要大得多。下面分别总结一下,以64位整数为例,源程序和解析都给出来了。这个题目虽然简单,但很多解法,尤其是HAKMEM解法非常精彩,让人看完以后不禁拍案叫绝又扼腕叹息,为什么我就想不到这种方法呢 T.T。 二、解法分析: 1) naive solution:依次移位,数1的个数,时间复杂度为O(N)。这里的N为整数的位宽。 2) less-naive solution: 对方法1)进行优化,x&(x-1)可以将最右端的(rightmost)1转化为0typedef unsigned __int64 uint64 时间复杂度为O(n),n为1的个数。这样在1比较少的时候比第一种方法快很多。int pop_count_lnaive(uint64 x) 同理,x | (x+1) 可以消除最右端的一个0(转化为1)。因此在0比较多的时候,可以先计算0的个数。下面是wikipedia上给出的版本。跟上面的代码类似,只是把循环展开了。 3) shift_and_add 时间复杂度O(logN)const uint64 hff = 0xffffffffffffffff; 这个方法主要利用两点,一是根据最直观的做法,把每一位相加后就可以得到结果,这个过程我们可以利用分治+并行加法来优化;二是对于n位整数,最多有n个1,而n必定能由n位二进制数来表示,因此我们在求出某k位中1的个数后,可以将结果直接存储在这k位中,不需要额外的空间。 以4位整数abcd为例,最终结果是a+b+c+d,循环的话需要4步加法。 1' 每一位一组[a][b][c][d],相邻两组相加得到[a+b][c+d],结合成两位一组。所有的加法可以像这样并行进行: [0] [b] [0] [d]其中ef=a+b, gh=c+d。而0b0d = (abcd) & 0101, 0a0c = (abcd)>>1 & 0101 2' 两位一组: [ef][gh],相邻两组相加,结合成四位一组。 [0 0] [g h]其中ijkl = ef + gh,00gh = (efgh) & 0011, 00ef = (abcd)>>2 && 0011。这样得出的ijkl就是最终结果。这样只需要log(N)步。 按照这个方法类推,我们很容易可以得出计算uint64的方法。 总体需要 6次shift, 12次and, 6次add 共24次算术运算。typedef unsigned __int64 uint64; //assume this gives 64-bits 4) 对shift_and_add进行优化 因为具体的分析实在是有点啰嗦,所以先看程序,再来分析。 共需要 6次shift, 5次and, 5次add, 1次sub,共17次算数运算。下面具体来看这7个与运算是如何省掉的。int popcount_2(uint64 x) { 1' 第一步要做的是将2bits的整数ab (=2*a+b)变成 a+b。不难看出,(2*a+b) - a = a+b。也就是说: x - (x>>1) & m1就是我们要的结果。这样省掉了1步与运算。 2' 先与后加=>先加后与,再省掉1步与运算。 之所以先与后加,是为了去掉不必要的干扰。比如说对于上面所讲的例子: [a] [b] [c] [d]我们所关心的结果只是奇数组(d+c)和(b+a)的结果,这里我们称之为有效组; 红色标注的部分(c+b)和(a+0)的结果是没有用的(上例中直接置为0),我们称之为无效组。每一步的操作,实际上是将有效组相加,结果存放在有效组和无效组连接所组成的新组中。 如果不通过and操作将abcd=>0b0d, 0abc=>0a0c,那么在做加法的时候无效组会出来捣乱。第一组的结果(d+c)如果有进位,就会被第二组的结果(c+b)所干扰。同理,第二组(c+b)的进位也可能会干扰到第三组的结果(b+a)。这样的无效组我们称之为干扰组,因此在加法操作进行之前有必要利用掩码将干扰组屏蔽。 通过上面的分析我们可以知道,干扰组的出现是由于两个k位分组的最大和(2k)超出了k位二进制数能表示的范围,从而不可避免地产生进位,干扰相邻组的结果。那么如果不会产生进位呢,就没有必要在加法操作之前利用掩码将干扰位过滤掉了,过滤操作可以延迟到加法操作之后进行。也就是说,我们可以先加后与,省掉一个与操作。(就为了省掉一个与运算,还真是折腾。。。) 不难看出,从4位分组开始,两个分组的最大和8就可以仅用原来的4位表示了。因此m4, m8, m16, m32都可以延迟到加法操作之后。 3' 只加不与,再省掉1步与运算 之所以加法操作之后还是要进行与运算,是为了防止将脏数据带入下一步计算中。比如说: [a1 a2 a3 a4] [b1 b2 b3 b4] [c1 c2 c3 c4] [d1 d2 d3 d4] [a1 a2 a3 a4] [b1 b2 b3 b4] [c1 c2 c3 c4] ------------------------------------------------------- [e1 e2 e3 e4] [f1 f2 f3 f4] [g1 g2 g3 g4] [h1 h2 h3 h4] 很明显,红色标注的部分的无效组并不会产生进位,从而不需要在加法操作之前过滤。那么如果加法操作之后还是不过滤呢?如果继续将这部分脏数据带到下一步运算中呢? [e1 e2 e3 e4 f1 f2 f3 f4] [g1 g2 g3 g4 h1 h2 h3 h4] [e1 e2 e3 e4 f1 f2 f3 f4] ---------------------------------------------------- [h1 h2 h3 h4] + [f1 f2 f3 f4]最大是16, 很显然4位已经存不下了,但上一步操作中的脏数据。也就是说,无效组即便在当前步骤中不会捣乱,也可能在下一步中出来捣乱,我们可以称之为延迟干扰。因此及时斩草除根免除后患是必要的。 那么如果无效组在今后所有的步骤中都不会形成延迟干扰呢?也就是说,之后每一步的中间结果都只用k位就能存下,不再需要进位。这样一来,每次计算只需要关心分组中后k位的结果就可以了,无效位即使不清除,也不会造成干扰,因此加法操作后的与运算也可以省掉。 不难看出,64位整数最多有64个1,而64只需要7位就可以存下。也就是说,从8位一组两两相加开始,我们只需要关心每组中后7位的运算结果,而且这后7位的结果不会受到任何干扰。因此m8, m16, m32全部都可以不要,只需要在最后return x& 0x7f就可以了。 To be continued…… P.S: 唉,live space居然提示我字数太多必须分篇…我很无奈…难道是因为经济危机? Popcount Problem: 求二进制数中1的个数 (下)5) 传说中的MIT HAKMEM169方法 HAKMEM 是1972年由MIT人工智能实验室的一帮牛人(当然也包括RMS)发布的一本备忘录,里面都是些很无敌的算法,主要的目标是更快更好地进行数学运算。其中的第169个算法,就跟popcount有关,原始的代码[3]是用汇编写的,翻译成C代码如下: 总共需要3次shift, 3次and, 2次add, 1次mul, 1次mod 共10次算数运算。这是32位整数的版本,改成适用于64位整数的版本也很简单。主要思想也是分治以及并行加法。只是与原始的shift_and_add有两点不同:typedef unsigned __int32 uint32; 一是第一步的时候是每位一组,相邻三组相加。比如说对于x=(abc)2=4*a+2*b+c,x>>1&m1= 2*a+c,x>>2&m2=a,于是 x - x>>1&m1 - x>>2&m2 = a+b+c。 二是在第二步做完之后,这时是每6位自成一组,以12位整数为例,x=(ab)64 = a*64 + b。很明显, a*64+b ≡ a+b mod 63。也就是说x与a+b关于模63同余。同理,对于64位整数我们也可以这么处理。 6) 再次优化shift_and_add方法,用乘法操作代替加法操作 利用CPU中的基本运算部件乘法器,我们可以继续优化shift_and_add方法。还是先看代码: 总共需要 4次shift, 4次and, 2次加法,1次减法,1次乘法共12次算数运算。const uint64 h01 = 0x0101010101010101; 可以看出,第三步以后的操作全部都被省略了。这是因为从这步开始,我们需要的操作是8位一组,8个组的数依次相加,就可以得到最终结果。这恰恰可以通过通过乘法器来做到。以32位整数为例,共有四组: 0a 0b 0c 0d * 01 01 01 01 ------------- 0a 0b 0c 0d 0a 0b 0c 0d 0a 0b 0c 0d 0a 0b 0c 0d -------------- ef gh ij kl 红色标注部分为溢出位,舍掉。橙色标注部分是我们需要的结果,右移24位就可以得到。同理对于64位整数,乘法操作后的结果右移56位就可以得到结果了。 注意如果CPU执行乘法操作指令比较慢的话,这样优化可能会适得其反。但一般来说不会这样,比如说AMD在两个时钟周期里就可以完成乘法运算。 7) 最笨最快的查表法: 很多情况下我们都可以以牺牲空间的代价来得到时间上的最优解。比如说对于这道题目,我们枚举8位整数的二进制中1的个数,组成一个查找表,看代码[4]: 之前几种方法中的所有操作都可以在寄存器中完成,而查找表法由于无法将查找表放在寄存器中,不可避免地要出现访问cache或内存的操作。但由于我们采用一个循环频繁访问查找表,在所有的实现中查找表都应该被锁定在cache中,访问开销很小[4]。因此从后面的评测我们可以看到,这种方法的效率最高。const int lut[256] = 三、性能评测 实际上我在总结这几种方法的时候,基本上是按照性能逐渐提升的顺序来的。也就是说对于时间开销: naive > less_naive > shift_and_add > shift_add_add_opt > HAKMEM169 > shift_and_add_mul > lut 对于很酷的HAKMEM169,由于用到了耗时的mod操作,在大多数平台上都不如shift_and_add的乘法版本速度快,当然就更比不上我们最笨最好的查找表大法了。KISS准则再次被证明是有效的,哦也。具体的评测数据,可以参考Bart Massey的结果[5]以及感言,或者看这个更加全面详尽啰嗦的评测[6]。 实际上,Intel已经将这个数1操作封装成一个指令 popcnt,在Itanium中就已提供。既然CPU提供原生支持,那想必应该是最快的了(据说1个时钟周期就可以[10])。参考文献: [1] Hamming Weight: http://en.wikipedia.org/wiki/Hamming_weight [2] Everything上的讨论: http://everything2.com/index.pl?node=Counting%201%20bits [3] HAKMEM ITEM 169: http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item169 [4] Set-bit Population Counts: http://www.technovelty.org/code/arch/popcount.html [5] Popcount: http://wiki.cs.pdx.edu/forge/popcount.html [6] HAKMEM 169 and other popcount implementations: http://www.dalkescientific.com/writings/diary/archive/2008/07/03/hakmem_and_other_popcounts.html [7] Population count of a 32-bit register: http://www.df.lth.se/~john_e/gems/gem002d.html [8] 《编程之美》读书笔记——“求二进制数中1的个数: http://bvcat007.javaeye.com/blog/203577 [9] Henry S. Warren, Jr. Chapter 10. The Quest for an Accelerated Population Count. Beautiful Code. [10]GMP: http://gmplib.org/ October 22 AIR及twhirl试用手记一直没个好用的Twitter客户端。 叽歪倒是可以直接输出到Twitter,但看别人的信息还是不方便。 找了个Pidgin的扩展Microblog-purple,纯文字的界面,看上去很不爽。 其实用起来也不怎么样,只是登录之初弹一下你follow的人的信息。 twhirl倒是不错...偏偏是基于AIR的,主页上挂着大大的Windows,MAC的图标,就是没有Linux... 而且"INSTALL"下面清清楚楚地码着一行字"Adobe AIR is not available for your system." !!!!!! 下午刚去听了Adobe的宣讲会(又赚了件T恤...还是长袖的...),心说Adobe没这么BC吧 口口声声号称连入Internet的机器98%都装了flash浏览器 难道到了推AIR的时候,就把linux这块放了? (后来一想....linux好像还真的是不到1%) 于是敢于尝试新鲜事物,不畏艰难,勇于探索,奋力拼搏的我 跑到Adobe的网站上去看了看,赫然发现:
哈哈看来还是有的嘛,twhirl太不厚道了。点download,接着... 又是一个页面!!!
使劲臭屁了一把AIR,不管那么多,接着点"Adobe AIR for Linux"
再次臭屁AIR,然后是Terms Of Use,最后才是下载链接.... !!!!!搞什么啊,Adobe难道需要这样来增加PV??真是搞不懂。。。 好了,最终的下载页面终于找到了,在这里 下载完以后是个adobeair_linux_b1_091508.BIN文件,看来目前最新的版本是9月15号释放出来的。 安装还算比较友好,chmod +x一下,然后sudo ./adobe*.bin 就好了。
![]() 好像今年流行黑色调的主题? ![]() 装完啦!!哈哈哈。点那个大大的Finish。 接下来从twhirl上下载.air安装包,从这里安装(当然双击安装也可以,我就是显摆下有这俩菜单项了 ^^) ![]() 接下来输入用户名,密码登录就好了。哇哈哈哈终于用上了。
哈哈哈终于可以用了。 P.S: 写个blog真费劲...重新安装,截图,传到picasa,粘链接到ScribeFire里,码图,写字。。。天...我以后再也不干这种傻事了。 September 13 Ubuntu Is *NOT* Hard Drive KillerUbuntu 中的Load/Unload Cycle Count问题及解决方案 说明:本文所描述的问题只在笔记本硬盘中才会出现。 1. 问题描述 几周前收到soldiers童鞋的短信说,Ubuntu伤硬盘?我说没事,好多人都用呢。过了一周,soldiers童鞋又问,Ubuntu伤硬盘?我说我查查看....
这样就可以看到Load/Unload Cycle Count数目了。用Windows的童鞋可以借助Everest工具,查看存储器->SMART信息,也可以找到相应项的数据。 不看不知道,一看吓一跳,我的是华丽的11W!!! T.T 据说到了60W,就离挂掉不远了。我才用了4个月,算下来照这个速度用下去的话,只能用4*60/10/12=2年.... 同寝的Acrest童鞋的也过了10W大关哈哈哈。
这样可以每隔5分钟查询一下LCC,一般来说每小时增长在15上下应该是正常的。这样的话即便你每天24小时开着本子,硬盘也可以坚持4年(当然是从理论上来讲)。 1.1 这个Load/Unload Cycle Count到底是什么? Load/Unload Cycle Count(以下简称为LCC)就是Load/Unload的次数,那么什么叫做Load/Unload呢,下面是一段非常罗嗦的解释,建议不感兴趣的同学出门右转,直接看下一节吧。 大家都知道,硬盘的数据传输是通过磁头读写磁盘上的数据来完成的。在工作过程中,磁头并不与磁盘的盘面直接接触,两者之间有一层很薄的空气薄膜,这层空气薄膜是由于磁盘的高速旋转产生的。如果磁盘停止旋转,空气薄膜消失,磁头则会直接接触到盘片,更详细一点说,会接触到盘片的landing zone,或者叫做start/stop zone,这无疑对盘片的寿命以及对存储在这块区域的数据造成不好的影响。因此在早期阶段,硬盘制造商一般会在对盘片的表面或landing zone部分做特殊的处理,并尽量避免在landing zone存储数据。 但是随着人们对于硬盘传输速度和硬盘容量需求的不断增加,制造商需要不断提高硬盘的面密度,同时要求盘片表面尽可能地平滑,这无疑与之前采用的技术产生了冲突,再加上其他的一些因素,硬盘制造商迫切地需要一种新的方式来替代之前采用的磁头直接接触盘面的行为。这时IBM的工程师们提出了一种叫做Load/Unload的技术。简单来说,Load/Unload技术有点像老式的点唱机,当盘片转速降低无法再产生空气薄膜的时候,就将磁臂以及磁头旋转一下,停靠到磁盘旁边的一个小斜坡上。这样就完全避免了磁头与盘片的直接接触。 总体来说,Load/Unload技术是有利的,比如可以提高硬盘的可靠性:硬盘遭到撞击的时候磁头不会划伤盘面;可以提高硬盘的面密度:不再需要对盘片表面做特殊的处理,可以提供平滑的盘面;以及可以有效地降低功耗:低功耗的程序可以通过多次请求Load/Unload来减少盘片的旋转时间,或者设置旋转超时时间(spin down timeout)来让磁头定期的做Load/Unload等等。 1.2 这个参数值高了有啥危害? 虽然Load/Unload技术有很多优点,但毫无疑问频繁的Load/Unload操作会造成磁头的磨损,严重的话会造成数据读写失效,也就说,硬盘挂了。 那么到底Load/Unload多少次会挂呢?最流行的说法是到60W次,西部数据的一份产品规格说明书上也明确标示出了这一数字。 1.3 LCC为啥会那么高? 简单来说,可能有下面几个原因: 1) 硬盘厂商在固件中制定的节能策略过于苛刻,以至于为了节能,硬盘频繁地Load/Unload 1.4 其他的发行版有没有这个问题?Windows呢,MAC OS呢? 各大linux发行版好像就Ubuntu被报告有这个问题,但这实际上并不是Ubuntu的电源策略太变态,恰恰相反,默认情况下Ubuntu会直接沿用硬件固件里面的设定。其他的发行版中SUSE也有类似的电源管理的BUG,初次之外的发行版似乎默认会忽略硬盘的这个节能功能,所以不会有类似的问题。 至于Windows,也会出现类似的现象,比如说我宿舍的Acrest童鞋,但我的没有。 总体来说这个并不是个别现象,也并不应该算是操作系统的问题。感觉由于Windows下硬盘几乎会一直不停地运作,所以硬件厂商不太重视硬盘固件中的初始设定,比如说我的日立硬盘,电源管理级别被设置为128,结果由于Linux并不像Windows那样频繁读盘,磁头为了节能会频繁地做Load/Unload操作。 2. 如何修复这个问题? 2.1 硬件修改法 (***推荐使用***) 正如上面所说,如果你的硬盘在Ubuntu下有这个问题,那么有可能是硬件本身的节能策略太激进了。最简单也是最根本的方法,就是用厂商提供的固件修改工具对出厂的默认设置进行修改,比如说日立的Feature Tools。 简单来说,数字越小越节能,数字越大性能越好。Feature Tools中将1-254分成三段并分别做了简单的说明,一般来说,设置到192-254则表示不允许Load/Unload操作,而255则表示禁用APM(Advanced Power Management)。这个数字也就是后文提到的APM级别。 2.2 软件修改法 修改硬盘固件是最根本的解决方案,除此之外,关于在Ubuntu中修改相关策略,网上有很多种不同的解法,有兴趣的童鞋可以看关于这个Bug的讨论, Ubuntu Wiki上关于这个Bug的介绍,起因分析以及解决方案的总结等。基本上流传的方法有这么两种: 2.2.1 启用laptop-mode,通过修改laptop-mode.conf中的相关设置达到控制Load/Unload的目的 具体内容见文后附注。归根结底,这两种方法都是利用hdparm工具,通过-B参数修改高级电源管理(APM)级别,通过-S参数修改旋转超时时间(Spin Down Timeout),从而控制硬盘的Load/Unload次数。所谓APM级别就是我们上面介绍过的1~255,而Spin-down Timeout就是指硬盘空闲(或者旋转?这个拿不准)多久后才会Spin Down,也就是停转,做Unload操作。相对应的,有一个Spin up Time,这是指硬盘重新启动到正常运转所需要的时间。 Windows下也有一款HDDScan软件可以很方便地做到这一点。这样的软件改法确实有效,但由于hdparm不会将设置写入固件,因此在关机、休眠以及待机之后,由于硬盘掉电,这些通过软件的设置会失效,需要重新启用一次。目前这两种方法在我的机器上的测试结果是待机唤醒之后参数不会重新启用。实际上,laptop-mode只会在开机的时候才会应用我们设定的参数,而acpi的resume.d目录下放置的脚本并不会被执行,不知道这是不是个别现象。 所以如果大家非要用软件的修改方法时,推荐下面这一种。 2.2.3 pm.utils大法 (推荐使用) 除了这两种修改方法之外,还有另外一种通过pm.utils来调用hdparm的方法。这实际上是Suse的一个解决方案。pm.utils全称是Power Management Utilities,与acpi类似,它可以通过加入Hook脚本的方法在待机、休眠和唤醒的时候修复一些待机/休眠方面的Bug或者实现某些特定的功能。pm.utils很有可能会在8.10中就取代acpi,所以从这个意义上来讲这个方案也会有更长的效用。具体步骤如下: 1) 首先做一些配置,主要就是设置省电模式开启和关闭的模式下hdparm的参数,具体的内容脚本中有注释。 你可能需要将“/dev/sda"修改成你的硬件设备,比如你有两个硬盘,可以修改为"/dev/sda /dev/sdb"。
2) 在power.d中加入Hook脚本,作用是在使用电池和AC电源的时候可以自动切换省电模式。
3) 在sleep.d中加入脚本,目的是在休眠/待机之后唤醒的时候重新设定hdparm的参数:
***注意最后一定要为disk脚本添加执行权限。否则pm.tuils不会自动执行这段脚本 4) 如果你没有启用laptop mode (默认是不启用的),可以跳过这部分了。 由于Ubuntu中acpi和pm.utils是共存的,所以如果你启用了laptop mode,那么在改变电源状态(指电池->AC电源或者反之)的时候,acpi会在启用/停用laptop mode的同时设置hdparm参数,会覆盖掉pm-utils所做的设置。 所以如果你启用了laptop mode的话,需要做如下修改: 1' $ sudo vi /etc/default/acpi-support 将最后的
修改为
2' $ sudo vi /etc/acpi/power.sh 将function laptop_mode_enable部分的
修改成
上述的解决方案在Dell Inspiron 700m + Ubuntu 8.04.1上测试通过。在待机唤醒之后参数会重新被设置,但是由于我的机器上休眠有问题,所以没有办法测试休眠。但理论上来也是可以的。 3. 我想定期检测Load_Cycle_Count,怎么办? 好办,这里是一个脚本,具体用法在注释里面粗体标明了。(不好意思...注释好像比代码都长)
按照上面的说明操作之后,LCC的结果就会存在你定义的log文件里面了。可以定期打开查看。 4. 最后附上之前的两种方法,启用laptop mode和添加acpi脚本。 4.1. 加入acpi脚本 1) 为使用电源和电池的时候定制不同的hdparm参数。你可能需要把/dev/sda修改成你的硬盘设备。
2) 将如上脚本安装到如下4个地方
这个方案比开启laptop简单且方便。因此如果你实在是不想用pm.utils的时候,推荐使用这种方法。 4.2. 启用laptop mode Ubuntu 8.04测试有效,但是待机/休眠唤醒之后设置会丢失。laptop mode 模块在Ubuntu 8.04中是默认包含的,只是没有启用。下面是具体的设置方法。 1) /etc/default/acpi-support中修改
2) /etc/laptop-mode/laptop-mode.conf中修改
3) /etc/acpi/power.sh中 把 "$HDPARM -B 1 /dev/$drive 2>/dev/null" 4) 禁用pm.utils的部分功能
否则laptop-mode不会随机启动。 5) 重启后,cat /proc/sys/vm/laptop_mode 结果是2表示laptop-mode已经启动,是0表示还未启动,请仔细检查上面的设置是否有遗漏。 ###############我是很郁闷的分割线############### 附:关于为啥要禁用pm.utils,具体的解释如下: 我从网上找到了laptop mode的解决方案之后,按照说明一步步操作,但是重新启动之后,查看cat /proc/sys/vm/laptop_mode,发现仍然是0.(是2才表示已经启动)。查看/etc/rc2.d/目录下确实有S99laptop-mode,这说明系统确实会加载这个服务(这个目录下的文件都是个符号链接,会链接到/etc/init.d目录下的同名脚本)。后来Google了一下发现这样的解释: 首先来说/proc/sys/vm/laptop_mode这个变量和初始化进程laptop-mode并不是一个意思。前者是个内核控制的变量,作用是将磁盘写操作聚簇,后者是一个脚本。 其次,Hardy加入了pm-utils,会覆盖或忽略一部分根据linux传统的配置。为了解决这个问题,可以修改/usr/lib/pm-utils/power.d/laptop-tools中相关的内容或者运行下述命令:
这条命令会禁用pm-utils的部分功能,从而修复你所遇到的问题(指laptop-mode不会随机启动)。注意得重启以后设置才会生效。 实际上pm-utils盲目地覆盖掉laptop-mode或者是/etc/sysctl.conf中的配置,所以chmod -x禁用相关脚本后, 在从AC POWER转到电池供电的时候,pm-utils就不会执行相关的脚本(laptop-tools),从而也就不会覆盖相关的设置。这种做法改动最小,如果之后你想重新启用pm-utils的这部分功能,只需要chmod +x就可以了。 ###############很郁闷的分割线又来啦############### 5. 最后是References: 日立关于Load/Unload技术的解释: Load/Unload白皮书下载
6. 最最后 折腾这个问题费了我一整天(实际上是半天,不过那天我中午才起...),总结这些破烂方法,再加上反复试验确定某个方法是否有效,硬着头皮分析脚本的功能,零零碎碎加起来也有一整天的时间,再加上写这篇总结,又花去一整天加上两节入学教育的时间(罪过啊罪过啊)。到此为止距离开始解决这个问题就已经过去整整一周了。就这还没总结全,好多东西都还没有写上来。不过倒是学到了不少东西,硬盘的原理是确确实实复习了一遍了又,另外学了些写Shell脚本的技巧以及ACPI和pm.utils的机制。感觉系统里面同时有俩搞电源管理的东西实在是太FT了,因为会有冲突的部分,好在据说Intrepid要搞掉acpi只用pm.utils,也许会清净一些。 无论如何总算是写完了。一边实验一边记录,一度想放弃了(实在是太费时间,感觉也没太大的意义),但一个是为了我的宝贝硬盘考虑(钱啊钱啊!),又觉得折腾了那么多不记录下来,功夫不就都白费了。正好今天有两节入学教育,于是就勇敢地抱本过去,写完最后一段哈哈哈。 贴到这里,希望会对遇到这个问题的人有所帮助。 July 05 我愛你 最近看到GF频频发blog 才意识到自己的space几乎快要荒废掉了 本打算暑假玩玩wordpress然后买个空间的 照现在的计划看来已经是不可能了 转一篇吧,来自女主人的沙龙,权当拔草了 是个在国外生活的台湾女人, 写东西的风格又彪悍又细腻, 所以有时看得很爽有时也会看得胸口堵得不行 似乎现实生活中也是如此,总之是很有个性 喜欢的人顺便收藏了吧 好了,开始。 ------------------我是牛B的分割线----------------- 我愛你 睡覺之前,小法把手臂環繞著我的脖子:「媽媽我愛你。」 我輕輕吻一下這個小痞子的臉頰,小孩光滑結實的皮膚碰到嘴唇的感覺非常的好。「I LOVE YOU TOO.」 痞子忽然的張大眼睛:「AND I LOVE YOU THREE AND FOUR AND FIVE AND SIX AND SEVEN EIGHT NINE TEN,」連珠砲一樣的數下去,得意非凡。「I WIN。」 我笑了,於那笑容中,一股深沉的近乎悲愴的情緒湧上來,我無聲的在心裡頭輕輕的說:「AND I LOVE YOU INFINITE。」 但是小子,你贏。 |
|
|||||||||||||||||||||||||||||||||||||||||||
|
|