0030583: Draw Harness - ignore cpulimit when Debugger is attached on Windows platform
[occt.git] / src / Draw / Draw_BasicCommands.cxx
CommitLineData
b311480e 1// Created on: 1995-02-23
2// Created by: Remi LEQUETTE
3// Copyright (c) 1995-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
b311480e 16
7fd59977 17
42cf5bc1 18#include <Draw.hxx>
7fd59977 19#include <Draw_Appli.hxx>
a60b9727 20#include <Draw_Chronometer.hxx>
42cf5bc1 21#include <Draw_Drawable3D.hxx>
7fd59977 22#include <Draw_Printer.hxx>
42cf5bc1 23#include <Draw_ProgressIndicator.hxx>
7fd59977 24#include <Message.hxx>
25#include <Message_Messenger.hxx>
8a262fa1 26#include <OSD.hxx>
42cf5bc1 27#include <OSD_Chronometer.hxx>
f4dee9bb 28#include <OSD_Environment.hxx>
8a262fa1 29#include <OSD_Exception_CTRL_BREAK.hxx>
42cf5bc1 30#include <OSD_MAllocHook.hxx>
31#include <OSD_MemInfo.hxx>
32#include <Standard_Macro.hxx>
33#include <Standard_SStream.hxx>
34#include <Standard_Stream.hxx>
35#include <Standard_Version.hxx>
36#include <TCollection_AsciiString.hxx>
7fd59977 37
42cf5bc1 38#include <OSD_PerfMeter.h>
a60b9727 39#ifdef _WIN32
7fd59977 40
7fd59977 41#include <windows.h>
42#include <winbase.h>
43#include <process.h>
44#include <stdio.h>
45#include <stdlib.h>
a60b9727 46#include <time.h>
47#include <limits>
48
49#define RLIM_INFINITY 0x7fffffff
50
51static clock_t CPU_CURRENT; // cpu time already used at last
52 // cpulimit call. (sec.)
a60b9727 53#else /* _WIN32 */
54
55#include <sys/resource.h>
03155c18 56#include <signal.h>
0b309a75 57#include <unistd.h>
7fd59977 58
59#if defined (__hpux) || defined ( HPUX )
60#define RLIM_INFINITY 0x7fffffff
61#define RLIMIT_CPU 0
62#endif
63
a60b9727 64#endif /* _WIN32 */
7fd59977 65
a60b9727 66extern Standard_Boolean Draw_Batch;
67
68static clock_t CPU_LIMIT; // Cpu_limit in Sec.
0b309a75 69static OSD_Timer aTimer;
7fd59977 70
71//=======================================================================
72// chronom
73//=======================================================================
74
75extern Standard_Boolean Draw_Chrono;
76
77static Standard_Integer chronom(Draw_Interpretor& di,
78 Standard_Integer n,const char** a)
79{
80 if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
81 if (n == 1)
82 Draw_Chrono = !Draw_Chrono;
83 else
84 Draw_Chrono = (*a[1] == '1');
85
586db386 86 if (Draw_Chrono) di << "Chronometers activated.\n";
87 else di << "Chronometers desactivated.\n";
7fd59977 88 }
89 else {
90 Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
91 Handle(Draw_Chronometer) C;
92 if (!D.IsNull()) {
93 C = Handle(Draw_Chronometer)::DownCast(D);
94 }
95 if (C.IsNull()) {
96 C = new Draw_Chronometer();
97 Draw::Set(a[1],C,Standard_False);
98 }
99 if (n <= 2) {
100 C->Timer().Reset();
101 }
102 else {
44fae8b1 103 for (Standard_Integer anIter = 2; anIter < n; ++anIter)
104 {
105 TCollection_AsciiString anArg (a[anIter]);
106 anArg.LowerCase();
107
108 if (anArg == "reset")
109 {
110 C->Timer().Reset();
111 }
112 else if (anArg == "restart")
113 {
114 C->Timer().Restart();
115 }
116 else if (anArg == "start")
117 {
118 C->Timer().Start();
119 }
120 else if (anArg == "stop")
121 {
122 C->Timer().Stop();
123 }
124 else if (anArg == "show")
125 {
126 C->Timer().Show();
127 }
128 else if (anArg == "counter")
129 {
130 Standard_Real aSeconds,aCPUtime;
131 Standard_Integer aMinutes, aHours;
132 C->Timer().Show(aSeconds,aMinutes,aHours,aCPUtime);
133 std::cout << "COUNTER " << a[++anIter] << ": " << aCPUtime << "\n";
134 }
135 else
136 {
137 std::cerr << "Unknown argument '" << a[anIter] << "'!\n";
138 }
139 }
7fd59977 140 }
141 }
142 return 0;
143}
144
44fae8b1 145static Standard_Integer dchronom(Draw_Interpretor& theDI,
7fd59977 146 Standard_Integer n,const char** a)
147{
148 if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
149 if (n == 1)
150 Draw_Chrono = !Draw_Chrono;
151 else
152 Draw_Chrono = (*a[1] == '1');
153
44fae8b1 154 if (Draw_Chrono) theDI << "Chronometers activated.\n";
155 else theDI << "Chronometers desactivated.\n";
7fd59977 156 }
157 else {
158 Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
159 Handle(Draw_Chronometer) C;
160 if (!D.IsNull()) {
161 C = Handle(Draw_Chronometer)::DownCast(D);
162 }
163 if (C.IsNull()) {
164 C = new Draw_Chronometer();
44fae8b1 165 Draw::Set(a[1],C,Standard_False);
7fd59977 166 }
167 if (n <= 2) {
168 C->Timer().Reset();
169 }
170 else {
44fae8b1 171 for (Standard_Integer anIter = 2; anIter < n; ++anIter)
172 {
173 TCollection_AsciiString anArg (a[anIter]);
174 anArg.LowerCase();
175
176 if (anArg == "reset")
177 {
178 C->Timer().Reset();
179 }
180 else if (anArg == "restart")
181 {
182 C->Timer().Restart();
183 }
184 else if (anArg == "start")
185 {
186 C->Timer().Start();
187 }
188 else if (anArg == "stop")
189 {
190 C->Timer().Stop();
191 }
192 else if (anArg == "show")
193 {
194 Standard_SStream ss;
195 C->Timer().Show(ss);
196 theDI << ss;
197 }
198 else if (anArg == "counter")
199 {
200 Standard_Real aSeconds,aCPUtime;
201 Standard_Integer aMinutes, aHours;
202 C->Timer().Show(aSeconds,aMinutes,aHours,aCPUtime);
203 theDI << "COUNTER " << a[++anIter] << ": " << aCPUtime << "\n";
204 }
205 else
206 {
207 theDI << "Unknown argument '" << a[anIter] << "'!\n";
208 }
7fd59977 209 }
210 }
211 }
212 return 0;
213}
214
215
216
217//=======================================================================
218//function : ifbatch
219//purpose :
220//=======================================================================
221
222static Standard_Integer ifbatch(Draw_Interpretor& DI, Standard_Integer , const char** )
223{
224 if (Draw_Batch)
225 DI << "1";
226 else
227 DI << "0";
228
229 return 0;
230}
231
232//=======================================================================
233//function : spy
234//purpose :
235//=======================================================================
236
237extern Standard_Boolean Draw_Spying;
238extern filebuf Draw_Spyfile;
239
240static Standard_Integer spy(Draw_Interpretor& di, Standard_Integer n, const char** a)
241{
242 if (Draw_Spying)
243 Draw_Spyfile.close();
244 Draw_Spying = Standard_False;
245 if (n > 1) {
246 if (!Draw_Spyfile.open(a[1],ios::out)) {
586db386 247 di << "Cannot open "<<a[1]<<" for writing\n";
7fd59977 248 return 1;
249 }
250 Draw_Spying = Standard_True;
251 }
252 return 0;
253}
254
aa02980d 255static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const char** a)
256{
257 if (n != 2 && n != 3)
258 {
259 cout << "Enable or disable logging: " << a[0] << " {on|off}" << endl;
260 cout << "Reset log: " << a[0] << " reset" << endl;
261 cout << "Get log content: " << a[0] << " get" << endl;
262 return 1;
263 }
264
265 if (! strcmp (a[1], "on") && n == 2)
266 {
267 di.SetDoLog (Standard_True);
268// di.Log() << "dlog on" << endl; // for symmetry
269 }
270 else if (! strcmp (a[1], "off") && n == 2)
271 {
272 di.SetDoLog (Standard_False);
273 }
274 else if (! strcmp (a[1], "reset") && n == 2)
275 {
e05c25c1 276 di.ResetLog();
aa02980d 277 }
278 else if (! strcmp (a[1], "get") && n == 2)
279 {
e05c25c1 280 di << di.GetLog();
aa02980d 281 }
282 else if (! strcmp (a[1], "add") && n == 3)
283 {
e05c25c1 284 di.AddLog (a[2]);
285 di.AddLog ("\n");
286 }
287 else if (! strcmp (a[1], "status") && n == 2)
288 {
289 di << (di.GetDoLog() ? "on" : "off");
aa02980d 290 }
291 else {
292 cout << "Unrecognized option(s): " << a[1] << endl;
293 return 1;
294 }
295 return 0;
296}
297
298static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const char** a)
299{
300 if (n != 2)
301 {
302 cout << "Enable or disable echoing: " << a[0] << " {on|off}" << endl;
303 return 1;
304 }
305
306 if (! strcmp (a[1], "on"))
307 {
308 di.SetDoEcho (Standard_True);
309 }
310 else if (! strcmp (a[1], "off"))
311 {
312 di.SetDoEcho (Standard_False);
313 }
314 else {
315 cout << "Unrecognized option: " << a[1] << endl;
316 return 1;
317 }
318 return 0;
319}
320
8a262fa1 321static Standard_Integer dbreak(Draw_Interpretor& di, Standard_Integer, const char**)
322{
323 try {
324 OSD::ControlBreak();
325 }
326 catch (OSD_Exception_CTRL_BREAK) {
327 di << "User pressed Control-Break";
328 return 1; // Tcl exception
329 }
330
331 return 0;
332}
333
334static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const char**)
335{
336 // print OCCT version and OCCTY-specific macros used
337 di << "Open CASCADE Technology " << OCC_VERSION_STRING_EXT << "\n";
0797d9d3 338#ifdef OCCT_DEBUG
339 di << "Extended debug mode\n";
340#elif defined(_DEBUG)
8a262fa1 341 di << "Debug mode\n";
342#endif
343#ifdef HAVE_TBB
344 di << "TBB enabled (HAVE_TBB)\n";
345#else
346 di << "TBB disabled\n";
347#endif
8a262fa1 348#ifdef HAVE_FREEIMAGE
349 di << "FreeImage enabled (HAVE_FREEIMAGE)\n";
350#else
351 di << "FreeImage disabled\n";
352#endif
08f8a185 353#ifdef HAVE_FFMPEG
354 di << "FFmpeg enabled (HAVE_FFMPEG)\n";
355#else
356 di << "FFmpeg disabled\n";
357#endif
f9f740d6 358#ifdef HAVE_GLES2
359 di << "OpenGL: ES2\n";
7ae4a307 360#else
f9f740d6 361 di << "OpenGL: desktop\n";
7ae4a307 362#endif
476e84b1 363#ifdef HAVE_VTK
364 di << "VTK enabled (HAVE_VTK)\n";
365#else
366 di << "VTK disabled\n";
367#endif
8a262fa1 368#ifdef No_Exception
369 di << "Exceptions disabled (No_Exception)\n";
370#else
371 di << "Exceptions enabled\n";
372#endif
373
374 // check compiler, OS, etc. using pre-processor macros provided by compiler
375 // see "Pre-defined C/C++ Compiler Macros" http://sourceforge.net/p/predef/wiki/
376 // note that only modern compilers that are known to be used for OCCT are recognized
377
378 // compiler; note that GCC and MSVC are last as other compilers (e.g. Intel) can also define __GNUC__ and _MSC_VER
379#if defined(__INTEL_COMPILER)
380 di << "Compiler: Intel " << __INTEL_COMPILER << "\n";
381#elif defined(__BORLANDC__)
382 di << "Compiler: Borland C++ (__BORLANDC__ = " << __BORLANDC__ << ")\n";
383#elif defined(__clang__)
384 di << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__ << "\n";
385#elif defined(__SUNPRO_C)
386 di << "Compiler: Sun Studio (__SUNPRO_C = " << __SUNPROC_C << ")\n";
387#elif defined(_MSC_VER)
f9f740d6 388 #if _MSC_VER < 1900
389 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";
390 #else
391 di << "Compiler: MS Visual C++ " << (int)(_MSC_VER/100-5) << "." << (int)((_MSC_VER/10)-50-10*(int)(_MSC_VER/100-5)) << " (_MSC_FULL_VER = " << _MSC_FULL_VER << ")\n";
392 #endif
8a262fa1 393#elif defined(__GNUC__)
394 di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n";
395#else
396 di << "Compiler: unrecognized\n";
397#endif
398
399 // Cygwin and MinGW specifics
400#if defined(__CYGWIN__)
401 di << "Cygwin\n";
402#endif
403#if defined(__MINGW64__)
7c65581d 404 di << "MinGW 64 " << __MINGW64_VERSION_MAJOR << "." << __MINGW64_VERSION_MINOR << "\n";
8a262fa1 405#elif defined(__MINGW32__)
406 di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n";
407#endif
408
409 // architecture
410#if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64)
411 di << "Architecture: AMD64\n";
412#elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_)
413 di << "Architecture: Intel x86\n";
414#elif defined(_M_IA64) || defined(__ia64__)
415 di << "Architecture: Intel Itanium (IA 64)\n";
416#elif defined(__sparc__) || defined(__sparc)
417 di << "Architecture: SPARC\n";
418#else
419 di << "Architecture: unrecognized\n";
420#endif
421
422 // OS
423#if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
424 di << "OS: Windows\n";
425#elif defined(__APPLE__) || defined(__MACH__)
426 di << "OS: Mac OS X\n";
427#elif defined(__sun)
428 di << "OS: SUN Solaris\n";
429#elif defined(__ANDROID__) /* must be before Linux */
430 #include <android/api-level.h>
431 di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n";
d8d01f6e 432#elif defined(__QNXNTO__)
433 di << "OS: QNX Neutrino\n";
434#elif defined(__QNX__)
435 di << "OS: QNX\n";
8a262fa1 436#elif defined(__linux__)
437 di << "OS: Linux\n";
438#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
439 #include <sys/param.h>
440 di << "OS: BSD (BSD = " << BSD << ")\n";
441#else
442 di << "OS: unrecognized\n";
443#endif
444
445 return 0;
446}
447
7fd59977 448//=======================================================================
449//function : wait
450//purpose :
451//=======================================================================
452
453static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
454{
455 Standard_Integer w = 10;
456 if (n > 1)
91322f44 457 w = Draw::Atoi(a[1]);
7fd59977 458 time_t ct = time(NULL) + w;
459 while (time(NULL) < ct) {};
460 return 0;
461}
462
47cbc555
A
463//=======================================================================
464//function : cpulimit
465//purpose :
466//=======================================================================
a60b9727 467#ifdef _WIN32
35e08fe8 468static unsigned int __stdcall CpuFunc (void * /*param*/)
47cbc555 469{
0b309a75 470 clock_t anElapCurrent;
47cbc555 471 clock_t aCurrent;
0b309a75 472
302f96fb 473 for(;;)
47cbc555
A
474 {
475 Sleep (5);
476 Standard_Real anUserSeconds, aSystemSeconds;
477 OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
478 aCurrent = clock_t(anUserSeconds + aSystemSeconds);
0b309a75 479 anElapCurrent = clock_t(aTimer.ElapsedTime());
47cbc555 480
d48df25d 481 if (CPU_LIMIT > 0 && (aCurrent - CPU_CURRENT) >= CPU_LIMIT)
47cbc555 482 {
0b309a75 483 aTimer.Stop();
667b5eb8 484 if (IsDebuggerPresent())
485 {
486 std::cout << "ERROR: CPU limit (" << CPU_LIMIT << " sec) has been reached but ignored because of attached Debugger" << std::endl;
487 return 0;
488 }
489 else
490 {
491 std::cout << "ERROR: Process killed by CPU limit (" << CPU_LIMIT << " sec)" << std::endl;
492 ExitProcess (2);
493 }
0b309a75 494 }
d48df25d 495 if (CPU_LIMIT > 0 && anElapCurrent >= CPU_LIMIT)
0b309a75 496 {
0b309a75 497 aTimer.Stop();
667b5eb8 498 if (IsDebuggerPresent())
499 {
500 std::cout << "ERROR: Elapsed limit (" << CPU_LIMIT << " sec) has been reached but ignored because of attached Debugger" << std::endl;
501 return 0;
502 }
503 else
504 {
505 std::cout << "ERROR: Process killed by elapsed limit (" << CPU_LIMIT << " sec)" << std::endl;
506 ExitProcess (2);
507 }
47cbc555
A
508 }
509 }
47cbc555 510}
a60b9727 511#else
0b309a75 512static void cpulimitSignalHandler (int)
a60b9727 513{
0b309a75 514 cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
a60b9727 515 exit(2);
516}
0b309a75 517static void *CpuFunc(void* /*threadarg*/)
518{
519 clock_t anElapCurrent;
520 for(;;)
521 {
522 sleep (5);
523 anElapCurrent = clock_t(aTimer.ElapsedTime());
d48df25d 524 if (CPU_LIMIT >0 && (anElapCurrent) >= CPU_LIMIT) {
0b309a75 525 cout << "Process killed by elapsed limit (" << CPU_LIMIT << " sec)" << endl;
526 exit(2);
527 }
528 }
529 return NULL;
530}
47cbc555 531#endif
7fd59977 532
35e08fe8 533#ifdef _WIN32
534static Standard_Integer cpulimit(Draw_Interpretor&, Standard_Integer n, const char** a)
535{
536#else
7fd59977 537static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
538{
35e08fe8 539#endif
0b309a75 540 static int aFirst = 1;
a60b9727 541#ifdef _WIN32
542 // Windows specific code
47cbc555
A
543 unsigned int __stdcall CpuFunc (void *);
544 unsigned aThreadID;
545
0b309a75 546 if (n <= 1){
a60b9727 547 CPU_LIMIT = RLIM_INFINITY;
0b309a75 548 } else {
91322f44 549 CPU_LIMIT = Draw::Atoi (a[1]);
47cbc555
A
550 Standard_Real anUserSeconds, aSystemSeconds;
551 OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
a60b9727 552 CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
0b309a75 553 aTimer.Reset();
554 aTimer.Start();
47cbc555
A
555 if (aFirst) // Launch the thread only at the 1st call.
556 {
557 aFirst = 0;
558 _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
559 }
7fd59977 560 }
561
a60b9727 562#else
a60b9727 563 // Unix & Linux
a60b9727 564 rlimit rlp;
565 rlp.rlim_max = RLIM_INFINITY;
566 if (n <= 1)
567 rlp.rlim_cur = RLIM_INFINITY;
568 else
91322f44 569 rlp.rlim_cur = Draw::Atoi(a[1]);
a60b9727 570 CPU_LIMIT = rlp.rlim_cur;
571
572 int status;
573 status=setrlimit(RLIMIT_CPU,&rlp);
574 if (status !=0)
575 di << "status cpulimit setrlimit : " << status << "\n";
576
577 // set signal handler to print a message before death
578 struct sigaction act, oact;
579 memset (&act, 0, sizeof(act));
0b309a75 580 act.sa_handler = cpulimitSignalHandler;
a60b9727 581 sigaction (SIGXCPU, &act, &oact);
582
0b309a75 583 // cpulimit for elapsed time
584 aTimer.Reset();
585 aTimer.Start();
586 pthread_t cpulimitThread;
587 if (aFirst) // Launch the thread only at the 1st call.
588 {
589 aFirst = 0;
590 pthread_create(&cpulimitThread, NULL, CpuFunc, NULL);
591 }
7fd59977 592#endif
7fd59977 593 return 0;
594}
595
0b309a75 596
7af17f1e
MA
597//=======================================================================
598//function : mallochook
599//purpose :
600//=======================================================================
601
602static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
603 const char** a)
604{
605 if (n < 2)
606 {
607 di << "\
608usage: mallochook cmd\n\
609where cmd is one of:\n\
610 set [<op>] - set callback to malloc/free; op is one of the following:\n\
611 0 - set callback to NULL,\n\
612 1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
613 2 - set callback OSD_MAllocHook::LogFileHandler\n\
614 reset - reset the CollectBySize handler\n\
615 report1 [<outfile>]\n\
616 - write report from CollectBySize handler in <outfile>\n\
617 open [<logfile>]\n\
618 - open file for writing the log with LogFileHandler\n\
619 close - close the log file with LogFileHandler\n\
620 report2 [<flag>] [<logfile>] [<outfile>]\n\
621 - scan <logfile> written with LogFileHandler\n\
622 and make synthesized report in <outfile>; <flag> can be:\n\
623 0 - simple stats by sizes (default),\n\
624 1 - with alive allocation numbers\n\
625By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
626 << "\n";
627 return 0;
628 }
629 if (strcmp(a[1], "set") == 0)
630 {
91322f44 631 int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
7af17f1e
MA
632 if (aType < 0 || aType > 2)
633 {
586db386 634 di << "unknown op of the command set\n";
7af17f1e
MA
635 return 1;
636 }
637 else if (aType == 0)
638 {
639 OSD_MAllocHook::SetCallback(NULL);
586db386 640 di << "callback is unset\n";
7af17f1e
MA
641 }
642 else if (aType == 1)
643 {
644 OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
586db386 645 di << "callback is set to CollectBySize\n";
7af17f1e
MA
646 }
647 else //if (aType == 2)
648 {
649 OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
586db386 650 di << "callback is set to LogFileHandler\n";
7af17f1e
MA
651 }
652 }
653 else if (strcmp(a[1], "reset") == 0)
654 {
655 OSD_MAllocHook::GetCollectBySize()->Reset();
586db386 656 di << "CollectBySize handler is reset\n";
7af17f1e
MA
657 }
658 else if (strcmp(a[1], "open") == 0)
659 {
660 const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
661 if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
662 {
586db386 663 di << "cannot create file " << aFileName << " for writing\n";
7af17f1e
MA
664 return 1;
665 }
586db386 666 di << "log file " << aFileName << " is opened for writing\n";
7af17f1e
MA
667 }
668 else if (strcmp(a[1], "close") == 0)
669 {
670 OSD_MAllocHook::GetLogFileHandler()->Close();
586db386 671 di << "log file is closed\n";
7af17f1e
MA
672 }
673 else if (strcmp(a[1], "report1") == 0)
674 {
675 const char* aOutFile = "mem-stat.txt";
676 if (n > 2)
677 aOutFile = a[2];
678 if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
679 {
586db386 680 di << "report " << aOutFile << " has been created\n";
7af17f1e
MA
681 }
682 else
683 {
684 di << "cannot create report " << aOutFile << "\n";
685 return 1;
686 }
687 }
688 else if (strcmp(a[1], "report2") == 0)
689 {
690 Standard_Boolean includeAlive = Standard_False;
691 const char* aLogFile = "mem-log.txt";
692 const char* aOutFile = "mem-stat.txt";
693 if (n > 2)
694 {
91322f44 695 includeAlive = (Draw::Atoi(a[2]) != 0);
7af17f1e
MA
696 if (n > 3)
697 {
698 aLogFile = a[3];
699 if (n > 4)
700 aOutFile = a[4];
701 }
702 }
703 if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
704 {
586db386 705 di << "report " << aOutFile << " has been created\n";
7af17f1e
MA
706 }
707 else
708 {
709 di << "cannot create report " << aOutFile << " from the log file "
710 << aLogFile << "\n";
711 return 1;
712 }
713 }
714 else
715 {
716 di << "unrecognized command " << a[1] << "\n";
717 return 1;
718 }
719 return 0;
720}
721
f0430952 722//==============================================================================
91322f44 723//function : dlocale
724//purpose :
725//==============================================================================
726
727static int dlocale (Draw_Interpretor& di, Standard_Integer n, const char** argv)
728{
729 int category = LC_ALL;
730 if (n > 1)
731 {
732 const char *cat = argv[1];
733 if ( ! strcmp (cat, "LC_ALL") ) category = LC_ALL;
734 else if ( ! strcmp (cat, "LC_COLLATE") ) category = LC_COLLATE;
735 else if ( ! strcmp (cat, "LC_CTYPE") ) category = LC_CTYPE;
736 else if ( ! strcmp (cat, "LC_MONETARY") ) category = LC_MONETARY;
737 else if ( ! strcmp (cat, "LC_NUMERIC") ) category = LC_NUMERIC;
738 else if ( ! strcmp (cat, "LC_TIME") ) category = LC_TIME;
739 else
740 {
741 cout << "Error: cannot recognize argument " << cat << " as one of LC_ macros" << endl;
742 return 1;
743 }
744 }
745 const char* locale = (n > 2 ? argv[2] : NULL);
746 const char* result = setlocale (category, locale);
747 if (result)
748 di << result;
749 else
750 cout << "Error: unsupported locale specification: " << locale << endl;
751 return 0;
752}
753
754//==============================================================================
f0430952 755//function : dmeminfo
756//purpose :
757//==============================================================================
758
759static int dmeminfo (Draw_Interpretor& theDI,
760 Standard_Integer theArgNb,
761 const char** theArgVec)
762{
763 OSD_MemInfo aMemInfo;
764 if (theArgNb <= 1)
765 {
766 theDI << aMemInfo.ToString();
767 return 0;
768 }
769
770 for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
771 {
772 TCollection_AsciiString anArg (theArgVec[anIter]);
773 anArg.LowerCase();
774 if (anArg == "virt" || anArg == "v")
775 {
776 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
777 }
67a1064e 778 else if (anArg == "heap" || anArg == "h")
779 {
780 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemHeapUsage)) << " ";
781 }
f0430952 782 else if (anArg == "wset" || anArg == "w")
783 {
784 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
785 }
786 else if (anArg == "wsetpeak")
787 {
788 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
789 }
790 else if (anArg == "swap")
791 {
792 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
793 }
794 else if (anArg == "swappeak")
795 {
796 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
797 }
798 else if (anArg == "private")
799 {
800 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
801 }
802 else
803 {
804 std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
805 }
806 }
807 theDI << "\n";
808 return 0;
809}
7fd59977 810
785a9540 811//==============================================================================
618617fe 812//function : dperf
813//purpose :
814//==============================================================================
815
816static int dperf (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
817{
818 // reset if argument is provided and it is not '0'
819 int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0);
820 char buffer[25600];
821 perf_sprint_all_meters (buffer, 25600 - 1, reset);
822 theDI << buffer;
823 return 0;
824}
825
826//==============================================================================
f4dee9bb 827//function : dsetsignal
828//purpose :
829//==============================================================================
830
831static int dsetsignal (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
832{
833 // arm FPE handler if argument is provided and its first symbol is not '0'
834 // or if environment variable CSF_FPE is set and its first symbol is not '0'
835 bool setFPE = false;
836 if (theArgNb > 1)
837 {
838 setFPE = (theArgVec[1][0] == '1' || theArgVec[1][0] == 't');
839 }
840 else
841 {
842 OSD_Environment aEnv ("CSF_FPE");
843 TCollection_AsciiString aEnvStr = aEnv.Value();
844 setFPE = (! aEnvStr.IsEmpty() && aEnvStr.Value(1) != '0');
845 }
846 OSD::SetSignal (setFPE);
847 theDI << "Signal handlers are set, with FPE " << (setFPE ? "armed" : "disarmed");
848 return 0;
849}
850
851//==============================================================================
785a9540 852//function : dtracelevel
853//purpose :
854//==============================================================================
855
856static int dtracelevel (Draw_Interpretor& theDI,
857 Standard_Integer theArgNb,
858 const char** theArgVec)
859{
860 Message_Gravity aLevel = Message_Info;
861 if (theArgNb < 1 || theArgNb > 2)
862 {
863 std::cout << "Error: wrong number of arguments! See usage:\n";
864 theDI.PrintHelp (theArgVec[0]);
865 return 1;
866 }
867 else if (theArgNb == 2)
868 {
869 TCollection_AsciiString aVal (theArgVec[1]);
870 aVal.LowerCase();
871 if (aVal == "trace")
872 {
873 aLevel = Message_Trace;
874 }
875 else if (aVal == "info")
876 {
877 aLevel = Message_Info;
878 }
879 else if (aVal == "warn"
880 || aVal == "warning")
881 {
882 aLevel = Message_Warning;
883 }
884 else if (aVal == "alarm")
885 {
886 aLevel = Message_Alarm;
887 }
888 else if (aVal == "fail")
889 {
890 aLevel = Message_Fail;
891 }
892 else
893 {
894 std::cout << "Error: unknown gravity '" << theArgVec[1] << "'!\n";
895 return 1;
896 }
897 }
898
899 Handle(Message_Messenger) aMessenger = Message::DefaultMessenger();
900 if (aMessenger.IsNull())
901 {
902 std::cout << "Error: default messenger is unavailable!\n";
903 return 1;
904 }
905
906 Message_SequenceOfPrinters& aPrinters = aMessenger->ChangePrinters();
907 if (aPrinters.Length() < 1)
908 {
909 std::cout << "Error: no printers registered in default Messenger!\n";
910 return 0;
911 }
912
913 for (Standard_Integer aPrinterIter = 1; aPrinterIter <= aPrinters.Length(); ++aPrinterIter)
914 {
915 Handle(Message_Printer)& aPrinter = aPrinters.ChangeValue (aPrinterIter);
916 if (theArgNb == 1)
917 {
918 if (aPrinterIter == 1)
919 {
920 aLevel = aPrinter->GetTraceLevel();
921 }
922 else if (aLevel == aPrinter->GetTraceLevel())
923 {
924 continue;
925 }
926
927 switch (aPrinter->GetTraceLevel())
928 {
929 case Message_Trace: theDI << "trace"; break;
930 case Message_Info: theDI << "info"; break;
931 case Message_Warning: theDI << "warn"; break;
932 case Message_Alarm: theDI << "alarm"; break;
933 case Message_Fail: theDI << "fail"; break;
934 }
935 continue;
936 }
937
938 aPrinter->SetTraceLevel (aLevel);
939 }
940
941 return 0;
942}
943
7fd59977 944void Draw::BasicCommands(Draw_Interpretor& theCommands)
945{
946 static Standard_Boolean Done = Standard_False;
947 if (Done) return;
948 Done = Standard_True;
949
aa02980d 950 ios::sync_with_stdio();
951
7fd59977 952 const char* g = "DRAW General Commands";
785a9540 953
7fd59977 954 theCommands.Add("batch", "returns 1 in batch mode",
955 __FILE__,ifbatch,g);
956 theCommands.Add("spy","spy [file], Save commands in file. no file close",
957 __FILE__,spy,g);
958 theCommands.Add("wait","wait [time(10)], wait time seconds",
959 __FILE__,Draw_wait,g);
960 theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
961 __FILE__,cpulimit,g);
7d3225b5 962 theCommands.Add("chrono","chrono [name action [action...]] \n Operates named timer.\n"
963 " Supported actions: reset, start, stop, restart, show, counter [text].\n"
964 " Without arguments enables / disables global timer for all DRAW commands.",
7fd59977 965 __FILE__,chronom,g);
7d3225b5 966 theCommands.Add("dchrono","see help of chrono command",
7fd59977 967 __FILE__,dchronom,g);
7af17f1e
MA
968 theCommands.Add("mallochook",
969 "debug memory allocation/deallocation, w/o args for help",
970 __FILE__, mallochook, g);
f0430952 971 theCommands.Add ("meminfo",
67a1064e 972 "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
f0430952 973 " : memory counters for this process",
974 __FILE__, dmeminfo, g);
618617fe 975 theCommands.Add("dperf","dperf [reset] -- show performance counters, reset if argument is provided",
976 __FILE__,dperf,g);
f4dee9bb 977 theCommands.Add("dsetsignal","dsetsignal [fpe=0] -- set OSD signal handler, with FPE option if argument is given",
978 __FILE__,dsetsignal,g);
aa02980d 979
785a9540 980 // Logging commands; note that their names are hard-coded in the code
aa02980d 981 // of Draw_Interpretor, thus should not be changed without update of that code!
982 theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
983 __FILE__,dlog,g);
984 theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
985 __FILE__,decho,g);
785a9540 986 theCommands.Add("dtracelevel", "dtracelevel [trace|info|warn|alarm|fail]",
987 __FILE__, dtracelevel, g);
988
8a262fa1 989 theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
990 __FILE__,dbreak,g);
991 theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)",
992 __FILE__,dversion,g);
91322f44 993 theCommands.Add("dlocale", "set and / or query locate of C subsystem (function setlocale())",
994 __FILE__,dlocale,g);
7fd59977 995}