0023152: Possibility to have echo of DRAW commands in log file
[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
22 #include <Standard_Macro.hxx>
23 #include <Standard_Stream.hxx>
24 #include <Standard_SStream.hxx>
25
26 #include <Draw.ixx>
27 #include <Draw_Appli.hxx>
28 #include <Draw_Printer.hxx>
29
30 #include <Message.hxx>
31 #include <Message_Messenger.hxx>
32 #include <OSD_MemInfo.hxx>
33
34 #ifdef HAVE_CONFIG_H
35 # include <config.h>
36 #endif
37
38 #if defined(HAVE_TIME_H) || defined(WNT)
39 # include <time.h>
40 #endif
41
42 #ifdef HAVE_SIGNAL_H
43 # include <signal.h>
44 #endif
45
46 #ifndef WNT
47 # include <sys/resource.h>
48 # ifdef HAVE_STRINGS_H
49 #  include <strings.h>
50 # endif
51 #else
52 //WNT
53 extern Standard_Boolean Draw_Batch;
54 #include <windows.h>
55 #include <winbase.h>
56 #include <process.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #ifdef HAVE_LIMITS 
60 # include <limits>
61 #elif defined (HAVE_LIMITS_H)
62 # include <limits.h>
63 #endif
64
65 #ifdef WNT
66 # include <limits>
67 #endif
68
69 static clock_t MDTV_CPU_LIMIT;   // Cpu_limit in Sec.
70 static clock_t MDTV_CPU_CURRENT; // cpu time already used at last
71                                  // cpulimit call. (sec.) 
72 //#define strcasecmp strcmp Already defined
73 #define RLIM_INFINITY   0x7fffffff
74 #endif
75
76 #include <Draw_Chronometer.hxx>
77 #include <OSD_MAllocHook.hxx>
78 #include <OSD_Chronometer.hxx>
79
80 #if defined (__hpux) || defined ( HPUX )
81 #define RLIM_INFINITY   0x7fffffff
82 #define RLIMIT_CPU      0
83 #endif
84
85
86
87 //=======================================================================
88 // chronom
89 //=======================================================================
90
91 extern Standard_Boolean Draw_Chrono;
92
93 static Standard_Integer chronom(Draw_Interpretor& di,
94                                 Standard_Integer n,const char** a)
95 {
96   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
97     if (n == 1)
98       Draw_Chrono = !Draw_Chrono;
99     else
100       Draw_Chrono = (*a[1] == '1');
101
102     if (Draw_Chrono) di << "Chronometers activated."<<"\n";
103     else di << "Chronometers desactivated."<<"\n";
104   }
105   else {
106     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
107     Handle(Draw_Chronometer) C;
108     if (!D.IsNull()) {
109       C = Handle(Draw_Chronometer)::DownCast(D);
110     }
111     if (C.IsNull()) {
112       C = new Draw_Chronometer();
113     Draw::Set(a[1],C,Standard_False);
114     }
115     if (n <= 2) {
116       C->Timer().Reset();
117     }
118     else {
119       if (!strcasecmp(a[2],"reset"))
120         C->Timer().Reset();
121       if (!strcasecmp(a[2],"start"))
122         C->Timer().Start();
123       if (!strcasecmp(a[2],"stop"))
124         C->Timer().Stop();
125       if (!strcasecmp(a[2],"show"))
126         C->Timer().Show();
127     }
128   }
129   return 0;
130 }
131
132 static Standard_Integer dchronom(Draw_Interpretor& I,
133                                  Standard_Integer n,const char** a)
134 {
135   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
136     if (n == 1)
137       Draw_Chrono = !Draw_Chrono;
138     else
139       Draw_Chrono = (*a[1] == '1');
140
141     if (Draw_Chrono) I << "Chronometers activated."<<"\n";
142     else I << "Chronometers desactivated."<<"\n";
143   }
144   else {
145     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
146     Handle(Draw_Chronometer) C;
147     if (!D.IsNull()) {
148       C = Handle(Draw_Chronometer)::DownCast(D);
149     }
150     if (C.IsNull()) {
151       C = new Draw_Chronometer();
152     Draw::Set(a[1],C,Standard_False);
153     }
154     if (n <= 2) {
155       C->Timer().Reset();
156     }
157     else {
158       if (!strcasecmp(a[2],"reset"))
159         C->Timer().Reset();
160       if (!strcasecmp(a[2],"start"))
161         C->Timer().Start();
162       if (!strcasecmp(a[2],"stop"))
163         C->Timer().Stop();
164       if (!strcasecmp(a[2],"show")) {
165         Standard_SStream ss;
166         C->Timer().Show(ss);
167         I << ss;
168       }
169     }
170   }
171   return 0;
172 }
173
174
175
176 //=======================================================================
177 //function : ifbatch
178 //purpose  : 
179 //=======================================================================
180
181 static Standard_Integer ifbatch(Draw_Interpretor& DI, Standard_Integer , const char** )
182 {
183   if (Draw_Batch)
184     DI << "1";
185   else
186     DI << "0";
187   
188   return 0;
189 }
190
191 //=======================================================================
192 //function : spy
193 //purpose  : 
194 //=======================================================================
195
196 extern Standard_Boolean Draw_Spying;
197 extern filebuf Draw_Spyfile;
198
199 static Standard_Integer spy(Draw_Interpretor& di, Standard_Integer n, const char** a)
200 {
201   if (Draw_Spying) 
202     Draw_Spyfile.close();
203   Draw_Spying = Standard_False;
204   if (n > 1) {
205     if (!Draw_Spyfile.open(a[1],ios::out)) {
206       di << "Cannot open "<<a[1]<<" for writing"<<"\n";
207       return 1;
208     }
209     Draw_Spying = Standard_True;
210   }
211   return 0;
212 }
213
214 static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const char** a)
215 {
216   if (n != 2 && n != 3)
217   {
218     cout << "Enable or disable logging: " << a[0] << " {on|off}" << endl;
219     cout << "Reset log: " << a[0] << " reset" << endl;
220     cout << "Get log content: " << a[0] << " get" << endl;
221     return 1;
222   }
223
224   if (! strcmp (a[1], "on") && n == 2)
225   {
226     di.SetDoLog (Standard_True);
227 //    di.Log() << "dlog on" << endl; // for symmetry
228   }
229   else if (! strcmp (a[1], "off") && n == 2)
230   {
231     di.SetDoLog (Standard_False);
232   }
233   else if (! strcmp (a[1], "reset") && n == 2)
234   {
235     di.Log().str("");
236   }
237   else if (! strcmp (a[1], "get") && n == 2)
238   {
239     di << di.Log().str().c_str();
240   }
241   else if (! strcmp (a[1], "add") && n == 3)
242   {
243     di.Log() << a[2] << "\n";
244   }
245   else {
246     cout << "Unrecognized option(s): " << a[1] << endl;
247     return 1;
248   }
249   return 0;
250 }
251
252 static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const char** a)
253 {
254   if (n != 2)
255   {
256     cout << "Enable or disable echoing: " << a[0] << " {on|off}" << endl;
257     return 1;
258   }
259
260   if (! strcmp (a[1], "on"))
261   {
262     di.SetDoEcho (Standard_True);
263   }
264   else if (! strcmp (a[1], "off"))
265   {
266     di.SetDoEcho (Standard_False);
267   }
268   else {
269     cout << "Unrecognized option: " << a[1] << endl;
270     return 1;
271   }
272   return 0;
273 }
274
275 //=======================================================================
276 //function : wait
277 //purpose  : 
278 //=======================================================================
279
280 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
281 {
282   Standard_Integer w = 10;
283   if (n > 1)
284     w = atoi(a[1]);
285   time_t ct = time(NULL) + w;
286   while (time(NULL) < ct) {};
287   return 0;
288 }
289
290 //=======================================================================
291 //function : cpulimit
292 //purpose  : 
293 //=======================================================================
294 #ifdef WNT
295 static unsigned int __stdcall CpuFunc (void * param)
296 {
297   clock_t aCurrent;
298   while (1)
299   {
300     Sleep (5);
301     Standard_Real anUserSeconds, aSystemSeconds;
302     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
303     aCurrent = clock_t(anUserSeconds + aSystemSeconds);
304     
305     if ((aCurrent - MDTV_CPU_CURRENT) >= MDTV_CPU_LIMIT)
306     {
307       printf ("CpuFunc : Fin sur Cpu Limit \n");
308       ExitProcess (2);
309       return 0;
310     }
311   }
312   return 0;
313 }
314 #endif
315
316 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
317 {
318 #ifndef WNT
319   rlimit rlp;
320   rlp.rlim_max = RLIM_INFINITY;
321   if (n <= 1)
322     rlp.rlim_cur = RLIM_INFINITY;
323   else
324     rlp.rlim_cur = atoi(a[1]);
325
326   int status;
327   status=setrlimit(RLIMIT_CPU,&rlp);
328   if (status !=0)
329     di << "status cpulimit setrlimit : " << status << "\n";
330
331 #else
332 //WNT
333   static int aFirst = 1;
334
335   unsigned int __stdcall CpuFunc (void *);
336   unsigned aThreadID;
337
338   if (n <= 1)
339     MDTV_CPU_LIMIT = RLIM_INFINITY;
340   else
341   {
342     MDTV_CPU_LIMIT = atoi (a[1]);
343     Standard_Real anUserSeconds, aSystemSeconds;
344     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
345     MDTV_CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
346
347     if (aFirst) // Launch the thread only at the 1st call.
348     {
349       aFirst = 0;
350       _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
351     }
352   }
353
354 #endif
355
356   return 0;
357 }
358
359 //=======================================================================
360 //function : mallochook
361 //purpose  : 
362 //=======================================================================
363
364 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
365                                    const char** a)
366 {
367   if (n < 2)
368   {
369     di << "\
370 usage: mallochook cmd\n\
371 where cmd is one of:\n\
372   set [<op>]      - set callback to malloc/free; op is one of the following:\n\
373                     0 - set callback to NULL,\n\
374                     1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
375                     2 - set callback OSD_MAllocHook::LogFileHandler\n\
376   reset           - reset the CollectBySize handler\n\
377   report1 [<outfile>]\n\
378                   - write report from CollectBySize handler in <outfile>\n\
379   open [<logfile>]\n\
380                   - open file for writing the log with LogFileHandler\n\
381   close           - close the log file with LogFileHandler\n\
382   report2 [<flag>] [<logfile>] [<outfile>]\n\
383                   - scan <logfile> written with LogFileHandler\n\
384                     and make synthesized report in <outfile>; <flag> can be:\n\
385                     0 - simple stats by sizes (default),\n\
386                     1 - with alive allocation numbers\n\
387 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
388       << "\n";
389     return 0;
390   }
391   if (strcmp(a[1], "set") == 0)
392   {
393     int aType = (n > 2 ? atoi(a[2]) : 1);
394     if (aType < 0 || aType > 2)
395     {
396       di << "unknown op of the command set" << "\n";
397       return 1;
398     }
399     else if (aType == 0)
400     {
401       OSD_MAllocHook::SetCallback(NULL);
402       di << "callback is unset" << "\n";
403     }
404     else if (aType == 1)
405     {
406       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
407       di << "callback is set to CollectBySize" << "\n";
408     }
409     else //if (aType == 2)
410     {
411       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
412       di << "callback is set to LogFileHandler" << "\n";
413     }
414   }
415   else if (strcmp(a[1], "reset") == 0)
416   {
417     OSD_MAllocHook::GetCollectBySize()->Reset();
418     di << "CollectBySize handler is reset" << "\n";
419   }
420   else if (strcmp(a[1], "open") == 0)
421   {
422     const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
423     if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
424     {
425       di << "cannot create file " << aFileName << " for writing" << "\n";
426       return 1;
427     }
428     di << "log file " << aFileName << " is opened for writing" << "\n";
429   }
430   else if (strcmp(a[1], "close") == 0)
431   {
432     OSD_MAllocHook::GetLogFileHandler()->Close();
433     di << "log file is closed" << "\n";
434   }
435   else if (strcmp(a[1], "report1") == 0)
436   {
437     const char* aOutFile = "mem-stat.txt";
438     if (n > 2)
439       aOutFile = a[2];
440     if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
441     {
442       di << "report " << aOutFile << " has been created" << "\n";
443     }
444     else
445     {
446       di << "cannot create report " << aOutFile << "\n";
447       return 1;
448     }
449   }
450   else if (strcmp(a[1], "report2") == 0)
451   {
452     Standard_Boolean includeAlive = Standard_False;
453     const char* aLogFile = "mem-log.txt";
454     const char* aOutFile = "mem-stat.txt";
455     if (n > 2)
456     {
457       includeAlive = (atoi(a[2]) != 0);
458       if (n > 3)
459       {
460         aLogFile = a[3];
461         if (n > 4)
462           aOutFile = a[4];
463       }
464     }
465     if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
466     {
467       di << "report " << aOutFile << " has been created" << "\n";
468     }
469     else
470     {
471       di << "cannot create report " << aOutFile << " from the log file "
472         << aLogFile << "\n";
473       return 1;
474     }
475   }
476   else
477   {
478     di << "unrecognized command " << a[1] << "\n";
479     return 1;
480   }
481   return 0;
482 }
483
484 //==============================================================================
485 //function : dmeminfo
486 //purpose  :
487 //==============================================================================
488
489 static int dmeminfo (Draw_Interpretor& theDI,
490                      Standard_Integer  theArgNb,
491                      const char**      theArgVec)
492 {
493   OSD_MemInfo aMemInfo;
494   if (theArgNb <= 1)
495   {
496     theDI << aMemInfo.ToString();
497     return 0;
498   }
499
500   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
501   {
502     TCollection_AsciiString anArg (theArgVec[anIter]);
503     anArg.LowerCase();
504     if (anArg == "virt" || anArg == "v")
505     {
506       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
507     }
508     else if (anArg == "wset" || anArg == "w")
509     {
510       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
511     }
512     else if (anArg == "wsetpeak")
513     {
514       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
515     }
516     else if (anArg == "swap")
517     {
518       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
519     }
520     else if (anArg == "swappeak")
521     {
522       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
523     }
524     else if (anArg == "private")
525     {
526       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
527     }
528     else
529     {
530       std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
531     }
532   }
533   theDI << "\n";
534   return 0;
535 }
536
537 void Draw::BasicCommands(Draw_Interpretor& theCommands)
538 {
539   static Standard_Boolean Done = Standard_False;
540   if (Done) return;
541   Done = Standard_True;
542
543   ios::sync_with_stdio();
544
545   const char* g = "DRAW General Commands";
546   
547   theCommands.Add("batch", "returns 1 in batch mode",
548                   __FILE__,ifbatch,g);
549   theCommands.Add("spy","spy [file], Save commands in file. no file close",
550                   __FILE__,spy,g);
551   theCommands.Add("wait","wait [time(10)], wait time seconds",
552                   __FILE__,Draw_wait,g);
553   theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
554                   __FILE__,cpulimit,g);
555   theCommands.Add("chrono","chrono [ name start/stop/reset/show]",
556                   __FILE__,chronom,g);
557   theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
558                   __FILE__,dchronom,g);
559   theCommands.Add("mallochook",
560                   "debug memory allocation/deallocation, w/o args for help",
561                   __FILE__, mallochook, g);
562   theCommands.Add ("meminfo",
563     "meminfo [virt|v] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
564     " : memory counters for this process",
565           __FILE__, dmeminfo, g);
566
567   // Logging commands; note that their names are hard-coded in the code 
568   // of Draw_Interpretor, thus should not be changed without update of that code!
569   theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
570                   __FILE__,dlog,g);
571   theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
572                   __FILE__,decho,g);
573 }