Chinaunix首页 | 论坛 | 博客
  • 博客访问: 175825
  • 博文数量: 13
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 832
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-16 22:43
个人简介

最近关注Python,Linux,LLVM

文章分类

全部博文(13)

文章存档

2014年(13)

分类: LINUX

2014-03-27 11:24:51

一. 概述


Linux/UNIX发展数十年,IPC可谓五花八门,好在后来POSIX和SUS标准化下了很多功夫,如今接口清晰稳定了不少,但各系统实现依然有不少大坑小坑,不仅要看书和查文档,还要多实践,才能逐步熟悉掌握,本文就是熟悉IPC的一种途径。

性能测试代码和思路主要基于UNIX网络编程第二卷[Stevens, 1999],后文简称UNPv2,但做了如下调整:
1. 去掉Linux不支持或不常用的IPC,如Doors和Sun RPC。
2. 用pthread API重写读写锁,Stevens写UNPv2时Solaris和Digital UNIX还没有pthread版本的读写锁。
3. 为了减少外部依赖,重写TCP/UDP/UNIX Domain socket带宽和延迟测试,UNPv2的该部分数据是利用了开源的lmbench。
4. 增加了gcc版本的atomic作为一种同步原语,atomic如今已在C++ 11和C11获得标准化。
5. 暂时没包含System V semaphore,因为在自己机器测试时,出现极高的性能下降,比其他同步方式慢100倍以上,还不能确定是虚拟机或内核版本或用法导致,等后续有结论时,再补充。
6. 所有设置维持系统默认参数,除非文中特别说明。 

二. 测试环境


硬件:CPU双核(2.3GHz,6MiB L3),内存2GiB
软件:Fedora 20(kernel 3.12.10, gcc 4.8.2, glibc 2.18)

三. IPC带宽测试


方法:程序分别选取1KiB | 2KiB | 4KiB | 8KiB | 16KiB  | 32KiB | 64KiB作为一个消息大小,父子进程间传输数据,每个消息大小传输500MiB数据,运行5次取均值,得出每秒带宽数值。

图表:

Message size

Bandwidth (MB/sec)

Pipe

POSIX message queue

System V message queue

TCP socket

UNIX domain socket

UDP socket

1024

1,233

405

354

1,756

1,603

15

2048

2,048

869

655

2,625

2,132

30

4096

2,944

1,653

1,075

3,483

3,013

60

8192

3,211

4,250

1,599

4,175

4,779

119

16384

3,300

5,982

2,510

4,552

6,414

231

32768

2,876

6,929

2,888

4,450

7,508

435

65536

2,830

7,483

3,830

4,692

3,953




说明:
1. UDP带宽很低,因为UDP是IPC中唯一不可靠的数据传输方式,没有流量控制,不得不自己实现一个应用层的简单PUSH-ACK协议,但副作用就是性能下降严重。实践中可以实现一个批量传输/异步重传的传输协议,性能会高很多。
2. TCP和UDP都是基于lo环回网络接口,MTU 64KiB。TCP是流式传输,应用层不会感知到MTU限制。UDP是有边界的数据包,要考虑path MTU的问题,理论上IP可以分片UDP大数据包,但会带来更大的性能和可靠性问题,所以多数系统都会限制UDP报文大小,比如MTU 64KiB减去IP和UDP头部与变长选项,实际可发报文数据会低于64KiB,为了图表整齐,UDP的message size只取到32KiB。
3. UNIX domain socket可以支持字节流和数据包两种形式,这里只选取了字节流方式,类似TCP。
4. 需要提升内核对消息队列的限制/proc/sys/fs/mqueue/msgsize_max,/proc/sys/kernel/msgmax, /proc/sys/kernel/msgmnb,前面三个值都要提升到至少64KiB。
5. 从曲线走势中可以明显分为两个阵营:字节流无边界,有 pipe/TCP socket/UNIX Domain socket,该种实现通常维护一个内部buffer,每次读取用户空间的数据块不超过某个大小,当用户message size超过该值时,带宽不会有明显增长,甚至会下降,像pipe有PIPE_BUF限制,我的本机是4KiB; 数据报有边界,有POSIX message queue/System V message queue/UDP socket,一个message size都是一次调用,带宽随着message size持续增长。

四. IPC延迟测试


方法:程序的父子进程交换1字节数据10K次取均值,程序运行5次再取均值。

图表: 

Latency (microseconds)

Pipe

POSIX message queue

System V message queue

TCP socket

UDP socket

UNIX domain socket

53

53

57

67

63

54


说明:
延迟方面实在没有意外发生。。。都差不多。


五. 多进程同步时间


方法:程序分别启动1 | 2 | 3 | 4 | 5个子进程,在共享内存中放一个long整数,每个子进程对其自增1M次,总计时间,程序运行5次取均值。

图表: 

# processes

time to count 1M times (microseconds)

atomic

mutex

read-write lock

memory semaphore

named semaphore

fcntl record locking

1

6,082

20,478

34,125

20,736

23,340

544,179

2

40,948

120,419

411,038

192,671

222,371

1,317,033

3

72,817

177,074

726,129

648,390

630,069

2,191,806

4

101,213

287,997

1,012,311

855,711

891,484

6,125,641

5

128,190

371,302

1,129,752

1,122,309

1,198,571

3,757,362


说明:
1. 因为整数自增操作是非常简单的运算,并发访问时最适合atomic操作(__atomic_fetch_add),不涉及系统调用,只是几条汇编指令,所以效率最高,但它能做的操作都很简单,更复杂的场景就要求助mutex等手段了,此处只为说明同步原语本身的代价。
2. fcntl记录锁最慢,毕竟是文件系统相关的操作,是意料之中的,但记录锁用起来非常简单,各平台都支持,多进程下是很好的同步方式。
3. 除了fcntl,其它同步方式都是内存操作,规律就是功能越多,效率越低。atomic只能做一些整数类型的原子操作,最快;mutex可以锁定任意代码段,但只有0-1两个状态,仅次于atomic;读写锁需要区分读锁和写锁,比mutex复杂,信号量要维护数值的变化,可以看做是互斥锁与条件变量的合体,也比mutex复杂,这两个比mutex慢也是情理之中。 

六. 多线程同步时间


方式:程序分别启动1 | 2 | 3 | 4 | 5个线程,在共享内存中放一个long整数,每个线程对其自增1M次,总计时间,程序运行5次取均值。

图表: 

# threads

time to count 1M times (microseconds)

atomic

mutex

read-write lock

memory semaphore

named semaphore

fcntl record locking

1

6,011

20,161

36,107

20,472

21,136

581,972

2

40,732

197,068

322,856

177,390

196,268


3

60,447

266,436

364,316

281,590

536,500


4

81,705

383,399

468,483

459,140

742,603


5

102,755

476,966

565,017

517,602

1,116,406



说明:
1. 对比上面的多进程同步时间,可以看出Linux的进程切换并不比线程切换慢多少。
2. fcntl记录锁是基于进程的,所以有意义的测试只需开启一个线程。

七. 总结

不可直接把上面的结论套用到任何实际项目中,IPC实际性能有很多因素影响,比如系统负载/进程上下文切换/各种参数设置等等,需要以自身机器测试结果为依据,但可以参考上述思路。

八. 参考资料

1. UNIX Network Programming, Volume 2, Second Edition: Interprocess Communications, Prentice Hall, 1999, ISBN 0-13-081081-9.
2. Linux/UNIX系统编程手册. Kerrisk, M著;孙剑等译. 人民邮电出版社
3. UNPv2源码,
4. matplotlib生成上述图表,


阅读(10664) | 评论(4) | 转发(6) |
给主人留下些什么吧!~~

timespace2014-03-31 10:57:13

引用已经删除!!!

不算仿真。测试前置条件尽量简单,参考系一致,变量保持为一个,运行很多次后取算术平均值,比如带宽测试,维持系统默认设置的前提下,只改变消息大小(1KiB    ... 64KiB),传递5 x 500MiB数据,最终取算术平均。至于表格和图像,只是前面各组平均值的直接翻译,不涉及数据拟合或线性回归等统计手段。

回复 | 举报

timespace2014-03-30 15:36:59

xchaye:好文章, 没看到socket的数据,但是理论上,socket应该耗时比较多,而且真实环境下,socket影响因素也应该是比较多的。

上面有TCP/UDP/UNIX domain socket三种的带宽和延迟,是基于lo接口,看起来性能并不差。真实网络环境就很复杂了,影响因素太多,而且也不好和本地IPC比较性能。

回复 | 举报

xchaye2014-03-28 15:12:59

好文章, 没看到socket的数据,但是理论上,socket应该耗时比较多,而且真实环境下,socket影响因素也应该是比较多的。