Linux Journal停刊了,BSD magazine还在继续。。。

2017年最后一个月里,发生了两件事:

(1)121日,从1994年创刊的Linux Journal杂志宣布停刊了(参考Linux Journal Ceases Publication),这本历史最悠久的Linux杂志正式退出了历史舞台。我个人觉得很是惋惜,有时搜索一些信息时,经常可以搜到Linux Journal的文章,虽然年代有些久远,但是内容依旧适用。

(2)昨天,也就是1231日,BSD Magazine发布了第100期。这个去年一度要停办的杂志,还是坚持了下来,我也希望它越办越好。我很喜欢每期里关于采访程序员的栏目,这可以让我了解其他国家软件工程师的日常生活和工作经历。此外,每期也会有一些当前的热点内容,比如这一期就介绍了比特币的背景和在FreeBSD上如何安装bitcoind程序。BSD Magazine是免费的,因此如果你对BSD感兴趣,可以考虑订阅一下。一分钱不花,学到新知识,何乐而不为?

Arch Linux —— 一个不错的Linux发行版

使用Arch Linux差不多有一年的时间了,总体感觉它是一个很不错的Linux发行版。

Arch Linux采用的是“滚动发布”(rolling release)模式,只需一个“pacman -Syu”命令,就可以用上最新的内核和软件包。这对那些对软件版本“追求极致”的开发者们(比如我),无疑是个“福音”。此外,Arch Linux的安装包做的很“人性化”。例如,我最近尝试使用clang开发OpenMP程序,不同于gccclang需要安装额外的包。而在安装clang时,系统会给出详细的提示信息:

# pacman -S clang
......
Optional dependencies for clang
    openmp: OpenMP support in clang with -fopenmp
    python2: for scan-view and git-clang-format
......

可以看到,除了表明需要openmp安装包外,系统还指出使用clang时要使用-fopenmp选项,这充分反映了安装包“考虑”的很“周全”。而在使用其它的一些Linux发行版时,安装clangOpenMP开发包时就很费一番周折。

另外,Arch Linux已经正式宣布不再支持i686平台了,这也提醒我们,也许是时候考虑和32位处理器说再见了。

如何计算进程占用的物理内存

How to get the process resident set size一文不仅介绍了在WindowsUnix(包括LinuxBSDmacOS等等)操作系统上如何获取进程所使用的峰值和实时物理内存,并提供了现成的代码。在这里我只分析一下Linux上相关功能的实现:

(1)获取峰值内存:

size_t getPeakRSS() {
    struct rusage rusage;
    getrusage(RUSAGE_SELF, &rusage);
    return (size_t)(rusage.ru_maxrss * 1024L);
}

getrusage函数获取进程资源的使用情况。当第一个参数时RUSAGE_SELF时,表示得到当前进程的统计数据。struct rusage中的ru_maxrss即表示该进程物理内存的使用峰值,因为度量单位是kilobytes,故而需要乘以1024

(2)获得实时内存:

size_t getCurrentRSS() {
    long rss = 0L;
    FILE* fp = NULL;
    if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
        return (size_t)0L;      /* Can't open? */
    if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
    {
        fclose( fp );
        return (size_t)0L;      /* Can't read? */
    }
    fclose( fp );
    return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
}

/proc/self/statm文件共包含7个字段,第二个即是进程当前时刻占用的物理内存,单位是页面大小。要获得精确的字节数,还需通过sysconf系统调用获得页面所占据的空间,通常为4096

 

Linux垄断超级计算机

top500网站公布的统计数据显示,目前世界排名前500的超级计算机使用的全部都是Linux操作系统:1
这就意味着之前“500强”中仅存的2Unix也终于“沦陷”了:

2

看一下关于Linux发行版的统计数据:

3

占据份额最大的是“Linux”,是因为不能确定具体的发行版?还是自己组装的,所以不属于任何发行版?我没有找到解释。但是“屈居亚军”的是CentOS,这倒也反映了这个RHEL的“免费社区版本”的稳定性以及受欢迎程度。如果你想选一个不花钱,又可靠的操作系统,CentOS可能是一个不错的选择。

此外,中国的超级计算机数量首次超越美国,成为世界第一:

4

最后,我的前东家HPE在生产厂商的排名中继续高居榜首,联想和浪潮,这两个来自中国的企业紧随其后:

5

Perf笔记(七)——perf trace

perf trace有类似于strace功能,可以实时监控程序的系统调用:

# perf trace ./a.out
 0.032 ( 0.002 ms): a.out/7673 brk(                                                                  ) = 0x1e6b000
 0.051 ( 0.005 ms): a.out/7673 access(filename: 0xb7c1cb00, mode: R                                  ) = -1 ENOENT No such file or directory
 0.063 ( 0.005 ms): a.out/7673 open(filename: 0xb7c1a7b7, flags: CLOEXEC                             ) = 3
 0.070 ( 0.002 ms): a.out/7673 fstat(fd: 3, statbuf: 0x7ffffb72bc80                                  ) = 0
 0.073 ( 0.004 ms): a.out/7673 mmap(len: 38436, prot: READ, flags: PRIVATE, fd: 3                    ) = 0x7f18b7e15000
 0.079 ( 0.001 ms): a.out/7673 close(fd: 3                                                           ) = 0
 0.087 ( 0.005 ms): a.out/7673 open(filename: 0xb7e21ec0, flags: CLOEXEC                             ) = 3
 0.093 ( 0.003 ms): a.out/7673 read(fd: 3, buf: 0x7ffffb72be28, count: 832                           ) = 832
 0.099 ( 0.002 ms): a.out/7673 fstat(fd: 3, statbuf: 0x7ffffb72bcc0                                  ) = 0
 0.102 ( 0.003 ms): a.out/7673 mmap(len: 8192, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS, fd: -1    ) = 0x7f18b7e13000
 0.110 ( 0.004 ms): a.out/7673 mmap(len: 2283024, prot: EXEC|READ, flags: PRIVATE|DENYWRITE, fd: 3   ) = 0x7f18b79cf000
 0.116 ( 0.007 ms): a.out/7673 mprotect(start: 0x7f18b79fc000, len: 2093056                          ) = 0
 0.125 ( 0.005 ms): a.out/7673 mmap(addr: 0x7f18b7bfb000, len: 8192, prot: READ|WRITE, flags: PRIVATE|DENYWRITE|FIXED, fd: 3, off: 180224) = 0x7f18b7bfb000
 0.142 ( 0.002 ms): a.out/7673 close(fd: 3                                                           ) = 0
 0.153 ( 0.006 ms): a.out/7673 open(filename: 0xb7e134c0, flags: CLOEXEC                             ) = 3
 0.161 ( 0.003 ms): a.out/7673 read(fd: 3, buf: 0x7ffffb72bdf8, count: 832                           ) = 832
 0.165 ( 0.002 ms): a.out/7673 fstat(fd: 3, statbuf: 0x7ffffb72bc90                                  ) = 0
 0.169 ( 0.005 ms): a.out/7673 mmap(len: 2216432, prot: EXEC|READ, flags: PRIVATE|DENYWRITE, fd: 3   ) = 0x7f18b77b1000
......

Perf笔记(四)——profile应用程序

使用perf record命令可以profile应用程序  (编译程序要使用-g,推荐使用-g -O2

perf record program [args]

或者在程序启动以后,使用-p pid选项:

perf record -p pid

默认情况下,信息会存在perf.data文件里,使用perf report命令可以解析这个文件:

Capture

哪些函数占用CPU比较多,一目了然。

另外,在使用perf record时可以加--call-graph dwarf选项:

--call-graph
 Setup and enable call-graph (stack chain/backtrace) recording, implies -g.
 Default is "fp".

采样结果如下:

Capture

关于ChildrenSelf的含义,perf wiki给了一个详尽的解释。以下列代码为例:

void foo(void) {
    /* do something */
}

void bar(void) {
    /* do something */
    foo();
}

int main(void) {
    bar()
    return 0;
}

Self表示函数本身的overhead:如果foo函数的overhead60%,那么barSelf overhead就是40%(刨除foo所占部分)。因为foobar都是main的子函数,所以二者的overhead都要计算入mainChildren overhead

对于采用--call-graph dwarf选项生成的perf.data做出的火焰图如下:

Capture可以看到显示了完整的函数调用栈。

Perf笔记(三)——tiptop

Tiptop是一个Linux系统性能工具,它通过读取CPU硬件计数器的信息(比如cahche missexecuted instructions per cycle等等),使我们对程序的执行效率有了更清晰的认识:

Capture

Tiptop通过perf_event_open(http://man7.org/linux/man-pages/man2/perfeventopen.2.html)系统调用(2.6.31版本称为perf_counter_open)来完成读取硬件计数器信息:

int perf_event_open(struct perf_event_attr *attr,
                           pid_t pid, int cpu, int group_fd,
                           unsigned long flags);

attr用来指定需要关注哪些硬件计数器;pidcpu指定关注运行在哪些CPU的进程(线程);group_fd用来设定event group,创建group leader时,group_fd设为-1flags可以置为0

perf_event_open执行成功后会返回一个有效的文件描述符,后续可通过ioctlread系统调用对这个文件描述符进行操作,达到想要的目的。

time和/usr/bin/time

当我在bash中敲入time命令时,运行的其实是bash内置的time命令:

$ time

real    0m0.000s
user    0m0.000s
sys     0m0.000s
$ type time
time is a shell keyword

这个time命令有一个-p选项,表示以posix格式输出:

$ time -p
real 0.00
user 0.00
sys 0.00

除此以外,还有一个time命令。不过我当前的机器并没有安装这个程序:

$ which time
which: no time in (/home/xiaonan/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl)

安装一下,对比bash内置的time命令:

$ sudo pacman -S time
$ type time
time is a shell keyword
$ which time
/usr/bin/time

单独运行“/usr/bin/time -p”,只会输出命令的帮助选项:

$ /usr/bin/time -p
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--help] command [arg...]

需要加上具体的需要度量时间的命令:

$ /usr/bin/time -p echo

real 0.00
user 0.00
sys 0.00

此外也可以给出命令执行的详细信息:

$ /usr/bin/time -v echo

    Command being timed: "echo"
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 0%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 1536
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 70
    Voluntary context switches: 1
    Involuntary context switches: 1
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

参考资料:
/usr/bin/time: not the command you think you know