Bugfix : Zooming works correct, no more errors on screen.
[xara-cairo.git] / wxOil / camprofile.cpp
blobc9d50efbae8d8631eb7fdfb4a2e656beee5d1325
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
30 ADDITIONAL RIGHTS
31 -----------------
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
35 rights.
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.
50 SCOPE OF LICENSE
51 ----------------
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
56 terms.
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).
85 MARKS
86 -----
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.
94 http://www.xara.com/
96 =================================XARAHEADEREND============================
100 #include "camtypes.h"
102 //#include "camconfig.h"
103 #include "camprofile.h"
105 #if WIN32
106 // include something for GetSytemTimeAsFileTime
107 #else
108 #include <sys/time.h>
109 #include <time.h>
110 #endif
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>
133 Created: 24/11/2005
134 Inputs: -
135 Outputs: -
136 Returns: -
137 Purpose: Default constructor
138 Errors: -
139 SeeAlso: -
141 ********************************************************************************************/
143 CamProfile::CamProfile(CamProfileMode myMode)
145 // Set up in isolation
147 Mode = CAMPROFILE_NONE;
148 pPrev = NULL;
149 pNext = NULL;
150 OilTime = 0;
152 Zombie = FALSE ;
154 if (!Running)
156 Zombie = TRUE;
157 return;
160 ERROR3IF(!Inited, "Profiling system not yet initialized");
162 // Add us to the end of the list
163 if (pTail)
165 pTail->pNext = this;
166 pPrev = pTail;
168 pTail = this;
170 if (!pHead)
172 pHead = this;
175 // note we didn't alter pCurrent above, so it's still set to the old one
176 SetMode(myMode);
180 /********************************************************************************************
182 > CamProfile::~CamProfile()
185 Author: Alex_Bligh <alex@alex.org.uk>
186 Created: 24/11/2005
187 Inputs: -
188 Outputs: -
189 Returns: -
190 Purpose: Destructor
191 Errors: -
192 SeeAlso: -
194 ********************************************************************************************/
196 CamProfile::~CamProfile()
198 if (Zombie)
200 return;
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");
208 if (pPrev)
210 pPrev->pNext = pNext;
212 else
214 // No previous, we must have been the head
215 pHead = pNext;
218 if (pNext)
220 pNext->pPrev = pPrev;
222 else
224 // We must have been the tail
225 pTail = pPrev;
228 // Make sure we don't appear to be in the list still
229 pNext=NULL;
230 pPrev=NULL;
232 // Reawake the previous profiler
233 if (pTail)
235 // this should wipe us off as pCurrent too.
236 pTail->SetMode(pTail->Mode);
238 else
240 pCurrent = NULL;
243 ERROR3IF(pCurrent == this, "Somehow current profiler did not get unset");
247 /********************************************************************************************
249 > BOOL CamProfile::Init()
251 Author: Alex_Bligh <alex@alex.org.uk>
252 Created: 24/11/2005
253 Inputs: None
254 Outputs: None
255 Returns: TRUE if worked, FALSE if failed (out of memory)
256 Purpose: Starts up the profiling system
257 Errors: Returns FALSE on failure.
258 Scope: Static
260 ********************************************************************************************/
263 BOOL CamProfile::Init()
265 if (Inited) return(FALSE);
267 for (INT32 i=0; i<CAMPROFILE_NONE; i++)
269 OilTimeArray[i]=0;
272 pHead = NULL;
273 pTail = NULL;
274 pCurrent = NULL;
275 OurHead = new CamProfile;
276 Running = FALSE;
278 if (!OurHead) return FALSE;
280 Inited = TRUE;
282 // Give the lists a work through
283 ActivateProfiling (TRUE);
284 ActivateProfiling (FALSE);
286 return TRUE;
291 /********************************************************************************************
293 > void CamProfile::SetMode(CamProfileMode myMode, BOOL Base=FALSE)
295 Author: Alex_Bligh <alex@alex.org.uk>
296 Created: 24/11/2005
297 Inputs: myMode - the new mode
298 Base - TRUE to ditch the existing stack of modes
299 Outputs: None
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.
303 Scope:
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)
317 return;
320 ERROR3IF(!Inited, "Profiling system not yet initialized");
322 UINT64 NewTime;
323 #if WIN32
324 // This windows code completely untested by Alex
325 GetSystemTimeAsFileTime ((LPFILETIME)(&NewTime));
326 #else
327 timeval tv;
328 gettimeofday(&tv, NULL);
329 NewTime = (UINT64)(tv.tv_usec)+ ((UINT64)(tv.tv_sec) * 1000000);
330 #endif
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
347 pCurrent=NULL;
349 #if 0
350 else
352 TRACE(_T("CAMPROFILER AWOOGA1 pCurrent=%llx\n"),pCurrent);
353 if (pCurrent)
355 TRACE(_T("CAMPROFILER AWOOGA2 Not crediting %llx ticks\n"),NewTime - pCurrent->OilTime);
358 #endif
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;
368 while (p)
370 CamProfile* pn = p->pPrev;
371 p->Zombie = TRUE;
372 p->pPrev = NULL;
373 p->pNext = NULL;
374 p = pn;
375 // sadly they are not ours to delete
378 // Now unjunk us
379 Zombie = FALSE;
380 pHead = this;
381 pTail = this;
385 // Now start us
386 if (myMode != CAMPROFILE_NONE)
388 OilTime = NewTime;
389 Mode = myMode;
390 pCurrent = this;
395 /********************************************************************************************
397 > static void CamProfile::UpdateOilTimes();
399 Author: Alex_Bligh <alex@alex.org.uk>
400 Created: 24/11/2005
401 Inputs: None
402 Outputs: None
403 Returns: None
404 Purpose: Updates the current oil times
405 Errors: Returns FALSE on failure.
406 Scope: static
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
410 time on.
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>
430 Created: 24/11/2005
431 Inputs: length - maximum length of string to be filled in, in CHARACTERS including NULL
432 Outputs: pTime - filled in with string
433 Returns: None
434 Purpose: Returns the current Oil time
435 Errors: Returns FALSE on failure.
436 Scope: static
439 ********************************************************************************************/
442 void CamProfile::GetTimeString(TCHAR * pTime, UINT32 length)
444 ERROR3IF(!Inited, "Profiling system not yet initialized");
445 UpdateOilTimes();
446 if ((length < 26+6) || pCurrent && Running && !pCurrent->Zombie)
448 // Read from LastOilTime
449 UINT64 Time=LastOilTime;
450 #if WIN32
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
453 // to add.
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)}'
463 // 11644473600
465 Time = Time-11644473600LL*10000000LL;
466 Time = (Time+5)/10;
467 #endif
468 // Time is now in microseconds since 1 Jan 1970
469 UINT64 uSecs = Time % 1000000;
470 UINT64 Secs = Time / 1000000;
471 time_t t = Secs;
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>
492 Created: 24/11/2005
493 Inputs: None
494 Outputs: None
495 Returns: None
496 Purpose: Indicates to the profiling system we are at the base of the system
497 Errors: Returns FALSE on failure.
498 Scope: Static
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");
512 if (!Running)
514 return;
517 if (!pTail)
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");
527 if (pTail)
529 pTail->SetMode(myMode, TRUE);
533 /********************************************************************************************
535 > static BOOL CamProfile::ResetCounters()
537 Author: Alex_Bligh <alex@alex.org.uk>
538 Created: 24/11/2005
539 Inputs: None
540 Outputs: None
541 Returns: TRUE if worked, FALSE if failed (out of memory)
542 Purpose: Resets the profiling counters
543 Errors: Returns FALSE on failure.
544 Scope: Static
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()
554 if (!Running)
556 return TRUE;
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;
568 if (pActive)
570 OldMode = pActive->Mode;
571 pActive->SetMode(CAMPROFILE_NONE);
574 for (INT32 i=0; i<CAMPROFILE_NONE; i++)
576 OilTimeArray[i]=0;
579 if (pActive)
581 pActive->SetMode(OldMode);
583 return TRUE;
586 /********************************************************************************************
588 > BOOL CamProfile::ActivateProfiling(BOOL Run = TRUE)
590 Author: Alex_Bligh <alex@alex.org.uk>
591 Created: 24/11/2005
592 Inputs: None
593 Outputs: None
594 Returns: TRUE if worked, FALSE if failed (out of memory)
595 Purpose: Starts up the profiling system
596 Errors: Returns FALSE on failure.
597 Scope: Static
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
610 if (Running == Run)
612 return TRUE;
615 ERROR3IF(!Inited, "Profiling system not yet initialized");
617 if (Run)
619 // Ignore old linked list
620 pHead = NULL;
621 pTail = NULL;
623 Running=TRUE;
624 if (!pHead)
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
633 ResetCounters();
634 return TRUE;
636 else
638 if (pCurrent)
640 pCurrent->SetMode(CAMPROFILE_NONE);
642 ResetCounters();
644 // Now go through the list removing them all
645 CamProfile * p = pTail;
646 while (p)
648 CamProfile* pn = p->pPrev;
649 p->Zombie = TRUE;
650 p->pPrev = NULL;
651 p->pNext = NULL;
652 p = pn;
653 // sadly they are not ours to delete
655 pHead = NULL;
656 pTail = NULL;
658 if (OurHead)
660 delete (OurHead);
661 OurHead = NULL;
663 Running = FALSE;
666 return TRUE;
669 /********************************************************************************************
671 > CamProfiler::CamProfiler()
674 Author: Alex_Bligh <alex@alex.org.uk>
675 Created: 24/11/2005
676 Inputs: -
677 Outputs: -
678 Returns: -
679 Purpose: Default constructor
680 Errors: -
681 SeeAlso: -
683 ********************************************************************************************/
685 CamProfiler::CamProfiler()
687 Reset();
690 /********************************************************************************************
692 > void CamProfiler::Reset()
695 Author: Alex_Bligh <alex@alex.org.uk>
696 Created: 24/11/2005
697 Inputs: -
698 Outputs: -
699 Returns: -
700 Purpose: Resets counters to current
701 Errors: -
702 SeeAlso: -
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>
719 Created: 24/11/2005
720 Inputs: -
721 Outputs: Results[CAMPROFILE_NONE] - array of doubles filled with number of seconds elapsed
722 Returns: total elapsed time
723 Purpose: Reads counters
724 Errors: -
725 SeeAlso: -
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])
736 CamProfileMode Mode;
737 CamProfile::UpdateOilTimes();
739 #if WIN32
740 // This windows code completely untested by Alex
741 const double factor = 1.0/10000000.0; // Windows uses 100 nanosecond timeslices apparently
742 #else
743 const double factor = 1.0/1000000.0; // UNIX counts in microseconds
744 #endif
746 INT64 check = 0;
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).
751 if (Results)
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);