public pb_Sample(string name, pb_Sample parent, int stackOffset = 2) { stackTrace = new StackTrace(stackOffset, true); // StackFrame sf = stackTrace.GetFrame(0); // string c = System.IO.Path.GetFileNameWithoutExtension(sf.GetFileName()) + "::" + sf.GetMethod().Name + " - " + sf.GetFileLineNumber(); // initialize stopwatches for(int i = 0; i < MAX_STACKED_SAMPLES; i++) times[i] = new System.Diagnostics.Stopwatch(); _sampleHistory = new Queue<long>(sampleHistorySize); this.name = name; this.parent = parent; timeIndex = 0; concurrentSamples = 0; // 0 because one sample is automatically started this.times[timeIndex].Stop(); this.times[timeIndex].Reset(); // Stopwatch.Restart() is .NET 4 + this.times[timeIndex].Start(); sampleCount = 0; sum = 0; average = 0; min = 0; max = 0; }
public pb_Sample(string name, pb_Sample parent, int stackOffset = 2) { stackTrace = new StackTrace(stackOffset, true); // StackFrame sf = stackTrace.GetFrame(0); // string c = System.IO.Path.GetFileNameWithoutExtension(sf.GetFileName()) + "::" + sf.GetMethod().Name + " - " + sf.GetFileLineNumber(); // initialize stopwatches for (int i = 0; i < MAX_STACKED_SAMPLES; i++) { times[i] = new System.Diagnostics.Stopwatch(); } _sampleHistory = new Queue <long>(sampleHistorySize); this.name = name; this.parent = parent; timeIndex = 0; concurrentSamples = 0; // 0 because one sample is automatically started this.times[timeIndex].Stop(); this.times[timeIndex].Reset(); // Stopwatch.Restart() is .NET 4 + this.times[timeIndex].Start(); sampleCount = 0; sum = 0; average = 0; min = 0; max = 0; }
public override void Draw() { currentEvent = Event.current; pb_Sample root = profiler != null?profiler.GetRootSample() : null; SampleGraph.Draw(selectedSample); DrawTreeView(root); }
/** * Returns the parent sample of this profiler tree. */ public pb_Sample GetRootSample() { pb_Sample root = this.sample; while (root.parent != null) { root = root.parent; } return(root); }
/** * Presents a pretty tiered string. * @todo Write a nice editor interface instead o' just relying on * the ToString representation. */ public override string ToString() { pb_Sample root = GetRootSample(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < root.children.Count; i++) { sb.AppendLine(root.children[i].ToStringRecursive()); } return(sb.ToString()); }
void DrawTreeView(pb_Sample root) { Color bg = GUI.backgroundColor; GUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.Label("Sample", EditorStyles.toolbarButton); GUI.backgroundColor = odd_column_color; GUILayout.Label("Calls", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = bg; GUILayout.Label("%", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = odd_column_color; GUILayout.Label("Avg", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = bg; GUILayout.Label("Sum", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = odd_column_color; GUILayout.Label("Min", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = bg; GUILayout.Label("Max", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = odd_column_color; GUILayout.Label("Current", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUILayout.EndHorizontal(); hoveringSample = null; scroll = EditorGUILayout.BeginScrollView(scroll); Color original = GUI.backgroundColor; if (root != null) { foreach (pb_Sample child in root.children) { DrawSampleTree(child); } } if (hoveringSample != null) { GUI.backgroundColor = highlight; GUI.Box(hoveringRect, "", ProfilerStyles.borderStyle); } GUI.backgroundColor = original; // add a little padding so that the last sample row isn't clipped by the scroll view GUILayout.Space(4); EditorGUILayout.EndScrollView(); }
/** * Draw a visual representation of the profiler. */ public static void Draw(pb_Sample sample) { Rect rect = EditorGUILayout.GetControlRect(false, 150); RectOffset margin = new RectOffset(2, 2, 4, 4); rect.x += margin.left; rect.y += margin.top; rect.width -= margin.left + margin.right; rect.height -= margin.top + margin.bottom; Color prev_color = GUI.color; GUI.color = Color.gray; GUI.Box(rect, "", ProfilerStyles.chartBackgroundStyle); GUI.color = prev_color; if( Event.current.type == EventType.Repaint ) { if(sample == null) { GUI.Label(rect, "Sample History Graph", ProfilerStyles.centeredGrayLabel); return; } List<long> samples = sample.sampleHistory; int count = samples.Count; if(count < 3) { GUI.Label(rect, "Too Few Samples to Graph", ProfilerStyles.centeredGrayLabel); return; } long min = samples[0], max = samples[0]; for(int i = 1; i < count; i++) { if(samples[i] < min) min = samples[i]; if(samples[i] > max) max = samples[i]; } MethodInfo mi = typeof(HandleUtility).GetMethod("ApplyWireMaterial", ALL_FLAGS); mi.Invoke(null, null); GL.Begin(GL.LINES); GL.Color(guideColor); // draw guides GL.Vertex3(rect.x, rect.y + (rect.height * .25f), 0f); GL.Vertex3(rect.x + rect.width, rect.y + (rect.height * .25f), 0f); GL.Vertex3(rect.x, rect.y + (rect.height * .5f), 0f); GL.Vertex3(rect.x + rect.width, rect.y + (rect.height * .5f), 0f); GL.Vertex3(rect.x, rect.y + (rect.height * .75f), 0f); GL.Vertex3(rect.x + rect.width, rect.y + (rect.height * .75f), 0f); GL.Color(lineColor); float x = rect.x; float y = (samples[0] / (float) max) * rect.height; for(int i = 1; i < count; i++) { GL.Vertex3(rect.x + x, rect.y + (rect.height - y), 0f ); x = (i / (float) (count - 1)) * rect.width; y = ((samples[i] - min) / (float) (max - min)) * rect.height; GL.Vertex3(rect.x + x, rect.y + (rect.height - y), 0f ); } GL.End(); GUIContent label = new GUIContent(ProfilerEditor.TickToString(min)); float height = ProfilerStyles.chartAxisLabel.CalcHeight(label, EditorGUIUtility.currentViewWidth); Rect r = new Rect(rect.x + 2, ((rect.y + rect.height) - height) - 2, 200, height); GUI.Label(r, label, ProfilerStyles.chartAxisLabel); r.y = rect.y + 2; GUI.Label(r, ProfilerEditor.TickToString(max), ProfilerStyles.chartAxisLabel); label.text = sample.name; r.x = (rect.x + rect.width) - (ProfilerStyles.chartAxisLabel.CalcSize(label).x + 12); GUI.Label(r, label); } }
void DrawSampleTree(pb_Sample sample, int indent, string key_prefix) { string key = key_prefix + sample.name; int childCount = sample.children.Count; if(!row_visibility.ContainsKey(key)) row_visibility.Add(key, true); GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal(GUILayout.MinWidth(name_width), GUILayout.MaxWidth(name_width)); GUILayout.Space(indent * (childCount > 0 ? 10 : 22)); if(childCount > 0) row_visibility[key] = EditorGUILayout.Foldout(row_visibility[key], sample.name); else GUILayout.Label(sample.name); GUILayout.EndHorizontal(); GUILayout.Label(sample.sampleCount.ToString(), GUILayout.MinWidth(sample_width), GUILayout.MaxWidth(sample_width)); GUILayout.Label(sample.Percentage().ToString("F2"), GUILayout.MinWidth(percent_width), GUILayout.MaxWidth(percent_width)); GUILayout.Label(sample.average.ToString() + " ms", GUILayout.MinWidth(avg_width), GUILayout.MaxWidth(avg_width)); GUILayout.Label(sample.sum.ToString() + " ms", GUILayout.MinWidth(sum_width), GUILayout.MaxWidth(sum_width)); GUILayout.Label(sample.min.ToString() + " ms", GUILayout.MinWidth(range_width), GUILayout.MaxWidth(range_width)); GUILayout.Label(sample.max.ToString() + " ms", GUILayout.MinWidth(range_width), GUILayout.MaxWidth(range_width)); GUILayout.Label(sample.lastSample.ToString() + " ms", GUILayout.MinWidth(range_width), GUILayout.MaxWidth(range_width)); GUILayout.EndHorizontal(); if(row_visibility[key]) { indent++; foreach(pb_Sample child in sample.children) { DrawSampleTree(child, indent, key); } } }
void DrawSampleTree(pb_Sample sample) { DrawSampleTree(sample, 0, ""); }
/** * Begin a profile sample. */ public void BeginSample(string methodName, int stackOffset = 0) { sample = sample.Add(methodName, stackOffset); }
/** * Clear all the internals and start with fresh slate. */ public void Reset() { sample = new pb_Sample("Parent", null); }
/** * Draw a visual representation of the profiler. */ public static void Draw(pb_Sample sample) { Rect rect = EditorGUILayout.GetControlRect(false, 150); RectOffset margin = new RectOffset(2, 2, 4, 4); rect.x += margin.left; rect.y += margin.top; rect.width -= margin.left + margin.right; rect.height -= margin.top + margin.bottom; Color prev_color = GUI.color; GUI.color = Color.gray; GUI.Box(rect, "", ProfilerStyles.chartBackgroundStyle); GUI.color = prev_color; if (Event.current.type == EventType.Repaint) { if (sample == null) { GUI.Label(rect, "Sample History Graph", ProfilerStyles.centeredGrayLabel); return; } List <long> samples = sample.sampleHistory; int count = samples.Count; if (count < 3) { GUI.Label(rect, "Too Few Samples to Graph", ProfilerStyles.centeredGrayLabel); return; } long min = samples[0], max = samples[0]; for (int i = 1; i < count; i++) { if (samples[i] < min) { min = samples[i]; } if (samples[i] > max) { max = samples[i]; } } MethodInfo mi = typeof(HandleUtility).GetMethod("ApplyWireMaterial", ALL_FLAGS); mi.Invoke(null, null); GL.Begin(GL.LINES); GL.Color(guideColor); // draw guides GL.Vertex3(rect.x, rect.y + (rect.height * .25f), 0f); GL.Vertex3(rect.x + rect.width, rect.y + (rect.height * .25f), 0f); GL.Vertex3(rect.x, rect.y + (rect.height * .5f), 0f); GL.Vertex3(rect.x + rect.width, rect.y + (rect.height * .5f), 0f); GL.Vertex3(rect.x, rect.y + (rect.height * .75f), 0f); GL.Vertex3(rect.x + rect.width, rect.y + (rect.height * .75f), 0f); GL.Color(lineColor); float x = rect.x; float y = (samples[0] / (float)max) * rect.height; for (int i = 1; i < count; i++) { GL.Vertex3(rect.x + x, rect.y + (rect.height - y), 0f); x = (i / (float)(count - 1)) * rect.width; y = ((samples[i] - min) / (float)(max - min)) * rect.height; GL.Vertex3(rect.x + x, rect.y + (rect.height - y), 0f); } GL.End(); GUIContent label = new GUIContent(ProfilerEditor.TickToString(min)); float height = ProfilerStyles.chartAxisLabel.CalcHeight(label, EditorGUIUtility.currentViewWidth); Rect r = new Rect(rect.x + 2, ((rect.y + rect.height) - height) - 2, 200, height); GUI.Label(r, label, ProfilerStyles.chartAxisLabel); r.y = rect.y + 2; GUI.Label(r, ProfilerEditor.TickToString(max), ProfilerStyles.chartAxisLabel); label.text = sample.name; r.x = (rect.x + rect.width) - (ProfilerStyles.chartAxisLabel.CalcSize(label).x + 12); GUI.Label(r, label); } }
void DrawSampleTree(pb_Sample sample, int indent, string key_prefix) { string key = key_prefix + sample.name; int childCount = sample.children.Count; if (!row_visibility.ContainsKey(key)) { row_visibility.Add(key, true); } GUILayout.BeginHorizontal(ProfilerStyles.chartStyle); int n = 0; GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.BeginHorizontal(ProfilerStyles.entryStyle); GUILayout.Space(indent * (childCount > 0 ? 10 : 14)); // don't use a Foldout control because it always eats the current event, which breaks clicking to follow stack trace if (childCount > 0) { GUI.backgroundColor = Color.white; GUI.color = Color.white; row_visibility[key] = EditorGUILayout.Toggle(row_visibility[key], EditorStyles.foldout, GUILayout.MaxWidth(14)); } GUILayout.Label(sample.name); GUILayout.EndHorizontal(); Rect r = GUILayoutUtility.GetLastRect(); color.r = sample.Percentage() / 100f; color.b = 1f - color.r; r.x = (r.width + r.x) - COLOR_BLOCK_SIZE - COLOR_BLOCK_PAD; r.width = COLOR_BLOCK_SIZE; r.y += (r.height - COLOR_BLOCK_SIZE) / 2f; r.height = COLOR_BLOCK_SIZE; DrawSolidColor(r, color); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(sample.sampleCount.ToString(), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(sample.Percentage().ToString("F2"), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.average), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.sum), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.min), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.max), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.lastSample), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.EndHorizontal(); Rect lastRect = GUILayoutUtility.GetLastRect(); if (currentEvent.type == EventType.MouseDown && lastRect.Contains(currentEvent.mousePosition)) { if (currentEvent.clickCount > 1) { StackFrame frame = sample.stackTrace.GetFrame(0); string filePathRel; if (RelativeFilePath(frame.GetFileName(), out filePathRel)) { UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(filePathRel, typeof(TextAsset)); int lineNumber = frame.GetFileLineNumber(); AssetDatabase.OpenAsset(obj, lineNumber); } } else { selectedSample = sample; } } if (lastRect.Contains(currentEvent.mousePosition)) { if (hoveringSample != sample) { hoveringSample = sample; hoveringRect = new Rect( lastRect.x + 6, lastRect.y, lastRect.width - 12, lastRect.height + 2); wantsRepaint = true; } } if (row_visibility[key]) { indent++; foreach (pb_Sample child in sample.children) { DrawSampleTree(child, indent, key); } } }
/** * Complete the sample. */ public void EndSample() { sample = sample.Stop(); }
pb_Sample sample = new pb_Sample("Parent", null); ///< The current sample tree. /** * Begin a profile sample. */ public void BeginSample(string methodName, int stackOffset = 0) { sample = sample.Add(methodName, stackOffset); }
void DrawSampleTree(pb_Sample sample, int indent, string key_prefix) { string key = key_prefix + sample.name; int childCount = sample.children.Count; if(!row_visibility.ContainsKey(key)) row_visibility.Add(key, true); GUILayout.BeginHorizontal(ProfilerStyles.chartStyle); int n = 0; GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.BeginHorizontal(ProfilerStyles.entryStyle); GUILayout.Space(indent * (childCount > 0 ? 10 : 14)); // don't use a Foldout control because it always eats the current event, which breaks clicking to follow stack trace if(childCount > 0) { GUI.backgroundColor = Color.white; GUI.color = Color.white; row_visibility[key] = EditorGUILayout.Toggle(row_visibility[key], EditorStyles.foldout, GUILayout.MaxWidth(14)); } GUILayout.Label(sample.name); GUILayout.EndHorizontal(); Rect r = GUILayoutUtility.GetLastRect(); color.r = sample.Percentage() / 100f; color.b = 1f - color.r; r.x = (r.width + r.x) - COLOR_BLOCK_SIZE - COLOR_BLOCK_PAD; r.width = COLOR_BLOCK_SIZE; r.y += (r.height-COLOR_BLOCK_SIZE)/2f; r.height = COLOR_BLOCK_SIZE; DrawSolidColor(r, color); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(sample.sampleCount.ToString(), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(sample.Percentage().ToString("F2"), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.average), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.sum), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.min), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.max), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.Label(ProfilerEditor.TickToString(sample.lastSample), ProfilerStyles.entryStyle, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = column_colors[n++ % 2]; GUILayout.EndHorizontal(); Rect lastRect = GUILayoutUtility.GetLastRect(); if( currentEvent.type == EventType.MouseDown && lastRect.Contains(currentEvent.mousePosition) ) { if(currentEvent.clickCount > 1) { StackFrame frame = sample.stackTrace.GetFrame(0); string filePathRel; if( RelativeFilePath(frame.GetFileName(), out filePathRel) ) { UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(filePathRel, typeof(TextAsset)); int lineNumber = frame.GetFileLineNumber(); AssetDatabase.OpenAsset(obj, lineNumber); } } else { selectedSample = sample; } } if( lastRect.Contains(currentEvent.mousePosition) ) { if(hoveringSample != sample) { hoveringSample = sample; hoveringRect = new Rect( lastRect.x + 6, lastRect.y, lastRect.width - 12, lastRect.height + 2); wantsRepaint = true; } } if(row_visibility[key]) { indent++; foreach(pb_Sample child in sample.children) { DrawSampleTree(child, indent, key); } } }
void DrawTreeView(pb_Sample root) { Color bg = GUI.backgroundColor; GUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.Label("Sample", EditorStyles.toolbarButton); GUI.backgroundColor = odd_column_color; GUILayout.Label("Calls", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = bg; GUILayout.Label("%", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = odd_column_color; GUILayout.Label("Avg", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = bg; GUILayout.Label("Sum", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = odd_column_color; GUILayout.Label("Min", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = bg; GUILayout.Label("Max", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUI.backgroundColor = odd_column_color; GUILayout.Label("Current", EditorStyles.toolbarButton, GUILayout.MinWidth(FIELD_WIDTH), GUILayout.MaxWidth(FIELD_WIDTH)); GUILayout.EndHorizontal(); hoveringSample = null; scroll = EditorGUILayout.BeginScrollView(scroll); Color original = GUI.backgroundColor; if(root != null) { foreach(pb_Sample child in root.children) DrawSampleTree(child); } if(hoveringSample != null) { GUI.backgroundColor = highlight; GUI.Box(hoveringRect, "", ProfilerStyles.borderStyle); } GUI.backgroundColor = original; // add a little padding so that the last sample row isn't clipped by the scroll view GUILayout.Space(4); EditorGUILayout.EndScrollView(); }