doc.h
00001
00002
00072
00073 }\endverbatim
00074
00075 Here the idea is that TRACER is a developer supplied macro that,
00076 when turned on, will print the name of routine to aid debugging.
00077
00078 A code instrumented by traceString can be re-instrumented repeatly. In
00079 this way it can be used as development continues so that when
00080 "int Foo::Bar(int a)" becomes "int Foo::Bar(int* a)" the tool can
00081 make the changes to the variable "myName" rather than the developer.
00082
00083 A developer has control over what traceString places in the source
00084 code via a pattern file. This file describes how the function name
00085 should be expanded. The above pattern was:
00086
00087 \verbatim
00088 static const char* myName = "$(FQNAME)"; TRACER(t,myName,"$(CLASS)");
00089 \endverbatim
00090
00091 Where "\$(FQNAME)" is the "fully qualified" name of the routine, that is
00092 the name of the routine and its arguments. The name of the routine
00093 with out is arguements is available (\$(NAME): "Foo::bar") as well the
00094 class name ($(CLASS): "Foo"). If the pattern line was
00095
00096 \verbatim
00097 FUNC_TRACE("$(NAME)");
00098 \endverbatim
00099
00100 then the expansion would be:
00101
00102 \verbatim
00103 int Foo::bar(int a)
00104 { FUNC_TRACE("Foo::bar");
00105
00106 }\endverbatim
00107
00108 There can be more than one pattern line in the pattern file. There is
00109 a default pattern and other named patterns. So the pattern file might
00110 look like:
00111
00112 \verbatim
00113 default: static const char* myName = "$(FQNAME)";TRACER(t,myName,"$(CLASS)");
00114 ifdef : \n#ifdef DEBUG\nstatic const char* myName = "$(FQNAME)";\n#endif\n
00115 FT : FUNC_TRACE("$(NAME)");
00116 FC : FT_wClass("$(FQNAME)","$(CLASS)");
00117 None :
00118 \endverbatim
00119
00120 If the source code originally looked like this:
00121
00122 \verbatim
00123 int Foo::bar(int a)
00124 {
00125
00126 }
00127 int Foo::baz(double b)
00128 {
00129
00130 }
00131 int Foo::biz(string b)
00132 {
00133
00134 }
00135 int Foo::getSomething()
00136 {
00137
00138 }
00139 int Foo::foo()
00140 {
00141
00142
00143 }
00144
00145 \endverbatim
00146
00147 It would be converted to this:
00148
00149 \verbatim
00150 int Foo::bar(int a)
00151 { static const char* myName = "Foo::Bar(int a)"; TRACER(t,myName,"$(CLASS)");
00152
00153 }
00154 int Foo::baz(double b)
00155 { FUNC_TRACE("Foo::baz");
00156
00157 }
00158 int Foo::biz(string b)
00159 { FT_wCLASS("Foo::biz(string b)","Foo");
00160
00161 }
00162 int Foo::getSomething()
00163 {
00164
00165 }
00166 int Foo::foo()
00167 {
00168
00169 #ifdef DEBUG
00170 static const char* myName = "Foo::foo()";
00171 #endif
00172
00173
00174 }
00175 \endverbatim
00176
00177 Thus, if there is no trace string already in the function, the default pattern is
00178 used. A named pattern is specified with:
00179
00180 \verbatim
00181
00182 \endverbatim
00183
00184 where the string in the square brackets controls which pattern is
00185 used. The "Foo::getSomething()" shows the use of the "None" pattern
00186 where no extra code was placed that function.
00187
00188 traceString will also expand `\n' in the pattern file. In this
00189 way a single line pattern can expand to multi-line code. In this
00190 way C-preprocessor directives like #ifdef can be used.
00191
00192 The tool "traceString" is fast. It is written in C++ and flex. On a Pentium 4
00193 it converted 23000 lines of code in 61 files in 0.1 seconds.
00194
00195
00196 \subsection example Tracer Example
00197
00198 This package also contains a tracer package to control tracing.
00199 Applications can freely include this if they choose to help will
00200 tracing the applications tracing program execution.
00201
00202 "tracer" depends on C++ ability to have user code construct objects
00203 that are automatically deleted at their end of scope. So we
00204 construct a tracer object at the beginning of a routine and at the
00205 end of the tracer object's lifetime the destructor is called and
00206 we print a message that we are leaving the routine.
00207
00208 We may wish to have a finer control on which routines that print
00209 out. There are four tests that must be true in order that a
00210 routine prints an entering/leaving message. (ignoring watch
00211 lists, see watch list discussion that follows)
00212
00213 a) The static member variable must be turned on. Printing will only
00214 occur if it is true.
00215
00216 b) The routine name must not be in the always_excluded list
00217
00218 c) There is a routine list which is either an include or an
00219 exclude list. To be printed the routine name must be on
00220 include list or not on the exclude list. This list of routines
00221 can only be either an include list or an exclude list not both.
00222 If there is no list then this is ignored.
00223
00224 d) There is a class list which is either an include or an
00225 exclude list. To be printed the class name must be on
00226 include list or not on the exclude list. This list of classes
00227 can only be either an include list or an exclude list not both.
00228 If there is no list then this is ignored.
00229
00230
00231 Watch list rules:
00232
00233 The purpose of the watch list to print out the call tree execution
00234 starting at watched routine. That is a routine or class listed in
00235 a watch list will print out the routine and all routines called
00236 until the execution returns back to that routine. To print
00237 following has to be true.
00238
00239 a) Tracing must be turned on
00240
00241 b) A routine or class must be on the appropriate watch list
00242 (FUNCTION_WATCH for functions and KLASS_WATCH for classes)
00243
00244 OR
00245
00246 called by a watched routine
00247
00248 c) the regular class and function include/exclude lists are
00249 ignored.
00250
00251 d) The always exclude list is obeyed.
00252
00253 \verbatim
00254 \#include <iostream>
00255 \#include "tracer.h"
00256
00257 void c(int i)
00258 {
00259 static const char* myName = "c(int i)"; TRACER(tr, myName,"");
00260 std::cout << "In middle of c " << i << "\n";
00261 }
00262
00263 void b(int i)
00264 {
00265 static const char* myName = "b(int i)"; TRACER(tr, myName,"");
00266 std::cout << "In middle of b " << i << "\n";
00267 c(i+1);
00268 }
00269
00270 void a(int i)
00271 {
00272 static const char* myName = "a(int i)"; TRACER(tr, myName,"");
00273 std::cout << "In middle of a " << i << "\n";
00274 b(i+1);
00275 }
00276
00277
00278 int main()
00279 {
00280 static const char* myName = "main()"; TRACER(tr, myName,"");
00281 NamesList nl;
00282
00283 nl.push_back("e(int i)");
00284 nl.push_back("d(int i)");
00285 nl.push_back("c(int i)");
00286 nl.push_back("f(int i)");
00287
00288 Tracer::turnOnEnv(&std::cout);
00289
00290 std::cout << "\nTesting Function exclude list\n";
00291 Tracer::applyList(nl,Tracer::FUNCTION, Tracer::EXCLUDE);
00292 a(1);
00293
00294 std::cout << "\nTesting Function watch list\n";
00295 watchList.push_back("b(int i)");
00296 Tracer::applyList(watchList,Tracer::FUNCTION_WATCH, Tracer::INCLUDE);
00297 a(1);
00298 }
00299 \endverbatim
00300
00301 The above code shows the general behavior. The main routine
00302 builts a list of routines to ignore then it calls
00303 "Tracer::turnOnEnv(&std::cout);" to check to see if the
00304 environment variable TRACER_ON is defined with some value. If
00305 so then program execution is printed. In the above execution
00306 when traceing is on is:
00307
00308 \verbatim
00309 Testing Function exclude list
00310
00311 > a(int i)
00312 In middle of a 1
00313
00314 > b(int i)
00315 In middle of b 2
00316 In middle of c 3
00317
00318 < b(int i)
00319
00320 < a(int i)
00321
00322 Testing Function watch list
00323 In middle of a 1
00324
00325 > b(int i)
00326 In middle of b 2
00327
00328 > c(int i)
00329 In middle of c 3
00330
00331 < c(int i)
00332
00333 < b(int i)
00334 \endverbatim
00335
00336 Note that the entering and leaving messages are indented and
00337 that the "c(int i)" routine did not print because it was on the
00338 exclude list for the first call to a(1).
00339
00340 In the watch list execution, a is ignored because it is not on
00341 the watch list but "b(int i)" is. Note that "c(int i)" is
00342 printed because it is called by "b(int i)" and a watch list
00343 ignores the "FUNCTION" and "KLASS" include/exclude lists.
00344
00345 */
00346
00347
00348
00349