0031002: Documentation - update Overview for 7.4.0
[occt.git] / dox / dev_guides / debug / debug.md
1 Debugging tools and hints {#occt_dev_guides__debug}
2 =========================
3
4 @tableofcontents
5
6 @section occt_debug_intro Introduction
7
8 This manual describes facilities included in OCCT to support debugging, and provides some hints for more efficient debug.
9
10 @section occt_debug_macro Compiler macro to enable extended debug messages
11
12 Many OCCT algorithms can produce extended debug messages, usually printed to cout.
13 These include messages on internal errors and special cases encountered, timing etc.
14 In OCCT versions prior to 6.8.0 most of these messages were activated by compiler macro *DEB*, enabled by default in debug builds.
15 Since version 6.8.0 this is disabled by default but can be enabled by defining compiler macro *OCCT_DEBUG*.
16
17 To enable this macro on Windows when building with Visual Studio projects, edit file custom.bat and add the line:
18
19     set CSF_DEFINES=OCCT_DEBUG
20
21 Some algorithms use specific macros for yet more verbose messages, usually started with OCCT_DEBUG_.
22 These messages can be enabled in the same way, by defining corresponding macro.
23
24 Note that some header files are modified when *OCCT_DEBUG* is enabled, hence binaries built with it enabled are not compatible with client code built without this option; this is not intended for production use.
25
26 @section occt_debug_exceptions Calling JIT debugger on exception
27
28 On Windows platform when using Visual Studio compiler there is a possibility to start the debugger automatically if an exception is caught in a program running OCCT. For this, set environment variable *CSF_DEBUG* to any value. Note that this feature works only if you enable OCCT exception handler in your application by calling *OSD::SetSignal()*.
29
30 @section occt_debug_bop Self-diagnostics in Boolean operations algorithm
31
32 In real-world applications modeling operations are often performed in a long sequence, while the user sees only the final result of the whole sequence. If the final result is wrong, the first debug step is to identify the offending operation to be debugged further. Boolean operation algorithm in OCCT provides a self-diagnostic feature which can help to do that step.
33
34 This feature can be activated by defining environment variable *CSF_DEBUG_BOP*, which should specify an existing writeable directory.
35
36 The diagnostic code checks validity of the input arguments and the result of each Boolean operation. When an invalid situation is detected, the report consisting of argument shapes and a DRAW script to reproduce the problematic operation is saved to the directory pointed by *CSF_DEBUG_BOP*.
37
38 Note that this feature does not applicable for UWP build.
39
40 @section occt_debug_call Functions for calling from debugger
41
42 Modern interactive debuggers provide the possibility to execute application code at a program break point. This feature can be used to analyse the temporary objects available only in the context of the debugged code. OCCT provides several global functions that can be used in this way.
43
44 Note that all these functions accept pointer to variable as <i>void*</i> to allow calling the function even when debugger does not recognize type equivalence or can not perform necessary type cast automatically. It is responsibility of the developer to provide the correct pointer. In general these functions are not guaranteed to work, thus use them with caution and at your own risk.
45
46 @subsection occt_debug_call_draw Interacting with DRAW
47
48 Open CASCADE Test Harness or @ref occt_user_guides__test_harness "DRAW" provides an extensive set of tools for inspection and analysis of OCCT shapes and geometric objects and is mostly used as environment for prototyping and debugging OCCT-based algorithms.
49
50 In some cases the objects to be inspected are available in DRAW as results of DRAW commands. In other cases, however, it is necessary to inspect intermediate objects created by the debugged algorithm. To support this, DRAW provides a set of commands allowing the developer to store intermediate objects directly from the debugger stopped at some point during the program execution (usually at a breakpoint).
51
52 ~~~~~
53 const char* Draw_Eval (const char *theCommandStr)
54 ~~~~~
55
56 Evaluates a DRAW command or script.
57 A command is passed as a string parameter.
58
59 ~~~~~
60 const char* DBRep_Set (const char* theNameStr, void* theShapePtr)
61 ~~~~~
62
63 Sets the specified shape as a value of DRAW interpreter variable with the given name.
64 - *theNameStr* -- the DRAW interpreter variable name to set.
65 - *theShapePtr* -- a pointer to *TopoDS_Shape* variable.
66
67 ~~~~~
68 const char* DBRep_SetComp (const char* theNameStr, void* theListPtr)
69 ~~~~~
70
71 Makes a compound from the specified list of shapes and sets it as a value of DRAW interpreter variable with the given name.
72 - *theNameStr* -- the DRAW interpreter variable name to set.
73 - *theListPtr* -- a pointer to *TopTools_ListOfShape* variable.
74
75 ~~~~~
76 const char* DrawTrSurf_Set (const char* theNameStr, void* theHandlePtr)
77 const char* DrawTrSurf_SetPnt (const char* theNameStr, void* thePntPtr)
78 const char* DrawTrSurf_SetPnt2d (const char* theNameStr, void* thePnt2dPtr)
79 ~~~~~
80
81 Sets the specified geometric object as a value of DRAW interpreter variable with the given name.
82 - *theNameStr* -- the DRAW interpreter variable name to set.
83 - *theHandlePtr* -- a pointer to the geometric variable (Handle to *Geom_Geometry* or *Geom2d_Curve* or descendant) to be set.
84 - *thePntPtr* -- a pointer to the variable of type *gp_Pnt* to be set.
85 - *thePnt2dPtr* -- a pointer to the variable of type *gp_Pnt2d* to be set.
86
87 All these functions are defined in *TKDraw* toolkit and return a string indicating the result of execution.
88
89 @subsection occt_debug_call_brep Saving and dumping shapes and geometric objects
90
91 The following functions are provided by *TKBRep* toolkit and can be used from debugger prompt:
92
93 ~~~~~
94 const char* BRepTools_Write (const char* theFileNameStr, void* theShapePtr)
95 ~~~~~
96
97 Saves the specified shape to a file with the given name.
98 - *theFileNameStr* -- the name of the file where the shape is saved.
99 - *theShapePtr* -- a pointer to *TopoDS_Shape* variable.
100
101 ~~~~~
102 const char* BRepTools_Dump (void* theShapePtr)
103 const char* BRepTools_DumpLoc (void* theShapePtr)
104 ~~~~~
105
106 Dumps shape or its location to cout.
107 - *theShapePtr* -- a pointer to *TopoDS_Shape* variable.
108
109 The following function is provided by *TKMesh* toolkit:
110
111 ~~~~~
112 const char* BRepMesh_Dump (void* theMeshHandlePtr, const char* theFileNameStr)
113 ~~~~~
114
115 Stores mesh produced in parametric space to BREP file.
116 - *theMeshHandlePtr* -- a pointer to *Handle(BRepMesh_DataStructureOfDelaun)* variable.
117 - *theFileNameStr* -- the name of the file where the mesh is stored.
118
119 The following functions are provided by *TKTopTest* toolkit:
120
121 ~~~~~
122 const char* MeshTest_DrawLinks(const char* theNameStr, void* theFaceAttr)
123 const char* MeshTest_DrawTriangles(const char* theNameStr, void* theFaceAttr)
124 ~~~~~
125
126 Sets the edges or triangles from mesh data structure of type *Handle(BRepMesh_FaceAttribute)* as DRAW interpreter variables, assigning a unique name in the form "<theNameStr>_<index>" to each object.
127 - *theNameStr* -- the prefix to use in names of objects.
128 - *theFaceAttr* -- a pointer to *Handle(BRepMesh_FaceAttribute)* variable.
129
130 The following additional function is provided by *TKGeomBase* toolkit:
131
132 ~~~~~
133 const char* GeomTools_Dump (void* theHandlePtr)
134 ~~~~~
135
136 Dump geometric object to cout.
137 - *theHandlePtr* -- a pointer to the geometric variable (<i>Handle</i> to *Geom_Geometry* or *Geom2d_Curve* or descendant) to be set.
138
139
140 @section occt_debug_dump_json Dump OCCT objects into Json
141
142 Many OCCT classes may dump the current state into the stream. This stream contains the information about the class field into the field value/s.
143 It is possible to prepare recursive dump using corresponded macro for class fields. The depth of this recursion is defined by parameter of the dump.
144 The object defines What parameters should be presented in the Dump. The usual way is to dump all object fields.
145
146 @subsection occt_debug_dump_json_object Implementation in object
147
148 Steps to prepare dump of the object into json:
149
150 1. Create method <b>DumpJson</b>. The method should accept the output stream and the depth for the fields dump.
151 Depth, equal to zero means that only fields of this class should be dumped. Default value -1 means that whole tree of dump will be built recursively calling dump of all fields.
152
153 2. Put into the first row of the method <b>OCCT_DUMP_CLASS_BEGIN</b>. This macro creates a local variable, that will open Json structure on start, and close on exit from this method.
154
155 3. Add several macro to store field values.
156
157 The following macro are defined to cover the object parameters into json format:
158
159 | Name                        | Result in json |
160 | :-------------------------- | :--------|
161 | OCCT_DUMP_FIELD_VALUE_NUMERICAL  | "field": value |
162 | OCCT_DUMP_FIELD_VALUE_STRING     | "field": "value" |
163 | OCCT_DUMP_FIELD_VALUE_POINTER    | "field": "pointer address" |
164 | OCCT_DUMP_FIELD_VALUES_DUMPED    | "field": { result of field->DumpJson(...) } |
165 | OCCT_DUMP_FIELD_VALUES_NUMERICAL | "field": [value_1, ..., value_n]
166 | OCCT_DUMP_FIELD_VALUES_STRING    | "field": ["value_1", ..., "value_n"]
167 | OCCT_DUMP_BASE_CLASS   | "kind": { result of kind::DumpJson(...) } |
168
169 @subsection occt_debug_dump_json_draw Using in DRAW
170
171 In DRAW, key '-dumpJson' is used to dump an object.
172 It is implemented in 'vaspect' and 'boundingbox' commands.
173
174 Json output for Bnd_OBB (using command 'bounding v -obb -dumpJson'):
175
176 ~~~~~
177 "Bnd_OBB": {
178    "Center": {
179       "gp_XYZ": [1, 2, 3]
180    },
181    "Axes[0]": {
182        "gp_XYZ:" [1, 0, 0]
183    },
184    "Axes[1]": {
185        "gp_XYZ:" [0, 1, 0]
186    },
187    "Axes[2]": {
188        "gp_XYZ:" [0, 0, 1]
189    },
190    "HDims[0]": 0,
191    "HDims[1]": 0,
192    "HDims[2]": 0,
193    "IsAABox": 1,
194 }
195 ~~~~~
196
197 @section occt_debug_vstudio Using Visual Studio debugger 
198
199 @subsection occt_debug_vstudio_command Command window 
200
201 Visual Studio debugger provides the Command Window (can be activated from menu <b>View / Other Windows / Command Window</b>), which can be used to evaluate variables and expressions interactively in a debug session (see https://msdn.microsoft.com/en-us/library/c785s0kz.aspx). Note that the Immediate Window can also be used but it has some limitations, e.g. does not support aliases.
202
203 When the execution is interrupted by a breakpoint, you can use this window to call the above described functions in context of the currently debugged function. Note that in most cases you will need to specify explicitly context of the function by indicating the name of the DLL where it is defined.
204
205 For example, assume that you are debugging a function, where local variable *TopoDS_Edge* *anEdge1* is of interest.
206 The following set of commands in the Command window will save this edge to file *edge1.brep*, then put it to DRAW variable *e1* and show it maximized in the axonometric DRAW view:
207
208 ~~~~~
209 >? ({,,TKBRep.dll}BRepTools_Write)("d:/edge1.brep",(void*)&anEdge1)
210 0x04a2f234 "d:/edge1.brep"
211 >? ({,,TKDraw.dll}DBRep_Set)("e1",(void*)&anEdge1)
212 0x0369eba8 "e1"
213 >? ({,,TKDraw.dll}Draw_Eval)("donly e1; axo; fit")
214 0x029a48f0 ""
215 ~~~~~
216
217 For convenience it is possible to define aliases to commands in this window, for instance (here ">" is prompt provided by the command window; in the Immediate window this symbol should be entered manually):
218
219 ~~~~~
220 >alias deval      ? ({,,TKDraw}Draw_Eval)
221 >alias dsetshape  ? ({,,TKDraw}DBRep_Set)
222 >alias dsetcomp   ? ({,,TKDraw}DBRep_SetComp)
223 >alias dsetgeom   ? ({,,TKDraw}DrawTrSurf_Set)
224 >alias dsetpnt    ? ({,,TKDraw}DrawTrSurf_SetPnt)
225 >alias dsetpnt2d  ? ({,,TKDraw}DrawTrSurf_SetPnt2d)
226 >alias saveshape  ? ({,,TKBRep}BRepTools_Write)
227 >alias dumpshape  ? ({,,TKBRep}BRepTools_Dump)
228 >alias dumploc    ? ({,,TKBRep}BRepTools_DumpLoc)
229 >alias dumpmesh   ? ({,,TKMesh}BRepMesh_Dump)
230 >alias dumpgeom   ? ({,,TKGeomBase}GeomTools_Dump)
231 ~~~~~ 
232
233 Note that aliases are stored in the Visual Studio user's preferences and it is sufficient to define them once on a workstation. With these aliases, the above example can be reproduced easier (note the space symbol after alias name!):
234
235 ~~~~~
236 >saveshape ("d:/edge1.brep",(void*)&anEdge1)
237 0x04a2f234 "d:/edge1.brep"
238 >dsetshape ("e1",(void*)&anEdge1)
239 0x0369eba8 "e1"
240 >deval ("donly e1; axo; fit")
241 0x029a48f0 ""
242 ~~~~~
243
244 Note that there is no guarantee that the call will succeed and will not affect the program execution, thus use this feature at your own risk. In particular, the commands interacting with window system (such as *axo*, *vinit*, etc.) are known to cause application crash when the program is built in 64-bit mode. To avoid this, it is recommended to prepare all necessary view windows in advance, and arrange these windows to avoid overlapping with the Visual Studio window, to ensure that they are visible during debug. 
245
246 @subsection occt_debug_vstudio_watch Customized display of variables content
247
248 Visual Studio provides a way to customize display of variables of different types in debugger windows (Watch, Autos, Locals, etc.).
249
250 In Visual Studio 2005-2010 the rules for this display are defined in file *autoexp.dat* located in  subfolder *Common7\\Packages\\Debugger* of the Visual Studio installation folder (hint: the path to that folder is given in the corresponding environment variable, e.g. *VS100COMNTOOLS* for vc10). This file contains two sections: *AutoExpand* and *Visualizer*. The following rules can be added to these sections to provide more convenient display of some OCCT data types. 
251
252 ### \[AutoExpand\] section 
253
254 ~~~~~
255 ; Open CASCADE classes
256 Standard_Transient=<,t> count=<count,d>
257 Handle_Standard_Transient=<entity,x> count=<entity->count,d> <,t>
258 TCollection_AsciiString=<mylength,d> <mystring,s>
259 TCollection_HAsciiString=<myString.mylength,d> <myString.mystring,s>
260 TCollection_ExtendedString=<mylength,d> <mystring,su>
261 TCollection_HExtendedString=<myString.mylength,d> <myString.mystring,su>
262 TCollection_BaseSequence=size=<Size,d> curr=<CurrentIndex,d>
263 TCollection_BasicMap=size=<mySize,d>
264 NCollection_BaseSequence=size=<mySize,d> curr=<myCurrentIndex,d>
265 NCollection_BaseList=length=<myLength,d>
266 NCollection_BaseMap=size=<mySize,d> buckets=<myNbBuckets>
267 NCollection_BaseVector=length=<myLength,d>
268 TDF_Label=<myLabelNode,x> tag=<myLabelNode->myTag>
269 TDF_LabelNode=tag=<myTag,d>
270 TDocStd_Document=format=<myStorageFormat.mystring,su> count=<count,d> <,t>
271 TopoDS_Shape=<myTShape.entity,x> <myOrient>
272 gp_XYZ=<x,g>, <y,g>, <z,g>
273 gp_Pnt=<coord.x,g>, <coord.y,g>, <coord.z,g>
274 gp_Vec=<coord.x,g>, <coord.y,g>, <coord.z,g>
275 gp_Dir=<coord.x,g>, <coord.y,g>, <coord.z,g>
276 gp_XY=<x,g>, <y,g>
277 gp_Pnt2d=<coord.x,g>, <coord.y,g>
278 gp_Dir2d=<coord.x,g>, <coord.y,g>
279 gp_Vec2d=<coord.x,g>, <coord.y,g>
280 gp_Mat2d={<matrix[0][0],g>,<matrix[0][1],g>}, {<matrix[1][0],g>,<matrix[1][1],g>}
281 gp_Ax1=loc={<loc.coord.x,g>, <loc.coord.y,g>, <loc.coord.z,g>} vdir={<vdir.coord.x,g>, <vdir.coord.y,g>, <vdir.coord.z,g>}
282 ~~~~~ 
283
284 ### \[Visualizer\] section
285
286 ~~~~~
287 ; Open CASCADE classes
288
289 NCollection_Handle<*> {
290   preview ( *((($T0::Ptr*)$e.entity)->myPtr) )
291   children ( (($T0::Ptr*)$e.entity)->myPtr )
292 }
293
294 NCollection_List<*> {
295   preview ( #( "NCollection_List [", $e.myLength, "]" ) )
296   children ( #list( head: $c.myFirst, next: myNext ) : #(*($T1*)(&$e+1)) )
297 }
298
299 NCollection_Array1<*> {
300   preview ( #( "NCollection_Array1 [", $e.myLowerBound, "..", $e.myUpperBound, "]" ) )
301   children ( #array( expr: $c.myData[$i], size: 1+$c.myUpperBound ) )
302 }
303
304 math_Vector {
305   preview ( #( "math_Vector [", $e.LowerIndex, "..", $e.UpperIndex, "]" ) )
306   children ( #array ( expr: ((double*)($c.Array.Addr))[$i], size: 1+$c.UpperIndex ) )
307 }
308
309 TColStd_Array1OfReal {
310   preview ( #( "Array1OfReal [", $e.myLowerBound, "..", $e.myUpperBound, "]" ) )
311   children ( #array ( expr: ((double*)($c.myStart))[$i], size: 1+$c.myUpperBound ) )
312 }
313
314 Handle_TColStd_HArray1OfReal {
315   preview ( #( "HArray1OfReal [",
316                ((TColStd_HArray1OfReal*)$e.entity)->myArray.myLowerBound, "..", 
317                ((TColStd_HArray1OfReal*)$e.entity)->myArray.myUpperBound, "] ",
318                [$e.entity,x], " count=", $e.entity->count ) )
319   children ( #array ( expr: ((double*)(((TColStd_HArray1OfReal*)$e.entity)->myArray.myStart))[$i],
320                       size: 1+((TColStd_HArray1OfReal*)$e.entity)->myArray.myUpperBound ) )
321 }
322
323 TColStd_Array1OfInteger {
324   preview ( #( "Array1OfInteger [", $e.myLowerBound, "..", $e.myUpperBound, "]" ) )
325   children ( #array ( expr: ((int*)($c.myStart))[$i], size: 1+$c.myUpperBound ) )
326 }
327
328 Handle_TColStd_HArray1OfInteger {
329   preview ( #( "HArray1OfInteger [",
330                ((TColStd_HArray1OfInteger*)$e.entity)->myArray.myLowerBound, "..", 
331                ((TColStd_HArray1OfInteger*)$e.entity)->myArray.myUpperBound, "] ",
332                [$e.entity,x], " count=", $e.entity->count ) )
333   children ( #array ( expr: ((int*)(((TColStd_HArray1OfInteger*)$e.entity)->myArray.myStart))[$i],
334                       size: 1+((TColStd_HArray1OfInteger*)$e.entity)->myArray.myUpperBound ) )
335 }
336
337 Handle_TCollection_HExtendedString {
338   preview ( #( "HExtendedString ", [$e.entity,x], " count=", $e.entity->count, 
339                " ", ((TCollection_HExtendedString*)$e.entity)->myString ) )
340   children ( #([actual members]: [$e,!] ) )
341 }
342
343 Handle_TCollection_HAsciiString {
344   preview ( #( "HAsciiString ", [$e.entity,x], " count=", $e.entity->count, 
345                " ", ((TCollection_HAsciiString*)$e.entity)->myString ) )
346   children ( #([actual members]: [$e,!], 
347              #array( expr: ((TCollection_HAsciiString*)$e.entity)->myString.mystring[$i], 
348                      size: ((TCollection_HAsciiString*)$e.entity)->myString.mylength) ) )
349 }
350 ~~~~~
351
352 In Visual Studio 2012 and later, visualizers can be put in a separate file in subdirectory *Visualizers*. See file *occt.natvis* for example.
353
354 @section occt_debug_perf Performance measurement tools
355
356 It is recommended to use specialized performance analysis tools to profile OCCT and application code.
357 However, when such tools are not available or cannot be used for some reason, tools provided by OSD package can be used: low-level C functions and macros defined in *OSD_PerfMeter.h* and *OSD_PerfMeter* class.
358
359 This tool maintains an array of 100 global performance counters that can be started and stopped independently. Adding a performance counter to a function of interest allows to get statistics on the number of calls and the total execution time of the function.
360 * In C++ code, this can be achieved by creating local variable *OSD_PerfMeter* in each block of code to be measured.
361 * In C or Fortran code, use functions *perf_start_meter* and *perf_stop_meter* to start and stop the counter.
362
363 Note that this instrumentation is intended to be removed when the profiling is completed.
364
365 Macros provided in *OSD_PerfMeter.h* can be used to keep instrumentation code permanently but enable it only when macro *PERF_ENABLE_METERS* is defined.
366 Each counter has its name shown when the collected statistics are printed.
367
368 In DRAW, use command *dperf* to print all performance statistics.
369
370 Note that performance counters are not thread-safe.