Archive for September, 2007

Small Mem Alloc: The Loki Way

Sunday, September 30th, 2007

Modern C++ Design 一书中有 Loki 库中用于小对象内存分配方法的详细介绍,不过书中用的 Loki 库的版本和我下到的版本应该不一样(我下载到的是 0.1.6 版),所以中间有一些细微的差别,不过总体上是一样的。

整体架构是这样:最上层是 SmallObjectSmallValueObject ,分别用于多态和 POD 情况下的小对象的基类,只要继承自他们就可以拥有小对象内存分配的特殊的 newdelete 函数。这两个类的区别就是是否有 virtual 的析构函数。如果是 POD 则不需要虚拟西沟函数,并且 SmallValueObject 这个时候把析构函数设置为 protected 避免误用基类指针来调用之类的析构函数。

Read the rest of this page »

混乱中:开学三周、国庆将至

Saturday, September 29th, 2007

一晃又开学三周了,国庆节也马上就开始了,然而自己却浑浑噩噩的不知到整天在干些什么。晕了晕了,好像要做的事情实在是太多了,但是好像又有比较闲的时候。也许是时间分配不好吧,总是闲下来的时候要做的事情统统忘记了,然而一忙起来就所有的事情都凑到一块了!

也许该好好看看 time-management 以及 GTD 相关的东西,规划规划自己的生活了!真的不再是小孩了。 :(

按照 Wikipedia 上的说法:

GTD rests on the principle that a person needs to move tasks out of the mind by recording them somewhere. That way, the mind is freed from the job of remembering everything that needs to be done, and can concentrate on actually performing those tasks.

我觉自己倒是经常把要做的事情从头脑里面移出去,只是然后就把他们忘了,直到非常紧急的时候才会突然想起来。

Cool Font for your Virtual Terminal

Thursday, September 27th, 2007

Terminus 是一种很不错的终端字体,如果要长时间在终端前工作的话,这是一个不错的选择。在 Debian 里面有 xfonts-terminusconsole-terminus 两个包,分别适用于 X 下的终端模拟器以及真实的 Virtual Terminal 。

我本来是很少适用 Virtual Terminal 的,不过 galilette 在我关于 Emacs Multi-tty 的那篇 Blog 中提到了 terminus 用于 VT 的事情,我也决定试一试。

其实对 VT 的东西非常不熟,因为我接触 Linux 的时候它的桌面应用已经做得非常不错了,除非系统崩溃或者紧急事态,基本上不用 VT :) 。不过没关系,Google 一下总能找到资料。

第一步当然是要安装字体包了:

sudo aptitude install console-terminus

然后 Ctrl+Alt+F1 切换到 VT 去试一试:

consolechars -f Uni3-Terminus16.psf

怎么样?是不是变得很漂亮呢?那要如何让它启动的时候就这么漂亮呢?参考一下自带的文档 /usr/share/doc/console-terminus/README.Debian.gz 的方法,可以在 /etc/console-tools/config 里面写上:

SCREEN_FONT=Uni3-Terminus16.psf

下次重新启动的时候就能看到默认字体变为 Terminus 了。

Small Mem Alloc: The SGI-STL way

Tuesday, September 25th, 2007

最初接触 C 语言的时候就对它 malloc 的内存管理感到奇怪,那么多 mallocfree 调用,申请内存的大小也没有什么规律,怎么能高效地管理呢?后来大概了解了下,感觉似乎产生碎片之类的情况是不可避免的,要不如果让算法太过复杂的话,调用一次 malloc 的成本也又太高了,这样反而让我平时写程序的时候调用 malloc 都显得有些心有余悸。

不过事情始终是不可避免的,为了少产生碎片,C 程序员们都倾向于一次申请大块的内存吧。但是到了 C++ 里面情况又变了,有许多小对象(诸如智能指针或者 Functor 一类的对象)如果在 heap 上分配空间,效率就会降下来。这个时候最好的解决办法应该就是对小对象采用特殊的内存分配机制了。

最近在侯捷先生的 STL 源码剖析 一书中看到关于 SGI 的 STL 中小对象内存分配机制的讲解,在这里做下笔记,一来加深理解,二来方便以后查阅。

SGI 的 STL 也是使用经典的 freelist 的方式来管理内存块的,但是为了避免产生碎片,它将分配的内存大小按照 8 的倍数对齐,并为 8、16、24、32、……、128 这些大小的内存块各自维护一个 freelist ,而对于大于 128 bytes 的内存申请工作直接交给 malloc 。流程如下图所示:

Read the rest of this page »

ImageMagick Tips: Shadow your picture

Tuesday, September 18th, 2007


ImageMagick 是一个非常强大的图像处理工具集合,并且有丰富的命令行借口,可以使用脚本让许多批量处理工作变得非常轻松。另外,许多编程语言都有 ImageMagick 的接口的库可以很方便地进行各种处理。

我在我的 Wiki 笔记上也记录了一些小 Tip 。正好我最近要给一个截图加上边框和阴影,我的Wiki 笔记中也有制作的方法,不过我想这样的功能其实很常用,干脆做一个脚本。其实 ImageMagick 本身虽然是非常强大灵活,但是每次实用都输入一长串命令确实是比较麻烦,把自己最常用的功能包装成脚本就很方便了。

添加阴影非常简单:

convert $1 \( +clone -background black -shadow 60x4+4+4 \) +swap \
    -background none -mosaic $1

如果要做成照片的那种效果,添加一个边框再加上阴影,也很方便:

convert $1 -bordercolor white -border 6 \
    -bordercolor grey60 -border 1 \
    \( +clone -background black -shadow 60x4+4+4 \) +swap \
    -background none -mosaic $1

或者再旋转个 30 度:

convert $1 -bordercolor white -border 6 \
    -bordercolor grey60 -border 1 \
    \( +clone -background black -shadow 60x4+4+4 \) +swap \
    -background none -mosaic -rotate 30 $1

三个脚本的效果分别如下所示:

Emacs Multi-tty Reloaded

Tuesday, September 18th, 2007

前不久得到一个消息,听说 Emacs Multi-tty 的代码 merge 到 CVS Head 里面去了,异常兴奋。可是看了 newsmth 上各位网友的试用及讨论之后,发现是 merge 到 trunk 里面,这里原来是 22 的 CVS ,现在 22 正式 Release 了,这里进行继续开发。换句话说,并没有和 unicode-branch 融合。而且版本号有些奇怪,现在 unicode-branch 里面的版本号是 23.0.0.2 这样的,而现在的 CVS Head 的版本号是 23.0.50.1

不管怎么说,multi-tty 的特性虽然很诱人(其实 XEmacs 早就有了这个功能),在中国最受欢迎的版本应该是 unicode-branch ,有两个重要原因:

  • 编码支持好。似乎整个核心都经过重写,改成 unicode 核心了,现在对 utf-8gbk 以及 gb18030 之类的编码都支持非常好。并且不需要安装额外的 mule-ucs 以及 mule-gbk 之类的包。
  • XFT 的支持。一来配置字体更方便了,二来更漂亮了。

Read the rest of this page »

多多益善的原则

Friday, September 14th, 2007

最近在看《Interaction Design — Beyond Human-Computer Interaction》一书的时候看到里面一处说起了人们“多多益善”的心理。一些有趣的行为,自己也经常那样去干,仔细去想就能发现那样的行为其实很傻,只是却被当做“理所当然”的行为而从来没有去想过罢了。

例如在杭州大热天里蒸了一天,终于回到室内,赶紧打开空调,如果你理想的温度是 22 度,你是会直接开到 22 度还是先开到更低的温度呢?如果是我,我会选择后者,事实上,我以前就是那么干的。人们仿佛觉得这样会让温度降低得更快一点,事实上稍微思考一下空调的工作方式就会知道这样其实并没有什么效果。当然,从另一方面来说,心理作用也是不可忽视的。 :)

另一个例子,就是经常有人在安装了 Linux 之后问我,为什么 Linux 下在桌面上右键菜单没有“刷新”选项。我问他们要那个选项干嘛。他们说习惯了。 :) 就算是习惯吧,那这个习惯缘何而起呢?应当是系统无响应或者变得很慢。系统死掉的时候人们总是拼命地移动鼠标,或者是狂点刷新,感觉好像是系统睡着了,这样就能赶快把它叫醒一样。其实这样也只能加重系统的负担罢了。

但是有这样的想法也是人之常情了,不能去责怪用户。为什么用户会用拳头拍打电视机后盖?无非是电视机画面不清晰了。要避免发生这样的误解,我们需要给用户提供“易于理解的、直观的交互方式”,并及时“响应用户的输入、给出有用的反馈”。

这样的问题在 Ajax 大行其道的今天也随处可见。以往点击一个连接可以看到浏览器“正在加载”的反馈,通常还有一个漂亮的滚动条。可是现在 Ajax 请求把一切隐藏起来,从浏览器看不到它的动作。如果某个关键动作有可能会需要进行一个比较耗时的连接的话,在页面上显示一些反馈信息就显得相当重要了,否则用户会觉得不知所措或者一阵狂点了。

Mac-like Google Reader theme

Thursday, September 13th, 2007

Google Reader 以简洁的界面以及实用而贴心的功能吸引许多人,但是时间久了也许换一换界面可以缓解视觉疲劳,这里有一款类 Mac 的主题,可以去试一试,它支持 Firefox 、Opera 、Safari 等众多浏览器,下面是我在 Firefox 下的一个截图:

不过说实话,习惯了原来的界面以后对新的界面会感觉一些不方便的地方。但是其实界面是可以自己定制的,例如在 Firefox 下它可以是以 Stylish 的定制格式或者 Greasemonkey 的 user script 的格式存在,这两种都是可以自己手工编辑的。

再从更高的视角来看的话,一些网站如果想做“换肤”功能的话,也不用去修改服务端的代码了,只要编写不同的客户端的定制文件,许多浏览器的用户都能方便地用上不同的皮肤了。

Does Visual Studio Rot the Mind?

Wednesday, September 12th, 2007

…there’s still coding to do, but there’s no APIs, there’s no classes, there’s no properties, there’s no forms, there’s no controls, there’s no event handlers, and there’s definitely no Visual Studio.

It’s just me and the code, and for awhile, I feel like a real programmer again.

从火的“发明”到电的“发明”再到信息技术和生命科学飞速发展的今天,人们不断地用技术在改善着自己的生活,然而,每一项技术的普及,都意味着人又对一个新的东西产生了依赖。试想,如果没有我面前的这台电脑以及 Internet,生活会怎么样?更严重一点,如果全国大停电,生活又会如何?如果连火也没有,又将如何呢?生活会变得乱糟糟,寸步难行,不!根本无法描述,甚至想都不敢想!

为什么我们会依赖它们?没有它们我们真的无法生活吗?当然不是!看看历史上的先辈们就知道。那这些工具和技术的出现(以及我们对它们的依赖)是否真的让我们的生活变得更美好呢?Charles Petzold 在 Does Visual Studio Rot the Mind? 一文中讨论了这个问题。

用 Charles 的话来说,这是一种“瘾(Addiction)”,人们总是说“没有 XXX 简直没法活”,其实对于大多数情况,这只是一种假象而已,就像是吸毒一样上了瘾。在我知道有电脑这个东西之前,我的生活一样很快乐,现在我却在说:“真不敢想像,没有电脑的生活会是怎么样!”这不是很奇妙吗?

作为程序员,IDE 正在成瘾,逐渐变成生活必需品,而 Visual Studio 无疑是一个优秀的 IDE ,它有许多异常方便的功能,例如 Form Designer 、Project Wizard 、Code Generation、Debugger 以及那强大的 IntelliSense :

IntelliSense is considered by some to be the most important programming innovation since caffeine.

哦!没有了 IDE 简直没法写程序了!我经常在一些 Linux 论坛里面看到有人来询问 Linux 下有没有什么好用的 IDE 。不知道在 Linux 下使用 Eclipse 的人多不多,只是我身边的 Linuxer 们写程序大多数都是用 Emacs 、Vim 甚至是 GEdit ,不用怀疑,没有 IDE 一样可以写程序!Windows 下也有不少 Notepad 铁杆 fans 。

那可爱的 IntelliSense 呢?是啊,在你输入的同时给予实时提示,甚至还会帮你改正你的“输入错误”(就像 Word 中诸如句首单词首字母自动大写一类的功能一样烦人,你输入 “id ” 它就变成了 “IDataGridColumnStyleEditingNotificationService”)。不用记各种各样的函数了,可是当你到一个没有 IntelliSense 的环境中时你就没辙了,更严重的是,你不再记东西了,谁都知道,大脑就是这样,你不去用它,它就会变“笨”,也许你开始逐渐发现,你甚至记不清自己一分钟以前定义的变量的名字,谁愿意去记呢?反正有提示,只要在列表里面找一下,总能找到一个“看上去像”的!

不再去记忆,甚至不再去思考!众所周知有“自顶向下”与“自底向上”两种编程方式存在,然而 IntelliSense 需要知道所有的信息才能给出完整的提示,于是你逐渐养成了先写出能写的所有的细节的习惯,写出需要引入的库、定义好所有后面要用的类、函数和变量……

Visual Studio 让我们成为更优秀的程序员了吗?没有!它只是让我们编程更快,仅此而已。Form Designer 、IntelliSense 的存在都让我们更加容忍诸如 form1button2 这样的变量名。项目里充斥着越来越多的生成的代码,它们的可读性非常值得怀疑。在越来越依赖于 IDE 的今天,我们不要忘记了写出来的程序主要是给人看的,只有在偶尔才会让编译器去阅读它,所以我们应当选择对人类更有亲和力的风格。

怎么说呢?当然不能否认技术进步给人类带来的好处,即使是毒品,适量地使用也是能治病的,只是别上了瘾。

Overflow in xl2tpd

Tuesday, September 11th, 2007

今天 VPN 突然连不上了,到终端启动 xl2tpd ,发现启动报错,说是无法读取配置文件:

$ sudo xl2tpd -D
xl2tpd[4344]: parse_config: line 13: data 'l parameters:' occurs with no context
xl2tpd[4344]: init: Unable to load config file

真是奇怪,我打开 /etc/xl2tpd/xl2tpd.conf 看了一下,十三行好好的嘛,只是注释而已。我甚至怀疑它打开的是什么文件,于是用 strace 跟踪了一下:

$ sudo strace xl2tpd -D
execve("/usr/sbin/xl2tpd", ["xl2tpd", "-D"], [/* 14 vars */]) = 0
brk(0)                                  = 0x8063000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fd9000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=76622, ...}) = 0
mmap2(NULL, 76622, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fc6000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\\177ELF\\1\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\\3\\0\\1\\0\\0\\0\\260a\\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=1336100, ...}) = 0
mmap2(NULL, 1340944, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e7e000
mmap2(0xb7fc0000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x142) = 0xb7fc0000
mmap2(0xb7fc3000, 9744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fc3000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e7d000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e7d6b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7fc0000, 4096, PROT_READ)   = 0
munmap(0xb7fc6000, 76622)               = 0
time(NULL)                              = 1189503420
brk(0)                                  = 0x8063000
brk(0x8084000)                          = 0x8084000
open("/etc/xl2tpd/xl2tpd.conf", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=5749, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fd8000
read(3, ";\n; Sample l2tpd configuration f"..., 1024) = 1024
getpid()                                = 4346
write(2, "xl2tpd[4346]: parse_config: line"..., 81xl2tpd[4346]: parse_config: line 13: data 'l parameters:' occurs with no context
) = 81
close(3)                                = 0
munmap(0xb7fd8000, 4096)                = 0
write(2, "xl2tpd[4346]: init: Unable to lo"..., 47xl2tpd[4346]: init: Unable to load config file
) = 47
exit_group(1)                           = ?
Process 4346 detached

可以看到它打开的确实是

/etc/xl2tpd/xl2tpd.conf

。半天都摸不着头脑,只好去 Google ,搜索出来唯一有点用的只有 l2tpd 的源码的 lxr 了。l2tpd 和 xl2tpd 应该大体上差不多吧。我找到那一行打印出错的地方,大致看了一下 parse_config 这个函数,发现它是自己手工在解析 ini 的配置文件格式,并且用 fgets 来读取一行的内容,而它的一行是多少呢?

992
char buf[STRLEN];

STRLEN 的定义是 80 。再看打印出错代码的那句代码:

1150
1151
1152
                log (LOG_WARN,
                      "parse_config: line %d: data '%s' occurs with no context\n",
                      linenum, s);

s 是读取的那一行去掉注释以后的内容。于是我再去搜索配置文件,发现确实有 “l parameters”,其实是一行注释(当然,并不是它说的那样在第 13 行):

11
; [global]                             ; Global parameters:

这下一切都明了了,它用 fgets 来读取一行,读到 “Global” 的 “l” 那里为止,下一次读的时候又读了一个尾巴,当然那不是什么有效的配置,所以就报错了,还因此把报错的行号都搞错了,因为它所谓的“一行”根本不是一行嘛。把那些超过 80 个字符的行编辑一下就可以了。

但是我比较奇怪的是这配置文件前面的一大段注释是它安装好就有的,而且我以前用都没有问题,怎么今天有好多行都就超过 80 个字符了。我今天只是用 Emacs 打开把一个 “a” 改成 “c” 了而已。要说也只有是 Emacs 自动把 tab 变成 8 个空格了,但是也没道理啊,我以前一直都是用 Emacs 改这个文件的,太奇怪了。

不过,l2tpd 那个代码也确实太不健壮了。。。 -.-bb