├── .gitignore
├── LICENSE
├── README.md
├── imgs
├── book.png
├── course.png
├── double.png
├── new_62_62.png
├── official_accounts.jpg
└── zsxq.png
└── tests
├── cpu
├── index.md
├── test01
│ ├── Makefile
│ ├── likely.c
│ └── unlikely.c
├── test02
│ └── main.c
├── test03
│ └── main.c
├── test04
│ └── main.go
├── test05
│ └── main.c
├── test06
│ └── cpu_stat.sh
├── test07
│ └── cpu_stat.sh
├── test08
│ └── main.c
├── test09
│ └── main.c
├── test10
│ ├── main.c
│ └── main.go
└── test11
│ └── main.c
├── disk
└── test01
│ ├── randread.fio
│ ├── randread.php
│ ├── randwrite.fio
│ ├── randwrite.php
│ ├── read.fio
│ ├── read.php
│ ├── write.fio
│ └── write.php
├── ebpf
└── test01
│ ├── hello.c
│ ├── hello_kprobe.bpf.c
│ ├── hello_kprobe.skel.h
│ └── index.md
├── index.md
├── memory
├── test01
│ ├── Makefile
│ ├── clock.c
│ ├── clock.h
│ └── main.c
└── test02
│ ├── Makefile
│ ├── clock.c
│ ├── clock.h
│ └── main.c
└── network
├── test01
├── client.php
├── clientd.php
└── server.php
├── test02
├── c
│ ├── Makefile
│ ├── client.c
│ ├── server.c
│ └── tool.sh
├── java
│ ├── Client.java
│ ├── Makefile
│ ├── Server.java
│ └── tool.sh
└── php
│ ├── Makefile
│ ├── client.php
│ ├── server.php
│ └── tool.sh
├── test03
├── c
│ ├── Makefile
│ ├── client.c
│ ├── server.c
│ └── tool.sh
├── java
│ ├── Client.java
│ ├── Makefile
│ ├── Server.java
│ └── tool.sh
└── php
│ ├── Makefile
│ ├── client.php
│ ├── server.php
│ └── tool.sh
├── test04
└── main.c
├── test05
├── Makefile
└── index.md
├── test06
├── Makefile
└── index.md
├── test07
├── Makefile
└── index.md
├── test08
├── Makefile
├── client.c
├── server.c
└── tool.sh
└── test09
├── Makefile
└── main.c
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.zip
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 我们所有的开发同学每时每刻都在使用内核、都在使用硬件。所以能正确理解内核是怎么工作的、硬件的性能指标大概是多少,这些对于高阶的开发工程师来说非常重要。想成为技术大牛,扎实练习内功是必经之路!
3 |
4 | 飞哥的开发内功修炼从 CPU、内存、磁盘、网络四大模块进行深度思考,总结出来,在这里分享给积极上进的你!
5 |
6 | 另外飞哥目前已经出版了两本书,名字分别叫做《深入理解Linux进程与内存》和《深入理解Linux网络》。这两本书的市场接受度非常的高,都是在首发当天就斩获了京东科技类图书的第一名。希望这两本书能帮大家驾驭技术,掌舵人生!
7 |
8 | 
9 |
10 | 另外大家也可以加飞哥微信(zhangyanfei748528)进读者交流群,或者互相围观朋友圈。
11 |
12 |
13 | 本 repo 持续更新ing...
14 |
15 | ---
16 | **新文置顶:**
17 | - [揭开 strace 命令捕获系统调用的神秘面纱](https://mp.weixin.qq.com/s/Iz4YPPmyjGrXVnZ8eSap2Q)
18 | - [为什么服务器内存硬件上的黑色颗粒这么多?](https://mp.weixin.qq.com/s/jfn8QAuZSErxLXd3kPAtiw)
19 | - [C语言竟可以调用Go语言函数,这是如何实现的?](https://mp.weixin.qq.com/s/zvI3SJ2zItHzx-7w1HWu0Q)
20 |
21 | ## 一、网络篇
22 | **1.1 内核收发包原理**
23 | - [🔥图解Linux网络包接收过程](https://mp.weixin.qq.com/s/GoYDsfy9m0wRoXi_NCfCmg)
24 | - [🔥25 张图,一万字,拆解 Linux 网络包发送过程](https://mp.weixin.qq.com/s/wThfD9th9e_-YGHJJ3HXNQ)
25 | - [Linux网络包接收过程的监控与调优](https://mp.weixin.qq.com/s/6iQ-OhEbQJbEcgi9kakSjg)
26 | - [🔥127.0.0.1 之本机网络通信过程知多少 ?!](https://mp.weixin.qq.com/s/6_OfoeD3ZpyQisY2F-4_bw)
27 | - [本机网络IO之Unix Domain Socket与普通socket的性能对比](https://mp.weixin.qq.com/s/fHzKYlW0WMhP2jxh2H_59A) [实验使用源码](https://github.com/rigtorp/ipc-bench)
28 |
29 | **1.2 内核如何与用户进程协作**
30 | - [图解 | 深入理解高性能网络开发路上的绊脚石 - 同步阻塞网络 IO](https://mp.weixin.qq.com/s/cIcw0S-Q8pBl1-WYN0UwnA)
31 | - [🔥图解 | 深入揭秘 epoll 是如何实现 IO 多路复用的!](https://mp.weixin.qq.com/s/OmRdUgO1guMX76EdZn11UQ)
32 | - [漫画 | 看进程小 P 讲述它的网络性能故事!](https://mp.weixin.qq.com/s/r7EDYsvVhWA2fv52mwM_zg)
33 | - [在 golang 中是如何对 epoll 进行封装的?](https://mp.weixin.qq.com/s/hjWhh_zHfxmH1yZFfvu_zA)
34 | - [万字多图,搞懂 Nginx 高性能网络工作原理!](https://mp.weixin.qq.com/s/AX6Fval8RwkgzptdjlU5kg)
35 | - [单线程 Redis 如何做到每秒数万 QPS 的超高处理能力!](https://mp.weixin.qq.com/s/2y60cxUjaaE2pWSdCBX1lA)
36 | - [Redis 6 中的多线程实现方式比我预期的要差](https://mp.weixin.qq.com/s/MU8cxoKS3rU9mN_CY3WxWQ)
37 | - [剖析Netty内部网络实现原理](https://mp.weixin.qq.com/s/DS52g3bibU9kNH75UFxGqA)
38 |
39 | **1.3 TCP之三次握手**
40 | - [为什么服务端程序都需要先 listen 一下?](https://mp.weixin.qq.com/s/hv2tmtVpxhVxr6X-RNWBsQ)
41 | - [深入理解Linux端口重用这一特性](https://mp.weixin.qq.com/s/SYCUMvzktgeGbyAfRdqhmg) [配套实验源码](https://github.com/yanfeizhang/coder-kung-fu/blob/main/tests/network/test08/server.c)
42 | - [绑定特殊 IP 之 0.0.0.0 的内部工作原理](https://mp.weixin.qq.com/s/IOs39stus5C2K6RQFc5CQQ)
43 | - [TCP连接中客户端的端口号是如何确定的?](https://mp.weixin.qq.com/s/C-Eeoeh9GHxugF4J30fz1A)
44 | - [能将三次握手理解到这个深度,面试官拍案叫绝!](https://mp.weixin.qq.com/s/vlrzGc5bFrPIr9a7HIr2eA)
45 | - [深入解析常见三次握手异常](https://mp.weixin.qq.com/s/7Cum6Y28H_gXLyrRFrthNw)
46 | - [如何正确查看线上半/全连接队列溢出情况?](https://mp.weixin.qq.com/s/f-TFX2t8CWRCGoyCByGkOw)
47 |
48 | **1.4 TCP连接时间开销、内存开销**
49 | - [聊聊TCP连接耗时的那些事儿](https://mp.weixin.qq.com/s/wXyerOFoibRsaBmbl224gw)
50 | - [刨根问底儿,看我如何处理 Too many open files 错误!](https://mp.weixin.qq.com/s/GBn94vdL4xUL80WYrGdUWQ)
51 | - [漫画 | 花了七天时间测试,我彻底搞明白了 TCP 的这些内存开销!](https://mp.weixin.qq.com/s/BwddYkVLSYlkKFNeA-NUVg)
52 |
53 | **1.5 单机百万并发系列**
54 | - [🔥漫画 | 一台Linux服务器最多能支撑多少个TCP连接](https://mp.weixin.qq.com/s/Lkyj42NtvqEj63DoCY5btQ)
55 | - [🔥漫画 | 理解了TCP连接的实现以后,客户端的并发也爆发了!](https://mp.weixin.qq.com/s/ta6upubg0o1w03YGUo8Trg)
56 | - [百看不如一练,动手测试单机百万连接的保姆级教程!](https://mp.weixin.qq.com/s/f_CMt2ni0vegB3-pf2BTTg)
57 |
58 | **1.6 网络工具**
59 | - [用户态 tcpdump 如何实现抓到内核网络包的?](https://mp.weixin.qq.com/s/ZX8Jluh-RgJXcVh3OvycRQ)
60 |
61 | **1.7 虚拟化**
62 | - [轻松理解 Docker 网络虚拟化基础之 veth 设备!](https://mp.weixin.qq.com/s/sSQFINJ8RO8Nc4XtcyQIjQ) (:cn:新)
63 | - [聊聊 Linux 上软件实现的“交换机” - Bridge!](https://mp.weixin.qq.com/s/JnKz1fUgZmGdvfxOm2ehZg) [配套实验源码](/tests/network/test05/) (:cn:新)
64 | - [彻底弄懂 Linux 网络命名空间](https://mp.weixin.qq.com/s/lscMpc5BWAEzjgYw6H0wBw) [配套实验源码](/tests/network/test06/) (:cn:新)
65 | - [手工模拟实现 Docker 容器网络!](https://mp.weixin.qq.com/s/Arcz3RWe_o0Ijw6uPWKdVw) [配套实验源码](/tests/network/test07/) (:cn:新)
66 | - [理解 iptables 原理](https://mp.weixin.qq.com/s/O084fYzUFk7jAzJ2DDeADg)
67 | - [天天讲路由,那 Linux 路由到底咋实现的!?](https://mp.weixin.qq.com/s/UHYE6vwMffaAb-o5eNMrDg)
68 |
69 | **1.8 性能优化**
70 | - [关于 Linux 网络性能的 15 个优化建议!](https://mp.weixin.qq.com/s/-xiWjPRiRsPcxODnJ3921Q)
71 |
72 | **1.9 电子书**
73 | - [🔥开发内功修炼网络篇电子书出炉!!!](https://mp.weixin.qq.com/s/kE8y9em9a0Xv80YaQqPbRg)
74 |
75 | ## 二、硬盘篇
76 | - [经典,Linux文件系统十问](https://mp.weixin.qq.com/s/pOKjwl3ONPMPSRF6RSmvaw)
77 |
78 | **2.1 硬件工作原理**
79 | - [磁盘开篇:扒开机械硬盘坚硬的外衣!](https://mp.weixin.qq.com/s/OqhwSI4WsEyZlBhkFGPUlg)
80 | - [磁盘分区也是隐含了技术技巧的](https://mp.weixin.qq.com/s/4HwUxy-4FClgIIei6JAzqw)
81 | - [我们怎么解决机械硬盘既慢又容易坏的问题?](https://mp.weixin.qq.com/s/n9Hf3Utm4NFp3jNRTgZNwg)
82 | - [拆解固态硬盘结构](https://mp.weixin.qq.com/s/6aPHMmz1kmiaBABhy8pF1Q)
83 |
84 | **2.2 文件系统浅析**
85 | - [新建一个空文件占用多少磁盘空间?](https://mp.weixin.qq.com/s/9YeUEnRnegplftpKlW4ZCA)
86 | - [只有1个字节的文件实际占用多少磁盘空间](https://mp.weixin.qq.com/s/WE6BodR_q0GSKks_TgYL1w)
87 | - [文件过多时ls命令为什么会卡住?](https://mp.weixin.qq.com/s/g-fFoYsBJkonV3ezdGDJKA)
88 | - [理解格式化原理](https://mp.weixin.qq.com/s/DobymgQ-TRXrO32wjf2fWQ)
89 |
90 | **2.3 文件读写性能**
91 | - [read文件一个字节实际会发生多大的磁盘IO?](https://mp.weixin.qq.com/s/vekemOfUHBjZSy3uXb49Rw)
92 | - [write文件一个字节后何时发起写磁盘IO?](https://zhuanlan.zhihu.com/p/142441899)
93 | - [机械硬盘随机IO慢的超乎你的想象](https://mp.weixin.qq.com/s/qz57uPtFaoQ_5z59NSBEUQ)
94 | - [搭载固态硬盘的服务器究竟比搭机械硬盘快多少?](https://mp.weixin.qq.com/s/4CKPLpEDDbIyqJGxYDAUeA)
95 |
96 |
97 | ## 三、内存篇
98 | **3.1 硬件工作原理**
99 | - [带你深入理解内存对齐最底层原理](https://mp.weixin.qq.com/s/F0NTfz-3x3UxQeF-GSavRg)
100 | - [内存随机也比顺序访问慢,带你深入理解内存IO过程](https://mp.weixin.qq.com/s/ps8VfGpbL4-xKggM2ywjHw)
101 | - [从DDR到DDR4,内存核心频率其实基本上就没太大的进步](https://mp.weixin.qq.com/s/LRxhKrUOgyCexYN1lOwTyA)
102 | - [看懂服务器 CPU 内存支持,学会计算内存带宽](https://mp.weixin.qq.com/s/ANKD54RPJePb27hi6dXAcA)
103 | - [为什么服务器内存硬件上的黑色颗粒这么多?](https://mp.weixin.qq.com/s/jfn8QAuZSErxLXd3kPAtiw)
104 | - [理解内存的Rank、位宽以及内存颗粒内部结构](https://mp.weixin.qq.com/s/wCzeFhTE8OEWaZmMhc0iUw)
105 | - [服务器之 ECC 内存的工作原理](https://mp.weixin.qq.com/s/erqfwC_zgL71xftxE7bINQ)
106 | - [Linux 下用 dmidecode 探秘服务器内存硬件](https://mp.weixin.qq.com/s/fIQyEtOIOoQF32avBekHLw)
107 |
108 | **3.2 内核内存管理模块启动过程**
109 | - [Linux 内核是如何检测可用物理内存地址范围的?](https://mp.weixin.qq.com/s/jZm9CbPayhAlKaptbkppnQ)
110 | - [Linux 内核“偷吃”了你的内存!](https://mp.weixin.qq.com/s/MSlvaSmX2NQIzK10jjLXZg)
111 | - [Linux 内核是如何感知到硬件上的 NUMA 信息的?]()
112 |
113 | **3.3 内核内存管理**
114 | - [说出来你可能不信,内核这家伙在内存的使用上给自己开了个小灶!](https://mp.weixin.qq.com/s/OR2XB4J76haGc1THeq7WQg)
115 | - [明明还有大量内存,为啥报错“无法分配内存”?](https://mp.weixin.qq.com/s/Jo8KEzfb1OXShrb3PT4U_A)
116 | - [从进程栈内存底层原理到Segmentation fault报错](https://mp.weixin.qq.com/s/pTP7ELOm4-JsAl1o_nyS-Q)
117 | - [聊聊跨进程共享内存的内部工作原理](https://mp.weixin.qq.com/s/KzKkXhxjBLcgiHHB18ASGw)
118 |
119 | **3.4 语言运行时内存管理**
120 | - [聊聊C语言中的malloc申请内存的内部原理](https://mp.weixin.qq.com/s/7ZyCXUABL0Urso4VeaEdBQ)
121 |
122 | **3.5 内存性能测试**
123 | - [实际测试内存在顺序IO和随机IO时的访问延时差异](https://mp.weixin.qq.com/s/_-Ar944KlztzmFYdA3JXnQ)
124 | - [揭穿内存厂家“谎言”,实测内存带宽真实表现](https://mp.weixin.qq.com/s/AJjBHCNPWN8YW8v0iXjjig)
125 | - [NUMA架构下的内存访问延迟区别!](https://mp.weixin.qq.com/s/xUZl5wGRVvJI_Hfivg0hVQ)
126 | - [挑战Redis单实例内存最大极限,“遭遇”NUMA陷阱!](https://mp.weixin.qq.com/s/dag1Zp1h4lQfqeUUGz4Ogw)
127 |
128 | **3.6 内存性能优化实例**
129 | - [一次内存性能提升的项目实践](https://mp.weixin.qq.com/s/foJJ2E7_jVgnOeJ9Du6qJg)
130 | - [PHP7内存性能优化的思想精髓](https://mp.weixin.qq.com/s/3DrDb0CY8dUmFUKtuWzhqA)
131 |
132 |
133 | ## 四、CPU篇
134 | **4.1 了解CPU硬件**
135 | - [你以为你的多核CPU都是真核吗?多核“假象”](https://mp.weixin.qq.com/s/XX1yh8BTgT256pAnfosQkw)
136 | - [听说你只知内存,而不知缓存?CPU表示很伤心!](https://mp.weixin.qq.com/s/PQTuFZO51an6OAe3WX4BVw)
137 | - [TLB缓存是个神马鬼,如何查看TLB miss?](https://mp.weixin.qq.com/s/mssTS3NN7-w2df1vhYSuYw)
138 | - [深入了解 CPU 的型号、代际架构与微架构](https://mp.weixin.qq.com/s/CIdehZeaCm2saYuzhUcqFA)
139 | - [聊聊近些年 CPU 在微架构、IO 速率上的演进过程](https://mp.weixin.qq.com/s/ungGwoy2zSALLpq8FgQvcg)
140 | - [深入了解服务器 CPU 的型号、代际、片内与片间互联架构](https://mp.weixin.qq.com/s/7nwiX3JaGwL-EOZz77GohA)
141 | - [个人电脑上CPU和服务器上的CPU都有哪些区别?](https://mp.weixin.qq.com/s/VY7Fj2X3rYg0S3gy5Hvi8A)
142 |
143 | **4.2 内核CPU开销浅析**
144 | - [进程/线程切换究竟需要多少开销?](https://mp.weixin.qq.com/s/uq5s5vwk5vtPOZ30sfNsOg)
145 | - [软中断会吃掉你多少CPU?](https://mp.weixin.qq.com/s/mlenlX3-6H0shfOIvi8E8g)
146 | - [一次系统调用开销到底有多大?](https://mp.weixin.qq.com/s/2nIDLeMR984_Sdgh01BHIQ)
147 | - [一次简单的php请求redis会有哪些开销?](https://mp.weixin.qq.com/s/yl5EuQ1wEXDuIg4E98QfZA)
148 |
149 | **4.3 用户态CPU开销分析**
150 | - [协程究竟比线程牛在什么地方?](https://mp.weixin.qq.com/s/N4W0-0cP1wlxtLILx3oXpg)
151 | - [函数调用太多了会有性能问题吗?](https://mp.weixin.qq.com/s/G30VtOIYjx2Wa54xlO7udw)
152 |
153 | **4.4 CPU性能优化**
154 | - [一个likely的简单使用,背后却是对CPU工作原理的深刻理解](https://mp.weixin.qq.com/s/2YJVAEanfjSYgmZh8GRNrg)
155 | - [Linux 中 CPU 利用率是如何算出来的?](https://mp.weixin.qq.com/s/40KWGKNBoa35s533YGWYIQ)
156 | - [如何正确获取容器的CPU利用率?](https://mp.weixin.qq.com/s/nKedQRFxmIgPBxtlIJasZw)
157 |
158 |
159 | **4.5 进程管理**
160 | - [Linux进程是如何创建出来的?](https://mp.weixin.qq.com/s/ftrSkVvOr6s5t0h4oq4I2w)
161 | - [你写的代码是如何跑起来的?](https://mp.weixin.qq.com/s/1bdktqYF7VyAMadRlcRrSg)
162 | - [聊聊Linux中线程和进程的联系与区别!](https://mp.weixin.qq.com/s/--S94B3RswMdBKBh6uxt0w)
163 | - [你的新进程是如何被内核调度执行到的?](https://mp.weixin.qq.com/s/y2axbQTzOGZweJn3LAhWvg)
164 | - [Linux 中的负载高低和 CPU 开销并不完全对应](https://mp.weixin.qq.com/s/1Pl4tT_Nq-fEZrtRpILiig)
165 | - [为什么新版内核将进程pid管理从bitmap替换成了radix-tree?](https://mp.weixin.qq.com/s/0w7dJh0Gr4PokUBcy8rN7w) (:cn:新)
166 |
167 | **4.6 容器进程管理**
168 | - [一次限制进程的 CPU 用量的实操过程](https://mp.weixin.qq.com/s/WQXURUChn8AZW17_Bi5plg)
169 | - [Docker容器里进程的 pid 是如何申请出来的?](https://mp.weixin.qq.com/s/LDu6s1eZw6_xEwfa6pMM-A)
170 | - [内核是如何给容器中的进程分配CPU资源的?](https://mp.weixin.qq.com/s/rUQLM8WfjMqa__Nvhjhmxw)
171 |
172 | **4.7 函数调用**
173 | - [C语言竟可以调用Go语言函数,这是如何实现的?](https://mp.weixin.qq.com/s/zvI3SJ2zItHzx-7w1HWu0Q)
174 |
175 | **4.8 信号管理**
176 | - [我的服务程序被 SIGPIPE 信号给搞崩了!](https://mp.weixin.qq.com/s/WpYW0E_b-8ktsFBpiR_ZzQ)
177 |
178 | ## 五、性能观测
179 | - [揭开 strace 命令捕获系统调用的神秘面纱](https://mp.weixin.qq.com/s/Iz4YPPmyjGrXVnZ8eSap2Q)
180 | - [人人都应该知道的CPU缓存运行效率](https://mp.weixin.qq.com/s/45QjjfkLrefWy2QjS_aDSw)
181 | - [剖析CPU性能火焰图生成的内部原理](https://mp.weixin.qq.com/s/A19RlLhSgbzw8UU4p1TZNA)
182 | - [盘点内核中常见的CPU性能卡点](https://mp.weixin.qq.com/s/moZjYijy2WcnGSTfv-nr9Q)
183 |
184 |
185 | ## 六、语言和框架
186 | - [深入剖析 Golang 程序启动原理 - 从 ELF 入口点到GMP初始化到执行 main!](https://mp.weixin.qq.com/s/0EZCmABsMEV3TFVmDZmzZA) (:cn:新)
187 | - [峰值 QPS 50 万 +,性能优异的网络框架开源力作 Sogou Workflow!](https://mp.weixin.qq.com/s/clILKrOO7_XJs6uHp5hoUw)
188 |
189 | ## 七、答读者问
190 | - [今天聊聊飞哥是怎么阅读内核源码的](https://mp.weixin.qq.com/s/-WA6J9BZeZJIQTZtDHD5hA)
191 | - [答读者问,飞哥能否给推荐几本硬核技术书?](https://mp.weixin.qq.com/s/OQyGEi0rvJRS0HJstaPWKQ)
192 | - [程序员完全没有时间提升自己该怎么办?](https://mp.weixin.qq.com/s/5f7x60bNCNK2a5nz8FL5yg)
193 | - [写给内功修炼读者的一封信!](https://mp.weixin.qq.com/s/Pzo46nZtSlsv_M6Tq7pv_A)
194 | - [我是怎么样写出开发内功修炼的?秘密都在这里!](https://mp.weixin.qq.com/s/rUWqVtoP3_f0M6ltN_1gqA)
195 | - [给想成长为高级别开发同学的七条建议](https://mp.weixin.qq.com/s/8lMGzBzXine-NAsqEaIE4g)
196 |
197 | ## 八、视频体系
198 | 目前应读者的诉求,我把我多年在系统领域积累的知识也整理成了一门成体系的视频课。在知识星球上更新。
199 | 内容总共分为如下几大块,覆盖了系统领域的各种硬核原理知识,也包含了能帮助已工作的同学提升性能优化能力。
200 | - 硬件原理 (已更新)
201 | - 内存管理 (已更新)
202 | - 进程管理 (已更新)
203 | - 网络管理 (已更新)
204 | - 容器原理 (正在更新中...)
205 | - 性能观测 (准备中)
206 | - 性能优化 (准备中)
207 |
208 | 其中已更新的部分如下图所示,累计 1859 分钟的内容。
209 |
210 | 
211 |
212 | 对这些视频内容感兴趣的同学可以通过下方二维码,或者在微信公众号「开发内功修炼」中回复「配套视频」观看。目前开放了 200 优惠券,优惠后是 299 一年。
213 |
214 | 
215 |
216 |
217 | ## 九、公众号二维码
218 |
219 | **敬请扫码关注微信公众号「开发内功修炼」,及时获得最新硬核文章!**
220 | 
221 |
222 | ---
223 | 为了方便大家阅读,本 Github 的网络篇核心内容整理成了 PDF 电子书,也即将出版。该书好评众多,欢迎大家下载! [**百度网盘地址**](https://pan.baidu.com/s/11u6z26xnRNlIOSQ4ohzNuA) 密码:q79d
224 |
225 | 如若网盘地址出问题,也可以通过微信(zhangyanfei748528)找飞哥,我直接发你!
--------------------------------------------------------------------------------
/imgs/book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/imgs/book.png
--------------------------------------------------------------------------------
/imgs/course.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/imgs/course.png
--------------------------------------------------------------------------------
/imgs/double.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/imgs/double.png
--------------------------------------------------------------------------------
/imgs/new_62_62.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/imgs/new_62_62.png
--------------------------------------------------------------------------------
/imgs/official_accounts.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/imgs/official_accounts.jpg
--------------------------------------------------------------------------------
/imgs/zsxq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/imgs/zsxq.png
--------------------------------------------------------------------------------
/tests/cpu/index.md:
--------------------------------------------------------------------------------
1 | - [likely 和 unlikely 汇编结果对比](tests/cpu/test01)
2 | - [物理机 cpu 系统利用率的计算过程](tests/cpu/test06)
3 | - [容器 cpu 系统利用率的计算过程](tests/cpu/test07)
4 | - [直接使用perf_event_open获取硬件计数](tests/cpu/test08)
5 | - [火焰图专用测试代码](tests/cpu/test09)
6 | - [C语言调用Golang函数原理](tests/cpu/test10)
7 | - [模拟 strace 命令捕获其它进程系统调用](tests/cpu/test11)
--------------------------------------------------------------------------------
/tests/cpu/test01/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: likely
2 | likely:
3 | gcc -O2 likely.c -o likely
4 | objdump -d -S likely > likely.txt
5 |
6 | .PHONY: unlikely
7 | unlikely:
8 | gcc -O2 unlikely.c -o unlikely
9 | objdump -d -S unlikely > unlikely.txt
10 |
11 |
--------------------------------------------------------------------------------
/tests/cpu/test01/likely.c:
--------------------------------------------------------------------------------
1 | # include
2 |
3 | #define likely(x) __builtin_expect(!!(x), 1)
4 | #define unlikely(x) __builtin_expect(!!(x), 0)
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | int n;
9 | n = atoi (argv[1]);
10 |
11 | if (likely(n == 10)){
12 | n = n + 2;
13 | } else {
14 | n = n - 2;
15 | }
16 | printf("%d\n", n);
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/tests/cpu/test01/unlikely.c:
--------------------------------------------------------------------------------
1 | # include
2 |
3 | #define likely(x) __builtin_expect(!!(x), 1)
4 | #define unlikely(x) __builtin_expect(!!(x), 0)
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | int n;
9 | n = atoi (argv[1]);
10 |
11 | if (unlikely(n == 10)){
12 | n = n + 2;
13 | } else {
14 | n = n - 2;
15 | }
16 | printf("%d\n", n);
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/tests/cpu/test02/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | int main()
6 | {
7 | char c;
8 | int in;
9 | int i;
10 |
11 | in = open("in.txt", O_RDONLY);
12 | for(i=0; i<100; i++){
13 | read(in,&c,1);
14 | }
15 | return 0;
16 | }
--------------------------------------------------------------------------------
/tests/cpu/test03/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include //pipe()
8 |
9 | int main()
10 | {
11 | int x, i, fd[2], p[2];
12 | char send = 's';
13 | char receive;
14 | pipe(fd);
15 | pipe(p);
16 | struct timeval tv;
17 | struct sched_param param;
18 | param.sched_priority = 0;
19 |
20 | while ((x = fork()) == -1);
21 | if (x==0) {
22 | sched_setscheduler(getpid(), SCHED_FIFO, ¶m);
23 | gettimeofday(&tv, NULL);
24 | printf("Before Context Switch Time%u s, %u us\n", tv.tv_sec, tv.tv_usec);
25 | for (i = 0; i < 10000; i++) {
26 | read(fd[0], &receive, 1);
27 | write(p[1], &send, 1);
28 | }
29 | exit(0);
30 | }
31 | else {
32 | sched_setscheduler(getpid(), SCHED_FIFO, ¶m);
33 | for (i = 0; i < 10000; i++) {
34 | write(fd[1], &send, 1);
35 | read(p[0], &receive, 1);
36 | }
37 | gettimeofday(&tv, NULL);
38 | printf("After Context SWitch Time%u s, %u us\n", tv.tv_sec, tv.tv_usec);
39 | }
40 | return 0;
41 | }
--------------------------------------------------------------------------------
/tests/cpu/test04/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | "runtime"
7 | )
8 |
9 | func cal() {
10 | for i :=0 ; i<1000000 ;i++{
11 | //fmt.Printf("call:%d\n",i)
12 | runtime.Gosched()
13 | }
14 | }
15 |
16 | func main() {
17 | runtime.GOMAXPROCS(1)
18 |
19 | currentTime:=time.Now()
20 | fmt.Println(currentTime)
21 |
22 | go cal()
23 | for i :=0 ; i<1000000 ;i++{
24 | //fmt.Printf("main:%d\n",i)
25 | runtime.Gosched()
26 | }
27 |
28 | currentTime=time.Now()
29 | fmt.Println(currentTime)
30 | }
31 |
--------------------------------------------------------------------------------
/tests/cpu/test05/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int pipes[20][3];
7 | char buffer[10];
8 | int running = 1;
9 |
10 | void inti()
11 | {
12 | int i =20;
13 | while(i--)
14 | {
15 | if(pipe(pipes[i])<0)
16 | exit(1);
17 | pipes[i][2] = i;
18 | }
19 | }
20 |
21 | void distroy()
22 | {
23 | int i =20;
24 | while(i--)
25 | {
26 | close(pipes[i][0]);
27 | close(pipes[i][1]);
28 | }
29 | }
30 |
31 | double self_test()
32 | {
33 | int i =20000;
34 | struct timeval start, end;
35 | gettimeofday(&start, NULL);
36 | while(i--)
37 | {
38 | if(write(pipes[0][1],buffer,10)==-1)
39 | exit(1);
40 | read(pipes[0][0],buffer,10);
41 | }
42 | gettimeofday(&end, NULL);
43 | return (double)(1000000*(end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec)/20000;
44 | }
45 |
46 | void *_test(void *arg)
47 | {
48 | int pos = ((int *)arg)[2];
49 | int in = pipes[pos][0];
50 | int to = pipes[(pos + 1)%20][1];
51 | while(running)
52 | {
53 | read(in,buffer,10);
54 | if(write(to,buffer,10)==-1)
55 | exit(1);
56 | }
57 | }
58 |
59 | double threading_test()
60 | {
61 | int i = 20;
62 | struct timeval start, end;
63 | pthread_t tid;
64 | while(--i)
65 | {
66 | pthread_create(&tid,NULL,_test,(void *)pipes[i]);
67 | }
68 | i = 10000;
69 | gettimeofday(&start, NULL);
70 | while(i--)
71 | {
72 | if(write(pipes[1][1],buffer,10)==-1)
73 | exit(1);
74 | read(pipes[0][0],buffer,10);
75 | }
76 | gettimeofday(&end, NULL);
77 | running = 0;
78 | if(write(pipes[1][1],buffer,10)==-1)
79 | exit(1);
80 | return (double)(1000000*(end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec)/10000/20;
81 | }
82 |
83 |
84 | int main()
85 | {
86 | inti();
87 | printf("%6.6f\n",self_test());
88 | printf("%6.6f\n",threading_test());
89 | distroy();
90 | exit(0);
91 | }
--------------------------------------------------------------------------------
/tests/cpu/test06/cpu_stat.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #获取宿主机的 CPU 使用情况
4 | function get_host_cpu_usage(){
5 | #内核会在/proc/stat中输出整机CPU的使用情况, 例如:cat /proc/stat 输出如下
6 | #cpu 52635657 657000 57094567 7675992570 422057 0 545206 0 0 0
7 | #其中各列中的数值都是从启动到现在的累计和,单位是jiffies
8 | #除了第一列外,其余每列的含义分别是:
9 | # 1.user:用户态花费的cpu时间
10 | # 2.nice:用户态在低优先级花费的cpu时间
11 | # 3.system:系统态花费的cpu时间
12 | # 4.idel:在空闲任务上花费的cpu时间
13 | # 5.iowait:等待I/O花费的cpu时间
14 | # 6.irq:硬中断花费的cpu时间
15 | # 7.softirq:软中断花费的cpu时间
16 | # 8.steal:系统处在虚拟化环境中,你的虚拟机被其他虚拟机占用的 CPU 时间
17 | # 9.guest:运行虚拟机花费的cpu时间
18 | # 10.guest_nice:运行低优先级虚拟机花费的cpu时间
19 |
20 | #获取宿主机的 CPU 用量的原理,是选择两个时间点,
21 | #cpu总时间=user+system+nice+idle+iowait+irq+softirq
22 | #cpu_usage=100-(idle2-idle1)/(cpu总时间2-cpu总时1)*100
23 |
24 | T1_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}')
25 | T1_IDLE=$(echo $T1_CPU_INFO | awk '{print $4}')
26 | T1_TOTAL=$(echo $T1_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}')
27 |
28 | sleep 10
29 |
30 | T2_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}')
31 | T2_IDLE=$(echo $T2_CPU_INFO | awk '{print $4}')
32 | T2_TOTAL=$(echo $T2_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}')
33 |
34 | CPU_UTILIZATION=`echo ${T1_IDLE} ${T1_TOTAL} ${T2_IDLE} ${T2_TOTAL}| awk '{printf "%.2f", (1-($3-$1)/($4-$2))*100}'`
35 | echo "Host CPU Utiliztion:${CPU_UTILIZATION}%"
36 | }
37 |
38 | get_host_cpu_usage
39 |
40 |
41 |
--------------------------------------------------------------------------------
/tests/cpu/test07/cpu_stat.sh:
--------------------------------------------------------------------------------
1 | cpu_stat.sh
--------------------------------------------------------------------------------
/tests/cpu/test08/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | // 封装perf_event_open系统调用
9 | int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
10 | {
11 | return syscall(__NR_perf_event_open, attr,pid, cpu, group_fd, flags);
12 | }
13 |
14 | int main()
15 | {
16 | // 第一步:创建perf文件描述符
17 | // 准备参数
18 | struct perf_event_attr attr;
19 | memset(&attr,0,sizeof(struct perf_event_attr));
20 | attr.size=sizeof(struct perf_event_attr);
21 | attr.type=PERF_TYPE_HARDWARE; // 监测硬件
22 | attr.config=PERF_COUNT_HW_INSTRUCTIONS; // 监测指令数
23 |
24 | // pid=0表示只检测当前进程
25 | // cpu=-1表示检测所有cpu核
26 | int fd=perf_event_open(&attr,0,-1,-1,0);
27 | if(fd<0)
28 | {
29 | perror("Cannot open perf fd!");
30 | return 1;
31 | }
32 |
33 | // 第二步:定时获取指标计数
34 | // 每隔1秒打印一次当前计数
35 | while(1)
36 | {
37 | uint64_t instructions;
38 | read(fd,&instructions,sizeof(instructions));
39 | printf("instructions=%ld\n",instructions);
40 | sleep(1);
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/tests/cpu/test09/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | void caculate(){
6 | for (i = 0; i < 10000000; i++) {
7 | }
8 | }
9 |
10 | void funcE(){
11 | caculate();
12 | }
13 |
14 | void funcD(){
15 | funcE();
16 | }
17 |
18 | void funcA(){
19 | funcD();
20 | }
21 |
22 | void funcB(){
23 | caculate();
24 | }
25 |
26 | void funcC(){
27 | caculate();
28 | }
29 |
30 | int main() {
31 | int i;
32 | for (i = 0; i < 100; i++) {
33 | if (i < 10) {
34 | funcA();
35 | } else if (i < 16) {
36 | funcB();
37 | } else {
38 | funcC();
39 | }
40 | }
41 |
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/tests/cpu/test10/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "libadd.h"
3 |
4 | int main(void)
5 | {
6 | int ret = add(2,3);
7 | printf("C调用Go函数2+3=%d", ret);
8 | return 0;
9 | }
--------------------------------------------------------------------------------
/tests/cpu/test10/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | //int add(int a, int b);
4 | import "C"
5 |
6 | //export add
7 | func add(a, b C.int) C.int {
8 | return a + b
9 | }
10 |
11 | func main() {
12 | }
13 |
--------------------------------------------------------------------------------
/tests/cpu/test11/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | void handle_syscall(pid_t pid) {
13 | long syscall_number;
14 | char *syscall_name = NULL;
15 |
16 | // 读取系统调用号
17 | syscall_number = ptrace(PTRACE_PEEKUSER, pid, 8 * ORIG_RAX, NULL); // 8 * ORIG_RAX 是 x86_64 架构下系统调用号的寄存器位置
18 |
19 | // 根据系统调用号获取系统调用名称
20 | switch (syscall_number) {
21 | case 5: syscall_name = "read"; break;
22 | case 6: syscall_name = "write"; break;
23 | case 10: syscall_name = "open"; break;
24 | case 11: syscall_name = "close"; break;
25 | // 添加更多系统调用号和名称的映射
26 | default: syscall_name = "unknown"; break;
27 | }
28 |
29 | printf("Syscall: %s (number: %ld)\n", syscall_name, syscall_number);
30 |
31 |
32 | }
33 |
34 | int main(int argc, char *argv[]) {
35 | if (argc != 2) {
36 | fprintf(stderr, "Usage: %s \n", argv[0]);
37 | exit(1);
38 | }
39 |
40 | pid_t pid = atoi(argv[1]);
41 |
42 | int status;
43 |
44 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
45 | perror("PTRACE_ATTACH");
46 | exit(1);
47 | }
48 |
49 | if (waitpid(pid, &status, 0) == -1) {
50 | perror("waitpid");
51 | exit(1);
52 | }
53 |
54 | if (!WIFSTOPPED(status)) {
55 | fprintf(stderr, "Process did not stop\n");
56 | exit(1);
57 | }
58 |
59 | printf("Attached to process %d\n", pid);
60 |
61 | while (1) {
62 | if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) == -1) {
63 | perror("PTRACE_SYSCALL");
64 | exit(1);
65 | }
66 |
67 | if (waitpid(pid, &status, 0) == -1) {
68 | perror("waitpid");
69 | exit(1);
70 | }
71 |
72 | if (WIFEXITED(status)) {
73 | printf("Process exited\n");
74 | break;
75 | }
76 |
77 | if (WIFSTOPPED(status)) {
78 | handle_syscall(pid);
79 | }
80 | }
81 |
82 | if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
83 | perror("PTRACE_DETACH");
84 | exit(1);
85 | }
86 |
87 | printf("Detached from process %d\n", pid);
88 |
89 | return 0;
90 | }
91 |
--------------------------------------------------------------------------------
/tests/disk/test01/randread.fio:
--------------------------------------------------------------------------------
1 | [global]
2 | ioengine=libaio
3 | direct=1
4 | filename=/search/odin/test.log
5 | size=100G
6 | ioscheduler=noop
7 | refill_buffers
8 | unified_rw_reporting=0
9 | time_based
10 | runtime=300
11 |
12 | [test-randrandread-512]
13 | ioengine=libaio
14 | rw=randread
15 | bs=512b
16 |
17 | [test-randread-1k]
18 | ioengine=libaio
19 | rw=randread
20 | bs=1k
21 |
22 | [test-randread-2k]
23 | ioengine=libaio
24 | rw=randread
25 | bs=2k
26 |
27 | [test-randread-4k]
28 | ioengine=libaio
29 | rw=randread
30 | bs=4k
31 |
32 | [test-randread-8k]
33 | ioengine=libaio
34 | rw=randread
35 | bs=8k
36 |
37 | [test-randread-16k]
38 | ioengine=libaio
39 | rw=randread
40 | bs=16k
41 |
42 | [test-randread-32k]
43 | ioengine=libaio
44 | rw=randread
45 | bs=32k
46 |
47 | [test-randread-64k]
48 | ioengine=libaio
49 | rw=randread
50 | bs=64k
51 |
52 | [test-randread-128k]
53 | ioengine=libaio
54 | rw=randread
55 | bs=128k
56 |
57 | [test-randread-256k]
58 | ioengine=libaio
59 | rw=randread
60 | bs=256k
61 |
62 | [test-randread-1m]
63 | ioengine=libaio
64 | rw=randread
65 | bs=1m
66 |
67 | [test-randread-2m]
68 | ioengine=libaio
69 | rw=randread
70 | bs=2m
71 |
72 | [test-randread-4m]
73 | ioengine=libaio
74 | rw=randread
75 | bs=4m
76 |
77 | [test-randread-8m]
78 | ioengine=libaio
79 | rw=randread
80 | bs=8m
81 |
82 | [test-randread-16m]
83 | ioengine=libaio
84 | rw=randread
85 | bs=16m
86 |
87 | [test-randread-32m]
88 | ioengine=libaio
89 | rw=randread
90 | bs=32m
91 |
92 |
--------------------------------------------------------------------------------
/tests/disk/test01/randread.php:
--------------------------------------------------------------------------------
1 | _out, "");
9 |
10 | $sections = $this->getSections($this->_in);
11 | foreach($sections as $sec){
12 | $fioResult = $this->runFioTest($sec);
13 | file_put_contents("data/".$sec, $fioResult);
14 | $res = $this->parseFioResult($fioResult);
15 |
16 | $line = $sec."\t".$res['bw']."\t".$res['lat']."\t".$res['iops']."\n";
17 | echo $line;
18 | file_put_contents($this->_out, $line, FILE_APPEND);
19 | sleep(60);
20 | }
21 | }
22 |
23 | public function parseFioResult($fioResult){
24 | $result = array();
25 | $fio = json_decode($fioResult, true);
26 | $result['iops'] = $fio["jobs"][0]['read']['iops_mean'];
27 | $result['bw'] = $fio["jobs"][0]['read']['bw_mean']; //kb
28 | $result['lat'] = $fio["jobs"][0]['read']["lat_ns"]['mean']; //ns
29 | return $result;
30 | }
31 |
32 | public function runFioTest($section){
33 | $cmd = "fio ".$this->_in." --section=".$section." --output-format=json";
34 | echo $cmd."\n";
35 | $result = shell_exec($cmd);
36 | return $result;
37 | }
38 |
39 | public function getSections($fioFile){
40 | $matches = array();
41 | $contents = file_get_contents($fioFile);
42 | $pattern = '/\[(.+)\]/';
43 | preg_match_all($pattern, $contents, $matches);
44 |
45 | $secs = array();
46 | foreach($matches[1] as $sec){
47 | if($sec=="global"){
48 | continue;
49 | }
50 | $secs[] = $sec;
51 | }
52 | return $secs;
53 | }
54 | }
55 |
56 | $test = new FioTest();
57 | $test->run();
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/tests/disk/test01/randwrite.fio:
--------------------------------------------------------------------------------
1 | [global]
2 | ioengine=libaio
3 | direct=1
4 | filename=/search/odin/test.log
5 | size=100G
6 | ioscheduler=noop
7 | refill_buffers
8 | unified_rw_reporting=0
9 | time_based
10 | runtime=300
11 |
12 | [test-randwrite-512]
13 | ioengine=libaio
14 | rw=randwrite
15 | bs=512b
16 |
17 | [test-randwrite-1k]
18 | ioengine=libaio
19 | rw=randwrite
20 | bs=1k
21 |
22 | [test-randwrite-2k]
23 | ioengine=libaio
24 | rw=randwrite
25 | bs=2k
26 |
27 | [test-randwrite-4k]
28 | ioengine=libaio
29 | rw=randwrite
30 | bs=4k
31 |
32 | [test-randwrite-8k]
33 | ioengine=libaio
34 | rw=randwrite
35 | bs=8k
36 |
37 | [test-randwrite-16k]
38 | ioengine=libaio
39 | rw=randwrite
40 | bs=16k
41 |
42 | [test-randwrite-32k]
43 | ioengine=libaio
44 | rw=randwrite
45 | bs=32k
46 |
47 | [test-randwrite-64k]
48 | ioengine=libaio
49 | rw=randwrite
50 | bs=64k
51 |
52 | [test-randwrite-128k]
53 | ioengine=libaio
54 | rw=randwrite
55 | bs=128k
56 |
57 | [test-randwrite-256k]
58 | ioengine=libaio
59 | rw=randwrite
60 | bs=256k
61 |
62 | [test-randwrite-512k]
63 | ioengine=libaio
64 | rw=randwrite
65 | bs=512k
66 |
67 | [test-randwrite-1m]
68 | ioengine=libaio
69 | rw=randwrite
70 | bs=1m
71 |
72 | [test-randwrite-2m]
73 | ioengine=libaio
74 | rw=randwrite
75 | bs=2m
76 |
77 | [test-randwrite-4m]
78 | ioengine=libaio
79 | rw=randwrite
80 | bs=4m
81 |
82 | [test-randwrite-8m]
83 | ioengine=libaio
84 | rw=randwrite
85 | bs=8m
86 |
87 | [test-randwrite-16m]
88 | ioengine=libaio
89 | rw=randwrite
90 | bs=16m
91 |
92 | [test-randwrite-32m]
93 | ioengine=libaio
94 | rw=randwrite
95 | bs=32m
96 |
--------------------------------------------------------------------------------
/tests/disk/test01/randwrite.php:
--------------------------------------------------------------------------------
1 | _out, "");
9 |
10 | $sections = $this->getSections($this->_in);
11 | foreach($sections as $sec){
12 | $fioResult = $this->runFioTest($sec);
13 | file_put_contents("data/".$sec, $fioResult);
14 | $res = $this->parseFioResult($fioResult);
15 |
16 | $line = $sec."\t".$res['bw']."\t".$res['lat']."\t".$res['iops']."\n";
17 | echo $line;
18 | file_put_contents($this->_out, $line, FILE_APPEND);
19 | sleep(60);
20 | }
21 | }
22 |
23 | public function parseFioResult($fioResult){
24 | $result = array();
25 | $fio = json_decode($fioResult, true);
26 | $result['iops'] = $fio["jobs"][0]['write']['iops_mean'];
27 | $result['bw'] = $fio["jobs"][0]['write']['bw_mean']; //kb
28 | $result['lat'] = $fio["jobs"][0]['write']["lat_ns"]['mean']; //ns
29 | return $result;
30 | }
31 |
32 | public function runFioTest($section){
33 | $cmd = "fio ".$this->_in." --section=".$section." --output-format=json";
34 | echo $cmd."\n";
35 | $result = shell_exec($cmd);
36 | return $result;
37 | }
38 |
39 | public function getSections($fioFile){
40 | $matches = array();
41 | $contents = file_get_contents($fioFile);
42 | $pattern = '/\[(.+)\]/';
43 | preg_match_all($pattern, $contents, $matches);
44 |
45 | $secs = array();
46 | foreach($matches[1] as $sec){
47 | if($sec=="global"){
48 | continue;
49 | }
50 | $secs[] = $sec;
51 | }
52 | return $secs;
53 | }
54 | }
55 |
56 | $test = new FioTest();
57 | $test->run();
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/tests/disk/test01/read.fio:
--------------------------------------------------------------------------------
1 | [global]
2 | ioengine=libaio
3 | direct=1
4 | filename=/search/odin/test.log
5 | size=100G
6 | ioscheduler=noop
7 | refill_buffers
8 | unified_rw_reporting=0
9 | time_based
10 | runtime=300
11 |
12 | [test-read-512]
13 | ioengine=libaio
14 | rw=read
15 | bs=512b
16 |
17 | [test-read-1k]
18 | ioengine=libaio
19 | rw=read
20 | bs=1k
21 |
22 | [test-read-2k]
23 | ioengine=libaio
24 | rw=read
25 | bs=2k
26 |
27 | [test-read-4k]
28 | ioengine=libaio
29 | rw=read
30 | bs=4k
31 |
32 | [test-read-8k]
33 | ioengine=libaio
34 | rw=read
35 | bs=8k
36 |
37 | [test-read-16k]
38 | ioengine=libaio
39 | rw=read
40 | bs=16k
41 |
42 | [test-read-32k]
43 | ioengine=libaio
44 | rw=read
45 | bs=32k
46 |
47 | [test-read-64k]
48 | ioengine=libaio
49 | rw=read
50 | bs=64k
51 |
52 | [test-read-128k]
53 | ioengine=libaio
54 | rw=read
55 | bs=128k
56 |
57 | [test-read-256k]
58 | ioengine=libaio
59 | rw=read
60 | bs=256k
61 |
62 | [test-read-1m]
63 | ioengine=libaio
64 | rw=read
65 | bs=1m
66 |
67 | [test-read-2m]
68 | ioengine=libaio
69 | rw=read
70 | bs=2m
71 |
72 | [test-read-4m]
73 | ioengine=libaio
74 | rw=read
75 | bs=4m
76 |
77 | [test-read-8m]
78 | ioengine=libaio
79 | rw=read
80 | bs=8m
81 |
82 | [test-read-16m]
83 | ioengine=libaio
84 | rw=read
85 | bs=16m
86 |
87 | [test-read-32m]
88 | ioengine=libaio
89 | rw=read
90 | bs=32m
91 |
92 |
--------------------------------------------------------------------------------
/tests/disk/test01/read.php:
--------------------------------------------------------------------------------
1 | _out, "");
9 |
10 | $sections = $this->getSections($this->_in);
11 | foreach($sections as $sec){
12 | $fioResult = $this->runFioTest($sec);
13 | file_put_contents("data/".$sec, $fioResult);
14 | $res = $this->parseFioResult($fioResult);
15 |
16 | $line = $sec."\t".$res['bw']."\t".$res['lat']."\t".$res['iops']."\n";
17 | echo $line;
18 | file_put_contents($this->_out, $line, FILE_APPEND);
19 | sleep(60);
20 | }
21 | }
22 |
23 | public function parseFioResult($fioResult){
24 | $result = array();
25 | $fio = json_decode($fioResult, true);
26 | $result['iops'] = $fio["jobs"][0]['read']['iops_mean'];
27 | $result['bw'] = $fio["jobs"][0]['read']['bw_mean']; //kb
28 | $result['lat'] = $fio["jobs"][0]['read']["lat_ns"]['mean']; //ns
29 | return $result;
30 | }
31 |
32 | public function runFioTest($section){
33 | $cmd = "fio ".$this->_in." --section=".$section." --output-format=json";
34 | echo $cmd."\n";
35 | $result = shell_exec($cmd);
36 | return $result;
37 | }
38 |
39 | public function getSections($fioFile){
40 | $matches = array();
41 | $contents = file_get_contents($fioFile);
42 | $pattern = '/\[(.+)\]/';
43 | preg_match_all($pattern, $contents, $matches);
44 |
45 | $secs = array();
46 | foreach($matches[1] as $sec){
47 | if($sec=="global"){
48 | continue;
49 | }
50 | $secs[] = $sec;
51 | }
52 | return $secs;
53 | }
54 | }
55 |
56 | $test = new FioTest();
57 | $test->run();
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/tests/disk/test01/write.fio:
--------------------------------------------------------------------------------
1 | [global]
2 | ioengine=libaio
3 | direct=1
4 | filename=/search/odin/test.log
5 | size=100G
6 | ioscheduler=noop
7 | refill_buffers
8 | unified_rw_reporting=0
9 | time_based
10 | runtime=300
11 |
12 | [test-write-512]
13 | ioengine=libaio
14 | rw=write
15 | bs=512b
16 |
17 | [test-write-1k]
18 | ioengine=libaio
19 | rw=write
20 | bs=1k
21 |
22 | [test-write-2k]
23 | ioengine=libaio
24 | rw=write
25 | bs=2k
26 |
27 | [test-write-4k]
28 | ioengine=libaio
29 | rw=write
30 | bs=4k
31 |
32 | [test-write-8k]
33 | ioengine=libaio
34 | rw=write
35 | bs=8k
36 |
37 | [test-write-16k]
38 | ioengine=libaio
39 | rw=write
40 | bs=16k
41 |
42 | [test-write-32k]
43 | ioengine=libaio
44 | rw=write
45 | bs=32k
46 |
47 | [test-write-64k]
48 | ioengine=libaio
49 | rw=write
50 | bs=64k
51 |
52 | [test-write-128k]
53 | ioengine=libaio
54 | rw=write
55 | bs=128k
56 |
57 | [test-write-256k]
58 | ioengine=libaio
59 | rw=write
60 | bs=256k
61 |
62 | [test-write-512k]
63 | ioengine=libaio
64 | rw=write
65 | bs=512k
66 |
67 | [test-write-1m]
68 | ioengine=libaio
69 | rw=write
70 | bs=1m
71 |
72 | [test-write-2m]
73 | ioengine=libaio
74 | rw=write
75 | bs=2m
76 |
77 | [test-write-4m]
78 | ioengine=libaio
79 | rw=write
80 | bs=4m
81 |
82 | [test-write-8m]
83 | ioengine=libaio
84 | rw=write
85 | bs=8m
86 |
87 | [test-write-16m]
88 | ioengine=libaio
89 | rw=write
90 | bs=16m
91 |
92 | [test-write-32m]
93 | ioengine=libaio
94 | rw=write
95 | bs=32m
96 |
--------------------------------------------------------------------------------
/tests/disk/test01/write.php:
--------------------------------------------------------------------------------
1 | _out, "");
9 |
10 | $sections = $this->getSections($this->_in);
11 | foreach($sections as $sec){
12 | $fioResult = $this->runFioTest($sec);
13 | file_put_contents("data/".$sec, $fioResult);
14 | $res = $this->parseFioResult($fioResult);
15 |
16 | $line = $sec."\t".$res['bw']."\t".$res['lat']."\t".$res['iops']."\n";
17 | echo $line;
18 | file_put_contents($this->_out, $line, FILE_APPEND);
19 | sleep(60);
20 | }
21 | }
22 |
23 | public function parseFioResult($fioResult){
24 | $result = array();
25 | $fio = json_decode($fioResult, true);
26 | $result['iops'] = $fio["jobs"][0]['write']['iops_mean'];
27 | $result['bw'] = $fio["jobs"][0]['write']['bw_mean']; //kb
28 | $result['lat'] = $fio["jobs"][0]['write']["lat_ns"]['mean']; //ns
29 | return $result;
30 | }
31 |
32 | public function runFioTest($section){
33 | $cmd = "fio ".$this->_in." --section=".$section." --output-format=json";
34 | echo $cmd."\n";
35 | $result = shell_exec($cmd);
36 | return $result;
37 | }
38 |
39 | public function getSections($fioFile){
40 | $matches = array();
41 | $contents = file_get_contents($fioFile);
42 | $pattern = '/\[(.+)\]/';
43 | preg_match_all($pattern, $contents, $matches);
44 |
45 | $secs = array();
46 | foreach($matches[1] as $sec){
47 | if($sec=="global"){
48 | continue;
49 | }
50 | $secs[] = $sec;
51 | }
52 | return $secs;
53 | }
54 | }
55 |
56 | $test = new FioTest();
57 | $test->run();
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/tests/ebpf/test01/hello.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "hello_kprobe.skel.h"
5 |
6 | static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) {
7 | return vfprintf(stderr, format, args);
8 | }
9 |
10 | int main(int argc, char **argv) {
11 | struct hello_kprobe_bpf *skel;
12 | int err;
13 |
14 | // 设置 libbpf 的日志输出函数
15 | libbpf_set_print(libbpf_print_fn);
16 |
17 | // 打开并加载 eBPF 对象
18 | skel = hello_kprobe_bpf__open();
19 | if (!skel) {
20 | fprintf(stderr, "Failed to open BPF skeleton\n");
21 | return 1;
22 | }
23 |
24 | // 加载 eBPF 对象
25 | err = hello_kprobe_bpf__load(skel);
26 | if (err) {
27 | fprintf(stderr, "Failed to load BPF skeleton: %d\n", err);
28 | goto cleanup;
29 | }
30 |
31 | // 附加 kprobe
32 | err = hello_kprobe_bpf__attach(skel);
33 | if (err) {
34 | fprintf(stderr, "Failed to attach BPF skeleton: %d\n", err);
35 | goto cleanup;
36 | }
37 |
38 | printf("Kprobe attached successfully. Press Ctrl+C to exit.\n");
39 |
40 | // 保持程序运行,直到用户中断
41 | while (1) {
42 | sleep(1);
43 | }
44 |
45 | cleanup:
46 | // 清理资源
47 | hello_kprobe_bpf__destroy(skel);
48 | return err < 0 ? -err : 0;
49 | }
--------------------------------------------------------------------------------
/tests/ebpf/test01/hello_kprobe.bpf.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | // 定义一个打印信息的函数
5 | SEC("kprobe/handle_mm_fault")
6 | int bpf_probe_handle_mm_fault() {
7 | // 打印一条消息到内核调试日志
8 | bpf_printk("Hello, World from kprobe!\n");
9 | return 0;
10 | }
11 |
12 | char _license[] SEC("license") = "GPL";
13 |
--------------------------------------------------------------------------------
/tests/ebpf/test01/hello_kprobe.skel.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | /* THIS FILE IS AUTOGENERATED! */
4 | #ifndef __HELLO_KPROBE_BPF_SKEL_H__
5 | #define __HELLO_KPROBE_BPF_SKEL_H__
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | struct hello_kprobe_bpf {
12 | struct bpf_object_skeleton *skeleton;
13 | struct bpf_object *obj;
14 | struct {
15 | struct bpf_map *rodata;
16 | } maps;
17 | struct {
18 | struct bpf_program *bpf_probe_handle_mm_fault;
19 | } progs;
20 | struct {
21 | struct bpf_link *bpf_probe_handle_mm_fault;
22 | } links;
23 | struct hello_kprobe_bpf__rodata {
24 | } *rodata;
25 | };
26 |
27 | static void
28 | hello_kprobe_bpf__destroy(struct hello_kprobe_bpf *obj)
29 | {
30 | if (!obj)
31 | return;
32 | if (obj->skeleton)
33 | bpf_object__destroy_skeleton(obj->skeleton);
34 | free(obj);
35 | }
36 |
37 | static inline int
38 | hello_kprobe_bpf__create_skeleton(struct hello_kprobe_bpf *obj);
39 |
40 | static inline struct hello_kprobe_bpf *
41 | hello_kprobe_bpf__open_opts(const struct bpf_object_open_opts *opts)
42 | {
43 | struct hello_kprobe_bpf *obj;
44 | int err;
45 |
46 | obj = (struct hello_kprobe_bpf *)calloc(1, sizeof(*obj));
47 | if (!obj) {
48 | errno = ENOMEM;
49 | return NULL;
50 | }
51 |
52 | err = hello_kprobe_bpf__create_skeleton(obj);
53 | err = err ?: bpf_object__open_skeleton(obj->skeleton, opts);
54 | if (err)
55 | goto err_out;
56 |
57 | return obj;
58 | err_out:
59 | hello_kprobe_bpf__destroy(obj);
60 | errno = -err;
61 | return NULL;
62 | }
63 |
64 | static inline struct hello_kprobe_bpf *
65 | hello_kprobe_bpf__open(void)
66 | {
67 | return hello_kprobe_bpf__open_opts(NULL);
68 | }
69 |
70 | static inline int
71 | hello_kprobe_bpf__load(struct hello_kprobe_bpf *obj)
72 | {
73 | return bpf_object__load_skeleton(obj->skeleton);
74 | }
75 |
76 | static inline struct hello_kprobe_bpf *
77 | hello_kprobe_bpf__open_and_load(void)
78 | {
79 | struct hello_kprobe_bpf *obj;
80 | int err;
81 |
82 | obj = hello_kprobe_bpf__open();
83 | if (!obj)
84 | return NULL;
85 | err = hello_kprobe_bpf__load(obj);
86 | if (err) {
87 | hello_kprobe_bpf__destroy(obj);
88 | errno = -err;
89 | return NULL;
90 | }
91 | return obj;
92 | }
93 |
94 | static inline int
95 | hello_kprobe_bpf__attach(struct hello_kprobe_bpf *obj)
96 | {
97 | return bpf_object__attach_skeleton(obj->skeleton);
98 | }
99 |
100 | static inline void
101 | hello_kprobe_bpf__detach(struct hello_kprobe_bpf *obj)
102 | {
103 | return bpf_object__detach_skeleton(obj->skeleton);
104 | }
105 |
106 | static inline int
107 | hello_kprobe_bpf__create_skeleton(struct hello_kprobe_bpf *obj)
108 | {
109 | struct bpf_object_skeleton *s;
110 |
111 | s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));
112 | if (!s)
113 | goto err;
114 |
115 | s->sz = sizeof(*s);
116 | s->name = "hello_kprobe_bpf";
117 | s->obj = &obj->obj;
118 |
119 | /* maps */
120 | s->map_cnt = 1;
121 | s->map_skel_sz = sizeof(*s->maps);
122 | s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);
123 | if (!s->maps)
124 | goto err;
125 |
126 | s->maps[0].name = "hello_kp.rodata";
127 | s->maps[0].map = &obj->maps.rodata;
128 | s->maps[0].mmaped = (void **)&obj->rodata;
129 |
130 | /* programs */
131 | s->prog_cnt = 1;
132 | s->prog_skel_sz = sizeof(*s->progs);
133 | s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
134 | if (!s->progs)
135 | goto err;
136 |
137 | s->progs[0].name = "bpf_probe_handle_mm_fault";
138 | s->progs[0].prog = &obj->progs.bpf_probe_handle_mm_fault;
139 | s->progs[0].link = &obj->links.bpf_probe_handle_mm_fault;
140 |
141 | s->data_sz = 4200;
142 | s->data = (void *)"\
143 | \x7f\x45\x4c\x46\x02\x01\x01\0\0\0\0\0\0\0\0\0\x01\0\xf7\0\x01\0\0\0\0\0\0\0\0\
144 | \0\0\0\0\0\0\0\0\0\0\0\x28\x0b\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x15\0\
145 | \x01\0\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb7\x02\0\0\x1b\0\0\0\x85\0\0\0\x06\
146 | \0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\
147 | \x72\x6c\x64\x20\x66\x72\x6f\x6d\x20\x6b\x70\x72\x6f\x62\x65\x21\x0a\0\x47\x50\
148 | \x4c\0\x01\x11\x01\x25\x0e\x13\x05\x03\x0e\x10\x17\x1b\x0e\x11\x01\x12\x06\0\0\
149 | \x02\x2e\x01\x11\x01\x12\x06\x40\x18\x97\x42\x19\x03\x0e\x3a\x0b\x3b\x0b\x49\
150 | \x13\x3f\x19\0\0\x03\x34\0\x03\x0e\x49\x13\x3a\x0b\x3b\x0b\x02\x18\0\0\x04\x01\
151 | \x01\x49\x13\0\0\x05\x21\0\x49\x13\x37\x0b\0\0\x06\x26\0\x49\x13\0\0\x07\x24\0\
152 | \x03\x0e\x3e\x0b\x0b\x0b\0\0\x08\x24\0\x03\x0e\x0b\x0b\x3e\x0b\0\0\x09\x34\0\
153 | \x03\x0e\x49\x13\x3a\x0b\x3b\x0b\0\0\x0a\x0f\0\x49\x13\0\0\x0b\x15\x01\x49\x13\
154 | \x27\x19\0\0\x0c\x05\0\x49\x13\0\0\x0d\x18\0\0\0\x0e\x16\0\x49\x13\x03\x0e\x3a\
155 | \x0b\x3b\x0b\0\0\x0f\x34\0\x03\x0e\x49\x13\x3f\x19\x3a\x0b\x3b\x0b\x02\x18\0\0\
156 | \0\xe1\0\0\0\x04\0\0\0\0\0\x08\x01\0\0\0\0\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
157 | \0\0\0\0\0\x30\0\0\0\x02\0\0\0\0\0\0\0\0\x30\0\0\0\x01\x5a\0\0\0\0\x01\x06\xdd\
158 | \0\0\0\x03\0\0\0\0\x59\0\0\0\x01\x08\x09\x03\0\0\0\0\0\0\0\0\0\x04\x65\0\0\0\
159 | \x05\x71\0\0\0\x1b\0\x06\x6a\0\0\0\x07\0\0\0\0\x06\x01\x08\0\0\0\0\x08\x07\x09\
160 | \0\0\0\0\x83\0\0\0\x03\xb9\x06\x88\0\0\0\x0a\x8d\0\0\0\x0b\x9e\0\0\0\x0c\xa5\0\
161 | \0\0\x0c\xaa\0\0\0\x0d\0\x07\0\0\0\0\x05\x08\x0a\x65\0\0\0\x0e\xb5\0\0\0\0\0\0\
162 | \0\x02\x1b\x07\0\0\0\0\x07\x04\x0f\0\0\0\0\xd1\0\0\0\x01\x0c\x09\x03\0\0\0\0\0\
163 | \0\0\0\x04\x6a\0\0\0\x05\x71\0\0\0\x04\0\x07\0\0\0\0\x05\x04\0\x44\x65\x62\x69\
164 | \x61\x6e\x20\x63\x6c\x61\x6e\x67\x20\x76\x65\x72\x73\x69\x6f\x6e\x20\x31\x31\
165 | \x2e\x30\x2e\x31\x2d\x32\x7e\x64\x65\x62\x31\x30\x75\x31\0\x68\x65\x6c\x6c\x6f\
166 | \x5f\x6b\x70\x72\x6f\x62\x65\x2e\x62\x70\x66\x2e\x63\0\x2f\x68\x6f\x6d\x65\x2f\
167 | \x7a\x68\x61\x6e\x67\x79\x61\x6e\x66\x65\x69\x2e\x61\x6c\x6c\x65\x6e\x2f\x77\
168 | \x6f\x72\x6b\x5f\x6d\x79\x2f\x70\x65\x72\x66\x6f\x72\x6d\x61\x6e\x63\x65\x2f\
169 | \x74\x65\x73\x74\x73\x2f\x65\x62\x70\x66\x2f\x74\x6f\x70\x69\x63\x30\x30\x37\0\
170 | \x5f\x5f\x5f\x5f\x66\x6d\x74\0\x63\x68\x61\x72\0\x5f\x5f\x41\x52\x52\x41\x59\
171 | \x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x62\x70\x66\x5f\x74\x72\x61\
172 | \x63\x65\x5f\x70\x72\x69\x6e\x74\x6b\0\x6c\x6f\x6e\x67\x20\x69\x6e\x74\0\x75\
173 | \x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\0\x5f\x5f\x75\x33\x32\0\x5f\x6c\
174 | \x69\x63\x65\x6e\x73\x65\0\x62\x70\x66\x5f\x70\x72\x6f\x62\x65\x5f\x68\x61\x6e\
175 | \x64\x6c\x65\x5f\x6d\x6d\x5f\x66\x61\x75\x6c\x74\0\x69\x6e\x74\0\x9f\xeb\x01\0\
176 | \x18\0\0\0\0\0\0\0\xd4\0\0\0\xd4\0\0\0\x1a\x01\0\0\0\0\0\0\0\0\0\x0d\x02\0\0\0\
177 | \x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\x05\0\0\0\x01\0\0\x0c\x01\0\0\0\0\0\
178 | \0\0\0\0\0\x0a\x05\0\0\0\xc6\0\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\0\
179 | \0\x03\0\0\0\0\x04\0\0\0\x07\0\0\0\x1b\0\0\0\xcb\0\0\0\0\0\0\x01\x04\0\0\0\x20\
180 | \0\0\0\xdf\0\0\0\0\0\0\x0e\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x05\0\0\
181 | \0\x07\0\0\0\x04\0\0\0\x01\x01\0\0\0\0\0\x0e\x09\0\0\0\x01\0\0\0\x0a\x01\0\0\
182 | \x01\0\0\x0f\0\0\0\0\x08\0\0\0\0\0\0\0\x1b\0\0\0\x12\x01\0\0\x01\0\0\x0f\0\0\0\
183 | \0\x0a\0\0\0\0\0\0\0\x04\0\0\0\0\x69\x6e\x74\0\x62\x70\x66\x5f\x70\x72\x6f\x62\
184 | \x65\x5f\x68\x61\x6e\x64\x6c\x65\x5f\x6d\x6d\x5f\x66\x61\x75\x6c\x74\0\x6b\x70\
185 | \x72\x6f\x62\x65\x2f\x68\x61\x6e\x64\x6c\x65\x5f\x6d\x6d\x5f\x66\x61\x75\x6c\
186 | \x74\0\x2f\x68\x6f\x6d\x65\x2f\x7a\x68\x61\x6e\x67\x79\x61\x6e\x66\x65\x69\x2e\
187 | \x61\x6c\x6c\x65\x6e\x2f\x77\x6f\x72\x6b\x5f\x6d\x79\x2f\x70\x65\x72\x66\x6f\
188 | \x72\x6d\x61\x6e\x63\x65\x2f\x74\x65\x73\x74\x73\x2f\x65\x62\x70\x66\x2f\x74\
189 | \x6f\x70\x69\x63\x30\x30\x37\x2f\x68\x65\x6c\x6c\x6f\x5f\x6b\x70\x72\x6f\x62\
190 | \x65\x2e\x62\x70\x66\x2e\x63\0\x20\x20\x20\x20\x62\x70\x66\x5f\x70\x72\x69\x6e\
191 | \x74\x6b\x28\x22\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x20\x66\x72\
192 | \x6f\x6d\x20\x6b\x70\x72\x6f\x62\x65\x21\x5c\x6e\x22\x29\x3b\0\x20\x20\x20\x20\
193 | \x72\x65\x74\x75\x72\x6e\x20\x30\x3b\0\x63\x68\x61\x72\0\x5f\x5f\x41\x52\x52\
194 | \x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x62\x70\x66\x5f\x70\
195 | \x72\x6f\x62\x65\x5f\x68\x61\x6e\x64\x6c\x65\x5f\x6d\x6d\x5f\x66\x61\x75\x6c\
196 | \x74\x2e\x5f\x5f\x5f\x5f\x66\x6d\x74\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\x2e\
197 | \x72\x6f\x64\x61\x74\x61\0\x6c\x69\x63\x65\x6e\x73\x65\0\x9f\xeb\x01\0\x20\0\0\
198 | \0\0\0\0\0\x14\0\0\0\x14\0\0\0\x2c\0\0\0\x40\0\0\0\0\0\0\0\x08\0\0\0\x1f\0\0\0\
199 | \x01\0\0\0\0\0\0\0\x03\0\0\0\x10\0\0\0\x1f\0\0\0\x02\0\0\0\0\0\0\0\x36\0\0\0\
200 | \x89\0\0\0\x05\x20\0\0\x20\0\0\0\x36\0\0\0\xb8\0\0\0\x05\x24\0\0\0\x0c\0\0\0\
201 | \xff\xff\xff\xff\x04\0\x08\0\x08\x7c\x0b\0\x14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
202 | \x30\0\0\0\0\0\0\0\x93\0\0\0\x04\0\x77\0\0\0\x08\x01\x01\xfb\x0e\x0d\0\x01\x01\
203 | \x01\x01\0\0\0\x01\0\0\x01\x2f\x75\x73\x72\x2f\x69\x6e\x63\x6c\x75\x64\x65\x2f\
204 | \x61\x73\x6d\x2d\x67\x65\x6e\x65\x72\x69\x63\0\x2f\x75\x73\x72\x2f\x69\x6e\x63\
205 | \x6c\x75\x64\x65\x2f\x62\x70\x66\0\0\x68\x65\x6c\x6c\x6f\x5f\x6b\x70\x72\x6f\
206 | \x62\x65\x2e\x62\x70\x66\x2e\x63\0\0\0\0\x69\x6e\x74\x2d\x6c\x6c\x36\x34\x2e\
207 | \x68\0\x01\0\0\x62\x70\x66\x5f\x68\x65\x6c\x70\x65\x72\x5f\x64\x65\x66\x73\x2e\
208 | \x68\0\x02\0\0\0\0\x09\x02\0\0\0\0\0\0\0\0\x17\x05\x05\x0a\x14\x4b\x02\x02\0\
209 | \x01\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xcc\0\0\0\x04\0\xf1\
210 | \xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\
211 | \0\0\0\0\0\0\0\0\0\0\x0a\0\x26\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\
212 | \x39\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\xd0\0\0\0\0\0\0\0\0\0\0\0\
213 | \0\0\0\0\0\0\0\0\0\0\x0a\0\x79\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\
214 | \x81\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\x86\0\0\0\0\0\0\0\0\0\0\0\
215 | \0\0\0\0\0\0\0\0\0\0\x0a\0\x9a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\
216 | \xab\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\xc1\0\0\0\0\0\0\0\0\0\0\0\
217 | \0\0\0\0\0\0\0\0\0\0\x0a\0\xb4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\
218 | \xc7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\0\xea\0\0\0\0\0\0\0\0\0\0\0\
219 | \0\0\0\0\x22\0\0\0\x01\0\x05\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\x03\0\
220 | \x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x05\0\0\0\0\0\0\0\0\0\0\0\
221 | \0\0\0\0\0\0\0\0\0\0\x03\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\
222 | \x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x11\0\0\0\0\0\0\0\0\0\0\0\
223 | \0\0\0\0\0\0\xa2\0\0\0\x11\0\x06\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\x44\0\0\0\
224 | \x12\0\x03\0\0\0\0\0\0\0\0\0\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x11\0\
225 | \0\0\x06\0\0\0\0\0\0\0\x0a\0\0\0\x12\0\0\0\x0c\0\0\0\0\0\0\0\x0a\0\0\0\x02\0\0\
226 | \0\x12\0\0\0\0\0\0\0\x0a\0\0\0\x03\0\0\0\x16\0\0\0\0\0\0\0\x0a\0\0\0\x14\0\0\0\
227 | \x1a\0\0\0\0\0\0\0\x0a\0\0\0\x04\0\0\0\x1e\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\
228 | \x2b\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\x39\0\0\0\0\0\0\0\x0a\0\0\0\x05\0\0\0\
229 | \x44\0\0\0\0\0\0\0\x0a\0\0\0\x06\0\0\0\x50\0\0\0\0\0\0\0\x01\0\0\0\x11\0\0\0\
230 | \x6b\0\0\0\0\0\0\0\x0a\0\0\0\x07\0\0\0\x72\0\0\0\0\0\0\0\x0a\0\0\0\x08\0\0\0\
231 | \x79\0\0\0\0\0\0\0\x0a\0\0\0\x09\0\0\0\x9f\0\0\0\0\0\0\0\x0a\0\0\0\x0a\0\0\0\
232 | \xaf\0\0\0\0\0\0\0\x0a\0\0\0\x0b\0\0\0\xb6\0\0\0\0\0\0\0\x0a\0\0\0\x0c\0\0\0\
233 | \xbd\0\0\0\0\0\0\0\x0a\0\0\0\x0d\0\0\0\xc9\0\0\0\0\0\0\0\x01\0\0\0\x15\0\0\0\
234 | \xde\0\0\0\0\0\0\0\x0a\0\0\0\x0e\0\0\0\xcc\0\0\0\0\0\0\0\x0a\0\0\0\x11\0\0\0\
235 | \xe4\0\0\0\0\0\0\0\0\0\0\0\x15\0\0\0\x2c\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x40\0\
236 | \0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x50\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x14\0\0\0\0\
237 | \0\0\0\x0a\0\0\0\x13\0\0\0\x18\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\x84\0\0\0\0\0\
238 | \0\0\x01\0\0\0\x10\0\0\0\x16\x0f\x15\0\x2e\x64\x65\x62\x75\x67\x5f\x61\x62\x62\
239 | \x72\x65\x76\0\x2e\x74\x65\x78\x74\0\x2e\x72\x65\x6c\x2e\x42\x54\x46\x2e\x65\
240 | \x78\x74\0\x62\x70\x66\x5f\x70\x72\x6f\x62\x65\x5f\x68\x61\x6e\x64\x6c\x65\x5f\
241 | \x6d\x6d\x5f\x66\x61\x75\x6c\x74\x2e\x5f\x5f\x5f\x5f\x66\x6d\x74\0\x62\x70\x66\
242 | \x5f\x70\x72\x6f\x62\x65\x5f\x68\x61\x6e\x64\x6c\x65\x5f\x6d\x6d\x5f\x66\x61\
243 | \x75\x6c\x74\0\x2e\x72\x65\x6c\x6b\x70\x72\x6f\x62\x65\x2f\x68\x61\x6e\x64\x6c\
244 | \x65\x5f\x6d\x6d\x5f\x66\x61\x75\x6c\x74\0\x2e\x64\x65\x62\x75\x67\x5f\x73\x74\
245 | \x72\0\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x69\x6e\x66\x6f\0\x2e\x6c\
246 | \x6c\x76\x6d\x5f\x61\x64\x64\x72\x73\x69\x67\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\
247 | \0\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x6c\x69\x6e\x65\0\x2e\x72\x65\
248 | \x6c\x2e\x64\x65\x62\x75\x67\x5f\x66\x72\x61\x6d\x65\0\x68\x65\x6c\x6c\x6f\x5f\
249 | \x6b\x70\x72\x6f\x62\x65\x2e\x62\x70\x66\x2e\x63\0\x2e\x73\x74\x72\x74\x61\x62\
250 | \0\x2e\x73\x79\x6d\x74\x61\x62\0\x2e\x72\x6f\x64\x61\x74\x61\0\x2e\x72\x65\x6c\
251 | \x2e\x42\x54\x46\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
252 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
253 | \xdf\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x23\x0a\0\0\0\0\0\0\0\x01\
254 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0f\0\0\0\x01\0\
255 | \0\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
256 | \0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x62\0\0\0\x01\0\0\0\x06\0\0\0\0\0\
257 | \0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\
258 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5e\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
259 | \0\x60\x08\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x14\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\
260 | \x10\0\0\0\0\0\0\0\xef\0\0\0\x01\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x70\0\
261 | \0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
262 | \0\xa3\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8b\0\0\0\0\0\0\0\x04\
263 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x01\
264 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8f\0\0\0\0\0\0\0\xaf\0\0\0\0\0\0\0\0\0\
265 | \0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\0\0\0\x01\0\0\0\0\0\0\0\0\0\
266 | \0\0\0\0\0\0\0\0\0\0\x3e\x01\0\0\0\0\0\0\xe5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\
267 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
268 | \0\0\x70\x08\0\0\0\0\0\0\x30\x01\0\0\0\0\0\0\x14\0\0\0\x08\0\0\0\x08\0\0\0\0\0\
269 | \0\0\x10\0\0\0\0\0\0\0\x79\0\0\0\x01\0\0\0\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
270 | \x23\x02\0\0\0\0\0\0\xee\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x01\0\
271 | \0\0\0\0\0\0\xfb\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x11\x03\0\0\0\
272 | \0\0\0\x06\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
273 | \xf7\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x09\0\0\0\0\0\0\x20\0\
274 | \0\0\0\0\0\0\x14\0\0\0\x0b\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x19\0\0\0\
275 | \x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x05\0\0\0\0\0\0\x60\0\0\0\0\0\0\
276 | \0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x15\0\0\0\x09\0\0\0\0\0\0\
277 | \0\0\0\0\0\0\0\0\0\0\0\0\0\xc0\x09\0\0\0\0\0\0\x30\0\0\0\0\0\0\0\x14\0\0\0\x0d\
278 | \0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\xbf\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\
279 | \0\0\0\0\0\0\0\0\x78\x05\0\0\0\0\0\0\x28\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\
280 | \0\0\0\0\0\0\0\0\0\0\0\0\0\xbb\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
281 | \xf0\x09\0\0\0\0\0\0\x20\0\0\0\0\0\0\0\x14\0\0\0\x0f\0\0\0\x08\0\0\0\0\0\0\0\
282 | \x10\0\0\0\0\0\0\0\xaf\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x05\
283 | \0\0\0\0\0\0\x97\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
284 | \0\xab\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\x0a\0\0\0\0\0\0\x10\
285 | \0\0\0\0\0\0\0\x14\0\0\0\x11\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x94\0\0\
286 | \0\x03\x4c\xff\x6f\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\x20\x0a\0\0\0\0\0\0\x03\0\
287 | \0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe7\0\0\0\x02\
288 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x38\x06\0\0\0\0\0\0\x28\x02\0\0\0\0\0\0\
289 | \x01\0\0\0\x15\0\0\0\x08\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0";
290 |
291 | obj->skeleton = s;
292 | return 0;
293 | err:
294 | bpf_object__destroy_skeleton(s);
295 | return -ENOMEM;
296 | }
297 |
298 | #endif /* __HELLO_KPROBE_BPF_SKEL_H__ */
299 |
--------------------------------------------------------------------------------
/tests/ebpf/test01/index.md:
--------------------------------------------------------------------------------
1 | ## 环境准备
2 |
3 | 安装 clang 10 以上,我安装的是 clang-11
4 |
5 | ```sh
6 | sudo apt install clang-11
7 | ```
8 |
9 | 安装 libbpf
10 | ```c
11 | git clone https://github.com/libbpf/libbpf
12 | cd libbpf/src
13 | make
14 | make install
15 | INSTALL bpf.h libbpf.h btf.h libbpf_common.h libbpf_legacy.h bpf_helpers.h bpf_helper_defs.h bpf_tracing.h bpf_endian.h bpf_core_read.h skel_internal.h libbpf_version.h usdt.bpf.h
16 | INSTALL ./libbpf.pc
17 | INSTALL ./libbpf.a ./libbpf.so ./libbpf.so.1 ./libbpf.so.1.6.0
18 | ```
19 |
20 | ## 编译运行程序
21 |
22 | 第一步,编译内核态程序 hello_kprobe.bpf.c
23 |
24 | ```sh
25 |
26 | clang-11 -g -O2 -target bpf -D__TARGET_ARCH_x86_64 -I/usr/include/x86_64-linux-gnu -I. -c hello_kprobe.bpf.c -o hello_kprobe.bpf.o
27 | ```
28 |
29 | 第二步,基于可重定位未见生成 libbpf 脚手架代码
30 |
31 | ```c
32 | bpftool gen skeleton hello_kprobe.bpf.o > hello_kprobe.skel.h
33 | ```
34 |
35 | 第三步,遍历链接用户态程序
36 |
37 | ```sh
38 | clang-11 -g -O2 -Wall -I . -c hello.c -o hello.o
39 | clang-11 -Wall -O2 -g hello.o -static -lbpf -lelf -lz -o hello
40 | ```
41 |
42 | 第四步,执行 eBPF 程序
43 |
44 | ```c
45 | # sudo ./hello
46 | ```
47 |
48 | 当程序运行起来后,就可以通过 trace_pipe 查看日志输出了
49 |
50 | ```sh
51 | #sudo cat /sys/kernel/debug/tracing/trace_pipe
52 | pidof-2599356 [005] .... 1056938.433919: 0: Hello, World from kprobe!
53 | pidof-2599356 [005] .... 1056938.434294: 0: Hello, World from kprobe!
54 | pidof-2599356 [005] .... 1056938.434358: 0: Hello, World from kprobe!
55 | sudo-2599331 [014] .... 1056938.543342: 0: Hello, World from kprobe!
56 | sudo-2599331 [014] .... 1056938.543368: 0: Hello, World from kprobe!
57 | ...
58 | ```
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/tests/index.md:
--------------------------------------------------------------------------------
1 |
2 | ## CPU相关实验
3 | - [likely 和 unlikely 汇编结果对比](tests/cpu/test01)
4 | - [read 系统调用开销](tests/cpu/test02)
5 | - [read 进程上下文切换开销](tests/cpu/test03)
6 | - [read 协程上下文切换开销](tests/cpu/test04)
7 | - [read 线程上下文切换开销](tests/cpu/test05)
8 |
9 | ## 磁盘相关实验
10 | - [使用fio磁盘压测工具进行性能压测分析](tests/disk/test01)
11 |
12 | ## 内存相关实验
13 | - [内存访问延时测试](tests/memory/test01)
14 | - [内存访问带宽测试](tests/memory/test02)
15 |
16 | ## 网络相关实验
17 | - [PHP单语言的百万连接测试源码](tests/network/test01)
18 | - [通过多 IP 达成单机百万连接(支持c、java、php三种语言)](tests/network/test02)
19 | - [通过端口重用达成单机百万连接(支持c、java、php三种语言)](tests/network/test03)
20 | - [一个模拟 tcpdump 的简单抓包程序](tests/network/test04)
21 | - [简单的veth通信](tests/network/test09)
22 | - [用 bridge 连接本机上的多组 veth,使其可以互相通信](tests/network/test05)
23 | - [命令行使用 namespace 的简单实验](tests/network/test06)
24 | - [手工模拟实现一个可以和外部通信的容器网络](tests/network/test07)
25 | - [socket端口复用SO_REUSEPORT测试](tests/network/test08)
26 |
27 | ## eBPF 程序
28 | - [使用 libbpf 开发的 hello world eBPF 程序](tests/ebpf/test01)
--------------------------------------------------------------------------------
/tests/memory/test01/Makefile:
--------------------------------------------------------------------------------
1 | CC = gcc
2 | CFLAGS = -Wall -O2 -lrt -D__i386__
3 |
4 | main: main.c clock.c
5 | $(CC) $(CFLAGS) -o main main.c clock.c
6 |
7 | clean:
8 | rm -f main *.o *~
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/memory/test01/clock.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "clock.h"
6 | #include
7 |
8 |
9 | /* Routines for using cycle counter */
10 |
11 | /* Detect whether running on Alpha */
12 | #ifdef __alpha
13 | #define IS_ALPHA 1
14 | #else
15 | #define IS_ALPHA 0
16 | #endif
17 |
18 | /* Detect whether running on x86 */
19 | #ifdef __i386__
20 | #define IS_x86 1
21 | #else
22 | #define IS_x86 0
23 | #endif
24 |
25 |
26 |
27 |
28 | /* Keep track of most recent reading of cycle counter */
29 | static unsigned cyc_hi = 0;
30 | static unsigned cyc_lo = 0;
31 |
32 | #if IS_ALPHA
33 | /* Use Alpha cycle timer to compute cycles. Then use
34 | measured clock speed to compute seconds
35 | */
36 |
37 | /*
38 | * counterRoutine is an array of Alpha instructions to access
39 | * the Alpha's processor cycle counter. It uses the rpcc
40 | * instruction to access the counter. This 64 bit register is
41 | * divided into two parts. The lower 32 bits are the cycles
42 | * used by the current process. The upper 32 bits are wall
43 | * clock cycles. These instructions read the counter, and
44 | * convert the lower 32 bits into an unsigned int - this is the
45 | * user space counter value.
46 | * NOTE: The counter has a very limited time span. With a
47 | * 450MhZ clock the counter can time things for about 9
48 | * seconds. */
49 | static unsigned int counterRoutine[] =
50 | {
51 | 0x601fc000u,
52 | 0x401f0000u,
53 | 0x6bfa8001u
54 | };
55 |
56 | /* Cast the above instructions into a function. */
57 | static unsigned int (*counter)(void)= (void *)counterRoutine;
58 |
59 |
60 | void start_counter()
61 | {
62 | /* Get cycle counter */
63 | cyc_hi = 0;
64 | cyc_lo = counter();
65 | }
66 |
67 | double get_counter()
68 | {
69 | unsigned ncyc_hi, ncyc_lo;
70 | unsigned hi, lo, borrow;
71 | double result;
72 | ncyc_lo = counter();
73 | ncyc_hi = 0;
74 | lo = ncyc_lo - cyc_lo;
75 | borrow = lo > ncyc_lo;
76 | hi = ncyc_hi - cyc_hi - borrow;
77 | result = (double) hi * (1 << 30) * 4 + lo;
78 | if (result < 0) {
79 | fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result);
80 | }
81 | return result;
82 | }
83 | #endif /* Alpha */
84 |
85 | #if IS_x86
86 | void access_counter(unsigned *hi, unsigned *lo)
87 | {
88 | /* Get cycle counter */
89 | asm("rdtsc; movl %%edx,%0; movl %%eax,%1"
90 | : "=r" (*hi), "=r" (*lo)
91 | : /* No input */
92 | : "%edx", "%eax");
93 | }
94 |
95 | void start_counter()
96 | {
97 | access_counter(&cyc_hi, &cyc_lo);
98 | }
99 |
100 | double get_counter()
101 | {
102 | unsigned ncyc_hi, ncyc_lo;
103 | unsigned hi, lo, borrow;
104 | double result;
105 | /* Get cycle counter */
106 | access_counter(&ncyc_hi, &ncyc_lo);
107 | /* Do double precision subtraction */
108 | lo = ncyc_lo - cyc_lo;
109 | borrow = lo > ncyc_lo;
110 | hi = ncyc_hi - cyc_hi - borrow;
111 | result = (double) hi * (1 << 30) * 4 + lo;
112 | if (result < 0) {
113 | fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result);
114 | }
115 | return result;
116 | }
117 | #endif /* x86 */
118 | struct timespec time1 = {0, 0};
119 | void start_timer()
120 | {
121 | clock_gettime(CLOCK_REALTIME, &time1);
122 | }
123 |
124 | long int get_timer()
125 | {
126 | struct timespec time2 = {0, 0};
127 | clock_gettime(CLOCK_REALTIME, &time2);
128 |
129 | long int usedMircoSecond = (time2.tv_sec-time1.tv_sec)*1000000000 + (time2.tv_nsec-time1.tv_nsec);
130 | return usedMircoSecond;
131 | }
132 |
133 | double ovhd()
134 | {
135 | /* Do it twice to eliminate cache effects */
136 | int i;
137 | double result;
138 | for (i = 0; i < 2; i++) {
139 | start_counter();
140 | result = get_counter();
141 | }
142 | return result;
143 | }
144 |
145 | /* Determine clock rate by measuring cycles
146 | elapsed while sleeping for sleeptime seconds */
147 | double mhz_full(int verbose, int sleeptime)
148 | {
149 | double rate;
150 | start_counter();
151 | sleep(sleeptime);
152 | rate = get_counter()/(1e6*sleeptime);
153 | if (verbose)
154 | printf("Processor Clock Rate ~= %.1f MHz\n", rate);
155 | return rate;
156 | }
157 |
158 | /* Version using a default sleeptime */
159 | double mhz(int verbose)
160 | {
161 | return mhz_full(verbose, 2);
162 | }
163 |
164 | /** Special counters that compensate for timer interrupt overhead */
165 |
166 | static double cyc_per_tick = 0.0;
167 |
168 | #define NEVENT 100
169 | #define THRESHOLD 1000
170 | #define RECORDTHRESH 3000
171 |
172 | /* Attempt to see how much time is used by timer interrupt */
173 | static void callibrate(int verbose)
174 | {
175 | double oldt;
176 | struct tms t;
177 | clock_t oldc;
178 | int e = 0;
179 | times(&t);
180 | oldc = t.tms_utime;
181 | start_counter();
182 | oldt = get_counter();
183 | while (e = THRESHOLD) {
186 | clock_t newc;
187 | times(&t);
188 | newc = t.tms_utime;
189 | if (newc > oldc) {
190 | double cpt = (newt-oldt)/(newc-oldc);
191 | if ((cyc_per_tick == 0.0 || cyc_per_tick > cpt) && cpt > RECORDTHRESH)
192 | cyc_per_tick = cpt;
193 | /*
194 | if (verbose)
195 | printf("Saw event lasting %.0f cycles and %d ticks. Ratio = %f\n",
196 | newt-oldt, (int) (newc-oldc), cpt);
197 | */
198 | e++;
199 | oldc = newc;
200 | }
201 | oldt = newt;
202 | }
203 | }
204 | if (verbose)
205 | printf("Setting cyc_per_tick to %f\n", cyc_per_tick);
206 | }
207 |
208 | static clock_t start_tick = 0;
209 |
210 | void start_comp_counter() {
211 | struct tms t;
212 | if (cyc_per_tick == 0.0)
213 | callibrate(0);
214 | times(&t);
215 | start_tick = t.tms_utime;
216 | start_counter();
217 | }
218 |
219 | double get_comp_counter() {
220 | double time = get_counter();
221 | double ctime;
222 | struct tms t;
223 | clock_t ticks;
224 | times(&t);
225 | ticks = t.tms_utime - start_tick;
226 | ctime = time - ticks*cyc_per_tick;
227 | /*
228 | printf("Measured %.0f cycles. Ticks = %d. Corrected %.0f cycles\n",
229 | time, (int) ticks, ctime);
230 | */
231 | return ctime;
232 | }
233 |
--------------------------------------------------------------------------------
/tests/memory/test01/clock.h:
--------------------------------------------------------------------------------
1 | /* Routines for using cycle counter */
2 |
3 | /* Start the counter */
4 | void start_counter();
5 |
6 | /* Get # cycles since counter started */
7 | double get_counter();
8 |
9 |
10 | void start_timer();
11 | long int get_timer();
12 |
13 |
14 | /* Measure overhead for counter */
15 | double ovhd();
16 |
17 | /* Determine clock rate of processor */
18 | double mhz(int verbose);
19 |
20 | /* Determine clock rate of processor, having more control over accuracy */
21 | double mhz_full(int verbose, int sleeptime);
22 |
23 | /** Special counters that compensate for timer interrupt overhead */
24 |
25 | void start_comp_counter();
26 |
27 | double get_comp_counter();
28 |
--------------------------------------------------------------------------------
/tests/memory/test01/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "clock.h"
4 |
5 | #define MINBYTES (1 << 11) // 内存测试区域从 2KB 开始
6 | #define MAXBYTES (1 << 26) // 最大到 64 MB
7 | #define MAXSTRIDE 64 // 循环步长从 1 到 64 字节
8 | #define MAXELEMS MAXBYTES/sizeof(double)
9 |
10 | double data[MAXELEMS]; // 测试用的全局内存数组
11 |
12 | void init_data(double *data, int n);
13 | void run_delay_testing();
14 | double get_seque_access_result(int size, int stride, int type);
15 | double get_random_access_result(int size, int type);
16 | void seque_access(int elems, int stride);
17 | void random_access(int* random_index_arr, int count);
18 | void create_rand_array(int max, int count, int* pArr);
19 |
20 | int main()
21 | {
22 | init_data(data, MAXELEMS);
23 |
24 | printf("Delay (ns)\n");
25 | run_delay_testing();
26 | printf("\n\n");
27 |
28 | exit(0);
29 | }
30 |
31 | // init_data 初始化要访问的内存数据
32 | void init_data(double *data, int n)
33 | {
34 | int i;
35 | for (i = 0; i < n; i++)
36 | {
37 | data[i] = i;
38 | }
39 | }
40 |
41 | // 运行内存访问延时测试
42 | void run_delay_testing(){
43 | int size; // 测试内存区域大小
44 | int stride; // 内存区域访问循环步长
45 |
46 | // 打印内存区域大小头信息
47 | printf("\t");
48 | for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {
49 | if (size > (1 << 20)){
50 | printf("%dm\t", size / (1 << 20));
51 | }else{
52 | printf("%dk\t", size / 1024);
53 | }
54 | }
55 | printf("\n");
56 |
57 | // 多次实验,进行内存顺序访问延时评估
58 | // 外层循环控制步长依次从 1 到 64,目的是不同的顺序步长的访问效果差异
59 | // 内存循环控制数据大小依次从 2KB 开始到 64MB,目的是要保证数据大小依次超过 L1、L2、L3
60 | for (stride = 1; stride <= MAXSTRIDE; stride=stride+1) {
61 | printf("s%d\t", stride);
62 | for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {
63 | printf("%.2f\t", get_seque_access_result(size, stride, 1));
64 | }
65 | printf("\n");
66 | }
67 |
68 | // 多次实验,进行内存随机访问延时评估
69 | printf("\random\t");
70 | for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {
71 | printf("%.2f\t", get_random_access_result(size,1));
72 | }
73 | printf("\n");
74 | }
75 |
76 | // get_seque_access_result 测试存储访问延迟(L1/L2/L3,内存)
77 | // 参数说明
78 | // - size: 要测试的数据大小
79 | // - stride: 步长
80 | // - type: 0 获取带宽测试结果
81 | // - 1 获取延时测试结果,单位是 CPU 周期数
82 | double get_seque_access_result(int size, int stride, int type)
83 | {
84 | int i;
85 | long int operations;
86 | long int total_accessed_bytes;
87 | long int used_microseconds;
88 |
89 | int samples = 1000;
90 | int elems = size / sizeof(double);
91 |
92 | //循环测试 1000 次,以最大程度减少实验计算结果误差
93 | start_timer();
94 | for(i=0; i
2 | #include
3 | #include
4 | #include
5 | #include "clock.h"
6 | #include
7 |
8 |
9 | /* Routines for using cycle counter */
10 |
11 | /* Detect whether running on Alpha */
12 | #ifdef __alpha
13 | #define IS_ALPHA 1
14 | #else
15 | #define IS_ALPHA 0
16 | #endif
17 |
18 | /* Detect whether running on x86 */
19 | #ifdef __i386__
20 | #define IS_x86 1
21 | #else
22 | #define IS_x86 0
23 | #endif
24 |
25 |
26 |
27 |
28 | /* Keep track of most recent reading of cycle counter */
29 | static unsigned cyc_hi = 0;
30 | static unsigned cyc_lo = 0;
31 |
32 | #if IS_ALPHA
33 | /* Use Alpha cycle timer to compute cycles. Then use
34 | measured clock speed to compute seconds
35 | */
36 |
37 | /*
38 | * counterRoutine is an array of Alpha instructions to access
39 | * the Alpha's processor cycle counter. It uses the rpcc
40 | * instruction to access the counter. This 64 bit register is
41 | * divided into two parts. The lower 32 bits are the cycles
42 | * used by the current process. The upper 32 bits are wall
43 | * clock cycles. These instructions read the counter, and
44 | * convert the lower 32 bits into an unsigned int - this is the
45 | * user space counter value.
46 | * NOTE: The counter has a very limited time span. With a
47 | * 450MhZ clock the counter can time things for about 9
48 | * seconds. */
49 | static unsigned int counterRoutine[] =
50 | {
51 | 0x601fc000u,
52 | 0x401f0000u,
53 | 0x6bfa8001u
54 | };
55 |
56 | /* Cast the above instructions into a function. */
57 | static unsigned int (*counter)(void)= (void *)counterRoutine;
58 |
59 |
60 | void start_counter()
61 | {
62 | /* Get cycle counter */
63 | cyc_hi = 0;
64 | cyc_lo = counter();
65 | }
66 |
67 | double get_counter()
68 | {
69 | unsigned ncyc_hi, ncyc_lo;
70 | unsigned hi, lo, borrow;
71 | double result;
72 | ncyc_lo = counter();
73 | ncyc_hi = 0;
74 | lo = ncyc_lo - cyc_lo;
75 | borrow = lo > ncyc_lo;
76 | hi = ncyc_hi - cyc_hi - borrow;
77 | result = (double) hi * (1 << 30) * 4 + lo;
78 | if (result < 0) {
79 | fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result);
80 | }
81 | return result;
82 | }
83 | #endif /* Alpha */
84 |
85 | #if IS_x86
86 | void access_counter(unsigned *hi, unsigned *lo)
87 | {
88 | /* Get cycle counter */
89 | asm("rdtsc; movl %%edx,%0; movl %%eax,%1"
90 | : "=r" (*hi), "=r" (*lo)
91 | : /* No input */
92 | : "%edx", "%eax");
93 | }
94 |
95 | void start_counter()
96 | {
97 | access_counter(&cyc_hi, &cyc_lo);
98 | }
99 |
100 | double get_counter()
101 | {
102 | unsigned ncyc_hi, ncyc_lo;
103 | unsigned hi, lo, borrow;
104 | double result;
105 | /* Get cycle counter */
106 | access_counter(&ncyc_hi, &ncyc_lo);
107 | /* Do double precision subtraction */
108 | lo = ncyc_lo - cyc_lo;
109 | borrow = lo > ncyc_lo;
110 | hi = ncyc_hi - cyc_hi - borrow;
111 | result = (double) hi * (1 << 30) * 4 + lo;
112 | if (result < 0) {
113 | fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result);
114 | }
115 | return result;
116 | }
117 | #endif /* x86 */
118 | struct timespec time1 = {0, 0};
119 | void start_timer()
120 | {
121 | clock_gettime(CLOCK_REALTIME, &time1);
122 | }
123 |
124 | long int get_timer()
125 | {
126 | struct timespec time2 = {0, 0};
127 | clock_gettime(CLOCK_REALTIME, &time2);
128 |
129 | long int usedMircoSecond = (time2.tv_sec-time1.tv_sec)*1000000000 + (time2.tv_nsec-time1.tv_nsec);
130 | return usedMircoSecond;
131 | }
132 |
133 | double ovhd()
134 | {
135 | /* Do it twice to eliminate cache effects */
136 | int i;
137 | double result;
138 | for (i = 0; i < 2; i++) {
139 | start_counter();
140 | result = get_counter();
141 | }
142 | return result;
143 | }
144 |
145 | /* Determine clock rate by measuring cycles
146 | elapsed while sleeping for sleeptime seconds */
147 | double mhz_full(int verbose, int sleeptime)
148 | {
149 | double rate;
150 | start_counter();
151 | sleep(sleeptime);
152 | rate = get_counter()/(1e6*sleeptime);
153 | if (verbose)
154 | printf("Processor Clock Rate ~= %.1f MHz\n", rate);
155 | return rate;
156 | }
157 |
158 | /* Version using a default sleeptime */
159 | double mhz(int verbose)
160 | {
161 | return mhz_full(verbose, 2);
162 | }
163 |
164 | /** Special counters that compensate for timer interrupt overhead */
165 |
166 | static double cyc_per_tick = 0.0;
167 |
168 | #define NEVENT 100
169 | #define THRESHOLD 1000
170 | #define RECORDTHRESH 3000
171 |
172 | /* Attempt to see how much time is used by timer interrupt */
173 | static void callibrate(int verbose)
174 | {
175 | double oldt;
176 | struct tms t;
177 | clock_t oldc;
178 | int e = 0;
179 | times(&t);
180 | oldc = t.tms_utime;
181 | start_counter();
182 | oldt = get_counter();
183 | while (e = THRESHOLD) {
186 | clock_t newc;
187 | times(&t);
188 | newc = t.tms_utime;
189 | if (newc > oldc) {
190 | double cpt = (newt-oldt)/(newc-oldc);
191 | if ((cyc_per_tick == 0.0 || cyc_per_tick > cpt) && cpt > RECORDTHRESH)
192 | cyc_per_tick = cpt;
193 | /*
194 | if (verbose)
195 | printf("Saw event lasting %.0f cycles and %d ticks. Ratio = %f\n",
196 | newt-oldt, (int) (newc-oldc), cpt);
197 | */
198 | e++;
199 | oldc = newc;
200 | }
201 | oldt = newt;
202 | }
203 | }
204 | if (verbose)
205 | printf("Setting cyc_per_tick to %f\n", cyc_per_tick);
206 | }
207 |
208 | static clock_t start_tick = 0;
209 |
210 | void start_comp_counter() {
211 | struct tms t;
212 | if (cyc_per_tick == 0.0)
213 | callibrate(0);
214 | times(&t);
215 | start_tick = t.tms_utime;
216 | start_counter();
217 | }
218 |
219 | double get_comp_counter() {
220 | double time = get_counter();
221 | double ctime;
222 | struct tms t;
223 | clock_t ticks;
224 | times(&t);
225 | ticks = t.tms_utime - start_tick;
226 | ctime = time - ticks*cyc_per_tick;
227 | /*
228 | printf("Measured %.0f cycles. Ticks = %d. Corrected %.0f cycles\n",
229 | time, (int) ticks, ctime);
230 | */
231 | return ctime;
232 | }
233 |
--------------------------------------------------------------------------------
/tests/memory/test02/clock.h:
--------------------------------------------------------------------------------
1 | /* Routines for using cycle counter */
2 |
3 | /* Start the counter */
4 | void start_counter();
5 |
6 | /* Get # cycles since counter started */
7 | double get_counter();
8 |
9 |
10 | void start_timer();
11 | long int get_timer();
12 |
13 |
14 | /* Measure overhead for counter */
15 | double ovhd();
16 |
17 | /* Determine clock rate of processor */
18 | double mhz(int verbose);
19 |
20 | /* Determine clock rate of processor, having more control over accuracy */
21 | double mhz_full(int verbose, int sleeptime);
22 |
23 | /** Special counters that compensate for timer interrupt overhead */
24 |
25 | void start_comp_counter();
26 |
27 | double get_comp_counter();
28 |
--------------------------------------------------------------------------------
/tests/memory/test02/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "clock.h"
4 |
5 | #define MINBYTES (1 << 11) // 内存测试区域从 2KB 开始
6 | #define MAXBYTES (1 << 26) // 最大到 64 MB
7 | #define MAXSTRIDE 64 // 循环步长从 1 到 64 字节
8 | #define MAXELEMS MAXBYTES/sizeof(double)
9 |
10 | double data[MAXELEMS]; // 测试用的全局内存数组
11 |
12 | void init_data(double *data, int n);
13 | void run_width_testing();
14 | double get_seque_access_result(int size, int stride, int type);
15 | double get_random_access_result(int size, int type);
16 | void seque_access(int elems, int stride);
17 | void random_access(int* random_index_arr, int count);
18 | void create_rand_array(int max, int count, int* pArr);
19 |
20 | int main()
21 | {
22 | init_data(data, MAXELEMS);
23 |
24 | printf("Band Width (MB/sec)\n");
25 | run_width_testing();
26 | printf("\n\n");
27 |
28 | exit(0);
29 | }
30 |
31 | // init_data 初始化要访问的内存数据
32 | void init_data(double *data, int n)
33 | {
34 | int i;
35 |
36 | for (i = 0; i < n; i++)
37 | data[i] = i;
38 | }
39 |
40 | // 运行内存访问带宽测试
41 | void run_width_testing()
42 | {
43 | int size; // 测试内存区域大小
44 | int stride; // 内存区域访问循环步长
45 |
46 | // 打印内存区域大小头信息
47 | printf("\t");
48 | for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {
49 | if (size > (1 << 20)){
50 | printf("%dm\t", size / (1 << 20));
51 | }else{
52 | printf("%dk\t", size / 1024);
53 | }
54 | }
55 | printf("\n");
56 |
57 | // 多次实验,进行内存顺序访问带宽评估
58 | // 外层循环控制步长依次从 1 到 64,目的是不同的顺序步长的访问效果差异
59 | // 内存循环控制数据大小依次从 2KB 开始到 64MB,目的是要保证数据大小依次超过 L1、L2、L3
60 | for (stride = 1; stride <= MAXSTRIDE; stride=stride+1) {
61 | printf("s%d\t", stride);
62 | for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {
63 | printf("%.1f\t", get_seque_access_result(size, stride, 0));
64 | }
65 | printf("\n");
66 | }
67 |
68 | // 多次实验,进行内存随机访问带宽评估
69 | printf("random\t");
70 | for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {
71 | printf("%.1f\t", get_random_access_result(size,0));
72 | }
73 | printf("\n");
74 | }
75 |
76 | // get_seque_access_result 测试存储访问延迟(L1/L2/L3,内存)
77 | // 参数说明
78 | // - size: 要测试的数据大小
79 | // - stride: 步长
80 | // - type: 0 获取带宽测试结果
81 | // - 1 获取延时测试结果,单位是 CPU 周期数
82 | double get_seque_access_result(int size, int stride, int type)
83 | {
84 | int i;
85 | long int operations;
86 | long int total_accessed_bytes;
87 | long int used_microseconds;
88 |
89 | int samples = 1000;
90 | int elems = size / sizeof(double);
91 |
92 | //循环测试 1000 次,以最大程度减少实验计算结果误差
93 | start_timer();
94 | for(i=0; i$ip){
47 | echo $ip.":".pingAddress($ip)."\n";
48 | }
49 | break;
50 |
51 | case "ifup":
52 | foreach($ips as $k=>$ip){
53 | shell_exec("ifconfig eth0:$k $ip netmask ".$netmask." up");
54 | }
55 | break;
56 |
57 | case "ifdown":
58 | foreach($ips as $k=>$ip){
59 | shell_exec("ifconfig eth0:$k down");
60 | }
61 | break;
62 |
63 | case "start":
64 | $cmd = "ps -ef | grep client.php | awk '{print $2}' | xargs kill -9";
65 | shell_exec($cmd);
66 | shell_exec("echo '' > clientd.log");
67 |
68 | foreach($ips as $ip){
69 | $cmd = "php client.php $ip $serverIp $serverPort >> clientd.log &";
70 | echo $cmd."\n";
71 | shell_exec($cmd);
72 | }
73 | break;
74 |
75 | case "stop":
76 | $cmd = "ps -ef | grep client.php | awk '{print $2}' | xargs kill -9";
77 | shell_exec($cmd);
78 | break;
79 |
80 | default:
81 | break;
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/tests/network/test01/server.php:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #define MAX_CONNECTION_NUM 50000
9 |
10 | int buildConnect(const char *lIp, const char *sIp, int sPort)
11 | {
12 | int skFd;
13 | if((skFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
14 | {
15 | printf("\n Error : Could not create socket\n");
16 | return 0;
17 | }
18 |
19 | struct sockaddr_in cliAddr;
20 | cliAddr.sin_family = AF_INET;
21 | cliAddr.sin_addr.s_addr = inet_addr(lIp);
22 | cliAddr.sin_port = 0;
23 | if(bind(skFd, (struct sockaddr *)&cliAddr, sizeof(cliAddr)) < 0)
24 | {
25 | printf("\n Error : Bind Failed \n");
26 | }
27 |
28 | struct sockaddr_in srvAddr;
29 | srvAddr.sin_family = AF_INET;
30 | srvAddr.sin_addr.s_addr = inet_addr(sIp);
31 | srvAddr.sin_port = htons(sPort);
32 | if(connect(skFd, (struct sockaddr *)&srvAddr, sizeof(srvAddr)) < 0)
33 | {
34 | printf("\n Error : Connect Failed \n");
35 | return 0;
36 | }
37 |
38 | return skFd;
39 | }
40 |
41 | int main(int argc, char *argv[])
42 | {
43 | int i = 0, sPort, fd;
44 | char lIp[16], sIp[16];
45 |
46 | if(argc != 4)
47 | {
48 | printf("\n Usage: %s \n", argv[0]);
49 | return 1;
50 | }
51 |
52 | //1. 从命令行获取并解析local ip、server ip以及端口
53 | strcpy(lIp, argv[1]);
54 | strcpy(sIp, argv[2]);
55 | sPort = atoi(argv[3]);
56 |
57 | //2. 开始建立连接
58 | int *sockets = (int *)malloc(sizeof(int) * MAX_CONNECTION_NUM);
59 | for(i = 1; i <= MAX_CONNECTION_NUM; i++)
60 | {
61 | if(0 == i % 1000)
62 | {//稍稍停顿一下,避免把服务端的握手队列打满
63 | printf("%s 连接 %s:%d成功了 %d 条!\n", lIp, sIp, sPort, i);
64 | sleep(1);
65 | }
66 |
67 | fd = buildConnect(lIp, sIp, sPort);
68 | if(fd > 0)
69 | {
70 | sockets[i-1] = fd;
71 | }else{
72 | return 1;
73 | }
74 | }
75 | sleep(300);
76 |
77 | //3. 释放所有的连接
78 | printf("关闭所有的连接...\n");
79 | for(i = 0; i < MAX_CONNECTION_NUM; i++)
80 | {
81 | close(sockets[i]);
82 | }
83 |
84 | return 0;
85 | }
86 |
--------------------------------------------------------------------------------
/tests/network/test02/c/server.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #define MAX_CONNECTION_NUM 1100000
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | char ip[16];
11 | int lisFd, conFd, port;
12 | struct sockaddr_in servAddr;
13 |
14 | if(argc != 3)
15 | {
16 | printf("\n Usage: %s \n", argv[0]);
17 | return 1;
18 | }
19 |
20 | //1. 从命令行获取并解析server ip以及端口
21 | strcpy(ip, argv[1]);
22 | port = atoi(argv[2]);
23 |
24 | //2. 创建server
25 | if((lisFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
26 | {
27 | printf("\n Error : Could not create socket\n");
28 | return 0;
29 | }
30 |
31 | servAddr.sin_family = AF_INET;
32 | servAddr.sin_addr.s_addr = inet_addr(ip);
33 | servAddr.sin_port = htons(port);
34 | if(bind(lisFd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0)
35 | {
36 | printf("\n Error : Bind Failed \n");
37 | }
38 | if((listen(lisFd, 1024)) < 0)
39 | {
40 | printf("\n Error : Listen Failed \n");
41 | }
42 |
43 | //3. 接收连接
44 | int i = 0;
45 | int *sockets = (int *)malloc(sizeof(int) * MAX_CONNECTION_NUM);
46 | while(1)
47 | {
48 | conFd = accept(lisFd, (struct sockaddr*)NULL, NULL);
49 | if(conFd > 0)
50 | {
51 | sockets[i++] = conFd;
52 | printf("%s %d accept success:%d\n", ip, port, i);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/network/test02/c/tool.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #--------------------------- begin -------------------------
4 | #注意:这一部分的内容需要根据你自己的实验环境来设置
5 |
6 | #1.客户端 IP 列表:选择20个,且不能在局域网中存在
7 | # 示例
8 | # IPS=(
9 | # "192.168.1.200"
10 | # "192.168.1.201"
11 | # )
12 |
13 | IPS=(
14 | "192.168.1.200"
15 | "192.168.1.201"
16 | )
17 |
18 | #2.客户端 IP 对应的子网掩码
19 | #示例:
20 | #NETMASK="255.255.248.0"
21 | NETMASK="255.255.248.0"
22 |
23 | #3.服务端的 IP 和 端口
24 | #示例
25 | #SERVERIP="192.168.1.100"
26 | #SERVERPORT="8090"
27 | SERVERIP="192.168.1.100"
28 | SERVERPORT="8090"
29 | #--------------------------- end -------------------------
30 |
31 | TYPE=$1
32 |
33 | exec_ping(){
34 | for i in "${!IPS[@]}"; do
35 | ping -c 1 -W 1 ${IPS[$i]} > /dev/null
36 | if [[ $? != 0 ]];then
37 | echo ${IPS[$i]}" false"
38 | else
39 | echo ${IPS[$i]}" true"
40 | fi
41 | done
42 | }
43 |
44 | exec_ifup(){
45 | for i in "${!IPS[@]}"; do
46 | echo ifconfig eth0:$i ${IPS[$i]} netmask $NETMASK up
47 | ifconfig eth0:$i ${IPS[$i]} netmask $NETMASK up
48 | done
49 | }
50 |
51 | exec_ifdown(){
52 | for i in "${!IPS[@]}"; do
53 | echo ifconfig eth0:$i down
54 | ifconfig eth0:$i down
55 | done
56 | }
57 |
58 | exec_runcli(){
59 | for i in "${!IPS[@]}"; do
60 | echo $CLIENT ${IPS[$i]} $SERVERIP $SERVERPORT
61 | $CLIENT ${IPS[$i]} $SERVERIP $SERVERPORT &
62 | done
63 | }
64 |
65 | exec_stopcli(){
66 | ps -ef | grep $CLIENT | awk '{print $2}' | xargs kill -9 > /dev/null
67 | }
68 |
69 | exec_runsrv(){
70 | echo $SERVER 0.0.0.0 $SERVERPORT
71 | $SERVER 0.0.0.0 $SERVERPORT
72 | }
73 |
74 | case $TYPE in
75 | "ping") exec_ping;;
76 | "ifup") exec_ifup;;
77 | "ifdown") exec_ifdown;;
78 | "runcli") CLIENT=$2; exec_runcli;;
79 | "stopcli") CLIENT=$2; exec_stopcli;;
80 | "runsrv") SERVER=$2; exec_runsrv;;
81 | *) echo "get unkown type $TYPE"; exit ;;
82 | esac
83 |
84 |
--------------------------------------------------------------------------------
/tests/network/test02/java/Client.java:
--------------------------------------------------------------------------------
1 | import java.net.Socket;
2 | import java.net.InetSocketAddress;
3 |
4 | public class Client {
5 |
6 | public static final int MAX_CONNECTION_NUM = 50000;
7 |
8 | public static void main(String[] args) throws Exception {
9 | if(3 != args.length){
10 | System.out.println("Usage: java Client \n");
11 | return;
12 | }
13 |
14 | //1. 从命令行获取并解析local ip、server ip以及端口
15 | String lIp = args[0];
16 | String sIp = args[1];
17 | int sPort = Integer.parseInt(args[2]);
18 |
19 | //2. 开始建立连接
20 | //用数组将 socket 保存起来,防止连接被过早释放
21 | Socket[] sockets = new Socket[MAX_CONNECTION_NUM];
22 | for(int i = 1; i <= MAX_CONNECTION_NUM; i++){
23 | try {
24 | Socket s = new Socket();
25 | s.bind(new InetSocketAddress(lIp, 0));
26 | s.connect(new InetSocketAddress(sIp, sPort));
27 |
28 | if(false == s.isConnected()){
29 | System.out.println(lIp + " 连接 "+sIp+":"+sPort+" 失败! ");
30 | return;
31 | }
32 | sockets[i-1] = s;
33 |
34 | } catch (Exception e) {
35 | //连接失败则小憩一会儿接着连
36 | Thread.sleep(500);
37 | e.printStackTrace();
38 | }
39 |
40 | //稍稍停顿一下,避免把服务端的握手队列打满
41 | if(0 == i % 500){
42 | Thread.sleep(500);
43 | System.out.println(lIp + " 连接 "+sIp+":"+sPort+" 成功了 "+i+" 条");
44 | }
45 | }
46 |
47 | //把所有连接都 hold 一会儿,方便观察
48 | Thread.sleep(300 * 1000);
49 |
50 | //3. 释放所有的连接
51 | System.out.println("关闭所有的连接...\n");
52 | for(int i = 0; i < MAX_CONNECTION_NUM; i++){
53 | sockets[i].close();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/tests/network/test02/java/Makefile:
--------------------------------------------------------------------------------
1 | CLIENT_BINARY_NAME := "java Client"
2 | SERVER_BINARY_NAME := "java Server"
3 |
4 | .PHONY: ping
5 | ping:
6 | sh tool.sh ping
7 |
8 | .PHONY: ifup
9 | ifup:
10 | sh tool.sh ifup
11 |
12 | .PHONY: ifdown
13 | ifdown:
14 | sh tool.sh ifdown
15 |
16 | .PHONY: build-cli
17 | build-cli:
18 | javac Client.java
19 |
20 | .PHONY: run-cli
21 | run-cli: build-cli
22 | sh tool.sh runcli $(CLIENT_BINARY_NAME)
23 |
24 | .PHONY: stop-cli
25 | stop-cli:
26 | sh tool.sh stopcli
27 |
28 | .PHONY: build-srv
29 | build-srv:
30 | javac Server.java
31 |
32 | .PHONY: run-srv
33 | run-srv: build-srv
34 | sh tool.sh runsrv $(SERVER_BINARY_NAME)
35 |
36 | .PHONY: clean
37 | clean:
38 | rm -f *.class
39 |
--------------------------------------------------------------------------------
/tests/network/test02/java/Server.java:
--------------------------------------------------------------------------------
1 | import java.io.IOException;
2 | import java.net.ServerSocket;
3 | import java.net.Socket;
4 | import java.net.InetSocketAddress;
5 |
6 | public class Server {
7 | public static final int MAX_CONNECTION_NUM = 1100000;
8 |
9 | public static void main(String[] args) {
10 | if(2 != args.length){
11 | System.out.println("Usage: java Server \n");
12 | return;
13 | }
14 |
15 | String sIp = args[0];
16 | int sPort = Integer.parseInt(args[1]);
17 |
18 | //用数组将 socket 保存起来,防止连接被过早回收
19 | Socket[] sockets = new Socket[MAX_CONNECTION_NUM];
20 |
21 | try {
22 | ServerSocket ss = new ServerSocket();
23 | ss.bind(new InetSocketAddress(sIp, sPort), 1024);
24 | System.out.println("启动Server " + sIp + ":" + sPort + "...");
25 |
26 | int i = 0;
27 | while(true){
28 | try{
29 | Socket s = ss.accept();
30 | sockets[i] = s;
31 | i++;
32 | System.out.println("Server " + sIp + ":" + sPort + " 接收到第 " + i +" 条连接!");
33 | } catch (IOException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | } catch (IOException e) {
38 | e.printStackTrace();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/network/test02/java/tool.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #--------------------------- begin -------------------------
4 | #注意:这一部分的内容需要根据你自己的实验环境来设置
5 |
6 | #1.客户端 IP 列表:选择20个,且不能在局域网中存在
7 | # 示例
8 | # IPS=(
9 | # "192.168.1.200"
10 | # "192.168.1.201"
11 | # )
12 |
13 | IPS=(
14 | "192.168.1.200"
15 | "192.168.1.201"
16 | )
17 |
18 | #2.客户端 IP 对应的子网掩码
19 | #示例:
20 | #NETMASK="255.255.248.0"
21 | NETMASK="255.255.248.0"
22 |
23 | #3.服务端的 IP 和 端口
24 | #示例
25 | #SERVERIP="192.168.1.100"
26 | #SERVERPORT="8090"
27 | SERVERIP="192.168.1.100"
28 | SERVERPORT="8090"
29 | #--------------------------- end -------------------------
30 |
31 | TYPE=$1
32 |
33 | exec_ping(){
34 | for i in "${!IPS[@]}"; do
35 | ping -c 1 -W 1 ${IPS[$i]} > /dev/null
36 | if [[ $? != 0 ]];then
37 | echo ${IPS[$i]}" false"
38 | else
39 | echo ${IPS[$i]}" true"
40 | fi
41 | done
42 | }
43 |
44 | exec_ifup(){
45 | for i in "${!IPS[@]}"; do
46 | echo ifconfig eth0:$i ${IPS[$i]} netmask $NETMASK up
47 | ifconfig eth0:$i ${IPS[$i]} netmask $NETMASK up
48 | done
49 | }
50 |
51 | exec_ifdown(){
52 | for i in "${!IPS[@]}"; do
53 | echo ifconfig eth0:$i down
54 | ifconfig eth0:$i down
55 | done
56 | }
57 |
58 | exec_runcli(){
59 | for i in "${!IPS[@]}"; do
60 | echo $CLIENT ${IPS[$i]} $SERVERIP $SERVERPORT
61 | $CLIENT ${IPS[$i]} $SERVERIP $SERVERPORT &
62 | done
63 | }
64 |
65 | exec_stopcli(){
66 | ps -ef | grep java | grep Client | awk '{print $2}' | xargs kill -9
67 | }
68 |
69 | exec_runsrv(){
70 | echo $SERVER 0.0.0.0 $SERVERPORT
71 | $SERVER 0.0.0.0 $SERVERPORT
72 | }
73 |
74 | case $TYPE in
75 | "ping") exec_ping;;
76 | "ifup") exec_ifup;;
77 | "ifdown") exec_ifdown;;
78 | "runcli") CLIENT=$2; exec_runcli;;
79 | "stopcli") CLIENT=$2; exec_stopcli;;
80 | "runsrv") SERVER=$2; exec_runsrv;;
81 | *) echo "get unkown type $TYPE"; exit ;;
82 | esac
83 |
84 |
--------------------------------------------------------------------------------
/tests/network/test02/php/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: ping
2 | ping:
3 | sh tool.sh ping
4 |
5 | .PHONY: ifup
6 | ifup:
7 | sh tool.sh ifup
8 |
9 | .PHONY: ifdown
10 | ifdown:
11 | sh tool.sh ifdown
12 |
13 | .PHONY: run-cli
14 | run-cli:
15 | sh tool.sh runcli
16 |
17 | .PHONY: stop-cli
18 | stop-cli:
19 | sh tool.sh stopcli
20 |
21 | .PHONY: run-srv
22 | run-srv:
23 | sh tool.sh runsrv
24 |
--------------------------------------------------------------------------------
/tests/network/test02/php/client.php:
--------------------------------------------------------------------------------
1 | /dev/null
36 | if [[ $? != 0 ]];then
37 | echo ${IPS[$i]}" false"
38 | else
39 | echo ${IPS[$i]}" true"
40 | fi
41 | done
42 | }
43 |
44 | exec_ifup(){
45 | for i in "${!IPS[@]}"; do
46 | echo ifconfig eth0:$i ${IPS[$i]} netmask $NETMASK up
47 | ifconfig eth0:$i ${IPS[$i]} netmask $NETMASK up
48 | done
49 | }
50 |
51 | exec_ifdown(){
52 | for i in "${!IPS[@]}"; do
53 | echo ifconfig eth0:$i down
54 | ifconfig eth0:$i down
55 | done
56 | }
57 |
58 | exec_runcli(){
59 | for i in "${!IPS[@]}"; do
60 | echo php client.php ${IPS[$i]} $SERVERIP $SERVERPORT &
61 | php client.php ${IPS[$i]} $SERVERIP $SERVERPORT &
62 | done
63 | }
64 |
65 | exec_stopcli(){
66 | ps -ef | grep client.php | awk '{print $2}' | xargs kill -9
67 | }
68 |
69 | exec_runsrv(){
70 | echo php server.php 0.0.0.0 $SERVERPORT
71 | php server.php 0.0.0.0 $SERVERPORT
72 | }
73 |
74 | case $TYPE in
75 | "ping") exec_ping;;
76 | "ifup") exec_ifup;;
77 | "ifdown") exec_ifdown;;
78 | "runcli") exec_runcli;;
79 | "stopcli") exec_stopcli;;
80 | "runsrv") exec_runsrv;;
81 | *) echo "get unkown type $TYPE"; exit ;;
82 | esac
83 |
84 |
--------------------------------------------------------------------------------
/tests/network/test03/c/Makefile:
--------------------------------------------------------------------------------
1 | CLIENT_BINARY_NAME := "test-client"
2 | SERVER_BINARY_NAME := "test-server"
3 |
4 | .PHONY: build-cli
5 | build-cli:
6 | gcc client.c -o $(CLIENT_BINARY_NAME)
7 |
8 | .PHONY: run-cli
9 | run-cli: build-cli
10 | sh tool.sh runcli ./$(CLIENT_BINARY_NAME)
11 |
12 | .PHONY: stop-cli
13 | stop-cli:
14 | sh tool.sh stopcli ./$(CLIENT_BINARY_NAME)
15 |
16 | .PHONY: build-srv
17 | build-srv:
18 | gcc server.c -o $(SERVER_BINARY_NAME)
19 |
20 | .PHONY: run-srv
21 | run-srv: build-srv
22 | sh tool.sh runsrv ./$(SERVER_BINARY_NAME)
23 |
24 | .PHONY: stop-srv
25 | stop-srv:
26 | sh tool.sh stopsrv ./$(SERVER_BINARY_NAME)
27 |
28 | .PHONY: clean
29 | clean:
30 | rm -f ${CLIENT_BINARY_NAME}
31 | rm -f $(SERVER_BINARY_NAME)
32 |
--------------------------------------------------------------------------------
/tests/network/test03/c/client.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 |
9 | #define MAX_CONNECTION_NUM 50000
10 |
11 | int buildConnect(const char *sIp, int sPort)
12 | {
13 | int skFd;
14 | if((skFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
15 | {
16 | printf("\n Error : Could not create socket\n");
17 | return 0;
18 | }
19 |
20 | struct sockaddr_in srvAddr;
21 | srvAddr.sin_family = AF_INET;
22 | srvAddr.sin_addr.s_addr = inet_addr(sIp);
23 | srvAddr.sin_port = htons(sPort);
24 | if(connect(skFd, (struct sockaddr *)&srvAddr, sizeof(srvAddr)) < 0)
25 | {
26 | printf("\n Error : Connect Failed \n");
27 | return 0;
28 | }
29 |
30 | return skFd;
31 | }
32 |
33 | int main(int argc, char *argv[])
34 | {
35 | int i = 0, sPort, fd;
36 | char sIp[16];
37 |
38 | if(argc != 3)
39 | {
40 | printf("\n Usage: %s \n", argv[0]);
41 | return 1;
42 | }
43 |
44 | //1. 从命令行获取并解析server ip以及端口
45 | strcpy(sIp, argv[1]);
46 | sPort = atoi(argv[2]);
47 |
48 | //2. 开始建立连接
49 | int *sockets = (int *)malloc(sizeof(int) * MAX_CONNECTION_NUM);
50 | for(i = 1; i <= MAX_CONNECTION_NUM; i++)
51 | {
52 | if(0 == i % 1000)
53 | {//稍稍停顿一下,避免把服务端的握手队列打满
54 | printf("连接 %s:%d成功了 %d 条!\n", sIp, sPort, i);
55 | sleep(1);
56 | }
57 |
58 | fd = buildConnect(sIp, sPort);
59 | if(fd > 0)
60 | {
61 | sockets[i-1] = fd;
62 | }else{
63 | return 1;
64 | }
65 | }
66 | sleep(300);
67 |
68 | //3. 释放所有的连接
69 | printf("关闭所有的连接...\n");
70 | for(i = 0; i < MAX_CONNECTION_NUM; i++)
71 | {
72 | close(sockets[i]);
73 | }
74 |
75 | return 0;
76 | }
77 |
--------------------------------------------------------------------------------
/tests/network/test03/c/server.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #define MAX_CONNECTION_NUM 1100000
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | char ip[16];
11 | int lisFd, conFd, port;
12 | struct sockaddr_in servAddr;
13 |
14 | if(argc != 3)
15 | {
16 | printf("\n Usage: %s \n", argv[0]);
17 | return 1;
18 | }
19 |
20 | //1. 从命令行获取并解析server ip以及端口
21 | strcpy(ip, argv[1]);
22 | port = atoi(argv[2]);
23 |
24 | //2. 创建server
25 | if((lisFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
26 | {
27 | printf("\n Error : Could not create socket\n");
28 | return 0;
29 | }
30 |
31 | servAddr.sin_family = AF_INET;
32 | servAddr.sin_addr.s_addr = inet_addr(ip);
33 | servAddr.sin_port = htons(port);
34 | if(bind(lisFd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0)
35 | {
36 | printf("\n Error : Bind Failed \n");
37 | }
38 | if((listen(lisFd, 10000)) < 0)
39 | {
40 | printf("\n Error : Listen Failed \n");
41 | }
42 |
43 | //3. 接收连接
44 | int i = 0;
45 | int *sockets = (int*)malloc(sizeof(int) * MAX_CONNECTION_NUM);
46 | while(1)
47 | {
48 | conFd = accept(lisFd, (struct sockaddr*)NULL, NULL);
49 | if(conFd > 0)
50 | {
51 | sockets[i++] = conFd;
52 | printf("%s %d accept success:%d\n", ip, port, i);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/network/test03/c/tool.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #--------------------------- begin -------------------------
4 | #注意:这一部分的内容需要根据你自己的实验环境来设置
5 |
6 | #1.服务端的 IP
7 | #示例
8 | #SERVERIP="192.168.1.100"
9 | SERVERIP="192.168.1.100"
10 |
11 | #2.服务端的端口
12 | SERVERPORTS=(
13 | "8100"
14 | "8101"
15 | "8102"
16 | "8103"
17 | "8104"
18 | "8105"
19 | "8106"
20 | "8107"
21 | "8108"
22 | "8109"
23 | "8110"
24 | "8111"
25 | "8112"
26 | "8113"
27 | "8114"
28 | "8115"
29 | "8116"
30 | "8117"
31 | "8118"
32 | "8119"
33 | )
34 | #--------------------------- end -------------------------
35 |
36 | TYPE=$1
37 |
38 | exec_runcli(){
39 | for i in "${!SERVERPORTS[@]}"; do
40 | echo $CLIENT $SERVERIP ${SERVERPORTS[$i]} &
41 | $CLIENT $SERVERIP ${SERVERPORTS[$i]} &
42 | done
43 | }
44 |
45 | exec_stopcli(){
46 | ps -ef | grep $CLIENT | awk '{print $2}' | xargs kill -9
47 | }
48 |
49 | exec_runsrv(){
50 | for i in "${!SERVERPORTS[@]}"; do
51 | echo $SERVER 0.0.0.0 ${SERVERPORTS[$i]} &
52 | $SERVER 0.0.0.0 ${SERVERPORTS[$i]} &
53 | done
54 | }
55 |
56 | exec_stopsrv(){
57 | ps -ef | grep $SERVER | awk '{print $2}' | xargs kill -9
58 | }
59 |
60 | case $TYPE in
61 | "runcli") CLIENT=$2; exec_runcli;;
62 | "stopcli") CLIENT=$2; exec_stopcli;;
63 | "runsrv") SERVER=$2; exec_runsrv;;
64 | "stopsrv") SERVER=$2; exec_stopsrv;;
65 | *) echo "get unkown type $TYPE"; exit ;;
66 | esac
67 |
68 |
--------------------------------------------------------------------------------
/tests/network/test03/java/Client.java:
--------------------------------------------------------------------------------
1 | import java.net.Socket;
2 | import java.net.InetSocketAddress;
3 |
4 | public class Client {
5 | public static final int MAX_CONNECTION_NUM = 50000;
6 |
7 | public static void main(String[] args) throws Exception {
8 | if(2 != args.length){
9 | System.out.println("Usage: java Client \n");
10 | return;
11 | }
12 |
13 | //1. 从命令行获取并解析local ip、server ip以及端口
14 | String sIp = args[0];
15 | int sPort = Integer.parseInt(args[1]);
16 |
17 | //2. 开始建立连接
18 | //用数组将 socket 保存起来,防止连接被过早释放
19 | Socket[] sockets = new Socket[MAX_CONNECTION_NUM];
20 | for(int i = 1; i <= MAX_CONNECTION_NUM; i++){
21 | try {
22 | Socket s = new Socket();
23 | s.connect(new InetSocketAddress(sIp, sPort));
24 |
25 | if(false == s.isConnected()){
26 | System.out.println(" 连接 "+sIp+":"+sPort+" 失败! ");
27 | return;
28 | }
29 | sockets[i-1] = s;
30 |
31 | } catch (Exception e) {
32 | //连接失败则小憩一会儿接着连
33 | Thread.sleep(500);
34 | e.printStackTrace();
35 | }
36 |
37 | //稍稍停顿一下,避免把服务端的握手队列打满
38 | if(0 == i % 500){
39 | Thread.sleep(500);
40 | System.out.println("连接 "+sIp+":"+sPort+" 成功了 "+i+" 条");
41 | }
42 | }
43 |
44 | //把所有连接都 hold 一会儿,方便观察
45 | Thread.sleep(300 * 1000);
46 |
47 | //3. 释放所有的连接
48 | System.out.println("关闭所有的连接...\n");
49 | for(int i = 0; i < MAX_CONNECTION_NUM; i++){
50 | sockets[i].close();
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/tests/network/test03/java/Makefile:
--------------------------------------------------------------------------------
1 | CLIENT_BINARY_NAME := "java Client"
2 | SERVER_BINARY_NAME := "java Server"
3 |
4 | .PHONY: build-cli
5 | build-cli:
6 | javac Client.java
7 |
8 | .PHONY: run-cli
9 | run-cli: build-cli
10 | sh tool.sh runcli $(CLIENT_BINARY_NAME)
11 |
12 | .PHONY: stop-cli
13 | stop-cli:
14 | sh tool.sh stopcli
15 |
16 | .PHONY: build-srv
17 | build-srv:
18 | javac Server.java
19 |
20 | .PHONY: run-srv
21 | run-srv: build-srv
22 | sh tool.sh runsrv $(SERVER_BINARY_NAME)
23 |
24 | .PHONY: stop-srv
25 | stop-srv:
26 | sh tool.sh stopsrv
27 |
28 | .PHONY: clean
29 | clean:
30 | rm -f *.class
31 |
--------------------------------------------------------------------------------
/tests/network/test03/java/Server.java:
--------------------------------------------------------------------------------
1 | import java.io.IOException;
2 | import java.net.ServerSocket;
3 | import java.net.Socket;
4 | import java.net.InetSocketAddress;
5 |
6 | public class Server {
7 |
8 | public static final int MAX_CONNECTION_NUM = 1100000;
9 |
10 | public static void main(String[] args) {
11 | if(2 != args.length){
12 | System.out.println("Usage: java Server \n");
13 | return;
14 | }
15 |
16 | String sIp = args[0];
17 | int sPort = Integer.parseInt(args[1]);
18 |
19 | //用数组将 socket 保存起来,防止连接被过早回收
20 | Socket[] sockets = new Socket[MAX_CONNECTION_NUM];
21 |
22 | try {
23 | ServerSocket ss = new ServerSocket();
24 | ss.bind(new InetSocketAddress(sIp, sPort), 1024);
25 | System.out.println("启动Server " + sIp + ":" + sPort + "...");
26 |
27 | int i = 0;
28 | while(true){
29 | try{
30 | Socket s = ss.accept();
31 | sockets[i] = s;
32 | i++;
33 | System.out.println("Server " + sIp + ":" + sPort + " 接收到第 " + i +" 条连接!");
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | }
37 | }
38 | } catch (IOException e) {
39 | e.printStackTrace();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/network/test03/java/tool.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #--------------------------- begin -------------------------
4 | #注意:这一部分的内容需要根据你自己的实验环境来设置
5 |
6 | #1.服务端的 IP
7 | #示例
8 | #SERVERIP="192.168.1.100"
9 | SERVERIP="192.168.1.100"
10 |
11 | #2.服务端的端口
12 | SERVERPORTS=(
13 | "8100"
14 | "8101"
15 | "8102"
16 | "8103"
17 | "8104"
18 | "8105"
19 | "8106"
20 | "8107"
21 | "8108"
22 | "8109"
23 | "8110"
24 | "8111"
25 | "8112"
26 | "8113"
27 | "8114"
28 | "8115"
29 | "8116"
30 | "8117"
31 | "8118"
32 | "8119"
33 | )
34 | #--------------------------- end -------------------------
35 |
36 | TYPE=$1
37 |
38 | exec_runcli(){
39 | for i in "${!SERVERPORTS[@]}"; do
40 | echo $CLIENT $SERVERIP ${SERVERPORTS[$i]} &
41 | $CLIENT $SERVERIP ${SERVERPORTS[$i]} &
42 | done
43 | }
44 |
45 | exec_stopcli(){
46 | ps -ef | grep java | grep Client | awk '{print $2}' | xargs kill -9
47 | }
48 |
49 | exec_runsrv(){
50 | for i in "${!SERVERPORTS[@]}"; do
51 | echo $SERVER 0.0.0.0 ${SERVERPORTS[$i]} &
52 | $SERVER 0.0.0.0 ${SERVERPORTS[$i]} &
53 | done
54 | }
55 |
56 | exec_stopsrv(){
57 | ps -ef | grep java | grep Server | awk '{print $2}' | xargs kill -9
58 | }
59 |
60 | case $TYPE in
61 | "runcli") CLIENT=$2; exec_runcli;;
62 | "stopcli") exec_stopcli;;
63 | "runsrv") SERVER=$2; exec_runsrv;;
64 | "stopsrv") exec_stopsrv;;
65 | *) echo "get unkown type $TYPE"; exit ;;
66 | esac
67 |
68 |
--------------------------------------------------------------------------------
/tests/network/test03/php/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: run-cli
2 | run-cli:
3 | sh tool.sh runcli
4 |
5 | .PHONY: stop-cli
6 | stop-cli:
7 | sh tool.sh stopcli
8 |
9 | .PHONY: run-srv
10 | run-srv:
11 | sh tool.sh runsrv
12 |
13 | .PHONY: stop-srv
14 | stop-srv:
15 | sh tool.sh stopsrv
16 |
--------------------------------------------------------------------------------
/tests/network/test03/php/client.php:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #define BUFFER_MAX 2048
10 |
11 | typedef int int32;
12 | typedef unsigned int u_int32;
13 | typedef unsigned char u_char;
14 | typedef unsigned short u_short;
15 |
16 | //参考内核 struct ethhdr 定义 (include/uapi/linux/if_ether.h)
17 | typedef struct eth_hdr {
18 | char h_dest[6];
19 | char h_source[6];
20 | short h_proto;
21 | }__attribute__((packed));
22 |
23 | //参考内核 struct iphdr 定义(include/uapi/linux/ip.h)
24 | typedef struct iphdr{
25 | #ifdef __LITTLE_ENDIAN_BIFIELD
26 | u_char ip_len:4, ip_ver:4;
27 | #else
28 | u_char ip_ver:4, ip_len:4;
29 | #endif
30 | u_char tos;
31 | u_short total_len;
32 | u_short id;
33 | u_short flags_off;
34 | u_char ttl;
35 | u_char protocol;
36 | u_short check;
37 | u_int32 saddr;
38 | u_int32 daddr;
39 | }__attribute__((packed));
40 |
41 | int main(int argc, char *argv[])
42 | {
43 | int sock;
44 | char buffer[BUFFER_MAX];
45 | int len;
46 |
47 | struct eth_hdr *mac_hdr;
48 | struct iphdr *ip_hdr;
49 | char* p;
50 |
51 | if( (sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0 ){
52 | printf("Create socket error.\n");
53 | exit(0);
54 | }
55 |
56 | while(1){
57 | len = recvfrom(sock, buffer, BUFFER_MAX, 0, NULL, NULL);
58 | if (len < 46) {
59 | printf("Catch packet length error.\n" );
60 | close(sock);
61 | exit(0);
62 | }
63 |
64 | printf("截获内容长度 %d\n", len);
65 |
66 | mac_hdr = buffer;
67 | ip_hdr = buffer + sizeof(struct ethhdr);
68 |
69 | printf("源 MAC:%X:%X:%X:%X:%X:%X",
70 | (u_char)mac_hdr->h_source[0],
71 | (u_char)mac_hdr->h_source[1],
72 | (u_char)mac_hdr->h_source[2],
73 | (u_char)mac_hdr->h_source[3],
74 | (u_char)mac_hdr->h_source[4],
75 | (u_char)mac_hdr->h_source[5]
76 | );
77 |
78 | printf(" ==> 目的 MAC:%X:%X:%X:%X:%X\n",
79 | (u_char)mac_hdr->h_dest[0],
80 | (u_char)mac_hdr->h_dest[1],
81 | (u_char)mac_hdr->h_dest[2],
82 | (u_char)mac_hdr->h_dest[3],
83 | (u_char)mac_hdr->h_dest[4],
84 | (u_char)mac_hdr->h_dest[5]
85 | );
86 |
87 | p = (char*)&ip_hdr->saddr;
88 | printf("源 IP: %d.%d.%d.%d",
89 | (u_char)p[0],
90 | (u_char)p[1],
91 | (u_char)p[2],
92 | (u_char)p[3]
93 | );
94 |
95 | p = (char*)&ip_hdr->daddr;
96 | printf(" ==> 目的 IP: %d.%d.%d.%d\n",
97 | (u_char)p[0],
98 | (u_char)p[1],
99 | (u_char)p[2],
100 | (u_char)p[3]
101 | );
102 |
103 | printf("协议类型:");
104 | switch(ip_hdr->protocol) {
105 | case IPPROTO_ICMP:
106 | printf("ICMP");
107 | break;
108 | case IPPROTO_IGMP:
109 | printf("IGMP");
110 | break;
111 | case IPPROTO_IPIP:
112 | printf("IPIP");
113 | break;
114 | case IPPROTO_TCP:
115 | printf("TCP");
116 | break;
117 | case IPPROTO_UDP:
118 | printf("UDP");
119 | break;
120 | case IPPROTO_RAW:
121 | printf("RAW");
122 | break;
123 | default:
124 | printf("Unknown type");
125 | break;
126 | }
127 |
128 | printf("\n\n");
129 | }
130 |
131 | close(sock);
132 | return 0;
133 | }
134 |
--------------------------------------------------------------------------------
/tests/network/test05/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: create-net1
2 | create-net1:
3 | ip netns add net1
4 | ip link add veth1 type veth peer name veth1_p
5 | ip link set veth1 netns net1
6 | ip netns exec net1 ip addr add 192.168.0.101/24 dev veth1
7 | ip netns exec net1 ip link set veth1 up
8 | ip netns exec net1 ip link list
9 | ip netns exec net1 ifconfig
10 | ip netns list
11 |
12 | .PHONY: create-net2
13 | create-net2:
14 | ip netns add net2
15 | ip link add veth2 type veth peer name veth2_p
16 | ip link set veth2 netns net2
17 | ip netns exec net2 ip addr add 192.168.0.102/24 dev veth2
18 | ip netns exec net2 ip link set veth2 up
19 | ip netns exec net2 ip link list
20 | ip netns exec net2 ifconfig
21 | ip netns list
22 |
23 | .PHONY: create-br
24 | create-br:
25 | brctl addbr br0
26 | ip addr add 192.168.0.100/24 dev br0
27 | ip link set dev veth1_p master br0
28 | ip link set dev veth2_p master br0
29 | ip link set veth1_p up
30 | ip link set veth2_p up
31 | ip link set br0 up
32 | brctl show
33 |
34 | .PHONY: clean
35 | clean:
36 | ip link delete br0
37 | ip link delete veth1_p
38 | ip link delete veth2_p
39 | ip link list
40 | ip netns del net1
41 | ip netns del net2
42 | ip netns list
43 |
--------------------------------------------------------------------------------
/tests/network/test05/index.md:
--------------------------------------------------------------------------------
1 |
2 | 本实验配套的 Makefile 位于本文件的同目录,其使用方法如下:
3 |
4 |
5 | **创建网络环境1**
6 |
7 | ```sh
8 | # make create-net1
9 | ```
10 |
11 | **创建网络环境2**
12 |
13 | ```sh
14 | # make create-net2
15 | ```
16 |
17 | **创建 bridge**,并把 net1、net2中的“网线插头”给接上
18 |
19 | ```sh
20 | # make create-br
21 | ```
22 |
23 | 从 net1 的网络环境中 ping 一下 net2 试试
24 |
25 | ```sh
26 | # ip netns exec net1 ping 192.168.0.102 -I veth1
27 | PING 192.168.0.102 (192.168.0.102) from 192.168.0.101 veth1: 56(84) bytes of data.
28 | 64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.037 ms
29 | 64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.008 ms
30 | 64 bytes from 192.168.0.102: icmp_seq=3 ttl=64 time=0.005 ms
31 | ```
32 |
33 | 最后,清理实验所创建的各种虚拟网络设备
34 |
35 | ```sh
36 | # make clean
37 | ```
--------------------------------------------------------------------------------
/tests/network/test06/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: create-net1
2 | create-net1:
3 | ip netns add net1
4 | ip netns exec net1 iptables -L
5 | ip netns exec net1 ip link list
6 | ip netns exec net1 ifconfig
7 |
8 | .PHONY: create-veth
9 | create-veth:
10 | ip link add veth1 type veth peer name veth1_p
11 | ip link set veth1 netns net1
12 | ip link list
13 | ip netns exec net1 ip link list
14 |
15 | .PHONY: start-veth
16 | start-veth:
17 | ip addr add 192.168.0.100/24 dev veth1_p
18 | ip netns exec net1 ip addr add 192.168.0.101/24 dev veth1
19 | ip link set dev veth1_p up
20 | ip netns exec net1 ip link set dev veth1 up
21 | ifconfig
22 | ip netns exec net1 ifconfig
23 |
24 | .PHONY: ping
25 | ping:
26 | ip netns exec net1 ping 192.168.0.100 -I veth1
27 |
28 | .PHONY: clean
29 | clean:
30 | ip link delete veth1_p
31 | ip link list
32 | ip netns del net1
33 | ip netns list
34 |
--------------------------------------------------------------------------------
/tests/network/test06/index.md:
--------------------------------------------------------------------------------
1 | 创建网络环境1
2 |
3 | ```sh
4 | # make create-net1
5 | ```
6 |
7 | 创建一对儿 veth,并把一头放到 net1中。分别在母机和 net1 中查看设备信息
8 |
9 | ```sh
10 | # make create-veth
11 | ```
12 |
13 | 配置 IP 并启动 veth
14 |
15 | ```sh
16 | # make start-veth
17 | ```
18 |
19 | ping一下试试
20 |
21 | ```sh
22 | # make ping
23 | ```
24 |
25 | 实验结果后,清理实验环境
26 |
27 | ```sh
28 | # make clean
29 | ```
--------------------------------------------------------------------------------
/tests/network/test07/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: create-net1
2 | create-net1:
3 | ip netns add net1
4 | ip link add veth1 type veth peer name veth1_p
5 | ip link set veth1 netns net1
6 | ip netns exec net1 ip addr add 192.168.0.2/24 dev veth1 # IP
7 | ip netns exec net1 ip link set veth1 up
8 | ip netns exec net1 ip link list
9 | ip netns exec net1 ifconfig
10 | ip netns exec net1 route add default gw 192.168.0.1 veth1 # 默认网关
11 | ip netns exec net1 route -n
12 |
13 | .PHONY: create-br
14 | create-br:
15 | brctl addbr br0
16 | ip addr add 192.168.0.1/24 dev br0
17 | ip link set dev veth1_p master br0
18 | ip link set veth1_p up
19 | ip link set br0 up
20 | brctl show
21 |
22 | .PHONY: create-nat
23 | create-nat:
24 | sysctl net.ipv4.conf.all.forwarding=1
25 | iptables -P FORWARD ACCEPT
26 | iptables -t nat -A POSTROUTING -s 192.168.0.0/24 ! -o br0 -j MASQUERADE
27 | iptables -t nat -A PREROUTING ! -i br0 -p tcp -m tcp --dport 8088 -j DNAT --to-destination 192.168.0.2:80
28 | iptables-save
29 |
30 | .PHONY: clean
31 | clean:
32 | ip link delete br0
33 | ip link delete veth1_p
34 | ip link list
35 | ip netns del net1
36 | ip netns list
37 | iptables -t nat -L -n --line-numbers
38 | iptables -t nat -D PREROUTING 1 # TODO:待优化
39 | iptables -t nat -D POSTROUTING 1 # TODO:待优化
40 | iptables-save
41 |
--------------------------------------------------------------------------------
/tests/network/test07/index.md:
--------------------------------------------------------------------------------
1 |
2 | ## 准备工作
3 |
4 | 创建一个虚拟网络环境
5 |
6 | ```sh
7 | # make create-net1
8 | ```
9 |
10 | 创建一个 bridge,并和刚才的创建的 veth 建立连接
11 |
12 | ```sh
13 | # make create-br
14 | ```
15 |
16 | 进行 nat 配置
17 |
18 | ```sh
19 | # make create-nat
20 | ```
21 |
22 |
23 | ## 访问外部网络
24 |
25 | 选择一个母机能 ping 同的 ip,ping 之
26 |
27 | ```
28 | # ip netns exec net1 ping 10.\*.\*.\*
29 | ```
30 | 访问外网,要保证这个 ip 用母机能 ping
31 |
32 | ```sh
33 | PING 10.\*.\*.\* (10.\*.\*.\*) 56(84) bytes of data.
34 | 64 bytes from 10.\*.\*.\*: icmp_seq=1 ttl=57 time=2.12 ms
35 | 64 bytes from 10.\*.\*.\*: icmp_seq=2 ttl=57 time=1.76 ms
36 | ```
37 |
38 | ## 提供服务给外网调用
39 |
40 | 使用 nc 命令在虚拟网络中监听一个服务
41 | ```
42 | # ip netns exec net1 nc -lp 80
43 | ```
44 |
45 | 在另外一台机器上使用 telnent 连接这台机器上的 8088 端口。
46 |
47 | **注意**, telnet 需要指定的是容器所在的母机的 ip,但 8088 这个端口上的服务是由虚拟容器网络提供的。
48 |
49 | ```c
50 | # telnet 10.\*.\*.\* 8088
51 | Trying 10.\*.\*.\*...
52 | Connected to 10.\*.\*.\*.
53 | Escape character is '^]'.
54 | ......
55 | ```
56 |
57 |
58 |
--------------------------------------------------------------------------------
/tests/network/test08/Makefile:
--------------------------------------------------------------------------------
1 | SERVER_BINARY_NAME := "test-server"
2 | CLIENT_BINARY_NAME := "test-client"
3 |
4 | .PHONY: build-server
5 | build-server:
6 | gcc server.c -o $(SERVER_BINARY_NAME)
7 |
8 | .PHONY: run-server
9 | run-server:
10 | sh tool.sh runsrv ./$(SERVER_BINARY_NAME)
11 |
12 | .PHONY: stop-server
13 | stop-server:
14 | sh tool.sh stopsrv ./$(SERVER_BINARY_NAME)
15 |
16 | .PHONY: build-client
17 | build-client:
18 | gcc client.c -o $(CLIENT_BINARY_NAME)
19 |
20 | .PHONY: run-client
21 | run-client:
22 | ./$(CLIENT_BINARY_NAME) 0.0.0.0 6000
--------------------------------------------------------------------------------
/tests/network/test08/client.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #define MAX_CONNECTION_NUM 100
9 |
10 | int buildConnect(const char *sIp, int sPort)
11 | {
12 | int skFd;
13 | if((skFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
14 | {
15 | printf("\n Error : Could not create socket\n");
16 | return 0;
17 | }
18 |
19 | struct sockaddr_in srvAddr;
20 | srvAddr.sin_family = AF_INET;
21 | srvAddr.sin_addr.s_addr = inet_addr(sIp);
22 | srvAddr.sin_port = htons(sPort);
23 | if(connect(skFd, (struct sockaddr *)&srvAddr, sizeof(srvAddr)) < 0)
24 | {
25 | printf("\n Error : Connect Failed \n");
26 | return 0;
27 | }
28 |
29 | return skFd;
30 | }
31 |
32 | int main(int argc, char *argv[])
33 | {
34 | int i = 0, sPort, fd;
35 | char sIp[16];
36 |
37 | if(argc != 3)
38 | {
39 | printf("\n Usage: %s \n", argv[0]);
40 | return 1;
41 | }
42 |
43 | //1. 从命令行获取并解析local ip、server ip以及端口
44 | strcpy(sIp, argv[1]);
45 | sPort = atoi(argv[2]);
46 |
47 | //2. 开始建立连接
48 | int *sockets = (int *)malloc(sizeof(int) * MAX_CONNECTION_NUM);
49 | for(i = 1; i <= MAX_CONNECTION_NUM; i++)
50 | {
51 |
52 | fd = buildConnect(sIp, sPort);
53 | if(fd > 0)
54 | {
55 | sockets[i-1] = fd;
56 | printf("连接 %s:%d成功了 %d 条!\n", sIp, sPort, i);
57 | }
58 | else
59 | {
60 | return 1;
61 | }
62 | }
63 | sleep(300);
64 |
65 | //3. 释放所有的连接
66 | printf("关闭所有的连接...\n");
67 | for(i = 0; i < MAX_CONNECTION_NUM; i++)
68 | {
69 | close(sockets[i]);
70 | }
71 |
72 | return 0;
73 | }
74 |
--------------------------------------------------------------------------------
/tests/network/test08/server.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #define MAX_CONNECTION_NUM 1100000
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | char ip[16];
11 | int lisFd, conFd, port;
12 | struct sockaddr_in servAddr;
13 | pid_t pid;
14 |
15 |
16 | if(argc != 3)
17 | {
18 | printf("\n Usage: %s \n", argv[0]);
19 | return 1;
20 | }
21 |
22 | pid = getpid();
23 |
24 | //1. 从命令行获取并解析server ip以及端口
25 | strcpy(ip, argv[1]);
26 | port = atoi(argv[2]);
27 |
28 | //2. 启动服务
29 | //2.1 创建server socket
30 | if((lisFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
31 | {
32 | printf("Server %d Error : Could not create socket!\n", pid);
33 | return 0;
34 | }
35 |
36 | //2.2 设置端口重用
37 | int val =1;
38 | if (setsockopt(lisFd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val))<0)
39 | {
40 | printf("\n Server %d Error : setsockopt failed!\n", pid);
41 | return 0;
42 | }
43 |
44 | //2.3 bind绑定
45 | servAddr.sin_family = AF_INET;
46 | servAddr.sin_addr.s_addr = inet_addr(ip);
47 | servAddr.sin_port = htons(port);
48 | if(bind(lisFd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0)
49 | {
50 | printf("\n Server %d Error : Bind Failed! \n", pid);
51 | return 0;
52 | }
53 |
54 | //2.4 启动监听
55 | if((listen(lisFd, 1024)) < 0)
56 | {
57 | printf("\n Server %d Error : Listen Failed \n", pid);
58 | return 0;
59 | }
60 | else
61 | {
62 | printf("\n Start server on %s:%d successed, pid is %d\n", ip, port, pid);
63 | }
64 |
65 | //3. 接收连接
66 | int i = 0;
67 | int *sockets = (int *)malloc(sizeof(int) * MAX_CONNECTION_NUM);
68 | while(1)
69 | {
70 | conFd = accept(lisFd, (struct sockaddr*)NULL, NULL);
71 | if(conFd > 0)
72 | {
73 | sockets[i++] = conFd;
74 | printf("Server %s %d (%d) accept success:%d\n", ip, port, pid, i);
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/tests/network/test08/tool.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | exec_runsrv(){
4 | for((i=1;i<=5;i++)); do
5 | echo $SERVER 0.0.0.0 6000 &
6 | $SERVER 0.0.0.0 6000 &
7 | done
8 |
9 | }
10 |
11 | exec_stopsrv(){
12 | ps -ef | grep $SERVER | awk '{print $2}' | xargs kill -9 > /dev/null
13 | }
14 |
15 | TYPE=$1
16 | case $TYPE in
17 | "runsrv") SERVER=$2; exec_runsrv;;
18 | "stopsrv") SERVER=$2; exec_stopsrv;;
19 | *) echo "get unkown type $TYPE"; exit ;;
20 | esac
21 |
--------------------------------------------------------------------------------
/tests/network/test09/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: create-veth
2 | create-veth:
3 | ip link add veth1 type veth peer name veth1_p
4 | ip addr add 192.168.1.1/24 dev veth1
5 | ip addr add 192.168.1.2/24 dev veth1_p
6 | ip link set veth1 up
7 | ip link set veth1_p up
8 | ifconfig
9 |
10 | .PHONY: setting
11 | setting:
12 | echo 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter
13 | echo 0 > /proc/sys/net/ipv4/conf/veth1_p/rp_filter
14 | echo 1 > /proc/sys/net/ipv4/conf/veth1/accept_local
15 | echo 1 > /proc/sys/net/ipv4/conf/veth1_p/accept_local
16 |
17 | .PHONY: ping
18 | ping:
19 | ping 192.168.1.2 -I veth1
20 |
21 |
22 | .PHONY: clean
23 | clean:
24 | ip link delete veth1
25 | ip link delete veth1_p
--------------------------------------------------------------------------------
/tests/network/test09/main.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanfeizhang/coder-kung-fu/190f82d7a4c6f4ef09805a07866b9b5bf34724aa/tests/network/test09/main.c
--------------------------------------------------------------------------------