From: Jean-Philippe Bruyère Date: Tue, 12 Jan 2021 09:42:21 +0000 (+0100) Subject: reintroduce PerformanceMeasures for simple main cycles time measurement X-Git-Tag: v0.9.5-beta~105 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=3eb112aa682802b9d6cc71c9d243a44ceeb9d7a1;p=jp%2Fcrow.git reintroduce PerformanceMeasures for simple main cycles time measurement --- diff --git a/Crow/Crow.csproj b/Crow/Crow.csproj index 281e5729..792794aa 100644 --- a/Crow/Crow.csproj +++ b/Crow/Crow.csproj @@ -23,7 +23,7 @@ True true $(NoWarn);1591;1587;1570;1572;1573;1574 - DESIGN_MODE + DESIGN_MODE;_MEASURE_TIME false false App.config diff --git a/Crow/src/DebugUtils/PerformanceMeasure.cs b/Crow/src/DebugUtils/PerformanceMeasure.cs new file mode 100644 index 00000000..f4cf76a8 --- /dev/null +++ b/Crow/src/DebugUtils/PerformanceMeasure.cs @@ -0,0 +1,105 @@ +// Copyright (c) 2013-2021 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + +using System; +using System.Diagnostics; + +namespace Crow +{ + public class PerformanceMeasure : IValueChange { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + if (ValueChanged != null) + ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + public enum Kind + { + Update, + Clipping, + Layouting, + Drawing + } + public static PerformanceMeasure[] Measures; + + [Conditional("MEASURE_TIME")] + public static void InitMeasures () { + Measures = new PerformanceMeasure[4]; + Measures[(int)Kind.Update] = new PerformanceMeasure (Kind.Update, 1); + Measures[(int)Kind.Clipping] = new PerformanceMeasure (Kind.Clipping, 1); + Measures[(int)Kind.Layouting] = new PerformanceMeasure (Kind.Layouting, 1); + Measures[(int)Kind.Drawing] = new PerformanceMeasure (Kind.Drawing, 1); + } + [Conditional ("MEASURE_TIME")] + public static void Notify () { + for (int i = 0; i < 4; i++) + Measures[i].NotifyChanges (); + } + [Conditional ("MEASURE_TIME")] + public static void Begin (Kind kind) { + Measures[(int)kind].StartCycle (); + } + [Conditional ("MEASURE_TIME")] + public static void End (Kind kind) { + Measures[(int)kind].StopCycle (); + } + + + public Stopwatch timer = new Stopwatch (); + public readonly Kind MeasureKind; + public long current, minimum, maximum, total, cptMeasures; + public long cancelLimit; + public string Name => MeasureKind.ToString (); + + public PerformanceMeasure (Kind measureKind, long _cancelLimit = 0){ + MeasureKind = measureKind; + cancelLimit = _cancelLimit; + ResetStats (); + } + + public void StartCycle(){ + timer.Restart(); + } + public void StopCycle(){ + timer.Stop(); + computeStats (); + } + public void NotifyChanges(){ + lock(this){ + if (cptMeasures == 0) + return; + NotifyValueChanged("minimum", minimum); + NotifyValueChanged("maximum", maximum); + NotifyValueChanged("current", current); + // NotifyValueChanged("total", total); + // NotifyValueChanged("cptMeasures", cptMeasures); + NotifyValueChanged("mean", total / cptMeasures); + } + } + + void computeStats(){ + current = timer.ElapsedMilliseconds; + if (current < cancelLimit) + return; + cptMeasures++; + total += timer.ElapsedMilliseconds; + if (timer.ElapsedMilliseconds < minimum) + minimum = timer.ElapsedMilliseconds; + if (timer.ElapsedMilliseconds > maximum) + maximum = timer.ElapsedMilliseconds; + } + void ResetStats(){ + Debug.WriteLine("reset measure cpt:{0}",cptMeasures); + cptMeasures = total = current = maximum = 0; + minimum = long.MaxValue; + } + void onResetClick(object sender, MouseButtonEventArgs e){ + lock(this) + ResetStats(); + } + } +} + diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index 62380aaf..daa76b25 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -114,9 +114,14 @@ namespace Crow }; t.Start (); } + + PerformanceMeasure.InitMeasures (); } #endregion +#if MEASURE_TIME + public PerformanceMeasure[] PerfMeasures => PerformanceMeasure.Measures; +#endif /** GLFW callback may return a custom pointer, this list makes the link between the GLFW window pointer and the manage VkWindow instance. */ static Dictionary windows = new Dictionary (); @@ -723,8 +728,9 @@ namespace Crow if (!Monitor.TryEnter (UpdateMutex)) return; - + DbgLogger.StartEvent (DbgEvtType.Update); + PerformanceMeasure.Begin (PerformanceMeasure.Kind.Update); processLayouting (); @@ -736,17 +742,24 @@ namespace Crow }else processDrawing (ctx); + PerformanceMeasure.End (PerformanceMeasure.Kind.Update); DbgLogger.EndEvent (DbgEvtType.Update, true); Monitor.Exit (UpdateMutex); + + PerformanceMeasure.Notify (); } /// Layouting loop, this is the first step of the udpate and process registered /// 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 (Monitor.TryEnter (LayoutMutex)) { - + if (LayoutingQueue.Count == 0) { + Monitor.Exit (LayoutMutex); + return; + } DbgLogger.StartEvent (DbgEvtType.Layouting); + PerformanceMeasure.Begin (PerformanceMeasure.Kind.Layouting); DiscardQueue = new Queue (); //Debug.WriteLine ("======= Layouting queue start ======="); @@ -757,6 +770,7 @@ namespace Crow } LayoutingQueue = DiscardQueue; + PerformanceMeasure.End (PerformanceMeasure.Kind.Layouting); DbgLogger.EndEvent (DbgEvtType.Layouting, true); Monitor.Exit (LayoutMutex); @@ -767,8 +781,11 @@ namespace Crow /// 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 (ClippingQueue.Count == 0) + return; DbgLogger.StartEvent (DbgEvtType.Clipping); + PerformanceMeasure.Begin (PerformanceMeasure.Kind.Clipping); Widget g = null; while (ClippingQueue.Count > 0) { @@ -779,6 +796,7 @@ namespace Crow g.ClippingRegistration (); } + PerformanceMeasure.End (PerformanceMeasure.Kind.Clipping); DbgLogger.EndEvent (DbgEvtType.Clipping, true); } /// Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be @@ -789,64 +807,68 @@ namespace Crow if (DragImage != null) clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight)); - if (!clipping.IsEmpty) { - IsDirty = true; - ctx.PushGroup (); + if (!clipping.IsEmpty) { + PerformanceMeasure.Begin (PerformanceMeasure.Kind.Drawing); + IsDirty = true; + + ctx.PushGroup (); - for (int i = GraphicTree.Count -1; i >= 0 ; i--){ - Widget p = GraphicTree[i]; - if (!p.Visible) - continue; - if (clipping.Contains (p.Slot) == RegionOverlap.Out) - continue; + for (int i = GraphicTree.Count -1; i >= 0 ; i--){ + Widget p = GraphicTree[i]; + if (!p.Visible) + continue; + if (clipping.Contains (p.Slot) == RegionOverlap.Out) + continue; + ctx.Save (); + p.Paint (ref ctx); + ctx.Restore (); + } + + if (DragAndDropOperation != null) { + if (DragImage != null) { + DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight); + DragImageX = MousePosition.X - DragImageWidth / 2; + DragImageY = MousePosition.Y - DragImageHeight / 2; ctx.Save (); - p.Paint (ref ctx); + ctx.ResetClip (); + ctx.SetSource (DragImage, DragImageX, DragImageY); + ctx.PaintWithAlpha (0.8); ctx.Restore (); + DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight); + IsDirty = true; + //System.Diagnostics.Debug.WriteLine ("dragimage drawn: {0},{1}", DragImageX, DragImageY); } - - if (DragAndDropOperation != null) { - if (DragImage != null) { - DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight); - DragImageX = MousePosition.X - DragImageWidth / 2; - DragImageY = MousePosition.Y - DragImageHeight / 2; - ctx.Save (); - ctx.ResetClip (); - ctx.SetSource (DragImage, DragImageX, DragImageY); - ctx.PaintWithAlpha (0.8); - ctx.Restore (); - DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight); - IsDirty = true; - //System.Diagnostics.Debug.WriteLine ("dragimage drawn: {0},{1}", DragImageX, DragImageY); - } - } + } #if DEBUG_CLIP_RECTANGLE - ctx.LineWidth = 1; - ctx.SetSourceColor(Color.Magenta.AdjustAlpha (0.5)); - for (int i = 0; i < clipping.NumRectangles; i++) - ctx.Rectangle(clipping.GetRectangle(i)); - ctx.Stroke (); + ctx.LineWidth = 1; + ctx.SetSourceColor(Color.Magenta.AdjustAlpha (0.5)); + for (int i = 0; i < clipping.NumRectangles; i++) + ctx.Rectangle(clipping.GetRectangle(i)); + ctx.Stroke (); #endif - ctx.PopGroupToSource (); + ctx.PopGroupToSource (); - for (int i = 0; i < clipping.NumRectangles; i++) - ctx.Rectangle (clipping.GetRectangle (i)); + for (int i = 0; i < clipping.NumRectangles; i++) + ctx.Rectangle (clipping.GetRectangle (i)); - ctx.ClipPreserve (); - ctx.Operator = Operator.Clear; - ctx.Fill (); - ctx.Operator = Operator.Over; + ctx.ClipPreserve (); + ctx.Operator = Operator.Clear; + ctx.Fill (); + ctx.Operator = Operator.Over; - ctx.Paint (); + ctx.Paint (); - surf.Flush (); + surf.Flush (); - clipping.Dispose (); - clipping = new Region (); - } + clipping.Dispose (); + clipping = new Region (); + + PerformanceMeasure.End (PerformanceMeasure.Kind.Drawing); + } DbgLogger.EndEvent (DbgEvtType.Drawing, true); } diff --git a/Crow/src/PerformanceMeasure.cs b/Crow/src/PerformanceMeasure.cs deleted file mode 100644 index 4f489eab..00000000 --- a/Crow/src/PerformanceMeasure.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -// PerformanceMeasure.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; - -namespace Crow -{ - public class PerformanceMeasure : IValueChange { - #region IValueChange implementation - public event EventHandler ValueChanged; - public virtual void NotifyValueChanged(string MemberName, object _value) - { - if (ValueChanged != null) - ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); - } - #endregion - - public Stopwatch timer = new Stopwatch (); - public string Name; - public long current, minimum, maximum, total, cptMeasures; - public long cancelLimit; - - public PerformanceMeasure(string name = "unamed", long _cancelLimit = 0){ - Name = name; - cancelLimit = _cancelLimit; - ResetStats (); - } - - public void StartCycle(){ - timer.Restart(); - } - public void StopCycle(){ - timer.Stop(); - computeStats (); - } - public void NotifyChanges(){ - lock(this){ - if (cptMeasures == 0) - return; - NotifyValueChanged("minimum", minimum); - NotifyValueChanged("maximum", maximum); - NotifyValueChanged("current", current); - // NotifyValueChanged("total", total); - // NotifyValueChanged("cptMeasures", cptMeasures); - NotifyValueChanged("mean", total / cptMeasures); - } - } - - void computeStats(){ - current = timer.ElapsedMilliseconds; - if (current < cancelLimit) - return; - cptMeasures++; - total += timer.ElapsedMilliseconds; - if (timer.ElapsedMilliseconds < minimum) - minimum = timer.ElapsedMilliseconds; - if (timer.ElapsedMilliseconds > maximum) - maximum = timer.ElapsedMilliseconds; - } - void ResetStats(){ - Debug.WriteLine("reset measure cpt:{0}",cptMeasures); - cptMeasures = total = current = maximum = 0; - minimum = long.MaxValue; - } - void onResetClick(object sender, MouseButtonEventArgs e){ - lock(this) - ResetStats(); - } - } -} - diff --git a/Samples/PerfTests/Program.cs b/Samples/PerfTests/Program.cs index 39ba8c88..6b239e9f 100644 --- a/Samples/PerfTests/Program.cs +++ b/Samples/PerfTests/Program.cs @@ -81,8 +81,8 @@ namespace PerfTests ClearInterface (); if (resetStylesAndTemplates) { - this.Styling.Clear (); - this.StylingConstants.Clear (); + //this.Styling.Clear (); + //this.StylingConstants.Clear (); this.Instantiators.Clear (); this.Templates.Clear (); this.DefaultTemplates.Clear ();