博文

目前显示的是 二月, 2012的博文

让C/C++程序一次编译,到处运行 (仅限Linux)

本文不考虑静态链接方式,很多库在静态链接的时候会有问题,比如libunwind,它的异常处理API会和gcc原有的冲突。还有一个显著的问题就是nss。它根据配置文件/etc/nsswitch.conf来动态决定加载哪个so,然后用这个so执行名称解析服务等等。(nss是glibc的一部分,是系统很基本的东西)。还有,jni的so,想要静态链接很难。意思就是说,我要编译一个so,但是这个so所依赖的其它库又都必须是静态链接的,很难,而且也许会引入很多BUG。出于种种原因,我完全放弃了静态链接。(程序采用静态链接完美世界的传统)即便你的程序简单到只是一个hello world,那么也需要链接到libc.so。很明显,不同的glibc版本之间,差别很大,经常不兼容。那么我能不能在低版本的Linux上使用高版本的Linux的libc.so呢?于是我做了一个测试,我这边主要有两种Linux系统:CentOS 5和CentOS 6。CentOS 5下ld-linux-x86-64.so.2指向的是ld-2.5.soCentOS 6下ld-linux-x86-64.so.2指向的是ld-2.12.so如果强行把CentOS 5的这个so替换成CentOS6的那个,那么会发现任何elf都执行不了,relocation error: /lib64/libc.so.6: symbol _dl_tls_get_addr_soft, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2系统基本是僵死状态。(还好我今天用/lib64/ld-2.5.so ln -s -f ld-2.5.so ld-linux-x86-64.so.2的方式救回来了)如果我们不替换ld.so,而只是替换libc.so,例如:LD_LIBRARY_PATH=/home/changming/apps/lib64 ls (/home/changming/apps/lib64放的是CentOS6的libc.so)那么会报告:error while loading shared libraries: /home/changming/apps/lib64/libc.so.6: ELF file OS ABI invalid用file查看一下:Ce…

Howto: 在FreeBSD下使用google perftools对C/C++程序做性能分析

这篇文章不是google perftools的Quick Start,阅读本文之前请先阅读官方文档 https://gperftools.github.io/gperftools/cpuprofile.html。这篇是讲在FreeBSD下怎么能让CPU Profiler正确的跑起来,因为做性能分析的时候需要得到当前栈的函数信息,这个不容易拿到。下面仅针对64位的FreeBSD讲。
当我们进行函数调用的时候,每进入一个函数,首先就会向栈上push一个指针,记录的是当前的eip,这样在子函数执行完的时候,才能知道该从哪条指令继续执行下去。于是我们通过回溯栈上的内容,就可以得到一层层的函数地址。
进行栈回溯有很多种方式:
libunwind。需要注意的是,google perftools的1.10版本,需要配合libunwind 0.99-beta使用。libunwind 的版本很重要,太老或者太新,都不推荐。采用这种方式,那么需要注意的是尽量不要用静态链接。在静态链接的时候要加上-Wl,--eh-frame-hdr。据报道,libunwind 0.99-beta在Linux下可能会引起你的程序crash,如果确实遇到了这个问题,那么就换1.0.1。http://groups.google.com/group/google-perftools/msg/2686d9f24ac4365f
使用google perftools自带的。使用这种方式的要求是:在编译所有库,以及自己的程序的时候都加上-fno-omit-frame-pointer。
devel/libexecinfo。这个是通过gcc的内置函数__builtin_frame_address来得到栈信息。但是不知道为什么,这种方式下有时候进行backtrace的时候会崩溃。详情请见:https://www.freebsdchina.org/forum/viewtopic.php?t=53029 。使用这种方式的要求是,所有的库在链接的时候都要加上-Wl,--export-dynamic。
综上所述,google最为推荐的方式是:使用libunwind,并采用动态链接。(ports中的google perftools采用的是第二种方式)
但是光得到函数地址不够。你光知道0x00000008012b2b0c这个函数被调用的次…

需要raid吗?

我在sina的时候,那时候还比较穷,很少有机器带的有raid卡,于是我就研究怎么在solaris/linux/freebsd下做软raid。你别笑,我们那系统太繁杂了,什么样的OS都有。系统部主任有句名言:“冗余不做,日子甭过;备份不做,十恶不赦。”后来到了完美,比较有钱,几乎所有机器都是raid1或者raid5+hotspare,连平时不怎么用的内网测试机都是。老兔负责机器采购,他的观点是,硬盘坏了就得歇息,我们开发任务这么紧,让100多号人因为你硬盘坏了歇上半天,你耽误的起吗? 万一明天是情人节,新活动上线呢?难道你等到后天再上?到了现在这个公司后,我在内网的测试机上装FreeBSD但是发现HBA卡的内置raid功能用不了,没有驱动。然后我就去找黄冬,说以后采购的机器能不能先拿FreeBSD做下硬件兼容性测试?谁知道他的观点很极端,他说以后的机器根本就再也不采购raid卡,内置raid都不要。统统不要。我们组的DBA当时慌了,这以后万一硬盘坏了,还不得半夜爬起来切从库。要知道,不是所有公司都有一套Sina App Engine那样的平台。最近我在做一个统计系统,准备架在hadoop FS上。由于本身是分布式存储,而且FS自身把每块数据都存了3遍,所以已经有冗余了,raid显然不必要。但是hadoop FS毕竟有其局限型,不能代替ext3,所以我在想,怎么更好的利用越来越宽的网络。现在我们的机房普遍都是千兆网卡,因为大部分应用的硬盘IO都不会达到百MB每秒,所以程序和数据确实没有必要一定在一台机器上(当然在一起更好,节省带宽降低延迟)。而infiniband更是个NB的东西,它会大大的改变我们程序的架构,只是我还没想好怎么用它,在什么场合用,嗯,以及怎么申请买几块来。Anyway,我以后写的程序,尽量不要raid来提高可用性。

北京联通的WLAN的认证方式很蹊跷

很多地方,wifi的认证方式都是基于web的,而不是802.1x那套WEP/WPA/WPA2之类的,我不明白为什么。最近联通推出了免费WLAN体验活动,首先,它提供一个不加密的公开的Wifi,连接之后,通过网页认证,以http方式(不是https)提交一个表单,里面含用户名密码的明文。于是我诧异的就是,如果这套系统真的开始收费,那么窃听到密码岂不是太容易了吗?
我大致看了一下,认证的时候,是往http://202.106.46.37/login.do post一个表单,含以下参数
allowNumber 186,156,130,133,131,132
basname
localArea bj
localNeedAuthId yes
password 123456
passwordType 6
roamNeedAuthID no
savepwd 0
username 18610290001
userOpenAddress bj
然后每隔20秒,发一个http get的keepalive: http://202.106.46.37/keepalive.do?rand=0.4706242383564883 ,cookie里面含有电话号码、jsessionid、以及密码。
如果是每隔20秒一个这样的包,如果这套系统真的开始收费,那么窃听到密码岂不是太容易了吗? 难道又是临时工干的?

我的mapper终于跑起来了。

我最近在做一套数据统计平台。这周,写了一个工具,从mysql里面读数据,转换成protocol buffers的格式,然后写入到leveldb中。测试了一下性能,大概是每秒2万条左右(单线程),每条记录长度100个字节。weibo上@郝立华 说“mysql自己dump成sql的速度比你这个快多了”,但是我比较怀疑。因为mysql一秒钟想插入几万条记录,还是很困难的。However,我的最主要的目的是转格式,因为sawzall的input只认两种格式,protocol buffers和plain text。如我之前的blog所说,这个数据流,主要分三个处理阶段:map、sort、reduce。google的文档中常说第二个阶段是shuffer/sort。我不是很明白此处shuffer的意义。我今天把map阶段整了一个demo出来,从leveldb里面读数据,然后做统计。我这个demo所做的统计相当于从httpd的access log统计每个页面的访问次数,实际运行效率,大概是每秒12万条左右。我没有想到的是,在硬盘带宽未跑满之前,先把CPU跑满了。整个进程CPU占有率始终在150%左右(我主逻辑是一个单线程的循环,后台还有一个线程是leveldb的后台线程)。然后我就一直在思考一个问题,把数据放哪。HDFS,还是支持水平切分的key-value database?下面分别说下我的想法。我最想要的是一个列存储的数据库,可惜没有合适的,而且没想好怎么把它和sawzall搭配起来,放弃。然后我就想,要一个Riak这样的东西。它其实很简单,就是把key,散列到多台机器上去,分散存储。然后我在每个机器上遍历各自的数据库(map阶段),然后发送到中央机器做汇总(reduce阶段)。这个想法是多么的朴素简洁啊。如果我不想用riak呢,如果不想因为rpc带来额外的开销,那么就在硬盘上放很多个目录,每个目录对应一个leveldb的db。然后自己打开目录读去,多简单啊。我当时还在想,要不要把不同人的任务合并在一起执行。比如,我现在正在扫描周一到周日的数据,正扫到周三了。恰好另一个任务进来,也要这么扫。那么你不妨跟我先一起从周三跑到周日,然后我就结束了。你再从周日跑到周一。但是google不是这么做的。google的map reduce框架中,reducer从来不只一个 ,一般是几千个,…