Tuesday, December 10, 2013

[C++] 纳秒(ns)级精度的计时

在调试以及优化高性能的程序中,常需要对一小段程序计时. 普通的clock函数精度达不到ns级别.这里记录一下几种可以得到ns级高精度的计时方法.

使用clock_gettime


C++ 中可以使用clock_gettime, 得到
 
    clock_gettime(CLOCK_REALTIME, &time1);
    ... your code to profile ...
    clock_gettime(CLOCK_REALTIME, &time2);

使用rdtscp


如果想得到更高精度的计时, 比如以CPU的时钟周期为单位, 对于比较新的Intel CPU, 可以使用rdtscp指令来获得当前CPU时钟周期读数.比较前后两次读数就可以得到以时钟周期为单位的逝去时间.
// rdtscp ensure serialization, supported by newer CPUs
static __inline__ uint64_t rdtscp(void)
{
    uint32_t hi, lo;
    __asm__ __volatile__ ("rdtscp" : "=a"(lo), "=d"(hi));
    return ((uint64_t)lo | ((uint64_t)hi << 32);
}

Wednesday, October 30, 2013

Sublime Text 3 插件开发 (未完)

Sublime Text (以下简称ST)提供了一个python的API接口. 在这个接口之上,用户可以开发自己的插件. 完整的ST3 API可以参见这里
如果你想仔细研究这些API的定义以及ST自带Python模块的细节, 可以在ST下找到这个python API的文件. MacOS上, 在/Applications/Sublime Text.app/Contents/MacOS/目录底下, 有2个文件 sublime.pysublime_plugin.py.

从一个最简单的plugin开始


import sublime, sublime_plugin
class HelloWorldCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.insert(edit, 0, "Hello, World!")
将其命名为"hello_world.py"以后, 存在Packages/User底下. 这个plugin就只干一件事儿, 当你在ST3自带的python console里(可以通过Ctrl+`呼出)运行
view.run_command("hello_world")
就会在你正在编辑的文件里添加一段"Hellow, World!". 这里注意ST的命名习惯. 这个类的名字叫HellowWorld, console中ST会将其命名为hellow_world, 从而使用run_command("hello_world")来运行之.

Sunday, October 13, 2013

在Sublime Text 3 中使用emacs键位

我的目标很简单: 就是把sublime text的操作折腾的和emacs 一样

第一步, 安装sublemacspro.


参见这里: https://github.com/grundprinzip/sublemacspro
基本上最基本的emacs操作比如ctrl-w, alt-w, ctrl-k, ctrl-y 等就有了.

第二步, 增加一些我自己管用的keybinding

我是通过定制PreferencesKey->Binding->User来增加以下我自己习惯的键位:
[
 { "keys": ["ctrl+f"], "command": "move", "args": {"by": "pages", "forward": true} },
 { "keys": ["ctrl+b"], "command": "move", "args": {"by": "pages", "forward": false} },
 { "keys": ["shift+ctrl+f"], "command": "move", "args": {"by": "pages", "forward": true, "extend": true} },
 { "keys": ["shift+ctrl+b"], "command": "move", "args": {"by": "pages", "forward": false, "extend": true} },

 { "keys": ["alt+down"], "command": "move", "args": {"by": "stops", "empty_line": true, "forward": true} },
 { "keys": ["alt+up"], "command": "move", "args": {"by": "stops", "empty_line": true, "forward": false} },
 { "keys": ["shift+alt+down"], "command": "move", "args": {"by": "stops", "empty_line": true, "forward": true, "extend": true} },
 { "keys": ["shift+alt+up"], "command": "move", "args": {"by": "stops", "empty_line": true, "forward": false, "extend": true} },

 { "keys": ["ctrl+c", "ctrl+c"], "command": "build"},
]

参考:

关于key binding 的commands
http://www.sublimetext.com/docs/commands
如何写一个plugin
http://sublimetext.info/docs/en/extensibility/plugins.html
st3的api
http://www.sublimetext.com/docs/3/api_reference.html

Wednesday, September 25, 2013

[Math] 有趣的无穷数列求和

1 + 2 + 3 + 4 + ... = -1/12
所有自然数之和为-1/12
这个在量子物理和弦论里有应用, 据说12个维度就是这么来的

1 - 2 + 3 - 4 + ... = 1/4

1 + 2 + 4 + 8 + ... = -1
或者等价于: 所有偶数和为-2
其实这个可以自己推出来

高斯他老人家就推了一堆这种神奇的结论

Friday, July 12, 2013

[git] 一些git的使用小技巧

记录一下我在平时使用git时候的一些小技巧. 关于git更全面的使用介绍(比如整个工作的流程 ), 参见我之前写的的"git 笔记".

  • 查看my_file和之前版本的区别
    $ git diff HEAD my_file #latest version checked-in
    $ git diff HEAD~1 my_file #previous of the latest version
    $ git diff HEAD~2 my_file #previous ^ 2 of the latest 
  • 跳过git add而直接commit当前修改过的文件中那些被track的
    $ git commit . -m "foo"
  • 把track的文件中所有被修改的都加入index
    $ git add -u
  • 和HEAD比较, 当前工作目录下有那些具体的修改(可能跨几个文件)
    $ git diff HEAD
  • 查看每次commit都改动了哪些文件
    $ git log --stat
    查看上一次commit有哪些文件被改动
    $ git log -n 1 --stat
  • 将当前branch rebase到本地的master branch上. 也就是当前branch的local commit会出现在commit log的最后
    $ git rebase master
  • 指定从origin/master 来更新
    $ git rebase origin master
  • 设置gitignore_global 建立~/.gitignore_global, 然后执行
    $ git config --global core.excludesfile ~/.gitignore_global
  • 查看当前git的config
    $ git config -l
  • 设定当前git repository的email
    $ git config user.email "apc999@youremail.com"
    查看当前git repository的email
    $ git config user.email

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;

}

Saturday, March 30, 2013

code style

Python的code style

Python官方约定的风格PEP 8 -- Style Guide for Python Code

C++的code style

C++并无官方约定的风格。 我一般会遵从 Google 的C++ style guide

Wednesday, March 27, 2013

在MacOS和Linux上使用Ramdisk

在Linux上使用Ramdisk


我使用如下脚本来生成一个大小可设定的tmpfs作为ramdisk
#!/bin/bash

TMPFS_SIZE=12G

mkdir -p ./ramdisk
sudo umount ./ramdisk >& /dev/null
sudo mount -t tmpfs -o size=$TMPFS_SIZE,mode=0775,gid=binfan tmpfs ./ramdisk

在MacOS上使用Ramdisk


创建一个Ramdisk
$ hdiutil attach -nomount ram://1165430
/dev/disk2                                           
$ diskutil erasevolume HFS+ "ramdisk" /dev/disk2
Started erase on disk2
Unmounting disk
Erasing
Initialized /dev/rdisk2 as a 569 MB HFS Plus volume
Mounting disk
Finished erase on disk2 ramdisk
然后使用df就可以看见这个device了
$ df
Filesystem                        512-blocks      Used Available Capacity  iused    ifree %iused  Mounted on
/dev/disk0s2                       818359360 273993824 543853536    34% 34313226 67981692   34%   /
devfs                                    381       381         0   100%      660        0  100%   /dev
map -hosts                                 0         0         0   100%        0        0  100%   /net
map auto_home                              0         0         0   100%        0        0  100%   /home
/dev/disk0s4                       156733432  41530424 115203008    27%   108561 57608399    0%   /Volumes/BOOTCAMP
localhost:/AI1XeO7VNLFdFPonF9OexW  818359360 818359360         0   100%        0        0  100%   /Volumes/MobileBackups
/dev/disk1s1s2                         35040     35040         0   100%     8758        0  100%   /Volumes/HTC Sync Manager
/dev/disk2                           1165424     27376   1138048     3%     3420   142256    2%   /Volumes/ramdisk
不用的时候在Finder里面弹出这个设备就可以了.

Sunday, March 03, 2013

Memory barrier, volatile, cache coherency

Linux Kernel关于memory barrier的介绍

volatile会强制在你的code里, 每次都re-read该变量值. 但是它不能控制这个值的来源---可能从memory中读入, 也可能因为你的code刚刚访问过这个变量从而从cache中读入而不是memory.

http://stackoverflow.com/questions/558848/can-i-force-cache-coherency-on-a-multicore-x86-cpu

RCU(Read-copy Update)笔记

Linux RCU实现者之一Paul E. McKenney的三篇介绍RCU
What is RCU, Fundamentally?
What is RCU? Part 2: Usage
RCU part 3: the RCU API
Linux Kernel 文档介绍RCU
Linux 2.6内核中新的锁机制--RCU

Sunday, February 24, 2013

[C++] 小探iterator

#include <iostream>
#include <map>

using namespace std;

main() {
    map<int int> a;
    map<int int>::const_iterator cit;
    map<int int>::iterator it;
    a[1] = 15;
    printf("&a[1] = %p a[1] = %d\n", &a[1], a[1]);
    cit = a.find(1);
    it = a.find(1);
    it->second = 255;
    printf("%lx %p %d\n", *((long*) &it), &(it->second), it->second);
    printf("%lx %p %d\n", *((long*) &cit), &(cit->second), cit->second);
}
运行结果:
$ ./a.out
&a[1] = 0x7fb58a403954 a[1] = 15
&it =0x7fff520aa898 it =7fb58a403930 &(it->second) =0x7fb58a403954 it->second =255
&cit=0x7fff520aa8a0 cit=7fb58a403930 &(cit->second)=0x7fb58a403954 cit->second=255
几个结论:
  • 从cit只占用8个字节大小来看(&it-&cit), map::const_iterator 或者map::iterator, 其实内容就是一个8-byte的指针
  • 从cit和it都存着同样内容(0x7fff520aa898)来看, 内容其实就是map中该元素的地址.
  • 而且iterator的first 和second并不是值拷贝. 比如我们使用it对a[1]的值更新后, const_iterator只是该iterator不能对map做改动而已.

Thursday, February 21, 2013

[Emacs] Doxymacs


C-c d ? will look up documentation for the symbol under the point.
C-c d r will rescan your Doxygen tags file.
C-c d f will insert a Doxygen comment for the next function.
C-c d i will insert a Doxygen comment for the current file.
C-c d ; will insert a Doxygen comment for the current member.
C-c d m will insert a blank multiline Doxygen comment.
C-c d s will insert a blank singleline Doxygen comment.
C-c d @ will insert grouping comments around the current region.

Sunday, February 17, 2013

[Golang] Golang笔记贴(坑)

啥是Go?

Go是Google在09年左右新推出的一门语言.在语法上说, Go有点类似于C.但是Go的特性在于其高并发性和事件处理,使得它特别适合作为分布式编程的语言.CMU的15-440(distributed systems)开始使用Go做教学语言, 结果效果出奇的好.

安装设置Go

Go的安装 $GOPATH, $GOROOT

如果GOPATH=/path/to/A:/path/to/B, 那么go在找库的时候就从/path/to/A/pkg, /path/to/B/pkg这样的顺序.
安装远端repository里的库

Reference

Go语言简介(上):语法
Go语言简介(下):特性

Saturday, February 16, 2013

[Linux] Linux上NUMA相关的命令

查看NUMA的memory设置等

$ cat /sys/devices/system/node/node*/meminfo 
Node 0 MemTotal:       16777216 kB
Node 0 MemFree:           14312 kB
Node 0 MemUsed:        16762904 kB
...
Node 0 HugePages_Total:  1000
Node 0 HugePages_Free:    744
Node 0 HugePages_Surp:      0
Node 1 MemTotal:       16763940 kB
Node 1 MemFree:         5289568 kB
Node 1 MemUsed:        11474372 kB
...
Node 1 HugePages_Total:  1000
Node 1 HugePages_Free:   1000
Node 1 HugePages_Surp:      0

查看NUMA统计数据

比如多少local node reference, 多少foreign node reference
$ cat /sys/devices/system/node/node*/numastat
numa_hit 759046092
numa_miss 333483705
numa_foreign 236930883
interleave_hit 12690
local_node 746065583
other_node 346464214
numa_hit 506048971
numa_miss 236930883
numa_foreign 333483705
interleave_hit 12713
local_node 507619074
other_node 235360780

使用numactl设置task的numa属性

prefer(并非强制)使用numa node0来执行my_app
$ numactl --preferred=0 ./my_app arg1 arg2
强制使用numa node0 的local cpu和local memory来执行my_app
$ numactl --cpubind=0 --membind=0 ./my_app arg1 arg2

Saturday, February 02, 2013

[Latex] 编辑文档的tips

watermark

有时候我们需要在每一页打上一个水印, 这时候可以使用draftwatermark这个package.
\usepackage{draftwatermark}
\SetWatermarkText{this is a draft}
\SetWatermarkScale{0.5}
更多的参数可见 http://texblog.org/tag/draftwatermark/还有一个叫draftcopy的package也是可以做类似的事情, 但是似乎在我这里有问题

Friday, January 18, 2013

[Latex] 修补Rubber

Rubber停更很久了,所以已经从我的Latex编译好帮手,堕落为了pain of ass.


bibtex 问题



比如编译tex文件的时候会出现如下错误导致bib文件不能正确的编译出来:
running post-compilation scripts...
running BibTeX on paper...
There were errors making the bibliography.
There were errors compiling paper.
这是因为, rubber是这样调用bibtex的
Popen(['bibtex /your/path/to/tex/file'])
而在新的bibtex中, 不能接受绝对路径作为输入参数

解决方法: 在bibtex.py(如果你的rubber是使用brew安装的话, 其路径为/usr/local/Cellar/rubber/20100306/share/rubber/rubber/latex_modules/bibtex.py)中修改run这个函数, 在调用Popen前加上:
cmd = ["bibtex", "-min-crossrefs=1000", msg.simplify(self.base)]
process = Popen(cmd, stdout=PIPE, stderr=PIPE)