软件开发: 04 2009存档

#include <stdint.h>

struct tdb
{
    uint32_t    c;
    uint64_t    a;
    uint64_t    b;
};

      64位系统默认按8个字节来align,所以tdb的第一个成员c会align成8个字节。这个struct在32位gcc上编译后的size是20个字节, 而在64位上的size是24个字节,这个struct tdb是要写入文件的(实际上是通过mmap),这下就不能通用了。解决办法之一是加再加一个uint32_t的成员来“填充”这个空缺:

struct tdb
{
    uint32_t    c;
    uint32_t    align;
    uint64_t    a;
    uint64_t    b;
};

同样的
struct page
{
    ushort       c;
    uint64_t    a;
};

也要改为
struct page
{
    ushort       b;
    ushort       align1;
    uint32_t    align2;   
    uint64_t    a;
};

      这是“手工”的方法,其实还有更方便的,就是gcc的attribute修饰符:

struct page    __attribute__ ((__packed__))
{
    ushort       c;
    uint64_t    a;
};

      这样不管实在32位还是64位机器上,struct page的大小都是10个字节。
      尽管intel中国有压榨软件学院实习生的恶迹,但抛开这些不说,intel的编译器和性能分析工具还是相当不赖。以前就在《程序员》杂志上看到 说intel编译器不仅优化代码的能力出众,而且对于代码中可以化为并行的部分会自动帮你编译为可并行执行的指令....简直是出神入化。
      前一阵下载了intel编译器的evaluation版试了试,性能的确能提高30-10%左右。
      最大的发现是intel编译器附带自己的c语言库,比如对于内存操作类的函数叫_intel_fast_memcpy, _intel_fast_memset, _intel_fast_memcmp等,由编译器加进object文件里。gcc的memcpy是一个byte一个byte的拷贝,而intel的_intel_fast_memcpy我估计是像linux内核的 __memcpy一样,先一个int(4个字节)一个int的拷,不够4个字节了,再一个short(2个字节)一个short的拷,最后如果剩一个字 节,单独拷它。因为movw花的时间肯定不到movb的四倍,所以这种分粒度的拷贝肯定更高效。当然,也不排除intel编译器另外用了什么高级指令,让 内存拷贝更快——类似MMX里面的矩阵乘法。
之前用了Berkeleydb的DB_THREAD标记,于是bdb的增删查都内部带锁,但最近发现有内存泄漏的嫌疑——即使只调用bdb的del,用 free看系统剩下的内存也会越来越少,后来才发现问题:原来一旦用了DB_THREAD标记,在 db->get,db->put,db->del 时操作的DBT必须带上DB_DBT_USERMEM或DB_DBT_MALLOC,以告知bdb是用户程序来分配内存还是bdb自己来分配内存给DBT key和DBT value。
即使是del操作,也必须写清楚这个flag:

    char    buff[64];
    // buff中是要删除的key
    ....
    

    DBT tKey;
    memset(&tKey,0,sizeof(DBT));

    tKey.flags = DB_DBT_USERMEM;
    tKey.data = buff;
    tKey.size = strlen(buff);
        
    int res = m_dbp->del(m_dbp,NULL,&tKey,0);

这样就没有所谓的“内存泄漏”了。