1 // Created on: 1995-02-23
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
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
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <Standard_Macro.hxx>
18 #include <Standard_Stream.hxx>
19 #include <Standard_SStream.hxx>
20 #include <Standard_Version.hxx>
23 #include <Draw_Appli.hxx>
24 #include <Draw_Chronometer.hxx>
25 #include <Draw_Printer.hxx>
27 #include <Message.hxx>
28 #include <Message_Messenger.hxx>
30 #include <OSD_MemInfo.hxx>
31 #include <OSD_MAllocHook.hxx>
32 #include <OSD_Chronometer.hxx>
34 #include <OSD_Exception_CTRL_BREAK.hxx>
46 #define RLIM_INFINITY 0x7fffffff
48 static clock_t CPU_CURRENT; // cpu time already used at last
49 // cpulimit call. (sec.)
53 #include <sys/resource.h>
56 #if defined (__hpux) || defined ( HPUX )
57 #define RLIM_INFINITY 0x7fffffff
63 extern Standard_Boolean Draw_Batch;
65 static clock_t CPU_LIMIT; // Cpu_limit in Sec.
67 //=======================================================================
69 //=======================================================================
71 extern Standard_Boolean Draw_Chrono;
73 static Standard_Integer chronom(Draw_Interpretor& di,
74 Standard_Integer n,const char** a)
76 if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
78 Draw_Chrono = !Draw_Chrono;
80 Draw_Chrono = (*a[1] == '1');
82 if (Draw_Chrono) di << "Chronometers activated."<<"\n";
83 else di << "Chronometers desactivated."<<"\n";
86 Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
87 Handle(Draw_Chronometer) C;
89 C = Handle(Draw_Chronometer)::DownCast(D);
92 C = new Draw_Chronometer();
93 Draw::Set(a[1],C,Standard_False);
99 if (!strcasecmp(a[2],"reset"))
101 if (!strcasecmp(a[2],"start"))
103 if (!strcasecmp(a[2],"stop"))
105 if (!strcasecmp(a[2],"show"))
112 static Standard_Integer dchronom(Draw_Interpretor& I,
113 Standard_Integer n,const char** a)
115 if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
117 Draw_Chrono = !Draw_Chrono;
119 Draw_Chrono = (*a[1] == '1');
121 if (Draw_Chrono) I << "Chronometers activated."<<"\n";
122 else I << "Chronometers desactivated."<<"\n";
125 Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
126 Handle(Draw_Chronometer) C;
128 C = Handle(Draw_Chronometer)::DownCast(D);
131 C = new Draw_Chronometer();
132 Draw::Set(a[1],C,Standard_False);
138 if (!strcasecmp(a[2],"reset"))
140 if (!strcasecmp(a[2],"start"))
142 if (!strcasecmp(a[2],"stop"))
144 if (!strcasecmp(a[2],"show")) {
156 //=======================================================================
159 //=======================================================================
161 static Standard_Integer ifbatch(Draw_Interpretor& DI, Standard_Integer , const char** )
171 //=======================================================================
174 //=======================================================================
176 extern Standard_Boolean Draw_Spying;
177 extern filebuf Draw_Spyfile;
179 static Standard_Integer spy(Draw_Interpretor& di, Standard_Integer n, const char** a)
182 Draw_Spyfile.close();
183 Draw_Spying = Standard_False;
185 if (!Draw_Spyfile.open(a[1],ios::out)) {
186 di << "Cannot open "<<a[1]<<" for writing"<<"\n";
189 Draw_Spying = Standard_True;
194 static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const char** a)
196 if (n != 2 && n != 3)
198 cout << "Enable or disable logging: " << a[0] << " {on|off}" << endl;
199 cout << "Reset log: " << a[0] << " reset" << endl;
200 cout << "Get log content: " << a[0] << " get" << endl;
204 if (! strcmp (a[1], "on") && n == 2)
206 di.SetDoLog (Standard_True);
207 // di.Log() << "dlog on" << endl; // for symmetry
209 else if (! strcmp (a[1], "off") && n == 2)
211 di.SetDoLog (Standard_False);
213 else if (! strcmp (a[1], "reset") && n == 2)
217 else if (! strcmp (a[1], "get") && n == 2)
219 di << di.Log().str().c_str();
221 else if (! strcmp (a[1], "add") && n == 3)
223 di.Log() << a[2] << "\n";
226 cout << "Unrecognized option(s): " << a[1] << endl;
232 static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const char** a)
236 cout << "Enable or disable echoing: " << a[0] << " {on|off}" << endl;
240 if (! strcmp (a[1], "on"))
242 di.SetDoEcho (Standard_True);
244 else if (! strcmp (a[1], "off"))
246 di.SetDoEcho (Standard_False);
249 cout << "Unrecognized option: " << a[1] << endl;
255 static Standard_Integer dbreak(Draw_Interpretor& di, Standard_Integer, const char**)
260 catch (OSD_Exception_CTRL_BREAK) {
261 di << "User pressed Control-Break";
262 return 1; // Tcl exception
268 static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const char**)
270 // print OCCT version and OCCTY-specific macros used
271 di << "Open CASCADE Technology " << OCC_VERSION_STRING_EXT << "\n";
272 #if defined(DEB) || defined(_DEBUG)
273 di << "Debug mode\n";
276 di << "TBB enabled (HAVE_TBB)\n";
278 di << "TBB disabled\n";
281 di << "GL2PS enabled (HAVE_GL2PS)\n";
283 di << "GL2PS disabled\n";
285 #ifdef HAVE_FREEIMAGE
286 di << "FreeImage enabled (HAVE_FREEIMAGE)\n";
288 di << "FreeImage disabled\n";
291 di << "OpenCL enabled (HAVE_OPENCL)\n";
293 di << "OpenCL disabled\n";
296 di << "Exceptions disabled (No_Exception)\n";
298 di << "Exceptions enabled\n";
301 // check compiler, OS, etc. using pre-processor macros provided by compiler
302 // see "Pre-defined C/C++ Compiler Macros" http://sourceforge.net/p/predef/wiki/
303 // note that only modern compilers that are known to be used for OCCT are recognized
305 // compiler; note that GCC and MSVC are last as other compilers (e.g. Intel) can also define __GNUC__ and _MSC_VER
306 #if defined(__INTEL_COMPILER)
307 di << "Compiler: Intel " << __INTEL_COMPILER << "\n";
308 #elif defined(__BORLANDC__)
309 di << "Compiler: Borland C++ (__BORLANDC__ = " << __BORLANDC__ << ")\n";
310 #elif defined(__clang__)
311 di << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__ << "\n";
312 #elif defined(__SUNPRO_C)
313 di << "Compiler: Sun Studio (__SUNPRO_C = " << __SUNPROC_C << ")\n";
314 #elif defined(_MSC_VER)
315 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";
316 #elif defined(__GNUC__)
317 di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n";
319 di << "Compiler: unrecognized\n";
322 // Cygwin and MinGW specifics
323 #if defined(__CYGWIN__)
326 #if defined(__MINGW64__)
327 di << "MinGW 64 " << __MINGW64_MAJOR_VERSION << "." << __MINGW64_MINOR_VERSION << "\n";
328 #elif defined(__MINGW32__)
329 di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n";
333 #if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64)
334 di << "Architecture: AMD64\n";
335 #elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_)
336 di << "Architecture: Intel x86\n";
337 #elif defined(_M_IA64) || defined(__ia64__)
338 di << "Architecture: Intel Itanium (IA 64)\n";
339 #elif defined(__sparc__) || defined(__sparc)
340 di << "Architecture: SPARC\n";
342 di << "Architecture: unrecognized\n";
346 #if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
347 di << "OS: Windows\n";
348 #elif defined(__APPLE__) || defined(__MACH__)
349 di << "OS: Mac OS X\n";
351 di << "OS: SUN Solaris\n";
352 #elif defined(__ANDROID__) /* must be before Linux */
353 #include <android/api-level.h>
354 di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n";
355 #elif defined(__linux__)
357 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
358 #include <sys/param.h>
359 di << "OS: BSD (BSD = " << BSD << ")\n";
361 di << "OS: unrecognized\n";
367 //=======================================================================
370 //=======================================================================
372 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
374 Standard_Integer w = 10;
376 w = Draw::Atoi(a[1]);
377 time_t ct = time(NULL) + w;
378 while (time(NULL) < ct) {};
382 //=======================================================================
383 //function : cpulimit
385 //=======================================================================
387 static unsigned int __stdcall CpuFunc (void * /*param*/)
393 Standard_Real anUserSeconds, aSystemSeconds;
394 OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
395 aCurrent = clock_t(anUserSeconds + aSystemSeconds);
397 if ((aCurrent - CPU_CURRENT) >= CPU_LIMIT)
399 cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
406 static void CpuFunc (int)
408 cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
414 static Standard_Integer cpulimit(Draw_Interpretor&, Standard_Integer n, const char** a)
417 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
421 // Windows specific code
423 static int aFirst = 1;
425 unsigned int __stdcall CpuFunc (void *);
429 CPU_LIMIT = RLIM_INFINITY;
432 CPU_LIMIT = Draw::Atoi (a[1]);
433 Standard_Real anUserSeconds, aSystemSeconds;
434 OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
435 CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
437 if (aFirst) // Launch the thread only at the 1st call.
440 _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
449 rlp.rlim_max = RLIM_INFINITY;
451 rlp.rlim_cur = RLIM_INFINITY;
453 rlp.rlim_cur = Draw::Atoi(a[1]);
454 CPU_LIMIT = rlp.rlim_cur;
457 status=setrlimit(RLIMIT_CPU,&rlp);
459 di << "status cpulimit setrlimit : " << status << "\n";
461 // set signal handler to print a message before death
462 struct sigaction act, oact;
463 memset (&act, 0, sizeof(act));
464 act.sa_handler = CpuFunc;
465 sigaction (SIGXCPU, &act, &oact);
472 //=======================================================================
473 //function : mallochook
475 //=======================================================================
477 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
483 usage: mallochook cmd\n\
484 where cmd is one of:\n\
485 set [<op>] - set callback to malloc/free; op is one of the following:\n\
486 0 - set callback to NULL,\n\
487 1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
488 2 - set callback OSD_MAllocHook::LogFileHandler\n\
489 reset - reset the CollectBySize handler\n\
490 report1 [<outfile>]\n\
491 - write report from CollectBySize handler in <outfile>\n\
493 - open file for writing the log with LogFileHandler\n\
494 close - close the log file with LogFileHandler\n\
495 report2 [<flag>] [<logfile>] [<outfile>]\n\
496 - scan <logfile> written with LogFileHandler\n\
497 and make synthesized report in <outfile>; <flag> can be:\n\
498 0 - simple stats by sizes (default),\n\
499 1 - with alive allocation numbers\n\
500 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
504 if (strcmp(a[1], "set") == 0)
506 int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
507 if (aType < 0 || aType > 2)
509 di << "unknown op of the command set" << "\n";
514 OSD_MAllocHook::SetCallback(NULL);
515 di << "callback is unset" << "\n";
519 OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
520 di << "callback is set to CollectBySize" << "\n";
522 else //if (aType == 2)
524 OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
525 di << "callback is set to LogFileHandler" << "\n";
528 else if (strcmp(a[1], "reset") == 0)
530 OSD_MAllocHook::GetCollectBySize()->Reset();
531 di << "CollectBySize handler is reset" << "\n";
533 else if (strcmp(a[1], "open") == 0)
535 const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
536 if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
538 di << "cannot create file " << aFileName << " for writing" << "\n";
541 di << "log file " << aFileName << " is opened for writing" << "\n";
543 else if (strcmp(a[1], "close") == 0)
545 OSD_MAllocHook::GetLogFileHandler()->Close();
546 di << "log file is closed" << "\n";
548 else if (strcmp(a[1], "report1") == 0)
550 const char* aOutFile = "mem-stat.txt";
553 if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
555 di << "report " << aOutFile << " has been created" << "\n";
559 di << "cannot create report " << aOutFile << "\n";
563 else if (strcmp(a[1], "report2") == 0)
565 Standard_Boolean includeAlive = Standard_False;
566 const char* aLogFile = "mem-log.txt";
567 const char* aOutFile = "mem-stat.txt";
570 includeAlive = (Draw::Atoi(a[2]) != 0);
578 if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
580 di << "report " << aOutFile << " has been created" << "\n";
584 di << "cannot create report " << aOutFile << " from the log file "
591 di << "unrecognized command " << a[1] << "\n";
597 //==============================================================================
600 //==============================================================================
602 static int dlocale (Draw_Interpretor& di, Standard_Integer n, const char** argv)
604 int category = LC_ALL;
607 const char *cat = argv[1];
608 if ( ! strcmp (cat, "LC_ALL") ) category = LC_ALL;
609 else if ( ! strcmp (cat, "LC_COLLATE") ) category = LC_COLLATE;
610 else if ( ! strcmp (cat, "LC_CTYPE") ) category = LC_CTYPE;
611 else if ( ! strcmp (cat, "LC_MONETARY") ) category = LC_MONETARY;
612 else if ( ! strcmp (cat, "LC_NUMERIC") ) category = LC_NUMERIC;
613 else if ( ! strcmp (cat, "LC_TIME") ) category = LC_TIME;
616 cout << "Error: cannot recognize argument " << cat << " as one of LC_ macros" << endl;
620 const char* locale = (n > 2 ? argv[2] : NULL);
621 const char* result = setlocale (category, locale);
625 cout << "Error: unsupported locale specification: " << locale << endl;
629 //==============================================================================
630 //function : dmeminfo
632 //==============================================================================
634 static int dmeminfo (Draw_Interpretor& theDI,
635 Standard_Integer theArgNb,
636 const char** theArgVec)
638 OSD_MemInfo aMemInfo;
641 theDI << aMemInfo.ToString();
645 for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
647 TCollection_AsciiString anArg (theArgVec[anIter]);
649 if (anArg == "virt" || anArg == "v")
651 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
653 else if (anArg == "heap" || anArg == "h")
655 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemHeapUsage)) << " ";
657 else if (anArg == "wset" || anArg == "w")
659 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
661 else if (anArg == "wsetpeak")
663 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
665 else if (anArg == "swap")
667 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
669 else if (anArg == "swappeak")
671 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
673 else if (anArg == "private")
675 theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
679 std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
686 //==============================================================================
687 //function : dtracelevel
689 //==============================================================================
691 static int dtracelevel (Draw_Interpretor& theDI,
692 Standard_Integer theArgNb,
693 const char** theArgVec)
695 Message_Gravity aLevel = Message_Info;
696 if (theArgNb < 1 || theArgNb > 2)
698 std::cout << "Error: wrong number of arguments! See usage:\n";
699 theDI.PrintHelp (theArgVec[0]);
702 else if (theArgNb == 2)
704 TCollection_AsciiString aVal (theArgVec[1]);
708 aLevel = Message_Trace;
710 else if (aVal == "info")
712 aLevel = Message_Info;
714 else if (aVal == "warn"
715 || aVal == "warning")
717 aLevel = Message_Warning;
719 else if (aVal == "alarm")
721 aLevel = Message_Alarm;
723 else if (aVal == "fail")
725 aLevel = Message_Fail;
729 std::cout << "Error: unknown gravity '" << theArgVec[1] << "'!\n";
734 Handle(Message_Messenger) aMessenger = Message::DefaultMessenger();
735 if (aMessenger.IsNull())
737 std::cout << "Error: default messenger is unavailable!\n";
741 Message_SequenceOfPrinters& aPrinters = aMessenger->ChangePrinters();
742 if (aPrinters.Length() < 1)
744 std::cout << "Error: no printers registered in default Messenger!\n";
748 for (Standard_Integer aPrinterIter = 1; aPrinterIter <= aPrinters.Length(); ++aPrinterIter)
750 Handle(Message_Printer)& aPrinter = aPrinters.ChangeValue (aPrinterIter);
753 if (aPrinterIter == 1)
755 aLevel = aPrinter->GetTraceLevel();
757 else if (aLevel == aPrinter->GetTraceLevel())
762 switch (aPrinter->GetTraceLevel())
764 case Message_Trace: theDI << "trace"; break;
765 case Message_Info: theDI << "info"; break;
766 case Message_Warning: theDI << "warn"; break;
767 case Message_Alarm: theDI << "alarm"; break;
768 case Message_Fail: theDI << "fail"; break;
773 aPrinter->SetTraceLevel (aLevel);
779 void Draw::BasicCommands(Draw_Interpretor& theCommands)
781 static Standard_Boolean Done = Standard_False;
783 Done = Standard_True;
785 ios::sync_with_stdio();
787 const char* g = "DRAW General Commands";
789 theCommands.Add("batch", "returns 1 in batch mode",
791 theCommands.Add("spy","spy [file], Save commands in file. no file close",
793 theCommands.Add("wait","wait [time(10)], wait time seconds",
794 __FILE__,Draw_wait,g);
795 theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
796 __FILE__,cpulimit,g);
797 theCommands.Add("chrono","chrono [ name start/stop/reset/show]",
799 theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
800 __FILE__,dchronom,g);
801 theCommands.Add("mallochook",
802 "debug memory allocation/deallocation, w/o args for help",
803 __FILE__, mallochook, g);
804 theCommands.Add ("meminfo",
805 "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
806 " : memory counters for this process",
807 __FILE__, dmeminfo, g);
809 // Logging commands; note that their names are hard-coded in the code
810 // of Draw_Interpretor, thus should not be changed without update of that code!
811 theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
813 theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
815 theCommands.Add("dtracelevel", "dtracelevel [trace|info|warn|alarm|fail]",
816 __FILE__, dtracelevel, g);
818 theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
820 theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)",
821 __FILE__,dversion,g);
822 theCommands.Add("dlocale", "set and / or query locate of C subsystem (function setlocale())",