多线程程序中,默认情况下各个线程的名字与进程名相同,但是可以通过操作系统提供的接口(prctl)修改这个名字。方法很简单,但某些时候,可以给程序的调试和运维带来很大的帮助。
  最近在调优tair的proxy server,其中使用到了tair client,每个tair client会创建若干个线程用于网络IO,另外proxy server本身还有其他IO线程。压测过程中发现,某个线程CPU彪到了100%,其他线程只有50%左右。根据该线程的调用栈可以推测出是tair client的IO线程,但其他IO线程不好分辨属于tair client还是proxy server。将IO线程按照功能命名后,发现4个tair client IO线程中,一个线程跑满了所在CPU核心,其他三个一直处于空闲状态。因此可以推断出tair client在连接分配上存在问题……找到了问题根源,解决起来就很容易了。

Tags: .

  最近看了些Memory Barrier的东西,针对一个经典的示例程序,做了重现性测试。
  对这个程序原型做一个简要介绍:有全局变量x/y/r1/r2,初始值均为0;线程1执行x = 1; r1 = y; 线程2执行y = 1; r2 = x。从“程序员角度”,在两个序列执行过后,r1 == r2 == 0不可能成立。但当发生执行时“访存重排序”时,却可能出现r1/r2同时为0的情况。使用CPU内存屏障适当“隔离”访存操作,杜绝重排序,就可以确保程序得到预想的结果。

Tags: .

  今天通过酷壳一篇推荐了解了一下 Cache 的“伪共享”(False Sharing). 写了小程序做了个简单的测试:

Tags: .

  经常需要查看一个文件有多少页面驻留在物理内存中,Linux中没有找到现成的命令,自己动手写了个小工具,基于mincore(2)系统调用。代码放在Github上面,可以git clone git://github.com/dutor/mincore.git获取。
  目前可用选项有限:查看特定文件驻留物理内存的页面数/字节数;将文件全部加载到物理内存;递归地查看某个目录下所有文件的映射情况。其他需要的功能,可能在以后添加。
  另外有一个叫vmtouch的工具,可以提供更丰富的功能。

Tags: .

  偶然发现glibc提供的lib.so是“可执行的”,这是快速查看glibc版本的一种方法,

1
2
3
4
5
6
7
~$ /lib/i386-linux-gnu/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.13-20ubuntu5.1) stable release version 2.13, by Roland McGrath et al.
Copyright (C) 2011 Free Software Foundation, Inc.
...
Compiled by GNU CC version 4.6.1.
Compiled on a Linux 3.0.17 system on 2012-03-07.
...

  这是gcc提供的一种叫做PIE(Position Independent Executable)的特性,可以创建位置无关的可以执行对象。它可以像共享库一样被加载到任何地址上执行。

Tags: ,.

  事情是这样的。我们对tair(淘宝的分布式Key/Value系统)动了一次大手术,更换了网络框架,经过长时间的测试/调试,终于完全通过了回归测试。但要打包发布的时候,却发现服务器可以正常启动,但却完全无法接受请求。调试无果,对比打包前后程序的差异,仅在于是否使用-O2选项对程序进行编译优化。
  无头苍蝇一样,Google搜索“gcc optimization problems”,找到StackOverflow上面的这个帖子,“抱着试试看的心态”,在编译选项中加入-fno-strict-aliasing,bingo!
  -fno-strict-aliasing这个选项是做什么的?aliasing又是什么?C和C++的标准给出了说明:

Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to 
objects of different types will never refer to the same memory location (i.e. alias eachother.)
Tags: ,,.

  pthread的mutex通常用在多线程的同步当中,至于多进程的同步,一直以为只能使用记录锁和信号量,而这两种机制都需要内核的支持,属于“重量级”部件。也曾经在多进程同步中使用pthread mutex,但前提有两个:mutex能为多个进程所见,使mutex对象驻留在共享内存中;mutex本身不额外使用进程本地的内存,如堆内存。第一个前提容易满足,对于第二个,GCC的pthread实现也满足。但我一直没有注意到的是,pthread mutex标准本身对多进程提供了“可选”支持,只要实现支持、初始化mutex时pthread_mutexattr_t的pshared成员置为PTHREAD_PROCESS_SHARED即可。
  pshared默认为PTHREAD_PROCESS_PRIVATE,即仅支持单进程。如果mutex驻留于共享内存,但pshared为PTHREAD_PROCESS_PRIVATE,此时多进程操作该mutex的行为是未定义的。这两天在写一个多进程可访问的库时就出现了这种“未定义”的行为,花费了一个多工作日才找到原因。

Tags: ,.

这两个程序的输出均是:

pure virtual method called
terminate called without an active exception
Aborted (core dumped)

原因和父类/子类的构造、析构的顺序,以及vtbl的相应变化有关,有兴趣的同学可以研究下。
注:纯虚函数在纯虚类的vtbl中的对应表项为函数__cxa_pure_virtual(),该函数会调用terminate(),后者打印”pure virtual method called”信息后调用abort自杀。

Tags: .

  这么一段程序,

1
2
3
4
5
6
7
8
9
typedef __gnu_cxx::hash_map<object *, object *, object_equal_to, object_hasher> object_hash_map_t;
object_hash_map_t hash_map;
hash_map.insert(make_pair(new object, new object));
object_hash_map_t::iterator it = hash_map.begin();
while (it != hash_map.end()) {
    delete it->first;
    delete it->second;
    ++it;
}

  了然了,iterator的operator++需要根据key计算出迭代器当前所在的bucket,然后在此bucket及后续bucket中顺序遍历以寻找下一个元素。所以在开头的示例代码中,由于在迭代过程中释放了key的内存,当迭代器“递增”计算当前bucket number时当然就core掉了。
  hash_map在STL中已经被标记为deprecated,已经过时了,若要使用hash_map,建议使用具有相同接口和特性的unordered_map。
  另外,使用hash_map时,一定要注意模板参数equal_to和hash_func,前者用来判断key是否相等,后者用来计算key的hash值,稍有不慎就会出现莫名其妙的错误,例如著名的hash_map的遍历死循环问题。

Tags: ,.

  本菜鸟写了一个server,经长时间激烈的测试以后,终于要在测试环境供外部使用了。经过一天激烈的打包,一枚rpm终于诞生了。上传到公司的yum包仓库,当PE同学部署时遇到了问题。程序在启动过程中莫名地core掉了,屡试不爽。使用gdb查看core文件的程序堆栈,发现程序core在了一个我从来没有修改过的类的析构函数中,core的直接原因就是C/C++程序员的老朋友Segmentation fault同学。查看该析构函数,里面只做了两个操作,简单讲,就是释放对象内存的两个delete。其中一个对象是在类的构造函数中创建,另外一个对象是在其他初始化函数startup中创建。析构函数中理所当然地对这两个对象的指针进行判断,非NULL则delete。这个类很特殊,正常情况下需要调用startup进行初始化,然后作为一个持久的对象使用。也可以不进行初始化,调用其他接口,然后销毁。我使用该类的场景就属于后者。在之前的测试过程中,core dump从未发生。

Tags: .
Page 1 of 3212345678910...2030...Last »