From 57010b29ccf36f59c9471f030f9d3572b264385e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Mon, 19 Mar 2018 01:52:07 +0100 Subject: [PATCH] Debug Events --- Crow.csproj | 4 +- CrowIDE/CrowIDE.csproj | 2 +- CrowIDE/src/DesignInterface.cs | 17 ++--- Tests/InterfaceControler.cs | 14 +--- src/DebugEvents/DebugEvent.cs | 125 +++++++++++++++++++++++++++++++++ src/Interface.cs | 115 ++++++++++++++++++++---------- src/LayoutingQueueItem.cs | 69 +++++------------- 7 files changed, 236 insertions(+), 110 deletions(-) create mode 100644 src/DebugEvents/DebugEvent.cs diff --git a/Crow.csproj b/Crow.csproj index 466e5b0a..0d8d85db 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -32,7 +32,7 @@ true false $(SolutionDir)build\Debug - DESIGN_MODE;DEBUG_LAYOUTING;DEBUG_UPDATE0;DEBUG_FOCUS0;DEBUG_DISPOSE0;TRACE0;DEBUG;MEASURE_TIME;DEBUG_LOAD0;DEBUG_BINDING0;DEBUG_CLIP_RECTANGLE0 + DESIGN_MODE;DBG_EVENTS;DEBUG_LAYOUTING0;DEBUG_UPDATE0;DEBUG_FOCUS0;DEBUG_DISPOSE0;TRACE0;DEBUG;MEASURE_TIME;DEBUG_LOAD0;DEBUG_BINDING0;DEBUG_CLIP_RECTANGLE0 true @@ -222,6 +222,7 @@ + @@ -251,6 +252,7 @@ + diff --git a/CrowIDE/CrowIDE.csproj b/CrowIDE/CrowIDE.csproj index 1cae7289..c1c92cde 100644 --- a/CrowIDE/CrowIDE.csproj +++ b/CrowIDE/CrowIDE.csproj @@ -24,7 +24,7 @@ true full false - DEBUG; + DEBUG;DBG_EVENTS prompt 4 false diff --git a/CrowIDE/src/DesignInterface.cs b/CrowIDE/src/DesignInterface.cs index 04666b11..9ac9e9a5 100644 --- a/CrowIDE/src/DesignInterface.cs +++ b/CrowIDE/src/DesignInterface.cs @@ -158,8 +158,8 @@ namespace Crow.Coding protected override void processLayouting () { - #if MEASURE_TIME - layoutingMeasure.StartCycle(); + #if DBG_EVENTS + DbgStartSubEvt(DbgEvtType.IFaceLayouting); #endif if (Monitor.TryEnter (LayoutMutex)) { @@ -167,20 +167,21 @@ namespace Crow.Coding LayoutingQueueItem lqi; while (LayoutingQueue.Count > 0) { lqi = LayoutingQueue.Dequeue (); - //Console.WriteLine (lqi.ToString ()); - #if DEBUG_LAYOUTING - currentLQI = lqi; - curLQIsTries.Add(currentLQI); + #if DBG_EVENTS + DbgStartSubEvt (new LayoutingDebugEvent(lqi.LayoutType,lqi.Layoutable as GraphicObject)); #endif lqi.ProcessLayouting (); + #if DBG_EVENTS + DbgEndSubEvt(); + #endif } LayoutingQueue = DiscardQueue; Monitor.Exit (LayoutMutex); DiscardQueue = null; } - #if MEASURE_TIME - layoutingMeasure.StopCycle(); + #if DBG_EVENTS + DbgEndSubEvt(); #endif } } diff --git a/Tests/InterfaceControler.cs b/Tests/InterfaceControler.cs index 034cab39..f3f9cc9d 100644 --- a/Tests/InterfaceControler.cs +++ b/Tests/InterfaceControler.cs @@ -148,24 +148,12 @@ namespace Crow ); #endif - Thread t = new Thread (interfaceThread); - t.IsBackground = true; - t.Start (); + CrowInterface.StartThread (); initGL (); } #endregion - void interfaceThread() - { - while (CrowInterface.ClientRectangle.Size.Width == 0) - Thread.Sleep (5); - - while (true) { - CrowInterface.Update (); - Thread.Sleep (2); - } - } #region Mouse And Keyboard handling public virtual void ProcessResize(Rectangle newSize){ diff --git a/src/DebugEvents/DebugEvent.cs b/src/DebugEvents/DebugEvent.cs new file mode 100644 index 00000000..68ae40e7 --- /dev/null +++ b/src/DebugEvents/DebugEvent.cs @@ -0,0 +1,125 @@ +// +// DebugEvent.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2013-2017 Jean-Philippe Bruyère +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading; + +namespace Crow +{ + #if DBG_EVENTS + public enum DbgEvtType { + Clipping = 8, + Interface = 0x10, + IfaceStart = 0x11, + IFaceUpdate = 0x12, + IFaceClipping = 0x13, + IFaceDrawing = 0x14, + Drawnig = 0x20, + OnDraw = 0x21, + Paint = 0x22, + UpdateCache = 0x23, + RecreateCache = 0x24, + IFaceLayouting = 0x80, + UpdateLayout = 0x81, + RegisterLayouting= 0x82, + } + + public class DebugEvent + { + public DebugEvent (DbgEvtType type, string message = "") + { + EventType = type; + ThreadId = Thread.CurrentThread.ManagedThreadId; + } + + public int ThreadId; + public DbgEvtType EventType; + public Stopwatch Time; + public string Message; + + public DebugEvent Parent; + public List ChildEvents = new List(); + + public virtual void Start () { + Time = Stopwatch.StartNew(); + } + public virtual void Finished () { + Time.Stop(); + } + } + public class WidgetDebugEvent : DebugEvent { + public GraphicObject Target; + public LayoutingType RegisteredLayoutings; + public LayoutingType RequestedLayoutings; + public Rectangle Slot; + public Measure Width; + public Measure Height; + + public WidgetDebugEvent (DbgEvtType type, GraphicObject go, string message = "") : base(type, message) + { + Target = go; + saveTargetState (); + } + protected virtual void saveTargetState () { + RegisteredLayoutings = Target.registeredLayoutings; + RequestedLayoutings = Target.requestedLayoutings; + Width = Target.Width; + Height = Target.Height; + Slot = Target.Slot; + } + public override void Finished () + { + base.Finished (); + saveTargetState (); + } + } + public class LayoutingDebugEvent : WidgetDebugEvent + { + public enum Result { + Ok, + Requeued, + Discarded, + Deleted, + } + public LayoutingDebugEvent (LayoutingType layoutingType, GraphicObject go) : base(DbgEvtType.IFaceLayouting, go) + { + LayoutingType = layoutingType; + Target = go; + } + public LayoutingType LayoutingType; + public Rectangle PreviousSlot; + public Result EndResult; + public override void Finished () + { + base.Finished (); + saveTargetState (); + PreviousSlot = Target.LastSlots; + } + } + #endif +} + diff --git a/src/Interface.cs b/src/Interface.cs index 7902424d..4fc7e669 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -65,6 +65,40 @@ namespace Crow /// public class Interface : ILayoutable { + #if DBG_EVENTS + const int MAX_THREAD = 20; + + public DebugEvent[] PerThreadCurDbgEvt = new DebugEvent[MAX_THREAD]; + public DebugEvent CurDbgEvt { + get { return PerThreadCurDbgEvt [Thread.CurrentThread.ManagedThreadId]; } + set { PerThreadCurDbgEvt [Thread.CurrentThread.ManagedThreadId] = value; } + } + public void DbgLogEvent (DebugEvent de) { + if (CurDbgEvt == null) + CurDbgEvt = new DebugEvent(DbgEvtType.IfaceStart) ; + de.Parent = CurDbgEvt; + if (CurDbgEvt != null) + CurDbgEvt.ChildEvents.Add(de); + } + public DebugEvent DbgStartSubEvt (DbgEvtType dbgType){ + DebugEvent de = new DebugEvent(dbgType); + DbgStartSubEvt(de); + return de; + } + public void DbgStartSubEvt (DebugEvent de){ + if (CurDbgEvt == null) + CurDbgEvt = new DebugEvent(DbgEvtType.IfaceStart) ; + de.Parent = CurDbgEvt; + CurDbgEvt.ChildEvents.Add(de); + CurDbgEvt = de; + CurDbgEvt.Start (); + } + public void DbgEndSubEvt () { + CurDbgEvt.Finished (); + CurDbgEvt = CurDbgEvt.Parent; + } + #endif + #region CTOR static Interface(){ if (Type.GetType ("Mono.Runtime") == null) { @@ -99,6 +133,25 @@ namespace Crow } #endregion + public void StartThread () { + Thread t = new Thread (interfaceThread); + t.IsBackground = true; + t.Start (); + } + void interfaceThread() + { + #if DBG_EVENTS + CurDbgEvt = new DebugEvent(DbgEvtType.IfaceStart); + #endif + + while (ClientRectangle.Size.Width == 0) + Thread.Sleep (5); + + while (true) { + Update (); + Thread.Sleep (2); + } + } public void Init () { CurrentInterface = this; loadCursors (); @@ -134,7 +187,7 @@ namespace Crow public const int MaxCacheSize = 2048; /// Above this count, the layouting is discard from the current /// update cycle and requeued for the next - public const int MaxLayoutingTries = 30; + public const int MaxLayoutingTries = 20; /// Above this count, the layouting is discard for the widget and it /// will not be rendered on screen public const int MaxDiscardCount = 3; @@ -535,6 +588,10 @@ namespace Crow /// Result: the Interface bitmap is drawn in memory (byte[] bmp) and a dirtyRect and bitmap are available /// public void Update(){ + #if DBG_EVENTS + DbgStartSubEvt(DbgEvtType.IFaceUpdate); + #endif + if (armedClickSender != null && clickTimer.ElapsedMilliseconds >= Interface.DoubleClick) { armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs); armedClickSender = null; @@ -562,30 +619,17 @@ namespace Crow if (!Monitor.TryEnter (UpdateMutex)) return; - #if MEASURE_TIME - updateMeasure.StartCycle(); - #endif - processLayouting (); - #if DEBUG_LAYOUTING - if (curLQIsTries.Count > 0){ - LQIsTries.Add(curLQIsTries); - curLQIsTries = new LQIList(); - LQIs.Add(curLQIs); - curLQIs = new LQIList(); - } - #endif - clippingRegistration (); processDrawing (); - #if MEASURE_TIME - updateMeasure.StopCycle(); - #endif - Monitor.Exit (UpdateMutex); + + #if DBG_EVENTS + DbgEndSubEvt (); + #endif } #if DEBUG_LAYOUTING public string BreakingName; @@ -594,39 +638,38 @@ namespace Crow /// Layouting queue items. Failing LQI's are requeued in this cycle until MaxTry is reached which /// trigger an enqueue for the next Update Cycle protected virtual void processLayouting(){ - #if MEASURE_TIME - layoutingMeasure.StartCycle(); + #if DBG_EVENTS + DbgStartSubEvt(DbgEvtType.IFaceLayouting); #endif if (Monitor.TryEnter (LayoutMutex)) { DiscardQueue = new Queue (); - //Debug.WriteLine ("======= Layouting queue start ======="); LayoutingQueueItem lqi; while (LayoutingQueue.Count > 0) { lqi = LayoutingQueue.Dequeue (); - #if DEBUG_LAYOUTING - currentLQI = lqi; - curLQIsTries.Add(currentLQI); - if (lqi.graphicObject.Name == BreakingName) - Debugger.Break(); + #if DBG_EVENTS + DbgStartSubEvt (new LayoutingDebugEvent(lqi.LayoutType,lqi.Layoutable as GraphicObject)); #endif lqi.ProcessLayouting (); + #if DBG_EVENTS + DbgEndSubEvt(); + #endif } LayoutingQueue = DiscardQueue; Monitor.Exit (LayoutMutex); DiscardQueue = null; } - #if MEASURE_TIME - layoutingMeasure.StopCycle(); + #if DBG_EVENTS + DbgEndSubEvt(); #endif } /// Degueue Widget to clip from DrawingQueue and register the last painted slot and the new one /// Clipping rectangles are added at each level of the tree from leef to root, that's the way for the painting /// operation to known if it should go down in the tree for further graphic updates and repaints void clippingRegistration(){ - #if MEASURE_TIME - clippingMeasure.StartCycle(); + #if DBG_EVENTS + DbgStartSubEvt(DbgEvtType.IFaceClipping); #endif GraphicObject g = null; while (ClippingQueue.Count > 0) { @@ -637,15 +680,15 @@ namespace Crow g.ClippingRegistration (); } - #if MEASURE_TIME - clippingMeasure.StopCycle(); + #if DBG_EVENTS + DbgEndSubEvt(); #endif } /// Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be /// repainted. If it contains also clip rectangles, its cache will be update, or if not cached a full redraw will take place void processDrawing(){ - #if MEASURE_TIME - drawingMeasure.StartCycle(); + #if DBG_EVENTS + DbgStartSubEvt(DbgEvtType.IFaceDrawing); #endif if (DragImage != null) clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight)); @@ -725,8 +768,8 @@ namespace Crow //surf.WriteToPng (@"/mnt/data/test.png"); } } - #if MEASURE_TIME - drawingMeasure.StopCycle(); + #if DBG_EVENTS + DbgEndSubEvt (); #endif } #endregion diff --git a/src/LayoutingQueueItem.cs b/src/LayoutingQueueItem.cs index cf72aeb9..ab9fe379 100644 --- a/src/LayoutingQueueItem.cs +++ b/src/LayoutingQueueItem.cs @@ -57,26 +57,6 @@ namespace Crow /// Unsuccessfull UpdateLayout and requeueing count public int LayoutingTries, DiscardCount; - #if DEBUG_LAYOUTING - public Stopwatch LQITime; - public GraphicObject graphicObject { - get { return Layoutable as GraphicObject; } - } - public string Name { - get { return graphicObject.Name; } - } - public string FullName { - get { return graphicObject.ToString(); } - } - public Measure Width { - get { return graphicObject.Width; } - } - public Measure Height { - get { return graphicObject.Height; } - } - public Rectangle Slot, NewSlot; - #endif - #region CTOR public LayoutingQueueItem (LayoutingType _layoutType, ILayoutable _graphicObject) { @@ -85,16 +65,9 @@ namespace Crow Layoutable.RegisteredLayoutings |= LayoutType; LayoutingTries = 0; DiscardCount = 0; - #if DEBUG_LAYOUTING - LQITime = new Stopwatch(); - Slot = Rectangle.Empty; - NewSlot = Rectangle.Empty; - Debug.WriteLine ("\tRegister => " + this.ToString ()); - #endif } #endregion - public void ProcessLayouting() { GraphicObject go = Layoutable as GraphicObject; @@ -104,30 +77,27 @@ namespace Crow if (go.Parent == null) {//TODO:improve this go.registeredLayoutings &= (~LayoutType); go.requestedLayoutings |= LayoutType; - //cancel layouting for object without parent, maybe some were in queue when - //removed from a listbox - #if DEBUG_UPDATE || DEBUG_LAYOUTING - Debug.WriteLine ("ERROR: processLayouting, no parent for: " + this.ToString ()); - #endif go.parentRWLock.ExitReadLock (); + #if DBG_EVENTS + (go.IFace.CurDbgEvt as LayoutingDebugEvent).EndResult = LayoutingDebugEvent.Result.Deleted; + go.IFace.CurDbgEvt.Message = "Parent is null"; + #endif return; } - #if DEBUG_LAYOUTING - LQITime.Start(); - Debug.WriteLine ("=> " + this.ToString ()); - #endif LayoutingTries++; if (!Layoutable.UpdateLayout (LayoutType)) { - #if DEBUG_LAYOUTING - Debug.WriteLine ("\t\tRequeued"); - #endif if (LayoutingTries < Interface.MaxLayoutingTries) { Layoutable.RegisteredLayoutings |= LayoutType; + + #if DBG_EVENTS + (go.IFace.CurDbgEvt as LayoutingDebugEvent).EndResult = LayoutingDebugEvent.Result.Requeued; + #endif + (Layoutable as GraphicObject).IFace.LayoutingQueue.Enqueue (this); } else if (DiscardCount < Interface.MaxDiscardCount) { - #if DEBUG_LAYOUTING - Debug.WriteLine ("\t\tDiscarded"); + #if DBG_EVENTS + (go.IFace.CurDbgEvt as LayoutingDebugEvent).EndResult = LayoutingDebugEvent.Result.Discarded; #endif go.LayoutingDiscardCheck (LayoutType); LayoutingTries = 0; @@ -135,19 +105,16 @@ namespace Crow Layoutable.RegisteredLayoutings |= LayoutType; (Layoutable as GraphicObject).IFace.DiscardQueue.Enqueue (this); } - //#if DEBUG_LAYOUTING + #if DBG_EVENTS else - Debug.WriteLine ("\tDELETED => " + this.ToString ()); - //#endif - } - - else{ - if (LayoutingTries > 2 || DiscardCount > 0) - Debug.WriteLine (this.ToString ()); + (go.IFace.CurDbgEvt as LayoutingDebugEvent).EndResult = LayoutingDebugEvent.Result.Deleted; + #endif } - #if DEBUG_LAYOUTING - LQITime.Stop(); + #if DBG_EVENTS + else + (go.IFace.CurDbgEvt as LayoutingDebugEvent).EndResult = LayoutingDebugEvent.Result.Ok; #endif + go.parentRWLock.ExitReadLock (); } -- 2.47.3