那些天一起刷过的Galaxy Note ICS ROM

May 16th, 2012 by gnawux No comments »

似乎我用Milestone那么久都没有心思写篇关于手机的blog,用GN没几天就第二次想写了,我得说,这会儿总算对Android有些好感了,使用体验、界面流畅程度啥的都没什么问题了,也没什么冲动想换个个头那么小的 iPhone 了。我不是说 Android 比 iPhone 好了,只是,这些手机已经是各有特色了,iPhone 可能不再是每个人的理想智能手机了(对很多人从来没是过哈,对某些人永远都是)。

本文所指的ROM和内核,都来自 XDA( http://forum.xda-developers.com ),由于个人装逼需要,不喜欢安装国内论坛上的“大牛”们做的,比如机锋什么的下 ROM,如果能在官方市场找到的软件也不喜欢用其它来源的,如果是付费软件,又很想要,就想办法伪装成米国用户买下来,偶们码农,得带头尊重软件版权、反对盗版,这个不是因为我们工资已经高到每月能买得起一两刀、三五刀的软件了,而是因为我们自己就是这么活的,我们不能自己偷自己的钱,是吧。

目前的Galaxy Note ICS ROM和内核

Galaxy Note 目前的两大 ICS ROM 分支是:基于三星官方修订的,以及基于纯开源项目构建的;内核也有两类:三星放出来的和基于纯开源构建的。开源的ROM也可能会用三星放出来的内核,反之大概亦然。

5月10号,三星欧洲在德国放出了他们的第一个官方的Note ICS ROM,版本号为 LPY,之前,中国泄漏过 LP1, LP5, LP6 三个 ICS ROM(这些似乎最早都是在机锋泄漏的),下面称呼的时候,官方版本的ROM和内核都直接称为LPY,泄漏版的三个,如果不特殊指某一个的话,直接说中国泄漏版。

在出现这些三星ROM之后,有几个 Team 都对官方版本的ROM做出了自己的 MOD,主要包括:

  • 换用ApexLauncher 或 NovaLauncher,很多人都不喜欢三星的 TouchWiz ,呵呵
  • 删掉一些应用,换上另一些(中国泄漏版里有人人、新浪微博之类的一大堆,我看着都想删掉,老外们更不例外了)
  • 加一些启动的init脚本来做优化
  • 换主题
  • 增加一些通知栏 toggle 之类的功能(替换 SystemUI)

随后或同时,有一些人开始直接从开源的 AOSP (Android Open Source Project,这个是 google 直接放出的),以及在上面进行了一些修订的 AOKP 项目,这其中比较成熟的一般都使用了三星放出的内核——中国泄漏的或是更新的 LPY,它们的主要特点是:

  • 应用精简了不少,三星的一个都没有了,当然 S-Pen 应用也没有了(笔还能用,笔的按键不好用了,截屏之类的就不能用笔了)
  • 一般用 ApexLauncher 或 NovaLauncher,优化、toggle、主题之类的也是有的
  • 更多的可定制配置,包括锁屏
  • 可以修改为平板模式,安装平板才可以用的软件,比如 Papyrus 之类的
  • 早期AOSP官方有录像无法保存之类的 Bug,但后来已经修复了。

除了AOSP/AOKP之外,还有著名的CM9系列ROM,它们的mod更多,甚至使用了基于 i9100 内核源代码构建的纯开源内核,这个内核目前只是可用,还缺少一些功能(这个变化很快,可能blog发出来的时候已经修复了呢)

  • 拍照的预览是黑的
  • Speaker还有部分问题,这个似乎是有人的内核解决了,有人的没有,不同的修复
  • 其他不确定的问题

嗯,好了,总结就到这里,下面是重要的安全提示——

安全提示

根据XDA总结的用户的报告,所有三星放出的内核,LPY或是中国泄漏的,都存在一定的 eMMC IO 缺陷,有可能在大 IO 时导致硬变砖,也就是 hard brick,这对于我们这些质保比较差用户来说更严重一些哈。发生这种情况的风险依次为:

  • 使用Chainfire 打包的基于三星内核的 CF-root kernel 时,在 Recovery 下进行 Wipe 和 Flash,这种风险是最高的,当然,实际我也在没得到这个安全提示的时候 wipe 过好几次,很多其他人也是,大部分都没变砖,变砖这个事,概率不高,但是风险高就很吓人,是吧
  • 不使用 CF-Root的时候,也有可能 wipe 的时候出事
  • 删除大文件的时候据认为也有可能有风险

这个,说的是个可能性,但有很多用户不以为然,认为变砖不是这会才开始的,历史上也不是没出现过,不用看得这么重,那些手机可能是硬件本身有问题的,有很多变砖和新 kernel 根本没关系。不论如何,鉴于存在有问题的可能,因此XDA的开发者们给出了一个解决方案:

安全操作方法与免责声明

鉴于 2.3.6 的内核没有问题,于是建议这么操作:

  • 下 Abyss Kernel 4.2 (点这里: http://www.mediafire.com/?c65mndvpk6ocbaa ),放到手机里
  • 进 recovery 刷 Abyss 内核
  • 在 advanced 里选择重启到recovery
  • 如果想 wipe就wipe,想刷新 Rom 就刷新 Rom
  • 重启,搞定

当然,重复一下,刷机怎么都是有风险的,所以,即使你这么做了,赶上天灾人祸的可能性仍然是存在的,但是,要是啥风险都不承担,就表玩手机了,是吧。

 ICS使用体验

用ICS时间久了,2.3.6 的啥体验记不清了,嗯,总体评价一下ICS吧

  • 设置界面的流量显示、电量显示都不错,wifi、蓝牙的设置也更方便了,打开设置就有开关,也可以点进去设置
  • 流畅度没什么问题,原来有问题么,我不记得了啊,我觉得一直挺流畅的吧,当然,我毕竟是用老 milestone 过来的,对流畅啥的期待本来就不高,说实话,我承认我土鳖,玩 iPhone 4S 和 iPad、iPad 2 的时候也没觉得惊艳的流畅啊……
  • 电池啥的,跟 Coly 显摆过好几次,我觉得正常情况下,原电坚持一天应该没问题,我的坚持的意思是不以影响使用体验为代价的,不关 wifi、不关背景数据传输,该拍照拍照,该上传上传,该微博微博,该看 RSS 看 RSS……
  • 人脸解锁说起来拉风,但用一下就知道了,这东西对长得像我这么丑的屌丝完全是自取其辱啊,如果当天没刮胡子,或者干了一天活一脸油光的话,每次解锁都让你感到一阵恶心,嗯,当然了,对改善个人卫生有好处,用人脸解锁的几天,我会一天洗几次脸、刮胡子间隔绝对不会超过两天,嗯,即使这样,后来还是关掉人脸解锁了
  • 只要有 root,就可以安装 busy box 和 openvpn,你懂的,这个没有任何使用问题

嗯,再来说下基于三星ROM做的东西

  • 用 LPY 吧,毕竟是官方的,没有中文界面,也就是菜单啥的是英文的,中文程序没有任何问题
  • 如果觉得 instagram 之类的开的时候有点卡的话,disable 掉一片三星自带的程序,什么 weather、news、软件更新啥的,有 root 的话,可以直接移除 /system/app/ 下不需要的程序,当然,有些是不能拿走的,这个见仁见智吧,我移走了50多个,看起来没什么问题
  • mod啥的都可以手动做,比如 mod 个主题、装个软件啥的,有 root 都可以手工做了,基本不需要装个特殊的ROM版本了。

然后是 AOKP 的 ROM,我用 stunner 比较多,从 Beta4.1 一直用到 1.4.26.1,说说感受:

  • 流畅度没问题,内存占用少很多。当然,要我说,内存剩余 200MB 还是 500MB 都是浮云,只要应用不卡,内存不就是用来用的么;
  • 面板啥的可定制性更强,我喜欢这个,相机有全景相机功能,比免费应用的全景相机功能好用
  • 平板模式基本不用,字小啊,但支持 Papyrus 和其他一些 Note 软件,还是挺有吸引力的
  • 没有 S-Pen 按键的功能,心里小不爽,似乎笔的定位比三星 ROM 有偏移,这个是感觉,不是确实量出来的,但心情上确实是这样的

总结一下:

  • 只要有 root,流畅度不是问题,电池也没问题
  • 应用各有特色,我更倾向于官方的 S-Pen,虽然常常留恋 AOKP 的 ROM
  • 仅供参考,不承担责任哈

创建 Debian/Ubuntu 风格的内核模块包

May 14th, 2012 by gnawux 1 comment »

很久不深入玩Debian系的东西了,最近,乘着工作之便,又打了个deb包,而且是我之前没干过的内核模块的deb包,恩,记一下吧。

Debian内核模块的一般构建方法

和 RHEL 不同,Debian 很少提供内核匹配的模块的二进制 deb 包,相反,一般会提供一些比较长用的模块的源码包,并配合 module-assistant 工具,生成与用户使用的内核版本一致的内核模块。

module-assistant 是一个菜单界面的CLI工具,用户可以在这里选择源码包,当然,也可以用 apt 安装 xxx-source 的源码包(也是deb包),然后,用命令

m-a a-i module-name-here

来自动生成模块的二进制 deb 包并安装。

打包模块源码

如果源里没有这个模块的话,就只能自己打包内核模块了。这个工作实际和一般软件的 deb 打包非常相似,可以借助 debhelper 的 dh_make(8) 命令。

生成 Debianize 文件

dh_make 实际上有一个专门的选项/参数 (k),可以用来制作模块的 deb 包,现在,在源码的顶层目录(目录的命名方式是 package-name-x.x.x)运行 dh_make 命令:

# dh_make -e account@examplel.com -k --createorig
#

恩,为了方便,我实际在源码的顶层目录里放了一个叫 driver 的目录,内核模块代码就在里面,这样复制的时候可以直接复制整个目录了。

执行玩上面的命令之后,你就可以看到,多了一个 debian 目录,这个目录里有很多文件,它们遵循 debian 的一般打包原则,简单介绍几个重要的,具体的参考《Debian新维护人员手册》吧:

  • rule:这个最重要,实际是个Makefile,后面具体介绍;
  • control:这个是软件包的描述,照着内容敲吧,section 之要遵循 debian 的约定,比如 kernel 就是一个 section,其他自便吧;
  • changelog:这个是打包版本的变更,每个版本开头里,目标distro一般写 unstable,urgency 一般是 low ;
  • README.Debian:是对这个包的说明,给人看的;
  • 可执行脚本:postinst 和 prerm 比较常用,分别是在安装之后进行配置和卸载之前进行清理的,preinst 和 postrm 一般用的不多。其他文件各有各的用处,.ex 结尾的都是例子,如果用的上就用,用不上的可以考虑删除。

内核模块包的特殊文件

恩,因为这 kernel module 包的做法是先做 source 的 deb 包,用户用 m-a 根据这个 deb包的内容再做一个二进制的 deb 包,所以需要为他们准备一些配置文件,一般用得上的是这两个:

  • control.modules.in  这个用作模块包的 control 文件;
  • ebs-driver1-modules-_KVERS_.postinst.modules.in 这个用作模块包的 postinst 脚本,比如要插模块、调整 daemon 什么的。

写内核模块包的 rules

这是关键折腾的一步,我也是头一次写,没找到什么现成的文档,自己琢磨的,有什么不对的地方还请指出来啊。

规则里面 kdist_clean, kdist_config, binary-modules 是用来编译内核的,编译内核时,有些规则是从 module-assistant 里导入进来的

# modifieable for experiments or debugging m-a
MA_DIR ?= /usr/share/modass
# load generic variable handling
-include $(MA_DIR)/include/generic.make
# load default rules, including kdist, kdist_image, ...
-include $(MA_DIR)/include/common-rules.make

这些会帮助我们在正式打包之前,在上面那几个给模块准备的配置文件里,加入内核版本号信息,并用正式的文件名。当然,在一开始 make kdist_clean 规则的时候,这些文件还没生成,所以应该把 dh_testdir 和 dh_clean 注掉,否则做不成的,如:

kdist_clean:
        #dh_testdir
        rm -f build-arch-stamp build-indep-stamp configure-stamp
        #dh_clean
        rm -f driver/*.o driver/*.ko

这里可以根据尝试的情况调整内容,稍稍注意一下即可。正式的 binary-module 目标倒是没什么特殊的,简单根据自己需求调整就行了,这里的安装过程会把模块放到

debian/$(PKGNAME)/lib/modules/$(KVERS)

目录里,如果有配置文件,也可以相应的放进去,debian 在安装包的时候,如果有配置文件的更改,是会提示用户的。

如果制作模块包的时候只要做源码包,不用做用户空间工具包的话,binary 目标只要依赖 binary-indep 就可以了,不需要依赖 binary-arch 了。

打包

写完配置文件之后,在源码顶级目录里,也就是有 debian 目录的目录里,运行

dpkg-buildpackage -uc -us -rfakeroot

就可以生成源码包了,安装之后,就可以像开头那样用 module-assistant 制作安装二进制模块了。

小结

实际上做内核模块的 deb 包并不难,只要有点 debian/ubuntu 经验,细心一点就可以做好里。估计短时间内我是不会更新 unleashed 了,就这篇 blog 供大家参考吧。

使用 iproute2 进行 MultiHoming 设置

April 21st, 2012 by gnawux 1 comment »

iproute2,也就是ip(8)这个命令的功能是非常强大的,之前就曾经用它建隧道之类的,但从来没涉及过路由,毕竟找不到什么不用 route(8) 命令的理由。不过,这次我们找到了一个——当你需要两个缺省路由的时候,该怎么配置?

按:这个是新研究出来的,有什么不对的地方敬请指出哈

iproute2

iproute2 是一整套网络设置工具,涵盖从网口(link, address)、ARP(neigh)、路由(rule, route)、隧道(tunnel)等各个方面,是 Linux 2.2 (如果没记错的话,应该有十三四年了吧)以来的网络“新”特性的用户态工具,可以替代 arp、ifconfig、route 这些经典但不够完善的工具。

如果你要搭 ipip 或 gre 隧道,无疑要使用 iproute2 的 ip tunnel 命令了,除此之外,你还能想到第二个用 iproute2 的场景么?我就遇到了一个——

问题背景:两张路由表

如果你有一台服务器,有两张网卡,对应了两个网络出口,都能连到目标网络,这时,怎么设置下一跳路由呢?经典的 route 设置,只有一个缺省路由条目可以生效的。你当然可以设置,让一部分目标地址走一个路由,另一部分目标地址走另一个路由,但是有两个问题:

  • 这样,流量很难均衡使用两个路由
  • 包从哪个网口进来是无法通过自己的路由表选择的,所以,如果按照上面那种划分方法,只要进入的包没有按照我们的期待分区划分,那么就无法正确地回复,也可能会被 rp_filter 直接过滤掉。

嗯,那么,怎么同时用上两块网卡呢——

我们需要按照出发 IP 划分,使用源 IP1 的包,走第一块网卡,使用 IP2 的包,走第二块网卡。(先不考虑未指定的)

但是,IP路由的基本哲学是——按照目的地址,从路由表里查询,不可能按照源地址来整路由表,于是,问题就变成了这样——

我们需要为每个 src IP 建立一张路由表:从第一个IP出来的包,进第一张路由表,出第一块网卡;从第二个IP出来的包,进第二张路由表,出第二块网卡。

思路很简单,但是 route(8) 命令在这里就束手无策了,嗯,看 iproute2 的:

多张路由表(rule)

好了,不卖关子了,iproute2 本来就支持多张路由表,配置文件位于这里:

root@swipe:~# cat /etc/iproute2/rt_tables
#
# reserved values
#
255	local
254	main
253	default
0	unspec
#
# local
#
#1	inr.ruhep

已经有三张表了:

root@swipe:~# ip rule ls
0:	from all lookup local
32766:	from all lookup main
32767:	from all lookup default

这三张表都对所有的IP来源生效(from all),这其中,main 就是我们通常设置的路由规则,

root@swipe:~# ip route ls table main
default via 192.168.12.1 dev eth0  proto static
169.254.0.0/16 dev eth0  scope link  metric 1000
192.168.12.0/24 dev eth0  proto kernel  scope link  src 192.168.12.104  metric 1
root@swipe:~# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         localhost       0.0.0.0         UG    0      0        0 eth0
link-local      *               255.255.0.0     U     1000   0        0 eth0
192.168.12.0    *               255.255.255.0   U     1      0        0 eth0

default表是空的,而local表则是本机链路的设置。如果我们需要,可以人为加入新规则(路由表)

root@swipe:~# echo "200 rt2" >> /etc/iproute2/rt_tables
root@swipe:~# ip rule add from 192.168.12.111 table rt2
root@swipe:~# ip rule ls
0:	from all lookup local
32765:	from 192.168.12.111 lookup rt2
32766:	from all lookup main
32767:	from all lookup default

这样,来自 192.168.12.111 的包就可以先进入 rt2 这张表了

路由设置

现在要做的是为每张表设置路由

root@swipe:~# ip route add 192.168.12.0/24 dev eth1 table rt2
root@swipe:~# ip route add default via 192.168.12.254 dev eth1 table rt2
root@swipe:~# ip route flush cache

对于本机发出的包,应该可以以某种机会,比较均衡地选择任意路由出去

root@swipe:~# ip route add default scope global nexthop via XX.XX.XX.XX dev eth0 weight 1 \
 nexthop via XX.XX.XX.XX dev eth1 weight 1

当然,这种基于路由表的负载均衡并不能做到完全均匀,毕竟路由表是可以被缓存的。

说明:上面的设置例子是在一台只有一块网卡的机器上码的,不过在写blog之前是在有两块网卡的机器上操作的,就是那个机器不方便写blog,所以看着细节上可能有点味道不太对,没关系哈

参考

下面是一些参考文献:

  1. Linux Advanced Routing & Traffic Control HOWTO : http://lartc.org/howto/index.html
  2. ip-cref : http://users.cis.fiu.edu/~esj/cnt4504/reading/ip-cref.pdf

清明假期北海游

April 19th, 2012 by gnawux No comments »

今年清明假期,连上请的年假,全家一起去了广西北海,延续了去年开始的每年春天,全家带儿子去南方海边吹海风的活动。我们全家对这次北海之行相当满意,由于去年的武夷山游记(http://wangxu.me/blog/p/555)受到好友的欢迎,在这里也把这次北海之行分享给大家,没准谁能用到呢。

实际上,路线的勘定,住宿的选择,机票的预定全是老婆(@跳舞的金子)完成的,攻略也是她查的。也就是说,她先分析学习,然后指导我执行,最后我输出新的游记——这是个很经典的反向工程案例啊。

行程概述

我们的行程是这样的:

  • 4月1日搭乘CA1881飞到北海,
  • 当日到达市区北部湾广场,并在旁边住下
  • 4月2日乘船登上涠洲岛,之后的时间主要在涠洲岛渡过
  • 4月5日下午乘船返回北海
  • 当日住在银滩
  • 4月6日下午搭乘CA1882回到北京
主要行程标在Google Earth上是这样的,嗯,直接用了foursquare的签到记录,它的那个feed是可以输出KML的,直接用Google Earth打开即可,嗯,当然了,会有些偏移,你懂的,我修正了下位置。这个是北海的全部经停地点:
嗯,可以看到,银滩离市中心还是比较近的,码头就在银滩边上,从码头到涠洲岛的距离大概是40公里,必须乘船前往,蹚水是过不去的。银滩上的主要景点概览如下:
我们用了一天时间游览小岛的大部分景点,其他时间主要就在住处附近的沙滩活动了,很舒服。 下面这个是北海市区和银滩的示意,实际银滩也是很不错的:

海滩,各种海滩

当我们从涠洲岛回到北海市,到了银滩之后,我在4sq签到的时候写到“对海滩都审美疲劳了⋯⋯”,不过,第二天在银滩的海滩上抓小螃蟹仍然让我们和斯屹兴致勃勃,每处海滩都有它的特点,总的讲,我觉得北海的海滩质量不错,没有三亚那么多的商业开发,没有亚龙湾住宿成本那么高,还是很舒服的度假地点的。

贝壳沙滩与渔家

我们提前联系了渔民林大哥家里,他们接待还是很热情的。住处在后背塘村,这里距离贝壳沙滩走路三分钟的样子(参见上面的卫星图,嗯,不过具体地点我不太确定哈)。我们用了两天多的时间,陪儿子在这里挖沙子、捡贝壳、蹚水⋯⋯,还搞了烧烤活动

“私家”海滩

我得说,即使你在亚龙湾,也没有这么大的人均海滩面积。有些贝壳的地方有点扎脚,但大部分地方的沙子还是很细的,接近白色的海滩和清澈的海水让人想起蜈支洲岛,但这里的最大好处是人少,即使在清明假期,仍然很难看到很多人出现在这里,拍到安静的、没有人的海滩易如反掌。而且,这里有很多海螺壳、贝壳之类的,在中午退潮的时候,一些礁石都露出水面,在沙滩上可以很容易地捡到很多海螺壳。

涠洲岛的景区

涠洲岛上有挺多景区,对于非教徒,天主教堂的意义也并不大,掠过之后,我们依次造访了五彩滩、鳄鱼山、滴水丹屏和石螺口。各有特点。

岛上风光

  • 五彩滩(右上角图)是一片石头海滩,据说早上有太阳的话会有五彩,嗯,我们去的时候阴天,没看到,不过这里有很多小螃蟹、寄居蟹啥的,小朋友很喜欢,就是石头滩比较塥脚;
  • 鳄鱼山是涠洲岛作为国家地质公园的主景区(右下角三张照片和左下角寄居蟹都是在这里拍的),是一个小半岛,需要走上或坐车上山,然后在爬下海边,然后爬上来,再下山去,有一点累,不过我驮着儿子都做到了,应该不算太累;下到海边,可以看到火山口标识,海边有很多活泼的寄居蟹,石头上还有些活的,可能是珊瑚的东西;
  • 滴水丹屏(背景图,还有“王旭斯屹爱海娟”的沙子组字都是在这里拍的)是涠洲岛上最细腻的沙滩,个人感觉细腻程度绝对不亚于亚龙湾;
  • 石螺口海滩是和滴水丹屏比较接近的一块海滩,有些水上和沙滩摩托车之类的项目,老婆在这里开了一段摩托车兜风
这几个景点大概是岛上仅有的商业旅游开发吧,嗯,似乎还有个看日出的地方,整个岛上的商业开发程度不高,还算自然吧。

银滩

银滩应该是北海大陆上最好的海滩了,这块海滩同样细腻、平坦、开阔,而且——小螃蟹太多了

到处都有小螃蟹

我们在这里停留了一个下午和一个上午,我们住的地方类似亚龙湾的二线海景,和海滩隔着一条马路,不过这里也没有一线海景,呵呵。第二天上午的时候我们才注意到,这里到处都是小螃蟹的巢穴,小螃蟹很类似泥土里的蚯蚓啊,都是一个小洞,外面很多小土粒。我和儿子转了一圈,儿子动不动就能抓到来不及从外面跑回洞里的小螃蟹,而且——有活物的海滩都是小朋友喜欢的海滩。

当然,这里沙滩也很好,也有摩托车之类的项目,不过,我们就是来吹吹海风、玩玩沙子、抓抓小螃蟹的,这里也很适合我们。

小结

  • 整个北海的海滩质量都不错,而且各有特点,贝壳、寄居蟹、小螃蟹都有不少
  • 涠洲岛上住在渔家,然后到贝壳沙滩上休闲、BBQ,还有北海银滩,都是不错的休闲场景
  • 潜水之类的项目都有,不过我们没尝试

衣食住行及其他

衣没什么可说的了,先说吃住:

 

  • 北海和涠洲岛渔家的吃东西价格都比较公道,尤其是我们住的涠洲岛渔家,螃蟹、扇贝、生蚝、皮皮虾都物美价廉,吃得我们浑身痒痒⋯⋯
  • 涠洲岛鳄鱼山顶上的吃饭的地方比较坑爹,价格贵、服务能力差、东西不全,而且不好吃
  • 渔家住宿很便宜,市内酒店也不贵,用去哪、携程之类的查到酒店价格如何,直接去前台订就可以,基本不需要预定酒店

然后说说出行:

  • 北海的交通费算比较贵的,过路过桥上岛费用都不低,机场到市区的出租车要价100块,不讲价,我们就坐机场大巴进城了,直接到了北部湾广场,不过去机场的大巴并不方便,我们还是打车了
  • 这里黑车比较猖狂,而且还威胁正规的出租车司机,抢客人
  • 涠洲岛的游船,B舱120/人,船是小水线面双体船型,属于快速船型,实际航速大约是20节,速度不错,就是比较贵,而且航行中不能上甲板;上岛费(国家地质公园门票)90块/人,这个比较黑
  • 岛上的载客三轮摩托车,环岛一天游100块、接送码头20,如果会开摩托车的话,可以考虑租摩托车转全岛;岛上没有正规渠道的加油站,所以汽油很贵,嗯,没办法。
总的说,北海的吃住都比较实惠,出行比较贵,综合考虑海滩很不错,嗯,趁着开发还不算过度,推荐一下,如果不想出国游,就北海吧,比三亚强。

 

版聚的另一话题——你是如何退出Emacs的

March 26th, 2012 by gnawux 4 comments »

版聚也讨论一些不太严肃的话题(严肃的请进上一篇: http://wangxu.me/blog/p/648)。

不知怎的,忽然间话题跑到了 Vim 上,是的,在场的卢瑟们不会用 Emacs,只能勉强学会 Vim。李凯童鞋表示——

一种产生随机字符的方法是,请一位新手退出Vim。

于是,话题被正式岔到在场童鞋们都不会的 Emacs 上了。

李凯说

我退出Emacs的方式是,且到另一个终端,然后 kill 那个 Emacs 进程。

好吧,他确实比较狠,我当场表示,当年我的操作比这个善良一些——

我是用的 Ctrl-z,放到后台,然后干掉的。

Colyli 童鞋不甘寂寞,问

Ctrl-d 行不行?

但这个方法当场被其他童鞋否定了。

各位,你们还有什么更2B一些的方法么。

mmap()和read()哪个快——linuxfb版聚上谈论的开发中的常见误解与陷阱

March 26th, 2012 by gnawux 3 comments »

本月版聚的规格最后是8人座谈 + 晚饭欢送 hzmangel (@hzmangel, @古月圣)同学南下,座谈比讲幻灯片更轻松了一点,不过,还是讨论了一些严肃问题,很多都是开发中的常见误解和误用。废话少说,一一列出,没列的出是我忘了,各位在场同学请补充。

mmap() 与 read() 哪个快

当Coly(@colyli, @淘泊松)抛出这个问题的时候,我们已经猜到 read() 快了,毕竟我们相信他会说些颠覆理解的东西,而且李凯(@leekayak)童鞋表示,他也听朱延海(@2002年一本漫画闯天涯)说过此事。那么,我们来听听 Coly 的解释:

  • 大家关于“mmap()”更快的认识来自于 read() 是需要内存拷贝的;
  • 当今硬件技术的发展,使得内存拷贝消耗的时间已经极大降低了;
  • 但“mmap()”的开销在于一次  pagefault,这个开销相比而言已经更高了,而且 pagefault 的处理任务现在比以前还更多了;
  • 而且,mmap之后,再有读操作不会经过系统调用,在 LRU 比较最近使用的页的时候不占优势;
  • 于是,普通读情况下(排除反复读之类的文艺与2B读操作),read() 通常会比 mmap() 来得更快。

mmap() 与 brk() 是否都会给分配的内存填0

这来自于李凯同学的一次提问,Coly同学断然否认了在这方面两者的不同,表示,自 kernel 0.9 以来,所有的分给用户的页全是初始化过的,没有用户数据的页一定会给0,这是一个安全问题,内核不会把不属于用户的内容给用户看的。而且,文件系统也是如此,空洞文件在读取未初始化过的文件内容时,返回的也一定是0。

当然,对于用户应用来说,C库提供的 malloc() 有可能会复用内存,而不是每次都从内核取,所以,有可能有未初始化内容。

sprintf() 的误用

提到初始化的时候,Coly 愤愤不平地表示,有童鞋居然这样初始化内存区域:

sprintf(buf,"");

并表示,这一操作的行为是未知、未定义的。我和Bergwolf(@oatgnep, @Bergwolf)、李凯现场测试了一下,在使用 -Wall 开关编译的时候,会报出 WARN,提示使用了空的格式字符串。这是 C 库标准未定义行为的情况,这样使用会导致不可预期的情况出现,为什么不直接给 buf[0] 赋值 ‘\0′ 呢。

memset() 初始化内存有什么问题(以及硬盘的FUA/DPO)

在场童鞋表示,他们都不会这么写 sprintf(),hzmangel 童鞋表示,他会用 memset() 填 0,于是,又引出了 Coly 的话题。他表示,这样操作在正确性上没有问题,但是会破坏 Cache Line,这些 0 区域将来会被重新写入,是完全没有读意义的,如果他们冲掉了正在很热的被访问的 Cache 中的内容,对于那块内存的访问可能对运行时间有严重的影响。所以,如果一定要写入,最好能够告诉 CPU,默默地写入,不要干扰 L1 Cache,这样可能会让写入更慢,但如果同时有其他 VIP 读 Cache 的内容的话,会因此受益。(怎么干我忘了,谁告诉我哈)

Update:Bergwolf 提醒,这一绕过 Cache 的手段称为 non-temporal write,详见这里:http://lwn.net/Articles/255364/

同时,对磁盘的访问也是如此,某些操作不希望写入硬盘的Cache,防止影响读取告诉缓存的数据,这样的写操作可以利用 SCSI 的 FUA/DPO 标识,在新内核中,对于支持 FUA/DPO 的设备,Ext4的 journal 会使用这种方式写入,而非 barrier,从而提高性能。

nanosleep() 的开销在新 kernel 上为什么会变大(任何Sleep都会至少睡1毫秒?)

Coly 同学还提到了在他们的新 Kernel 上,老应用遇到的新问题。其中之一是某应用抱怨 sleep 开销变大,追查下去,是有四个线程频繁地 nanosleep 10 微秒,导致抢锁造成的。

“关于 sleep 一次至少会消耗1-2毫秒的认识早已经过时了”

这个问题来自于早期程序员们坚信,sleep会让出CPU,由于调度问题,会有至少1-2毫秒的消耗,于是,甚至会有人用 sleep(0)。但是,高精度计时器(HPET)的引入使得 sleep 的精度已经大幅提升了,你要10微秒,就会给你 10 微妙,于是,锁的时候的 spinlock 争抢变得异常激烈了……

这个故事告诉我们,那些没有明确承诺过的 feature,也会随着时间的推移,悄悄地消失,成为陷阱,要么避开不用,要么总是留意。

iowait% 大了,是否是开销就变大了

这也是一个新 kernel 带来的问题,hadoop 运维童鞋会观测到 iowait 比原来的老 kernel 高了 10% 以上,这个究竟是不是问题呢。Coly告诉我们,请看看运行时间——实际任务的运行时间会快 10%……这是为什么呢?

这个,解释下 wait time 是怎么计算的:内核每次采样看每个 CPU 的状态,如果 CPU 上是 idle,而且有任务在等 IO,就标记为 wait,那么,假设有16个CPU,如果有8个任务,分到16个CPU上,一直等IO,就是 50%,而如果有10个任务,分到两个 CPU上,就是 12.5%。这说明了什么问题呢——wait 并不全面反映等 IO 的严重性,新 kernel 更倾向于均匀地把任务分到更多 CPU 上,于是看起来 wait 值就高了。

这涉及到一个更科学的数据观的问题——你更关注的应该是任务的执行时间和效率、throughput、qps,而不是 CPU 的 wait time。

另外,iowait 时间是从 idle 中分化出来的,某些老的监控程序会直接用 (100% – idle%)当成 CPU 占用率,在 iowait 独立出去之后,会显得占用率变高。

其他

已经写了不少了,其他的不是我不想写,是想不起来了……请补充啊。

另外,Coly 强烈感谢了马涛(@淘泊瑜)为首的淘宝内核组童鞋们(羡慕嫉妒恨地说,他们还有美女 kernel 程序员……),作为国内互联网公司内,并入主线的 kernel patch 量当之无愧的老大,他们也是我们版聚的很多话题的来源,linuxfb 也感谢你们。

 

生日快乐,斯屹

March 20th, 2012 by gnawux No comments »

今天是斯屹的四岁生日,祝你生日快乐,也祝你妈妈青春永驻

 

 

列出某一CPU上跑的所有进程/线程

March 9th, 2012 by gnawux 6 comments »

比如 CPU2 上的:

ps -eLo pid,psr,command |sed -ne '/^\W\+[0-9]\+\W\+2\W\+/p'

嗯,后面 sed 匹配串里选第几个CPU,嗯前面的参数里,psr 是 CPU 号,嗯。

 

Galaxy Note入手体验

February 17th, 2012 by gnawux 3 comments »

特别声明:主观评测,所有评测意见来自本人主观感受,既不权威也不客观。

在被 Moto Milestone 伤了心之后,多年的 moto 用户也将目光投向了三星,关注了 Galaxy Nexus  良久之后,终于入手了 Galaxy Note。

Engaget 的编辑指出“Galaxy Note 是一台不是喜爱到不行就是会饬知以鼻的产品 — 它之于一般智能型手机尺寸的庞大身躯,实际上并不是每个人都可以接受的。“(来源:http://cn.engadget.com/2011/11/02/samsung-galaxy-note-review/ ) 对我来说也是如此,我总觉得这个身材跨界的怪胎会和我的 iPad 的定位发生冲突,所以一直将目光聚焦在略小一点点,有 ICS 的 Galaxy Nexus,怎奈后者的硬件配置实在是平平,最终,在老婆的预算支持下,还是入手了 Galaxy Note。

 物理观感

其实连我自己也不确定,5.3寸的手机是否适合自己的手,不过,到手之后的感觉还是很不错的。手机做得很薄很轻,重量上完全没有挑战,当然,想要舒适的单手操作也不太可能了。

1280×800 的 Super AMOLED 屏,虽然是 pentile 排列的,但看起来还是相当细腻的,这个差不多是前两年 12 寸的笔记本屏的分辨率了吧。不论你是看书、写字、玩游戏,都游刃有余,虚拟键盘的空间也相当宽裕,这个屏幕的体验绝对让你增加很多关注手机的时间。

当然,劣势也在这里,说实话,手握的时间长了还是有些累的,而且⋯⋯我不太敢在人面前拿着这个手机打电话,效果着实有点震撼,所以这几天我一直是在用蓝牙耳机的。

 硬件与系统配置

和两年前的 Milestone 相比,Note 的配置不可同日而语了,让我颇为不适应的事情包括——放了这么多应用之后,还有1.5G剩余,RAM也总是很空,我甚至可以肆无忌惮地在主屏上放好多 Widget,这在原来可是能省则省的啊。各种操作相当流畅,很多原来觉得死慢死慢的东西,比如”图库“,也一下就开了,很不适应啊。

电池方面,昨天晚上试了一下,一宿待机,啥都没关——无线网络、GPS、背景数据传输全开着,睡前还玩了一阵新买的 Sketch Book Mobile 应用,再算上早上端详了半天,掉电大约 10%,我觉得可以接受了,电池问题没有 @colyli 同学说得那么严重,2500mAh 的电池还是相当给力的。

  

当然,电力方面部分得益于新刷的一个 kernel,我第一天到手 root 之后,第二天刷了个 ROM,第三天刷了个 kernel,无愧于 Android 用户的忠实爱好——刷机、重启、换电池。感觉 Samsung 对用户还是很开放的,没有像 milestone 那样恶劣的锁 bootloader 的行为,这才像一个真的 linux 手机嘛。

 应用情况

丢了 iPad 之后,我醒悟到的一点就是 —— iPad 可以吸引用户在丢掉之后立刻就想再买一个的核心价值在于平台上面的体验超棒的优秀应用,特别是那些花钱买来的应用——GoodReader、Keynote、Instapaper 还有很多游戏都在此列,所以,对 Galaxy Note,我的重点也在应用。应用方面,首先说一些兼容性的问题,然后说一点游戏和界面响应的感受,最后说说有啥特别好玩、好用的应用。

实际上很多应用还不能适应5.3寸的屏幕,原来用得好好的 Moji 天气 widget 在 Note 上完全不能看,找了半天找到 Go Weather,还算好用。Pulse 在 Note 上显示时,字也好大啊,调都很难调好,只好删掉了。而且,在 5.3″ 的屏幕上,摆 Widget 也很有难度,为了摆出一个我看着还顺眼的主屏,费了好大力气啊。

对于界面的操控感觉,我觉得在大部分场合都没有什么问题,我装了一些小游戏,比如 Angry Bird, Air Attack, Slice it, Fruit Ninja Free 之类的,都是免费版的,没舍得花钱装收费版本的,呵呵,收费版本的回头到 iPad 上玩吧。都玩了一下,只有 Fruit Ninja 的操控感觉比 iPad 差一些,经常削漏,而且界面似乎被拉扁了,斗胆怀疑是应用本身的适配问题,不过这也在一个侧面说明五花八门的 Android 设备让开发者们有点无所适从。

再来说说一些有意思的应用,对中国用户,要想买付费应用,首先需要root,用 MarketAccess 把自己的手机设为米国或类似地方的服务商的网络代码,才可以访问米国的市场;另外,Android Market 版本太新就无法购买付费应用,所以还要用 OldMarket,替换回老版本的 Market。

有几个应用在原来 Milestone 上就很常用:Switch Pro Widget,用来在界面上安放很多开关的,还有 1-VPN,也是用 Widget 点一下就连 VPN 的,这个比不越狱的 iOS 方便。

Galaxy Note 有自己的 S Pen 和相关应用,点两下就截屏这个很好用,做笔记啥的也很舒服,iPad 要是有这个就好了,呵呵。对于 Galaxy Note 来说,这么大的屏幕,远胜于 iPad 2 的 800万像素摄像头,还有好用的 S Pen,用作笔记和绘图非常方便,Evernote、Skitch 都很好用,还有就是 AutoDesk 的 Sketch Book Mobile 也很好用,这个在 iPad 上也有,界面基本一样,画草图什么的很方便,5.3寸还可以用,太小的屏幕就没什么意思了。当然,这么大屏幕,用来看电子书也是不错的。

  

 

[译文] Flushing out pdflush

February 9th, 2012 by gnawux 1 comment »

按:谨以此译文献给仍然挣扎在 CentOS 5/RHEL 5 上的同学们,RHEL 6/CentOS 6 已经包含这个改进了。

原作者:Goldwyn Rodrigues
原文时间:April 1, 2009
原文链接:http://lwn.net/Articles/326552/
译者:王旭( @gnawux, http://wangxu.me/blog/
翻译时间:2012年2月7-9日

在内核的页缓存(page cache)之中,存放着永久存储设备上的文件内容的内存副本。当程序把数据写入到页面之中,但还没写到磁盘上的时候,这些数据就放在缓存之中,这就是“脏页”。脏页的数量可以从 /proc/meminfo 中看到。每30秒,脏页都会被刷入(flush)磁盘。Pdflush 是一组负责将脏页刷入磁盘的内核线程,它或者是由显式的 sync() 调用出发,或者在页面被清出 page cache 时隐式地自动触发,具体情况包括,如果页面在内存中的时间过长,或者 page cache 中有过多的脏页(过多的界定由 /proc/sys/vm/dirty_ratio 确定)。

在任意给定的时间,系统中会有 2-8 个 pdflush 线程。pdflush 线程的数量由 page chche 的负载确定,如果一秒钟之内,没有空闲的 pdflush线程,但工作队列里还有很多工作要做,就会创建一个新的 pdflush 线程。另一方面,如果最后一个活跃的 pdflush 线程也已经睡了超过1秒了,那就会有一个 pdflush 线程被终止,知道只剩下了两个 pdflush 线程。当前的 pdflush 线程数可以通过 /proc/sys/vm/nr_pdflush_threads 查看。

很久以来,就有很多 pdflush 相关问题让它饱受诟病。Pdflush 线程是所有块设备共享的,但是,如果它们能专注于每一个磁臂的话,性能可能会更好一些。通过 backing_dev_info 结构的 BDI_pdflush 标志,可以避免 pdflush 线程的竞争,但是,互相影响还是会影响写回的性能。Pdflush的另一个问题是请求的饥饿问题。系统的每个队列中都可以有固定个数的I/O请求。如果超过了限制,所有应用的I/O请求都会被阻塞住,直到有新的空位出现。因为 pdflush 是为多个队列工作的,它不会阻塞在某一个队列上。这样,它会设置 wbc->nonblocking 写回信息标志。如果其他应用继续在设备上写入数据,pdflush 就无法分配出空位了。如果 pdflush 不断发现一个队列处于拥塞状态,就会导致这个队列的请求被饿死。

Jens Axboe 在一组 patch 中提出了一个新的方案,使用为每个块设备(backing device info, BDI)配置的 flusher 线程作为 pdflush 的替代品。与 pdflush 不同,BDI 专属的 flusher 线程专注于一个磁臂。在 BDI 刷写的情况下,当请求队列出现拥塞的时候,请求的分配会被阻塞住,避免饿死请求,提供了更好的公平性。

使用 pdflush,脏的 inode list 存储于文件系统的超级块。由于 per-BDI flusher 需要直到知道要写入的脏页属于哪个块设备,所以,这个列表现在存储到了 BDI 里。这样,要刷入一个 superblock 上的所有脏 inode,就会导致刷入这个文件系统占用的所有后端设备上的脏 inode 列表。

与使用 pdflush 时类似,per-BDI 的写回是通过 writeback_control 数据结构控制的,写回程序从中知道写回什么、如何去做。这个结构中的重要字段包括:

  • sync_mode: 定义对于 inode 加锁的情况下,进行同步的方式。如果设置为 WB_SYNC_NONE,写回操作会跳过加锁的 inode,而如果设置为 WB_SYNC_ALL,则会等待加锁的 inode 被 unlock,再进行写回。
  • nr_to_write:要写的页的数量。这个值随着页面被写入而减少。
  • older_than_this:如果不为NULL,所有比这个字段中给出的 jiffies 值老的页面都会被刷入块设备。这个字段会优先于 nr_to_write。

bdi_writeback 结构保存了所有用于刷入脏页的信息:

struct bdi_writeback {
	struct backing_dev_info *bdi;
	unsigned int nr;
	struct task_struct	*task;
	wait_queue_head_t	wait;
	struct list_head	b_dirty;
	struct list_head	b_io;
	struct list_head	b_more_io;

	unsigned long		nr_pages;
	struct super_block	*sb;
};

bdi_writeback结构是在设备使用 bdi_register() 进行注册的时候初始化的。结构的各个字段的含义如下:

  • bdi: 和本结构实例相关联的 backing_device_info,
  • task: 指向缺省flusher线程的指针,这个线程用于启动进行刷写工作的线程,
  • wait: 用于同步flusher线程的等待队列,
  • b_dirty: 本 BDI 上面,需要刷入块设备的所有脏 inode 的 list,
  • b_io: 要进行 I/O 的 inodes ,
  • b_more_io: 更多的要进行 I/O 的 inodes ;所有要刷入的 inode 都先被插入到这个队列中来,之后再移送到 b_io,
  • nr_pages: 要刷入的页的总数,以及
  • sb: 指向当前 BDI 上的文件系统的超级块的指针。

nr_pages 和 sb 是异步传送给 BDI 刷写线程的参数,并且在 bdi_writeback 的生命周期中是可能发生变化的。这是因为有些设备上会有多个文件系统,也就会有多个超级块。当一个设备上有多个超级块的时候,sync 操作可以针对设备上的某一个特定的文件系统。

bdi_writeback_task 函数会周期性发起 wb_do_writeback(wb) 调用,调用周期为 dirty_writeback_interval,缺省值是5秒。如果5分钟内都没有页面被写入,flusher 线程就回退出(计时精度为 dirty_writeback_interval)。(退出)之后如果又需要工作了,那么就会由缺省写回线程来启动一个新的 flusher 线程。

写回的flush有两种工作方式:

  • pdflush方式:由显式的协会请求触发,比如 sync 一个超级块的所有 inode 页面。这时会以超级块的信息和要刷入的页面数量为参数调用 wb_start_writeback()。这个函数会去获取与此 BDI 相关联的 bdi_writeback 结构。如果获取成功的话,会将 superblock 指针和要刷入的页的数量写入 bdi_writeback 结构,并唤醒 flusher 线程,为该超级块进行实际的写操作。这个操作和 pdflush 的写入操作有所不同:pdflush 会根据写的路径来获取设备,阻塞住其他进城的写操作。
  • kupdated 方式:如果没有显式的写回请求,写回线程会周期性地刷入脏数据。当一个 BDI 的一个 inode 的页面第一次变脏的时候,会将 dirtying-time 记入 inode 的地址空间中。当周期性的写回代码检查到这个超级块的 inode 列表的时候,就回写回比某一时间更早变脏的 inode。这一操作的周期是 dirty_writeback_interval,缺省是5秒钟。

第一轮的讨论之后,Jens 根据 Andrew Morton 的建议,添加了每个设备有多个 flusher 线程的支持。Dave Chinner 建议,文件系统可能会希望每个分配组有一个 flusher 线程。在随后的(第二轮)补丁中,Jens 在 superblock 中添加了一个新的接口,来通过一个 inode 获取相关联的 bdi_writeback 结构:

struct bdi_writeback *(*inode_get_wb) (struct inode *);

如果 inode_get_wb 为空,就会返回 BDI 缺省的 bdi_writeback 结构,这就意味着这个 BDI 只有一个 bdi_writeback 线程。每个 BDI 可以启动的最大线程数为 32。

Jens 对一块 SATA 硬盘使用 Flexible File System Benchmark (ffsb) 进行的测试显示,可以获得 8% 的性能提升。通过 vmstat 观察,与未打过补丁的内核相比,文件操作的分布更加平滑 ,缓冲区的写回呈现出均匀分布。而对于一个10块硬盘的 btrfs 文件系统,per-BDI 刷写可以获得 25% 的提速。这组代码位于 Jens 的块设备层 git tree  (git://git.kernel.dk/linux-2.6-block.git)  的 writeback 分支。目前,第二轮讨论还没有新的意见出现,但 per-BDI flusher 线程还不足以进入 2.6.30 内核。

致谢:感谢 Jens Axboe 审阅本文并对这组补丁的一些内容进行了解释。【译文完】

Switch to our mobile site