《深入剖析Nginx》——2.5 加桩调试

2.5 加桩调试

如果我们对代码做过单元测试,那么肯定知道加桩的概念,简单点说就是为了让一个模块执行起来,额外添加的一些支撑代码。比如,我要简单测试一个实现某种排序算法的子函数的功能是否正常,那么我也许需要写一个main()函数,设置一个数组,提供一些乱序的数据,然后利用这些数据调用排序子函数(假设它提供的接口就是对数组的排序),然后printf打印排序后的结果,看是否排序正常,所有写的这些额外代码(main()函数、数组、printf打印)就是桩代码。

上面提到的这种用于单元测试的方法,同样也可以用来深度调试Nginx内部逻辑,而且Nginx很多的基础实现(比如slab机制、红黑树、chain链、array数组等)都比较独立,要调试它们只需提供少量的桩代码即可。

以Nginx的slab机制为例,我们通过下面所提供的这些桩代码即可调试该功能的具体实现。Nginx 的 slab 机制用于对多进程共享内存的管理,不过单进程也是一样的执行逻辑,除了加/解锁直通以外(即加锁时必定成功),所以我们采取最简单的办法,直接在 Nginx 本身的main()函数内插入我们的桩代码。当然,必须根据具体情况把桩代码放在合适的调用位置,比如这里的slab机制就依赖一些全局变量(像ngx_pagesize等),所以需要把桩代码的调用位置放在这些全局变量的初始化之后。

197: 代码片段2.5-1,文件名: nginx.c
198: void ngx_slab_test()
199: {
200:       ngx_shm_t shm;
201:       ngx_slab_pool_t *sp;
202:       u_char *file;
203:       void *one_page;
204:       void *two_page;
205:
206:       ngx_memzero(&shm, sizeof(shm));
207:       shm.size = 4 * 1024 * 1024;
208:       if (ngx_shm_alloc(&shm) != NGX_OK) {
209:              goto failed;
210:       }
211:
212:      sp = (ngx_slab_pool_t *) shm.addr;
213:      sp->end = shm.addr + shm.size;
214:      sp->min_shift = 3;
215:      sp->addr = shm.addr;
216:
217: #if (NGX_HAVE_ATOMIC_OPS)
218:       file = NULL;
219: #else
220:      #error must support NGX_HAVE_ATOMIC_OPS.
221: #endif
222:      if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) {
223:             goto failed;
224:      }
225:
226:      ngx_slab_init(sp);
227:
228:      one_page = ngx_slab_alloc(sp, ngx_pagesize);
229:      two_page = ngx_slab_alloc(sp, 2 * ngx_pagesize);
230:
231:      ngx_slab_free(sp, one_page);
232:      ngx_slab_free(sp, two_page);
233:
234:      ngx_shm_free(&shm);
235:
236:      exit(0);
237: failed:
238:      printf("failed.\n");
239:      exit(-1);
240: }
241: …
353:      if (ngx_os_init(log) != NGX_OK) {
354:             return 1;
355:      }
356:
357:      ngx_slab_test();
358: …

上面是修改之后的nginx.c源文件,直接make后生成新的Nginx,不过这个可执行文件不再是一个Web服务器,而是一个简单的调试slab机制的辅助程序。可以看到,程序在进入main()函数后先做一些初始化工作,然后通过ngx_slab_test()函数调入到桩代码内执行调试逻辑,完成既定目标后便直接exit()退出整个程序。

正常运行时,Nginx本身对内存的申请与释放是不可控的,所以直接去调试Nginx内存管理的slab机制的相关代码逻辑非常困难,利用这种加桩的办法,ngx_slab_alloc()申请内存和ngx_slab_free()释放内存都能精确控制,对每一次内存的申请或释放后,slab机制的内部结构发生了怎样的变化都能准确地掌握,对其相关逻辑的理解也就没有那么困难了。

时间: 2024-10-26 10:54:15

《深入剖析Nginx》——2.5 加桩调试的相关文章

《深入剖析Nginx》一第2章  跟踪与调试

第2章 跟踪与调试 深入剖析Nginx 跟踪与调试,不仅是我们解决程序Bug的有力途径,也是帮助我们理解现有代码的有效方法.通过跟踪程序执行的过程,我们可以清楚地了解程序的内部逻辑,对于不明就里的实现细节,调试查看程序内部变量也能更好地帮助我们做出正确的理解.本章将介绍一些跟踪与调试程序的方法,除了最基本的 gdb 调试,我还将结合个人经验,介绍一些相对高级的应用技巧.

《深入剖析Nginx》一2.1 利用gdb调试

2.1 利用gdb调试 深入剖析Nginx gdb是Linux下调试程序的常用工具,任何Linux开发工程师初学程序调试时第一个接触到的工具应该就是gdb.关于gdb本身的详细用法,我们不多详述,读者可以参考gdb官网手册1,而在这里,我们将重点介绍一些与Nginx相关的注意点与调试技巧. 2.1.1 绑定Nginx到gdb 利用gdb调式Nginx,首先得在生成Nginx程序时把-g编译选项打开.当然,这并不是说不打开-g选项就无法用gdb调试它,只是会因为缺少相应的符号信息导致调试不便,而此

《深入剖析Nginx》一2.3 利用strace/pstack调试Nginx

2.3 利用strace/pstack调试Nginx 深入剖析NginxLinux下有两个命令strace1和ltrace2可以分别用来查看一个应用程序在运行过程中所发起的系统函数调用和动态库函数调用,这对作为标准应用程序的Nginx自然同样可用.由于这两个命令大同小异,下面就仅以strace为例做简单介绍,大致了解一些它能帮助我们获取哪些有用的调试信息.关于strace/ltrace以及后面介绍的pstack更多的用法请参考对应的Man手册. 从strace的Man手册可以看到几个有用的选项.

《深入剖析Nginx》一2.6 特殊应用逻辑的调试

2.6 特殊应用逻辑的调试 深入剖析Nginx前面所讲的调试方法都是针对Nginx本身很容易跑到的逻辑,而对于某些只有在特定情况下才会被执行到的代码,又该怎样去调试呢?举个例子,我们知道Nginx里有大量的超时处理,比如,如果读取客户端请求头部数据超时,Nginx就将执行对应的超时处理函数,假设我想通过单步执行的方式来了解这部分相关逻辑,无疑就得让Nginx的执行逻辑走到这条路径上来.由于此时影响Nginx行为的决定因素是客户端所发送的请求头部数据,我们就必须在客户端做动作来构造出这种场景.一般

《深入剖析Nginx》一导读

前 言 深入剖析Nginx慕名对Nginx源码进行学习与研究是早在2008年的事情.当时正在为职业规划与未来发展困惑不已,一筹莫展之际不知从哪里得知高性能服务器是一个很有"前途"的努力方向,几经搜索又机缘偶合地得识Lighttpd与Nginx.在逐步了解和熟悉它们的源码后,我开始感到自己的无知与浅薄,发现原来代码也可以写得如此优雅. 我已编著过一本<Lighttpd源码分析>.先解析Lighttpd源码并没有什么特别的原因,只是因为在当时Lighttpd比Nginx要火,应

《深入剖析Nginx》一2.2 利用日志信息跟踪Nginx

2.2 利用日志信息跟踪Nginx 深入剖析Nginx 优秀的程序都会带有自己的日志输出接口,并且一般还会给出不同等级的输出级别,以便于重次信息的过滤,比如 Linux 内核的日志输出标准接口为 printk,并且给出了KERN_EMERG.KERN_ALERT.KERN_DEBUG等这样的输出等级.Nginx 与此类似,下面具体来看. 为了获取最丰富的日志信息,我们在进行configure配置时,需要把--with-debug选项加上,这样能生成一个名为NGX_DEBUG的宏,而在Nginx源

《深入剖析Nginx》一1.4 源码分析工具

1.4 源码分析工具 深入剖析Nginx 对于Windows平台,首选Source Insight1源码阅读工具.该工具功能强大,根据其官方网站的介绍,Source Insight是一款面向项目开发的程序编辑器和代码浏览器,它拥有内置的对C/C++.C#和Java等程序的分析功能.Source Insight能自动分析和动态维护源码工程的符号数据库,并在用户查看代码时显示有用的对应上下文信息. 如果是在Linux平台下,则可以利用Vi2.Taglist3.Cscope4以及Ctag5这几个工具来

《深入剖析Nginx》一1.6 编译与执行

1.6 编译与执行 深入剖析Nginx Nginx的编译安装很简单,使用Linux下通用的三板斧即可:./configure.make.make install.当然,这样做的话,那么一切都是使用的默认配置,如果要做修改,则必须在执行configure时指定,比如对Nginx加上调试功能. [root@localhost nginx-1.2.0]# ./configure --with-debug 修改默认安装路径. [root@localhost nginx-1.2.0]# ./configu

《深入剖析Nginx》——导读

前言 慕名对Nginx源码进行学习与研究是早在2008年的事情.当时正在为职业规划与未来发展困惑不已,一筹莫展之际不知从哪里得知高性能服务器是一个很有"前途"的努力方向,几经搜索又机缘偶合地得识Lighttpd与Nginx.在逐步了解和熟悉它们的源码后,我开始感到自己的无知与浅薄,发现原来代码也可以写得如此优雅. 我已编著过一本<Lighttpd源码分析>.先解析Lighttpd源码并没有什么特别的原因,只是因为在当时Lighttpd比Nginx要火,应用得也较广:而近几年