1 // $Id: camprofile.cpp 1464 2006-07-18 12:32:26Z gerry $
2 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
3 ================================XARAHEADERSTART===========================
5 Xara LX, a vector drawing and manipulation program.
6 Copyright (C) 1993-2006 Xara Group Ltd.
7 Copyright on certain contributions may be held in joint with their
8 respective authors. See AUTHORS file for details.
10 LICENSE TO USE AND MODIFY SOFTWARE
11 ----------------------------------
13 This file is part of Xara LX.
15 Xara LX is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License version 2 as published
17 by the Free Software Foundation.
19 Xara LX and its component source files are distributed in the hope
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 See the GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License along
25 with Xara LX (see the file GPL in the root directory of the
26 distribution); if not, write to the Free Software Foundation, Inc., 51
27 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
37 The additional rights are to use, modify, and distribute the software
38 together with the wxWidgets library, the wxXtra library, and the "CDraw"
39 library and any other such library that any version of Xara LX relased
40 by Xara Group Ltd requires in order to compile and execute, including
41 the static linking of that library to XaraLX. In the case of the
42 "CDraw" library, you may satisfy obligation under the GNU General Public
43 License to provide source code by providing a binary copy of the library
44 concerned and a copy of the license accompanying it.
46 Nothing in this section restricts any of the rights you have under
47 the GNU General Public License.
53 This license applies to this program (XaraLX) and its constituent source
54 files only, and does not necessarily apply to other Xara products which may
55 in part share the same code base, and are subject to their own licensing
58 This license does not apply to files in the wxXtra directory, which
59 are built into a separate library, and are subject to the wxWindows
60 license contained within that directory in the file "WXXTRA-LICENSE".
62 This license does not apply to the binary libraries (if any) within
63 the "libs" directory, which are subject to a separate license contained
64 within that directory in the file "LIBS-LICENSE".
67 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
68 ----------------------------------------------
70 Subject to the terms of the GNU Public License (see above), you are
71 free to do whatever you like with your modifications. However, you may
72 (at your option) wish contribute them to Xara's source tree. You can
73 find details of how to do this at:
74 http://www.xaraxtreme.org/developers/
76 Prior to contributing your modifications, you will need to complete our
77 contributor agreement. This can be found at:
78 http://www.xaraxtreme.org/developers/contribute/
80 Please note that Xara will not accept modifications which modify any of
81 the text between the start and end of this header (marked
82 XARAHEADERSTART and XARAHEADEREND).
88 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
89 designs are registered or unregistered trademarks, design-marks, and/or
90 service marks of Xara Group Ltd. All rights in these marks are reserved.
93 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
96 =================================XARAHEADEREND============================
100 #include "camtypes.h"
102 //#include "camconfig.h"
103 #include "camprofile.h"
106 // include something for GetSytemTimeAsFileTime
108 #include <sys/time.h>
112 CC_IMPLEMENT_DYNCREATE(CamProfile
, CCObject
)
113 CC_IMPLEMENT_DYNCREATE(CamProfiler
, CCObject
)
115 // Declare smart memory handling in Debug builds
116 #define new CAM_DEBUG_NEW
118 CamProfile
* CamProfile::pHead
=NULL
;
119 CamProfile
* CamProfile::pTail
=NULL
;
120 CamProfile
* CamProfile::pCurrent
=NULL
;
121 CamProfile
* CamProfile::OurHead
=NULL
;
122 UINT64
CamProfile::LastOilTime
=0;
123 UINT64
CamProfile::OilTimeArray
[CAMPROFILE_NONE
];
124 BOOL
CamProfile::Running
=0;
125 BOOL
CamProfile::Inited
=0;
127 /********************************************************************************************
129 > CamProfile::CamProfile(CamProfileMode myMode = CAMPROFILE_NONE )
132 Author: Alex_Bligh <alex@alex.org.uk>
137 Purpose: Default constructor
141 ********************************************************************************************/
143 CamProfile::CamProfile(CamProfileMode myMode
)
145 // Set up in isolation
147 Mode
= CAMPROFILE_NONE
;
160 ERROR3IF(!Inited
, "Profiling system not yet initialized");
162 // Add us to the end of the list
175 // note we didn't alter pCurrent above, so it's still set to the old one
180 /********************************************************************************************
182 > CamProfile::~CamProfile()
185 Author: Alex_Bligh <alex@alex.org.uk>
194 ********************************************************************************************/
196 CamProfile::~CamProfile()
203 // If it's not a Zombie, but we are still running, we need to do
204 // list maintenance etc.
206 ERROR3IF(!Inited
, "Profiling system not yet initialized");
210 pPrev
->pNext
= pNext
;
214 // No previous, we must have been the head
220 pNext
->pPrev
= pPrev
;
224 // We must have been the tail
228 // Make sure we don't appear to be in the list still
232 // Reawake the previous profiler
235 // this should wipe us off as pCurrent too.
236 pTail
->SetMode(pTail
->Mode
);
243 ERROR3IF(pCurrent
== this, "Somehow current profiler did not get unset");
247 /********************************************************************************************
249 > BOOL CamProfile::Init()
251 Author: Alex_Bligh <alex@alex.org.uk>
255 Returns: TRUE if worked, FALSE if failed (out of memory)
256 Purpose: Starts up the profiling system
257 Errors: Returns FALSE on failure.
260 ********************************************************************************************/
263 BOOL
CamProfile::Init()
265 if (Inited
) return(FALSE
);
267 for (INT32 i
=0; i
<CAMPROFILE_NONE
; i
++)
275 OurHead
= new CamProfile
;
278 if (!OurHead
) return FALSE
;
282 // Give the lists a work through
283 ActivateProfiling (TRUE
);
284 ActivateProfiling (FALSE
);
291 /********************************************************************************************
293 > void CamProfile::SetMode(CamProfileMode myMode, BOOL Base=FALSE)
295 Author: Alex_Bligh <alex@alex.org.uk>
297 Inputs: myMode - the new mode
298 Base - TRUE to ditch the existing stack of modes
300 Returns: TRUE if worked, FALSE if failed (out of memory)
301 Purpose: Changes the mode of a profiler
302 Errors: Returns FALSE on failure.
305 This is the heart of the profiling system. We've just been told our timer has changed
306 from its current state, to myMode. Therefore, if we were profiling before, we attribute
307 the time passed since that timer started to the relevant array, and mark the old profiler
308 as being dormant. We then set our own time, and set our start position.
310 ********************************************************************************************/
313 void CamProfile::SetMode(CamProfileMode myMode
, BOOL Base
)
315 if (Zombie
|| !Running
)
320 ERROR3IF(!Inited
, "Profiling system not yet initialized");
324 // This windows code completely untested by Alex
325 GetSystemTimeAsFileTime ((LPFILETIME
)(&NewTime
));
328 gettimeofday(&tv
, NULL
);
329 NewTime
= (UINT64
)(tv
.tv_usec
)+ ((UINT64
)(tv
.tv_sec
) * 1000000);
332 // Mainly for debugging
333 LastOilTime
= NewTime
;
335 // TRACE(_T("CAMPROFILER OilTime is %lld\n"),NewTime);
337 // If there is a current profiler, stop it.
338 if (pCurrent
&& ( pCurrent
->Mode
!= CAMPROFILE_NONE
))
340 // Stop the current profiler running - note this may be us
341 UINT64 Elapsed
= NewTime
- pCurrent
->OilTime
;
342 OilTimeArray
[pCurrent
->Mode
] += Elapsed
;
344 // TRACE(_T("CAMPROFILER Credit %lld to %d\n"),Elapsed,(INT32)pCurrent->Mode);
346 pCurrent
->OilTime
= 0; // So we can detect screw-ups - we'll set it again when we start it
352 TRACE(_T("CAMPROFILER AWOOGA1 pCurrent=%llx\n"),pCurrent
);
355 TRACE(_T("CAMPROFILER AWOOGA2 Not crediting %llx ticks\n"),NewTime
- pCurrent
->OilTime
);
360 // If the Base flag is set, junk all the others on the list.
361 if (Base
&& ( (pTail
!= this) || (pHead
!= this))) // don't bother if we're the only one on the list
363 // We are going to junk all the existing profiles except us. Bwahahaha
364 TRACE(_T("CAMPROFILER Clearing up redudant profiling entries\n"));
366 // First junk them all
367 CamProfile
* p
= pTail
;
370 CamProfile
* pn
= p
->pPrev
;
375 // sadly they are not ours to delete
386 if (myMode
!= CAMPROFILE_NONE
)
395 /********************************************************************************************
397 > static void CamProfile::UpdateOilTimes();
399 Author: Alex_Bligh <alex@alex.org.uk>
404 Purpose: Updates the current oil times
405 Errors: Returns FALSE on failure.
408 This writes the OIL time back into the cumulative time. It should be used before
409 reading the OilTimesArray to ensure the current profiler hasn't got uncredited
412 ********************************************************************************************/
415 void CamProfile::UpdateOilTimes()
417 ERROR3IF(!Inited
, "Profiling system not yet initialized");
418 if (pCurrent
&& Running
&& !pCurrent
->Zombie
)
420 // Resetting the mode is sufficient
421 pCurrent
->SetMode(pCurrent
->Mode
);
425 /********************************************************************************************
427 > static void CamProfile::GetTimeString(TCHAR * pTime, UINT32 length);
429 Author: Alex_Bligh <alex@alex.org.uk>
431 Inputs: length - maximum length of string to be filled in, in CHARACTERS including NULL
432 Outputs: pTime - filled in with string
434 Purpose: Returns the current Oil time
435 Errors: Returns FALSE on failure.
439 ********************************************************************************************/
442 void CamProfile::GetTimeString(TCHAR
* pTime
, UINT32 length
)
444 ERROR3IF(!Inited
, "Profiling system not yet initialized");
446 if ((length
< 26+6) || pCurrent
&& Running
&& !pCurrent
->Zombie
)
448 // Read from LastOilTime
449 UINT64 Time
=LastOilTime
;
451 // Convert LastOil time to secs since 1 Jan 1970. We don't care about the date,
452 // we only care about the time, so we pick a roughly correct number of DAYS
454 // That's 369 years, which would have 92 leap years, except for the fact that
455 // 1700, 1800, 1900 were not leap years. So that's 369 years of 365 days plus 89
456 // leap year days, or 134,774 days, or 11,644,473,600 seconds
457 // For the purist, I suppose we might be a few leap seconds out. Yawn.
458 // Another test (thta's all one line):
459 // 11perl -e '{use DateTime;$o=DateTime->new(year=>1601,month=>1,day=>1);
460 // $n=DateTime->new(year=>1970,month=>1,day=>1),
461 // printf "%d\n", $n->subtract_datetime_absolute($o)->in_units(seconds)}'
465 Time
= Time
-11644473600LL*10000000LL;
468 // Time is now in microseconds since 1 Jan 1970
469 UINT64 uSecs
= Time
% 1000000;
470 UINT64 Secs
= Time
/ 1000000;
473 // Don't use ctime_r as it isn't present on Windows
475 //Ask wx for a string with the time
476 wxDateTime
TheTime(t
);
477 wxString
sTime(TheTime
.FormatISOTime());
479 // Now camSnprintf this into the string. This turns it into UNICODE if appropriate
480 camSnprintf (pTime
, length
, _T("%s.%06d"), sTime
.c_str(), uSecs
);
482 else camStrncpy(pTime
, _T("[UNAVAILABLE]"), length
);
483 pTime
[length
-1]=0; // ensure string terminated - string copy primatives do funny thing
487 /********************************************************************************************
489 > static void CamProfile::AtBase(CamProfileMode myMode=CAMPROFILE_NONE)
491 Author: Alex_Bligh <alex@alex.org.uk>
496 Purpose: Indicates to the profiling system we are at the base of the system
497 Errors: Returns FALSE on failure.
500 This is the heart of the profiling system. We've just been told our timer has changed
501 from its current state, to myMode. Therefore, if we were profiling before, we attribute
502 the time passed since that timer started to the relevant array, and mark the old profiler
503 as being dormant. We then set our own time, and set our start position.
505 ********************************************************************************************/
508 void CamProfile::AtBase(CamProfileMode myMode
)
510 ERROR3IF(!Inited
, "Profiling system not yet initialized");
519 // Note we allocate this, and discard the pointer. That's because it has already
520 // added itself to the linked list
521 if (OurHead
) delete(OurHead
);
522 OurHead
= new CamProfile
;
523 if (!OurHead
) return;
526 ERROR3IF(!pTail
,"Didn't get a tail pointer");
529 pTail
->SetMode(myMode
, TRUE
);
533 /********************************************************************************************
535 > static BOOL CamProfile::ResetCounters()
537 Author: Alex_Bligh <alex@alex.org.uk>
541 Returns: TRUE if worked, FALSE if failed (out of memory)
542 Purpose: Resets the profiling counters
543 Errors: Returns FALSE on failure.
546 Reset the counters. DO NOT CALL THIS unless you know what you are doing as it will
547 mean that anyone with stored counter values is going to get a nasty shock.
549 ********************************************************************************************/
552 BOOL
CamProfile::ResetCounters()
559 ERROR3IF(!Inited
, "Profiling system not yet initialized");
561 CamProfileMode OldMode
=CAMPROFILE_NONE
;
563 // Save the old mode of the current operator so we do not credit
564 // already elapsed time
566 CamProfile
* pActive
= pCurrent
;
570 OldMode
= pActive
->Mode
;
571 pActive
->SetMode(CAMPROFILE_NONE
);
574 for (INT32 i
=0; i
<CAMPROFILE_NONE
; i
++)
581 pActive
->SetMode(OldMode
);
586 /********************************************************************************************
588 > BOOL CamProfile::ActivateProfiling(BOOL Run = TRUE)
590 Author: Alex_Bligh <alex@alex.org.uk>
594 Returns: TRUE if worked, FALSE if failed (out of memory)
595 Purpose: Starts up the profiling system
596 Errors: Returns FALSE on failure.
599 This is the heart of the profiling system. We've just been told our timer has changed
600 from its current state, to myMode. Therefore, if we were profiling before, we attribute
601 the time passed since that timer started to the relevant array, and mark the old profiler
602 as being dormant. We then set our own time, and set our start position.
604 ********************************************************************************************/
607 BOOL
CamProfile::ActivateProfiling(BOOL Run
)
609 // Do nothing if we are already in that state
615 ERROR3IF(!Inited
, "Profiling system not yet initialized");
619 // Ignore old linked list
626 // Note we allocate this, and discard the pointer. That's because it has already
627 // added itself to the linked list
628 if (OurHead
) delete(OurHead
);
629 OurHead
= new CamProfile
;
630 if (!OurHead
) return FALSE
;
632 // We can't wake the zombies up as we don't have a list of them
640 pCurrent
->SetMode(CAMPROFILE_NONE
);
644 // Now go through the list removing them all
645 CamProfile
* p
= pTail
;
648 CamProfile
* pn
= p
->pPrev
;
653 // sadly they are not ours to delete
669 /********************************************************************************************
671 > CamProfiler::CamProfiler()
674 Author: Alex_Bligh <alex@alex.org.uk>
679 Purpose: Default constructor
683 ********************************************************************************************/
685 CamProfiler::CamProfiler()
690 /********************************************************************************************
692 > void CamProfiler::Reset()
695 Author: Alex_Bligh <alex@alex.org.uk>
700 Purpose: Resets counters to current
704 ********************************************************************************************/
706 void CamProfiler::Reset()
708 CamProfile::UpdateOilTimes();
709 memcpy(OilTimeArray
, CamProfile::OilTimeArray
, sizeof(OilTimeArray
));
710 FirstOilTime
= CamProfile::LastOilTime
;
713 /********************************************************************************************
715 > double CamProfiler::Read(double Results[CAMPROFILE_NONE])
718 Author: Alex_Bligh <alex@alex.org.uk>
721 Outputs: Results[CAMPROFILE_NONE] - array of doubles filled with number of seconds elapsed
722 Returns: total elapsed time
723 Purpose: Reads counters
727 Results may be NULL, in which case only the total elapsed time will be returned.
729 The results in the array should add up to the total returned, but may not if profiling
730 has been turned off in the mean time.
732 ********************************************************************************************/
734 double CamProfiler::Read(double Results
[CAMPROFILE_NONE
])
737 CamProfile::UpdateOilTimes();
740 // This windows code completely untested by Alex
741 const double factor
= 1.0/10000000.0; // Windows uses 100 nanosecond timeslices apparently
743 const double factor
= 1.0/1000000.0; // UNIX counts in microseconds
748 for (Mode
= (CamProfileMode
)0 ; Mode
< CAMPROFILE_NONE
; Mode
=(CamProfileMode
)((INT32
)Mode
+1))
750 // Cast via INT64 to cope with wrap event (ha ha ha).
752 Results
[Mode
] = factor
* (double)((INT64
)(CamProfile::OilTimeArray
[Mode
] - OilTimeArray
[Mode
]));
753 TRACE(_T("CAMPROFILER type %d=%lld\n"),(INT32
)Mode
,CamProfile::OilTimeArray
[Mode
] - OilTimeArray
[Mode
]);
754 check
+=CamProfile::OilTimeArray
[Mode
] - OilTimeArray
[Mode
];
757 INT64 total
= (INT64
)(CamProfile::LastOilTime
- FirstOilTime
);
758 TRACE(_T("CAMPROFILER check=%lld, total=%lld\n"),check
,total
);
760 return factor
* (double)(total
);