📄 debug.tex
字号:
\chapter{Debugging ns}\label{sec:debug}\ns is a simulator engine built in C++ and has an OTcl (Object-orientedTcl) interface that is used for configuration and commands. Thus in orderto debug \ns we will have to deal with debugging issues involvingboth OTcl and C++. This chapter gives debugging tips at Tcl and C++level and shows how to move to-fro the Tcl and C++ boundaries. It alsobriefly covers memory debugging and memory conservation in \ns.\section{Tcl-level Debugging}\label{sec:tcldebug}Ns supports Don Libs' Tcl debugger ( see its Postscript documentation athttp://expect.nist.gov/tcl-debug/tcl-debug.ps.Z and its source code athttp://expect.nist.gov/tcl-debug/tcl-debug.tar.gz ).Install the program or leave the source code in a directoryparallel to ns-2 and it will be built. Unlike expect, described in thetcl-debug documentation, we do not support the -D flag. To enter thedebugger, add the lines "debug 1" to your script at the appropriatelocation. In order to build ns with the debugging flag turned on,configure ns with configuration option "--enable-debug"and incase the Tcl debugger has been installed in a directory not parallelto ns-2, provide the path with configuration option "--with-tcldebug=<give/your/path/to/tcl-debug/library>".An useful debugging command is \code{$ns_ gen-map} which may be used to list all OTcl objects in a raw form. This is useful to correlate theposition and function of an object given its name. The name of the objectis the OTcl handle, usually of the form \code{_o###}. For TclObjects, thisis also available in a C++ debugger, such as gdb, as \code{this->name_}. \section{C++-Level Debugging}\label{sec:cdebug}Debugging at C++ level can be done using any standard debugger. Thefollowing macro for gdb makes it easier to see what happens in Tcl-basedsubroutines: \begin{program}## for Tcl codedefine pargvcset $i=0while $i < argc p argv[$i] set $i=$i+1 endenddocument pargvcPrint out argc argv[i]'s common in Tcl code.(presumes that argc and argv are defined)end\end{program}\section{Mixing Tcl and C debugging}\label{sec:mixdebug}It is a painful reality that when looking at the Tcl code and debuggingTcl level stuff, one wants to get at the C-level classes, and vice versa.This is a smallish hint on how one can make that task easier. If you arerunning ns through gdb, then the following incantation (shown below) getsyou access to the Tcl debugger. Notes on how you can then use this debugger and what you can dowith it are documented earlier in this chapter and at this URL(http://expect.nist.gov/tcl-debug/tcl-debug.ps.Z).\begin{program} (gdb) runStarting program: /nfs/prot/kannan/PhD/simulators/ns/ns-2/ns ...Breakpoint 1, AddressClassifier::AddressClassifier (this=0x12fbd8) at classifier-addr.cc:47(gdb) p this->name_$1 = 0x2711e8 "_o73"(gdb) call Tcl::instance().eval("debug 1")15: lappend auto_path $dbg_librarydbg15.3> w*0: application 15: lappend auto_path /usr/local/lib/dbgdbg15.4> Simulator info instances_o1dbg15.5> _o1 now0dbg15.6> # and other fun stuffdbg15.7> _o73 info classClassifier/Addrdbg15.8> _o73 info varsslots_ shift_ off_ip_ offset_ off_flags_ mask_ off_cmn_dbg15.9> c(gdb) wAmbiguous command "w": while, whatis, where, watch.(gdb) where#0 AddressClassifier::AddressClassifier (this=0x12fbd8) at classifier-addr.cc:47#1 0x5c68 in AddressClassifierClass::create (this=0x10d6c8, argc=4, argv=0xefffcdc0) at classifier-addr.cc:63...(gdb)\end{program}In a like manner, if you have started ns through gdb, then you can alwaysget gdb's attention by sending an interrupt, usually a \code{<Ctrl-c>}onberkeloidrones. However, note that these do tamper with the stack frame, and on occasion,may (sometimes can (and rarely, does)) screw up the stack so that, you maynot be in a position to resume execution. To its credit, gdb appears to besmart enough to warn you about such instances when you should treadsoftly, and carry a big stick. \section{Memory Debugging}\label{sec:memdebug}The first thing to do if you run out of memory is to make sure you can useall the memory on your system. Some systems by default limit the memoryavailable for individual programs to something less than all availablememory. To relax this, use the limit or ulimit command. These are shellfunctions---see the manual page for your shell for details. Limit is forcsh, ulimit is for sh/bash. Simulations of large networks can consume a lot of memory. Ns-2.0b17supports Gray Watson's dmalloc library (see its web documentation athttp://www.letters.com/dmalloc/ and get the source code fromftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz ).To add it, install it on your system or leave its source ina directory parallel to ns-2 and specify --with-dmalloc when configuringns. Then build all components of ns for which you want memory informationwith debugging symbols (this should include at least ns-2, possibly tclcland otcl and maybe also tcl). \subsection{Using dmalloc}\label{sec:usedmalloc}In order to use dmalloc do the following:\begin{itemize}\item Define an alias \begin{verbatim}for csh: alias dmalloc 'eval `\dmalloc -C \!*`', for bash: function dmalloc { eval `command dmalloc -b $*` }\end{verbatim}\item Next turn debugging on by typing \code{dmalloc -l logfile low }\item Run your program (which was configured and built with dmalloc asdescribed above). \item Interpret logfile by running \code{dmalloc_summarize ns <logfile}.(You need to download \code{dmalloc_summarize} separately.) \end{itemize}On some platforms you may need to link things statically to get dmalloc towork. On Solaris this is done by linking with these options:\code{"-Xlinker -B -Xlinker -static {libraries} -Xlinker -B -Xlinker -dynamic -ldl -lX11 -lXext"}.(You'll need to change Makefile. Thanks toHaobo Yu and Doug Smith for working this out.) We can interpret a sample summary produced from this process onns-2/tcl/ex/newmcast/cmcast-100.tcl with an exit statement after the200'th duplex-link-of-interefaces statement: Ns allocates ~6MB of memory. \\~1MB is due to TclObject::bind \\~900KB is StringCreate, all in 32-byte chunks \\~700KB is NewVar, mostly in 24-byte chunks \\Dmalloc\_summarize must map function names to and from their addresses. Itoften can't resolve addresses for shared libraries, so if you see lots ofmemory allocated by things beginning with ``ra='', that's what it is. Thebest way to avoid this problem is to build ns statically (if not all, thenas much as possible). Dmalloc's memory allocation scheme is somewhat expensive, plus there'sbookkeeping costs. Programs linked against dmalloc will consume morememory than against most standard mallocs. Dmalloc can also diagnose other memory errors (duplicate frees, bufferoverruns, etc.). See its documentation for details. \subsection{Memory Conservation Tips}\label{sec:memconserve}Some tips to saving memory (some of these use examples from the cmcast-100.tcl script): If you have many links or nodes: \begin{description}\item[Avoid \code{trace-all} :]\code{$ns trace-all $f} causes trace objects to be pushed on all links. If you only want to trace one link, there's no need for this overhead. Savingis about 14 KB/link. \item[Use arrays for sequences of variables :]Each variable, say \code{n$i} in \code{set n$i [$ns node]}, has a certainoverhead. If a sequence of nodes are created as an array, i.e.\code{n($i)}, then only one variable is created, consuming much lessmemory. Saving is about 40+ Byte/variable. \item[Avoid unnecessary variables :]If an object will not be referred to later on, avoid naming the object.E.g.\code{set cmcast(1) [new CtrMcast $ns $n(1) $ctrmcastcomp [list 1 1]]}would be better if replaced by\code{new CtrMcast $ns $n(1) $ctrmcastcomp [list 1 1]}.Saving is about 80 Byte/variable. \item[Run on top of FreeBSD :]malloc() overhead on FreeBSD is less than on some other systems. We willeventually port that allocator to other platofrms. \item[Dynamic binding (NEW) :]Using bind() in C++ consumes memory for each object you create. Thisapproach can be very expensive if you create many identical objects.Changing \code{bind()} to \code{delay_bind()} changes this memoryrequirement to per-class. See \ns/object.cc for an example of how to dobinding, either way. \end{description}\subsection{Some statistics collected by dmalloc}\label{sec:statdmalloc}A memory consumption problem occured in recent simulations (cmcast-[150,200,250].tcl), so we decided to take a closer look at scalingissue. See page http://www-mash.cs.berkeley.edu/ns/ns-scaling.htmlwhich demostrates the efforts in finding the bottlneck. The following table summarises the results of investigating thebottleneck:\\\begin{table}[h]\begin{center}\begin{tabular}{|c|c|c|}\hline {\em KBytes} &{\em cmcast-50.tcl(217 Links)} &{\em cmcast-100.tcl(950 Links)}\\\hline trace-all &8,084 &28,541\\\hlineturn off trace-all &5,095 &15,465 \\\hlineuse array &5,091 &15,459\\\hline remove unnecessay variables &5,087 &15,451 \\\hlineon SunOS &5,105 &15,484\\\hline\end{tabular}\end{center}\end{table}\section{Memory Leaks}\label{memleak}This section deals with memory leak problems in \ns, both in Tcl as wellas C/C++.\subsection{OTcl}\label{leakTcl}OTcl, especially TclCL, provides a way to allocate new objects. However,it does not accordingly provide a garbage collection mechanism for theseallocated objects. This can easily lead to unintentional memory leaks.Important: tools such as dmalloc and purify are unable to detect this kindof memory leaks. For example, consider this simple piece of OTcl script: \begin{program}set ns [new Simulator]for {set i 0} {$i < 500} {incr i} { set a [new RandomVariable/Constant]}\end{program}One would expect that the memory usage should stay the same after thefirst RandomVariable is allocated. However, because OTcl does not havegarbage collection, when the second RandomVariable is allocated, theprevious one is not freed and hence results in memory leak. Unfortunately,there is no easy fix for this, because garbage collection of allocatedobjects is essentially incompatible with the spirit of Tcl. The only wayto fix this now is to always explicitly free every allocated OTcl objectin your script, in the same way that you take care of malloc-ed object inC/C++. \subsection{C/C++}\label{leakC}Another source of memory leak is in C/C++. This is much easier to trackgiven tools that are specifically designed for this task, e.g., dmallocand purify. \ns has a special target ns-pure to build purified nsexecutable. First make sure that the macro PURIFY in the ns Makefilecontains the right -collector for your linker (check purify man page ifyou don't know what this is). Then simply type \code{make ns-pure}. Seeearlier sections in this chapter on how to use ns with libdmalloc.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -