0023081: This is desirable to retrieve GPU memory information from graphic driver
[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 //=======================================================================
215 //function : wait
216 //purpose  : 
217 //=======================================================================
218
219 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
220 {
221   Standard_Integer w = 10;
222   if (n > 1)
223     w = atoi(a[1]);
224   time_t ct = time(NULL) + w;
225   while (time(NULL) < ct) {};
226   return 0;
227 }
228
229 //=======================================================================
230 //function : cpulimit
231 //purpose  : 
232 //=======================================================================
233 #ifdef WNT
234 static unsigned int __stdcall CpuFunc (void * param)
235 {
236   clock_t aCurrent;
237   while (1)
238   {
239     Sleep (5);
240     Standard_Real anUserSeconds, aSystemSeconds;
241     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
242     aCurrent = clock_t(anUserSeconds + aSystemSeconds);
243     
244     if ((aCurrent - MDTV_CPU_CURRENT) >= MDTV_CPU_LIMIT)
245     {
246       printf ("CpuFunc : Fin sur Cpu Limit \n");
247       ExitProcess (2);
248       return 0;
249     }
250   }
251   return 0;
252 }
253 #endif
254
255 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
256 {
257 #ifndef WNT
258   rlimit rlp;
259   rlp.rlim_max = RLIM_INFINITY;
260   if (n <= 1)
261     rlp.rlim_cur = RLIM_INFINITY;
262   else
263     rlp.rlim_cur = atoi(a[1]);
264
265   int status;
266   status=setrlimit(RLIMIT_CPU,&rlp);
267   if (status !=0)
268     di << "status cpulimit setrlimit : " << status << "\n";
269
270 #else
271 //WNT
272   static int aFirst = 1;
273
274   unsigned int __stdcall CpuFunc (void *);
275   unsigned aThreadID;
276
277   if (n <= 1)
278     MDTV_CPU_LIMIT = RLIM_INFINITY;
279   else
280   {
281     MDTV_CPU_LIMIT = atoi (a[1]);
282     Standard_Real anUserSeconds, aSystemSeconds;
283     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
284     MDTV_CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
285
286     if (aFirst) // Launch the thread only at the 1st call.
287     {
288       aFirst = 0;
289       _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
290     }
291   }
292
293 #endif
294
295   return 0;
296 }
297
298 //=======================================================================
299 //function : mallochook
300 //purpose  : 
301 //=======================================================================
302
303 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
304                                    const char** a)
305 {
306   if (n < 2)
307   {
308     di << "\
309 usage: mallochook cmd\n\
310 where cmd is one of:\n\
311   set [<op>]      - set callback to malloc/free; op is one of the following:\n\
312                     0 - set callback to NULL,\n\
313                     1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
314                     2 - set callback OSD_MAllocHook::LogFileHandler\n\
315   reset           - reset the CollectBySize handler\n\
316   report1 [<outfile>]\n\
317                   - write report from CollectBySize handler in <outfile>\n\
318   open [<logfile>]\n\
319                   - open file for writing the log with LogFileHandler\n\
320   close           - close the log file with LogFileHandler\n\
321   report2 [<flag>] [<logfile>] [<outfile>]\n\
322                   - scan <logfile> written with LogFileHandler\n\
323                     and make synthesized report in <outfile>; <flag> can be:\n\
324                     0 - simple stats by sizes (default),\n\
325                     1 - with alive allocation numbers\n\
326 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
327       << "\n";
328     return 0;
329   }
330   if (strcmp(a[1], "set") == 0)
331   {
332     int aType = (n > 2 ? atoi(a[2]) : 1);
333     if (aType < 0 || aType > 2)
334     {
335       di << "unknown op of the command set" << "\n";
336       return 1;
337     }
338     else if (aType == 0)
339     {
340       OSD_MAllocHook::SetCallback(NULL);
341       di << "callback is unset" << "\n";
342     }
343     else if (aType == 1)
344     {
345       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
346       di << "callback is set to CollectBySize" << "\n";
347     }
348     else //if (aType == 2)
349     {
350       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
351       di << "callback is set to LogFileHandler" << "\n";
352     }
353   }
354   else if (strcmp(a[1], "reset") == 0)
355   {
356     OSD_MAllocHook::GetCollectBySize()->Reset();
357     di << "CollectBySize handler is reset" << "\n";
358   }
359   else if (strcmp(a[1], "open") == 0)
360   {
361     const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
362     if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
363     {
364       di << "cannot create file " << aFileName << " for writing" << "\n";
365       return 1;
366     }
367     di << "log file " << aFileName << " is opened for writing" << "\n";
368   }
369   else if (strcmp(a[1], "close") == 0)
370   {
371     OSD_MAllocHook::GetLogFileHandler()->Close();
372     di << "log file is closed" << "\n";
373   }
374   else if (strcmp(a[1], "report1") == 0)
375   {
376     const char* aOutFile = "mem-stat.txt";
377     if (n > 2)
378       aOutFile = a[2];
379     if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
380     {
381       di << "report " << aOutFile << " has been created" << "\n";
382     }
383     else
384     {
385       di << "cannot create report " << aOutFile << "\n";
386       return 1;
387     }
388   }
389   else if (strcmp(a[1], "report2") == 0)
390   {
391     Standard_Boolean includeAlive = Standard_False;
392     const char* aLogFile = "mem-log.txt";
393     const char* aOutFile = "mem-stat.txt";
394     if (n > 2)
395     {
396       includeAlive = (atoi(a[2]) != 0);
397       if (n > 3)
398       {
399         aLogFile = a[3];
400         if (n > 4)
401           aOutFile = a[4];
402       }
403     }
404     if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
405     {
406       di << "report " << aOutFile << " has been created" << "\n";
407     }
408     else
409     {
410       di << "cannot create report " << aOutFile << " from the log file "
411         << aLogFile << "\n";
412       return 1;
413     }
414   }
415   else
416   {
417     di << "unrecognized command " << a[1] << "\n";
418     return 1;
419   }
420   return 0;
421 }
422
423 //==============================================================================
424 //function : dmeminfo
425 //purpose  :
426 //==============================================================================
427
428 static int dmeminfo (Draw_Interpretor& theDI,
429                      Standard_Integer  theArgNb,
430                      const char**      theArgVec)
431 {
432   OSD_MemInfo aMemInfo;
433   if (theArgNb <= 1)
434   {
435     theDI << aMemInfo.ToString();
436     return 0;
437   }
438
439   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
440   {
441     TCollection_AsciiString anArg (theArgVec[anIter]);
442     anArg.LowerCase();
443     if (anArg == "virt" || anArg == "v")
444     {
445       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
446     }
447     else if (anArg == "wset" || anArg == "w")
448     {
449       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
450     }
451     else if (anArg == "wsetpeak")
452     {
453       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
454     }
455     else if (anArg == "swap")
456     {
457       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
458     }
459     else if (anArg == "swappeak")
460     {
461       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
462     }
463     else if (anArg == "private")
464     {
465       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
466     }
467     else
468     {
469       std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
470     }
471   }
472   theDI << "\n";
473   return 0;
474 }
475
476 void Draw::BasicCommands(Draw_Interpretor& theCommands)
477 {
478   static Standard_Boolean Done = Standard_False;
479   if (Done) return;
480   Done = Standard_True;
481
482   const char* g = "DRAW General Commands";
483   
484   theCommands.Add("batch", "returns 1 in batch mode",
485                   __FILE__,ifbatch,g);
486   theCommands.Add("spy","spy [file], Save commands in file. no file close",
487                   __FILE__,spy,g);
488   theCommands.Add("wait","wait [time(10)], wait time seconds",
489                   __FILE__,Draw_wait,g);
490   theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
491                   __FILE__,cpulimit,g);
492   theCommands.Add("chrono","chrono [ name start/stop/reset/show]",
493                   __FILE__,chronom,g);
494   theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
495                   __FILE__,dchronom,g);
496   theCommands.Add("mallochook",
497                   "debug memory allocation/deallocation, w/o args for help",
498                   __FILE__, mallochook, g);
499   theCommands.Add ("meminfo",
500     "meminfo [virt|v] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
501     " : memory counters for this process",
502           __FILE__, dmeminfo, g);
503 }