├── .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 | ![avatar](imgs/double.png) 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 | ![avatar](imgs/course.png) 211 | 212 | 对这些视频内容感兴趣的同学可以通过下方二维码,或者在微信公众号「开发内功修炼」中回复「配套视频」观看。目前开放了 200 优惠券,优惠后是 299 一年。 213 | 214 | ![avatar](imgs/zsxq.png) 215 | 216 | 217 | ## 九、公众号二维码 218 | 219 | **敬请扫码关注微信公众号「开发内功修炼」,及时获得最新硬核文章!** 220 | ![avatar](imgs/official_accounts.jpg) 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 --------------------------------------------------------------------------------