0023818: Extend OSD_MemInfo to report C heap statistics
[occt.git] / src / Draw / Draw_BasicCommands.cxx
1 // Created on: 1995-02-23
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21 #include <Standard_Macro.hxx>
22 #include <Standard_Stream.hxx>
23 #include <Standard_SStream.hxx>
24 #include <Standard_Version.hxx>
25
26 #include <Draw.ixx>
27 #include <Draw_Appli.hxx>
28 #include <Draw_Chronometer.hxx>
29 #include <Draw_Printer.hxx>
30
31 #include <Message.hxx>
32 #include <Message_Messenger.hxx>
33
34 #include <OSD_MemInfo.hxx>
35 #include <OSD_MAllocHook.hxx>
36 #include <OSD_Chronometer.hxx>
37 #include <OSD.hxx>
38 #include <OSD_Exception_CTRL_BREAK.hxx>
39
40 #ifdef _WIN32
41
42 #include <windows.h>
43 #include <winbase.h>
44 #include <process.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <time.h>
48 #include <limits>
49
50 #define RLIM_INFINITY   0x7fffffff
51
52 static clock_t CPU_CURRENT; // cpu time already used at last
53                             // cpulimit call. (sec.) 
54
55 #else /* _WIN32 */
56
57 #include <sys/resource.h>
58
59 #ifdef HAVE_CONFIG_H
60 # include <config.h>
61 #endif
62
63 #ifdef HAVE_STRINGS_H
64 # include <strings.h>
65 #endif
66
67 #if defined(HAVE_TIME_H)
68 # include <time.h>
69 #endif
70
71 #ifdef HAVE_SIGNAL_H
72 # include <signal.h>
73 #endif
74
75 #ifdef HAVE_SYS_SIGNAL_H
76 # include <sys/signal.h>
77 #endif
78
79 #if defined (__hpux) || defined ( HPUX )
80 #define RLIM_INFINITY   0x7fffffff
81 #define RLIMIT_CPU      0
82 #endif
83
84 #endif /* _WIN32 */
85
86 extern Standard_Boolean Draw_Batch;
87
88 static clock_t CPU_LIMIT;   // Cpu_limit in Sec.
89
90 //=======================================================================
91 // chronom
92 //=======================================================================
93
94 extern Standard_Boolean Draw_Chrono;
95
96 static Standard_Integer chronom(Draw_Interpretor& di,
97                                 Standard_Integer n,const char** a)
98 {
99   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
100     if (n == 1)
101       Draw_Chrono = !Draw_Chrono;
102     else
103       Draw_Chrono = (*a[1] == '1');
104
105     if (Draw_Chrono) di << "Chronometers activated."<<"\n";
106     else di << "Chronometers desactivated."<<"\n";
107   }
108   else {
109     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
110     Handle(Draw_Chronometer) C;
111     if (!D.IsNull()) {
112       C = Handle(Draw_Chronometer)::DownCast(D);
113     }
114     if (C.IsNull()) {
115       C = new Draw_Chronometer();
116     Draw::Set(a[1],C,Standard_False);
117     }
118     if (n <= 2) {
119       C->Timer().Reset();
120     }
121     else {
122       if (!strcasecmp(a[2],"reset"))
123         C->Timer().Reset();
124       if (!strcasecmp(a[2],"start"))
125         C->Timer().Start();
126       if (!strcasecmp(a[2],"stop"))
127         C->Timer().Stop();
128       if (!strcasecmp(a[2],"show"))
129         C->Timer().Show();
130     }
131   }
132   return 0;
133 }
134
135 static Standard_Integer dchronom(Draw_Interpretor& I,
136                                  Standard_Integer n,const char** a)
137 {
138   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
139     if (n == 1)
140       Draw_Chrono = !Draw_Chrono;
141     else
142       Draw_Chrono = (*a[1] == '1');
143
144     if (Draw_Chrono) I << "Chronometers activated."<<"\n";
145     else I << "Chronometers desactivated."<<"\n";
146   }
147   else {
148     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
149     Handle(Draw_Chronometer) C;
150     if (!D.IsNull()) {
151       C = Handle(Draw_Chronometer)::DownCast(D);
152     }
153     if (C.IsNull()) {
154       C = new Draw_Chronometer();
155     Draw::Set(a[1],C,Standard_False);
156     }
157     if (n <= 2) {
158       C->Timer().Reset();
159     }
160     else {
161       if (!strcasecmp(a[2],"reset"))
162         C->Timer().Reset();
163       if (!strcasecmp(a[2],"start"))
164         C->Timer().Start();
165       if (!strcasecmp(a[2],"stop"))
166         C->Timer().Stop();
167       if (!strcasecmp(a[2],"show")) {
168         Standard_SStream ss;
169         C->Timer().Show(ss);
170         I << ss;
171       }
172     }
173   }
174   return 0;
175 }
176
177
178
179 //=======================================================================
180 //function : ifbatch
181 //purpose  : 
182 //=======================================================================
183
184 static Standard_Integer ifbatch(Draw_Interpretor& DI, Standard_Integer , const char** )
185 {
186   if (Draw_Batch)
187     DI << "1";
188   else
189     DI << "0";
190   
191   return 0;
192 }
193
194 //=======================================================================
195 //function : spy
196 //purpose  : 
197 //=======================================================================
198
199 extern Standard_Boolean Draw_Spying;
200 extern filebuf Draw_Spyfile;
201
202 static Standard_Integer spy(Draw_Interpretor& di, Standard_Integer n, const char** a)
203 {
204   if (Draw_Spying) 
205     Draw_Spyfile.close();
206   Draw_Spying = Standard_False;
207   if (n > 1) {
208     if (!Draw_Spyfile.open(a[1],ios::out)) {
209       di << "Cannot open "<<a[1]<<" for writing"<<"\n";
210       return 1;
211     }
212     Draw_Spying = Standard_True;
213   }
214   return 0;
215 }
216
217 static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const char** a)
218 {
219   if (n != 2 && n != 3)
220   {
221     cout << "Enable or disable logging: " << a[0] << " {on|off}" << endl;
222     cout << "Reset log: " << a[0] << " reset" << endl;
223     cout << "Get log content: " << a[0] << " get" << endl;
224     return 1;
225   }
226
227   if (! strcmp (a[1], "on") && n == 2)
228   {
229     di.SetDoLog (Standard_True);
230 //    di.Log() << "dlog on" << endl; // for symmetry
231   }
232   else if (! strcmp (a[1], "off") && n == 2)
233   {
234     di.SetDoLog (Standard_False);
235   }
236   else if (! strcmp (a[1], "reset") && n == 2)
237   {
238     di.Log().str("");
239   }
240   else if (! strcmp (a[1], "get") && n == 2)
241   {
242     di << di.Log().str().c_str();
243   }
244   else if (! strcmp (a[1], "add") && n == 3)
245   {
246     di.Log() << a[2] << "\n";
247   }
248   else {
249     cout << "Unrecognized option(s): " << a[1] << endl;
250     return 1;
251   }
252   return 0;
253 }
254
255 static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const char** a)
256 {
257   if (n != 2)
258   {
259     cout << "Enable or disable echoing: " << a[0] << " {on|off}" << endl;
260     return 1;
261   }
262
263   if (! strcmp (a[1], "on"))
264   {
265     di.SetDoEcho (Standard_True);
266   }
267   else if (! strcmp (a[1], "off"))
268   {
269     di.SetDoEcho (Standard_False);
270   }
271   else {
272     cout << "Unrecognized option: " << a[1] << endl;
273     return 1;
274   }
275   return 0;
276 }
277
278 static Standard_Integer dbreak(Draw_Interpretor& di, Standard_Integer, const char**)
279 {
280   try {
281     OSD::ControlBreak();
282   }
283   catch (OSD_Exception_CTRL_BREAK) {
284     di << "User pressed Control-Break";
285     return 1; // Tcl exception
286   }
287
288   return 0;
289 }
290
291 static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const char**)
292 {
293   // print OCCT version and OCCTY-specific macros used
294   di << "Open CASCADE Technology " << OCC_VERSION_STRING_EXT << "\n";
295 #if defined(DEB) || defined(_DEBUG)
296   di << "Debug mode\n";
297 #endif
298 #ifdef HAVE_TBB
299   di << "TBB enabled (HAVE_TBB)\n";
300 #else 
301   di << "TBB disabled\n";
302 #endif
303 #ifdef HAVE_GL2PS
304   di << "GL2PS enabled (HAVE_GL2PS)\n";
305 #else
306   di << "GL2PS disabled\n";
307 #endif
308 #ifdef HAVE_FREEIMAGE
309   di << "FreeImage enabled (HAVE_FREEIMAGE)\n";
310 #else
311   di << "FreeImage disabled\n";
312 #endif
313 #ifdef No_Exception
314   di << "Exceptions disabled (No_Exception)\n";
315 #else
316   di << "Exceptions enabled\n";
317 #endif
318
319   // check compiler, OS, etc. using pre-processor macros provided by compiler
320   // see "Pre-defined C/C++ Compiler Macros" http://sourceforge.net/p/predef/wiki/
321   // note that only modern compilers that are known to be used for OCCT are recognized
322
323   // compiler; note that GCC and MSVC are last as other compilers (e.g. Intel) can also define __GNUC__ and _MSC_VER
324 #if defined(__INTEL_COMPILER)
325   di << "Compiler: Intel " << __INTEL_COMPILER << "\n";
326 #elif defined(__BORLANDC__)
327   di << "Compiler: Borland C++ (__BORLANDC__ = " << __BORLANDC__ << ")\n";
328 #elif defined(__clang__)
329   di << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__ << "\n";
330 #elif defined(__SUNPRO_C)
331   di << "Compiler: Sun Studio (__SUNPRO_C = " << __SUNPROC_C << ")\n";
332 #elif defined(_MSC_VER)
333   di << "Compiler: MS Visual C++ " << (int)(_MSC_VER/100-6) << "." << (int)((_MSC_VER/10)-60-10*(int)(_MSC_VER/100-6)) << " (_MSC_FULL_VER = " << _MSC_FULL_VER << ")\n";
334 #elif defined(__GNUC__)
335   di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n";
336 #else
337   di << "Compiler: unrecognized\n";
338 #endif
339
340   // Cygwin and MinGW specifics
341 #if defined(__CYGWIN__)
342   di << "Cygwin\n";
343 #endif
344 #if defined(__MINGW64__)
345   di << "MinGW 64 " << __MINGW64_MAJOR_VERSION << "." << __MINGW64_MINOR_VERSION << "\n";
346 #elif defined(__MINGW32__)
347   di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n";
348 #endif 
349
350   // architecture
351 #if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64)
352   di << "Architecture: AMD64\n";
353 #elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_)
354   di << "Architecture: Intel x86\n";
355 #elif defined(_M_IA64) || defined(__ia64__)
356   di << "Architecture: Intel Itanium (IA 64)\n";
357 #elif defined(__sparc__) || defined(__sparc)
358   di << "Architecture: SPARC\n";
359 #else
360   di << "Architecture: unrecognized\n";
361 #endif
362
363   // OS
364 #if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
365   di << "OS: Windows\n";
366 #elif defined(__APPLE__) || defined(__MACH__)
367   di << "OS: Mac OS X\n";
368 #elif defined(__sun) 
369   di << "OS: SUN Solaris\n";
370 #elif defined(__ANDROID__) /* must be before Linux */
371   #include <android/api-level.h>
372   di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n";
373 #elif defined(__linux__)
374   di << "OS: Linux\n";
375 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
376   #include <sys/param.h>
377   di << "OS: BSD (BSD = " << BSD << ")\n";
378 #else
379   di << "OS: unrecognized\n";
380 #endif
381
382   return 0;
383 }
384
385 //=======================================================================
386 //function : wait
387 //purpose  : 
388 //=======================================================================
389
390 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
391 {
392   Standard_Integer w = 10;
393   if (n > 1)
394     w = Draw::Atoi(a[1]);
395   time_t ct = time(NULL) + w;
396   while (time(NULL) < ct) {};
397   return 0;
398 }
399
400 //=======================================================================
401 //function : cpulimit
402 //purpose  : 
403 //=======================================================================
404 #ifdef _WIN32
405 static unsigned int __stdcall CpuFunc (void * param)
406 {
407   clock_t aCurrent;
408   while (1)
409   {
410     Sleep (5);
411     Standard_Real anUserSeconds, aSystemSeconds;
412     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
413     aCurrent = clock_t(anUserSeconds + aSystemSeconds);
414     
415     if ((aCurrent - CPU_CURRENT) >= CPU_LIMIT)
416     {
417       cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
418       ExitProcess (2);
419       return 0;
420     }
421   }
422   return 0;
423 }
424 #else
425 static void CpuFunc (int)
426 {
427   cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
428   exit(2);
429 }
430 #endif
431
432 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
433 {
434 #ifdef _WIN32
435   // Windows specific code
436
437   static int aFirst = 1;
438
439   unsigned int __stdcall CpuFunc (void *);
440   unsigned aThreadID;
441
442   if (n <= 1)
443     CPU_LIMIT = RLIM_INFINITY;
444   else
445   {
446     CPU_LIMIT = Draw::Atoi (a[1]);
447     Standard_Real anUserSeconds, aSystemSeconds;
448     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
449     CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
450
451     if (aFirst) // Launch the thread only at the 1st call.
452     {
453       aFirst = 0;
454       _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
455     }
456   }
457
458 #else 
459
460   // Unix & Linux
461
462   rlimit rlp;
463   rlp.rlim_max = RLIM_INFINITY;
464   if (n <= 1)
465     rlp.rlim_cur = RLIM_INFINITY;
466   else
467     rlp.rlim_cur = Draw::Atoi(a[1]);
468   CPU_LIMIT = rlp.rlim_cur;
469
470   int status;
471   status=setrlimit(RLIMIT_CPU,&rlp);
472   if (status !=0)
473     di << "status cpulimit setrlimit : " << status << "\n";
474
475   // set signal handler to print a message before death
476   struct sigaction act, oact;
477   memset (&act, 0, sizeof(act));
478   act.sa_handler = CpuFunc;
479   sigaction (SIGXCPU, &act, &oact);
480
481 #endif
482
483   return 0;
484 }
485
486 //=======================================================================
487 //function : mallochook
488 //purpose  : 
489 //=======================================================================
490
491 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
492                                    const char** a)
493 {
494   if (n < 2)
495   {
496     di << "\
497 usage: mallochook cmd\n\
498 where cmd is one of:\n\
499   set [<op>]      - set callback to malloc/free; op is one of the following:\n\
500                     0 - set callback to NULL,\n\
501                     1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
502                     2 - set callback OSD_MAllocHook::LogFileHandler\n\
503   reset           - reset the CollectBySize handler\n\
504   report1 [<outfile>]\n\
505                   - write report from CollectBySize handler in <outfile>\n\
506   open [<logfile>]\n\
507                   - open file for writing the log with LogFileHandler\n\
508   close           - close the log file with LogFileHandler\n\
509   report2 [<flag>] [<logfile>] [<outfile>]\n\
510                   - scan <logfile> written with LogFileHandler\n\
511                     and make synthesized report in <outfile>; <flag> can be:\n\
512                     0 - simple stats by sizes (default),\n\
513                     1 - with alive allocation numbers\n\
514 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
515       << "\n";
516     return 0;
517   }
518   if (strcmp(a[1], "set") == 0)
519   {
520     int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
521     if (aType < 0 || aType > 2)
522     {
523       di << "unknown op of the command set" << "\n";
524       return 1;
525     }
526     else if (aType == 0)
527     {
528       OSD_MAllocHook::SetCallback(NULL);
529       di << "callback is unset" << "\n";
530     }
531     else if (aType == 1)
532     {
533       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
534       di << "callback is set to CollectBySize" << "\n";
535     }
536     else //if (aType == 2)
537     {
538       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
539       di << "callback is set to LogFileHandler" << "\n";
540     }
541   }
542   else if (strcmp(a[1], "reset") == 0)
543   {
544     OSD_MAllocHook::GetCollectBySize()->Reset();
545     di << "CollectBySize handler is reset" << "\n";
546   }
547   else if (strcmp(a[1], "open") == 0)
548   {
549     const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
550     if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
551     {
552       di << "cannot create file " << aFileName << " for writing" << "\n";
553       return 1;
554     }
555     di << "log file " << aFileName << " is opened for writing" << "\n";
556   }
557   else if (strcmp(a[1], "close") == 0)
558   {
559     OSD_MAllocHook::GetLogFileHandler()->Close();
560     di << "log file is closed" << "\n";
561   }
562   else if (strcmp(a[1], "report1") == 0)
563   {
564     const char* aOutFile = "mem-stat.txt";
565     if (n > 2)
566       aOutFile = a[2];
567     if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
568     {
569       di << "report " << aOutFile << " has been created" << "\n";
570     }
571     else
572     {
573       di << "cannot create report " << aOutFile << "\n";
574       return 1;
575     }
576   }
577   else if (strcmp(a[1], "report2") == 0)
578   {
579     Standard_Boolean includeAlive = Standard_False;
580     const char* aLogFile = "mem-log.txt";
581     const char* aOutFile = "mem-stat.txt";
582     if (n > 2)
583     {
584       includeAlive = (Draw::Atoi(a[2]) != 0);
585       if (n > 3)
586       {
587         aLogFile = a[3];
588         if (n > 4)
589           aOutFile = a[4];
590       }
591     }
592     if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
593     {
594       di << "report " << aOutFile << " has been created" << "\n";
595     }
596     else
597     {
598       di << "cannot create report " << aOutFile << " from the log file "
599         << aLogFile << "\n";
600       return 1;
601     }
602   }
603   else
604   {
605     di << "unrecognized command " << a[1] << "\n";
606     return 1;
607   }
608   return 0;
609 }
610
611 //==============================================================================
612 //function : dlocale
613 //purpose  :
614 //==============================================================================
615
616 static int dlocale (Draw_Interpretor& di, Standard_Integer n, const char** argv)
617 {
618   int category = LC_ALL;
619   if (n > 1)
620   {
621     const char *cat = argv[1];
622     if ( ! strcmp (cat, "LC_ALL") ) category = LC_ALL;
623     else if ( ! strcmp (cat, "LC_COLLATE") ) category = LC_COLLATE;
624     else if ( ! strcmp (cat, "LC_CTYPE") ) category = LC_CTYPE;
625     else if ( ! strcmp (cat, "LC_MONETARY") ) category = LC_MONETARY;
626     else if ( ! strcmp (cat, "LC_NUMERIC") ) category = LC_NUMERIC;
627     else if ( ! strcmp (cat, "LC_TIME") ) category = LC_TIME;
628     else 
629     {
630       cout << "Error: cannot recognize argument " << cat << " as one of LC_ macros" << endl;
631       return 1;
632     }
633   }
634   const char* locale = (n > 2 ? argv[2] : NULL);
635   const char* result = setlocale (category, locale);
636   if (result)
637     di << result;
638   else 
639     cout << "Error: unsupported locale specification: " << locale << endl;
640   return 0;
641 }
642
643 //==============================================================================
644 //function : dmeminfo
645 //purpose  :
646 //==============================================================================
647
648 static int dmeminfo (Draw_Interpretor& theDI,
649                      Standard_Integer  theArgNb,
650                      const char**      theArgVec)
651 {
652   OSD_MemInfo aMemInfo;
653   if (theArgNb <= 1)
654   {
655     theDI << aMemInfo.ToString();
656     return 0;
657   }
658
659   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
660   {
661     TCollection_AsciiString anArg (theArgVec[anIter]);
662     anArg.LowerCase();
663     if (anArg == "virt" || anArg == "v")
664     {
665       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
666     }
667     else if (anArg == "heap" || anArg == "h")
668     {
669       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemHeapUsage)) << " ";
670     }
671     else if (anArg == "wset" || anArg == "w")
672     {
673       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
674     }
675     else if (anArg == "wsetpeak")
676     {
677       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
678     }
679     else if (anArg == "swap")
680     {
681       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
682     }
683     else if (anArg == "swappeak")
684     {
685       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
686     }
687     else if (anArg == "private")
688     {
689       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
690     }
691     else
692     {
693       std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
694     }
695   }
696   theDI << "\n";
697   return 0;
698 }
699
700 void Draw::BasicCommands(Draw_Interpretor& theCommands)
701 {
702   static Standard_Boolean Done = Standard_False;
703   if (Done) return;
704   Done = Standard_True;
705
706   ios::sync_with_stdio();
707
708   const char* g = "DRAW General Commands";
709   
710   theCommands.Add("batch", "returns 1 in batch mode",
711                   __FILE__,ifbatch,g);
712   theCommands.Add("spy","spy [file], Save commands in file. no file close",
713                   __FILE__,spy,g);
714   theCommands.Add("wait","wait [time(10)], wait time seconds",
715                   __FILE__,Draw_wait,g);
716   theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
717                   __FILE__,cpulimit,g);
718   theCommands.Add("chrono","chrono [ name start/stop/reset/show]",
719                   __FILE__,chronom,g);
720   theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
721                   __FILE__,dchronom,g);
722   theCommands.Add("mallochook",
723                   "debug memory allocation/deallocation, w/o args for help",
724                   __FILE__, mallochook, g);
725   theCommands.Add ("meminfo",
726     "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
727     " : memory counters for this process",
728           __FILE__, dmeminfo, g);
729
730   // Logging commands; note that their names are hard-coded in the code 
731   // of Draw_Interpretor, thus should not be changed without update of that code!
732   theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
733                   __FILE__,dlog,g);
734   theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
735                   __FILE__,decho,g);
736   
737   theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
738                   __FILE__,dbreak,g);
739   theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)",
740                   __FILE__,dversion,g);
741   theCommands.Add("dlocale", "set and / or query locate of C subsystem (function setlocale())",
742                   __FILE__,dlocale,g);
743 }