Showing posts with label C++. Show all posts
Showing posts with label C++. Show all posts

Wednesday, May 22, 2013

查看gcc预定义的macro

在Linux或者MacOS的terminal里运行:
$ cpp -dM /dev/null
#define __DBL_MIN_EXP__ (-1021)
#define __UINT_LEAST16_MAX__ 65535
#define __FLT_MIN__ 1.17549435082228750797e-38F
#define __UINT_LEAST8_TYPE__ unsigned char
#define __INTMAX_C(c) c ## L
#define __CHAR_BIT__ 8
#define __UINT8_MAX__ 255
#define __WINT_MAX__ 4294967295U
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __SIZE_MAX__ 18446744073709551615UL
#define __WCHAR_MAX__ 2147483647
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __DBL_DENORM_MIN__ ((double)4.94065645841246544177e-324L)
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
#define __FLT_EVAL_METHOD__ 0
#define __unix__ 1
...
一般说来Linux平台上会预定义__linux__, 而MacOS会预定义__APPLE__

Saturday, April 13, 2013

[C] 线程局部存储 (thread-local storage)

GCC 支持使用线程局部存储(TLS)来方便多线程的编程.通俗来说, TLS就是一些看起来global的变量, 但是它实际上是per-thread的
使用TLS很简单,只需要用__thread关键字来修饰一个"全局变量",比如下面例子里的tid. 它在不同的thread里被输出的时候就是输出不同的值
#include <stdio.h>
#include <pthread.h<
#define NUM_THREADS     5

__thread long tid;

void print_tid() {
    printf("Hello World! It's me, thread #%ld!\n", tid);
}

void *run_thread(void *threadid)
{
    tid = (long)threadid;
    print_tid();
    pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
    pthread_t threads[NUM_THREADS];
    int rc;
    long t;
    for(t=0; t<NUM_THREADS; t++){
        rc = pthread_create(&threads[t], NULL, run_thread, (void *)t);
        if (rc){
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }

    /* Last thing that main() should do */
    pthread_exit(NULL);
}
运行
$ gcc test_tls.c
$ ./a.out 
Hello World! It's me, thread #0!
Hello World! It's me, thread #1!
Hello World! It's me, thread #2!
Hello World! It's me, thread #3!
Hello World! It's me, thread #4!

参考

GCC对TLS的支持

Thursday, April 11, 2013

[C/C++] 随机数

C里的RAND


#include <stdlib.h>    
#include <stdio.h>    

int main()    
{    
    srand(time(0));   
    printf("%d\n", rand());    
    return 0;    
}

使用C++11 里的Mersenne Twister随机数


C++11支持的Mersenne Twister可以非常轻量级的快速生成大量随机数.适合在benchmark的时候使用
#include <iostream>
#include <random>
main() {    
    std::mt19937_64 rng;
    // 使用系统时间生成随机数种子
    rng.seed(static_cast<unsigned int>(std::time(0)));

    // 生成32-bit的随机整数
    std::cout << rng() << std::endl;

    // 生成 1到255之间(包括1和255) 的随机数
    std::uniform_int_distribution<int> unif(1, 255);
    std::cout << unif(rng)<< std::endl;

    // 以概率0.3生成true, 0.7生成false
    std::bernoulli_distribution bern(0.3);
    std::cout << bern(rng) << std::endl;

}

Sunday, August 12, 2012

[Linux] backtrace

使用gdb可以在断点处停下来从而允许我们查看call strack. 可是有时候我们希望在程序里自动的显示当前的call stack --- 比如在异常的时候写到log当中.这时候就需要使用backtrace:
1 使用backtrace
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
显示出当前call stack 的backtrace: 每一行为一个frame对应的binary和在binary中的地址

Obtained 7 stack frames.
/home/foo/bench_cache() [0x4050f5]
/home/foo/bench_cache() [0x405f4e]
/home/foo/bench_cache() [0x407d8d]
/home/foo/bench_cache() [0x40283a]
/home/foo/bench_cache() [0x402e13]
/lib/libc.so.6(__libc_start_main+0xfe) [0x7fad2481dd8e]
/home/foo/bench_cache() [0x401eb9]
2 使用addrline
addr2line将binary的相对offset地址转化为对应的文件以及行数
$ addr2line -e bench_cache -f 0x4050f5
print_backtrace
/home/foo/bench_util.h:28
参数:
  • -e binary, 指定对应的binary
  • -f, 显示对应的function名称

Friday, May 04, 2012

[Linux]使用C设置线程的CPU affinity

随着多核机器的越来越普及. 对线程设置CPU affinity变得对性能越来越重要.linux提供的affinity设置功能可以将一个线程绑定到一个CPU的集合上(该集合可以包括一个或者多个CPU), 使得这个线程只被调度在属于给定CPU集合中的CPU上执行.
与CPU集合描述有关的几个宏:
  • CPU_ZERO():清空一个cpu_set_t类型的集合
  • CPU_SET()与CPU_CLR(): 将某个特定CPU加到某个集合或者从一个集合中删除.
  • CPU_ISSET(): 返回一个给定CPU是否在一个给定集合中.
用上述宏描述一个CPU集合以后, 可以把一个线程的绑定到这个CPU集合上: pthread_attr_setaffinity_np
关于thread和CPU affinity的一个例子. 这个程序里面函数cpunum得到当前机器cpu数目
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>

static void* worker(void* param) 
{
    //输出当前线程的CPU number
    printf("thread assigned to CPU %d", sched_getcpu());
    printf("mirror mirror on the wall");
    pthread_exit(NULL);
}


//返回当前CPU的core数目: 最多到32
static int cpunum()
{
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    sched_getaffinity(0, sizeof(cpuset), &cpuset);
    int num = 0;
    for (int i = 0; i < 32; i++)
    {
        if (CPU_ISSET(i, &cpuset))
            num++;
    }
    printf("%d cores on this machine");
    return num;
}

int main(int argc, char** argv) 
{
    cpu_set_t cpuset;
    pthread_t threads[10];
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    for(int i = 0; i < 10; i++) {
        //将第i个线程绑定至第i个core上执行
        CPU_ZERO(&cpuset);
        CPU_SET(i, &cpuset);
        pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);

        int rc = pthread_create(&threads[i], &attr, worker, NULL);
        if (rc) {
            exit(-1);
        }
    }

    pthread_attr_destroy(&attr);

    /* 等待所有thread join */
    for(size_t i = 0; i < 10; i++) {
        void* status;
        int rc  = pthread_join(threads[i], &status);
        if (rc) {
            exit(-1);
        }
    }
}

Wednesday, May 25, 2011

关于uint64_t(64位整数)的一些操作

显示

#include <inttypes.h>
#include <stdio.h>

int main()
{
  uint64_t a = 90;
  printf("test uint64_t : %" PRIu64 "\n", a);
  return 0;
}
如果是使用C++编译器编译上述代码,有时候会报如下错误
main.cpp: In function ‘int main()’:
main.cpp:9:30: error: expected ‘)’ before ‘PRIu64’
main.cpp:9:47: warning: spurious trailing ‘%’ in format [-Wformat]
解决方法是在inttypes.h这个头文件前加上一个__STDC_FORMAT_MACROS宏定义
#define __STDC_FORMAT_MACROS
#include <inttypes.h>

左移

对于32bit或者更短的的integer, 1左移x位就是 1≤≤x
但是对于64bit的integer, 比如unsigned long long或者uint64_t, 1≤≤32却是0. 如果需要2^32或者更大的数, 需要用1ULL≤≤32

http://cboard.cprogramming.com/c-programming/62790-bitshift-64-bit-integers.html

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main( void )
{
   uint64_t a = 1ULL << 32;
   uint64_t b = 1 << 32;
   printf( "a = %016"PRIx64", b = %016"PRIx64"\n",  a, b);
   return 0;
}
a = 0000000100000000, b = 0000000000000000

Sunday, March 27, 2011

libc interface v.s. system call

啥是System Call

$man 2 intro
INTRO(2)                                                Linux Programmer's Manual                                               INTRO(2)

NAME
       intro - Introduction to system calls

DESCRIPTION
       Section  2 of the manual describes the Linux system calls.  A system call is an entry point into the Linux kernel.  Usually, sys‐
       tem calls are not invoked directly: instead, most system calls have corresponding C library wrapper functions which  perform  the
       steps  required (e.g., trapping to kernel mode) in order to invoke the system call.  Thus, making a system call looks the same as
       invoking a normal library function.


每个system call都有一个number在<syscall.h>中. system call列表在Linux Kernel Source的arch/i386/kernel/entry.S中.

strace: 跟踪一个程序, 输出程序执行过程中所调用的system call

$strace ls 
execve("/bin/ls", ["ls"], [/* 25 vars */]) = 0
brk(0)                                  = 0x25b3000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7c0f616000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=144586, ...}) = 0
...

System Call Reference