TopMarkers.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. using System;
  2. using System.Text;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.Profiling;
  6. namespace UnityEditor.Performance.ProfileAnalyzer
  7. {
  8. internal class TopMarkers
  9. {
  10. internal class RangeSettings
  11. {
  12. public readonly ProfileDataView dataView;
  13. public readonly int depthFilter;
  14. public readonly List<string> nameFilters;
  15. public readonly List<string> nameExcludes;
  16. public readonly TimingOptions.TimingOption timingOption;
  17. public readonly int threadSelectionCount;
  18. public RangeSettings(ProfileDataView dataView, int depthFilter, List<string> nameFilters, List<string> nameExcludes, TimingOptions.TimingOption timingOption, int threadSelectionCount)
  19. {
  20. // Make a copy rather than keeping a reference
  21. this.dataView = dataView==null ? new ProfileDataView() : new ProfileDataView(dataView);
  22. this.depthFilter = depthFilter;
  23. this.nameFilters = nameFilters;
  24. this.nameExcludes = nameExcludes;
  25. this.timingOption = timingOption;
  26. this.threadSelectionCount = threadSelectionCount;
  27. }
  28. public override int GetHashCode()
  29. {
  30. int hash = 13;
  31. hash = (hash * 7) + dataView.GetHashCode();
  32. hash = (hash * 7) + depthFilter.GetHashCode();
  33. hash = (hash * 7) + nameFilters.GetHashCode();
  34. hash = (hash * 7) + nameExcludes.GetHashCode();
  35. hash = (hash * 7) + timingOption.GetHashCode();
  36. hash = (hash * 7) + threadSelectionCount.GetHashCode();
  37. return hash;
  38. }
  39. public override bool Equals(object b)
  40. {
  41. if (System.Object.ReferenceEquals(null, b))
  42. {
  43. return false;
  44. }
  45. if (System.Object.ReferenceEquals(this, b))
  46. {
  47. return true;
  48. }
  49. if (b.GetType() != this.GetType())
  50. {
  51. return false;
  52. }
  53. return IsEqual((RangeSettings)b);
  54. }
  55. bool IsEqual(RangeSettings b)
  56. {
  57. if (timingOption != b.timingOption)
  58. return false;
  59. if (b.dataView == null && dataView != null)
  60. return false;
  61. // Check contents of data view (the reference will definitly not match as we made a copy)
  62. if (b.dataView != null)
  63. {
  64. // Only need to check data, analysis and selectedIndices
  65. if (dataView.data != b.dataView.data)
  66. return false;
  67. if (dataView.analysis != b.dataView.analysis)
  68. return false;
  69. if (dataView.selectedIndices != b.dataView.selectedIndices)
  70. return false;
  71. if (dataView.selectedIndices.Count != b.dataView.selectedIndices.Count)
  72. return false;
  73. // Want to check if contents match, not just if reference is the same
  74. for (int i = 0; i < dataView.selectedIndices.Count; i++)
  75. {
  76. if (dataView.selectedIndices[i] != b.dataView.selectedIndices[i])
  77. return false;
  78. }
  79. }
  80. if (depthFilter != b.depthFilter)
  81. return false;
  82. if (threadSelectionCount != b.threadSelectionCount)
  83. return false;
  84. if (nameFilters.Count != b.nameFilters.Count)
  85. return false;
  86. if (nameExcludes.Count != b.nameExcludes.Count)
  87. return false;
  88. // Want to check if contents match, not just if reference is the same
  89. for (int i = 0; i < nameFilters.Count; i++)
  90. {
  91. if (nameFilters[i] != b.nameFilters[i])
  92. return false;
  93. }
  94. for (int i = 0; i < nameExcludes.Count; i++)
  95. {
  96. if (nameExcludes[i] != b.nameExcludes[i])
  97. return false;
  98. }
  99. return true;
  100. }
  101. public static bool operator==(RangeSettings a, RangeSettings b)
  102. {
  103. // If both are null, or both are same instance, return true.
  104. if (System.Object.ReferenceEquals(a, b))
  105. {
  106. return true;
  107. }
  108. // If one is null, but not both, return false.
  109. if (((object)a == null) || ((object)b == null))
  110. {
  111. return false;
  112. }
  113. return a.IsEqual(b);
  114. }
  115. public static bool operator!=(RangeSettings a, RangeSettings b)
  116. {
  117. return !(a == b);
  118. }
  119. }
  120. internal class Settings
  121. {
  122. public readonly int barCount;
  123. public readonly float timeRange;
  124. public readonly bool includeOthers;
  125. public readonly bool includeUnaccounted;
  126. public RangeSettings rangeSettings { get ; private set ; }
  127. public Settings(RangeSettings rangeSettings, int barCount, float timeRange, bool includeOthers, bool includeUnaccounted)
  128. {
  129. this.rangeSettings = rangeSettings;
  130. this.barCount = barCount;
  131. this.timeRange = timeRange;
  132. this.includeOthers = includeOthers;
  133. this.includeUnaccounted = includeUnaccounted;
  134. }
  135. public override int GetHashCode()
  136. {
  137. int hash = 13;
  138. hash = (hash * 7) + rangeSettings.GetHashCode();
  139. hash = (hash * 7) + barCount.GetHashCode();
  140. hash = (hash * 7) + timeRange.GetHashCode();
  141. hash = (hash * 7) + includeOthers.GetHashCode();
  142. hash = (hash * 7) + includeUnaccounted.GetHashCode();
  143. return hash;
  144. }
  145. public override bool Equals(object b)
  146. {
  147. if (System.Object.ReferenceEquals(null, b))
  148. {
  149. return false;
  150. }
  151. if (System.Object.ReferenceEquals(this, b))
  152. {
  153. return true;
  154. }
  155. if (b.GetType() != this.GetType())
  156. {
  157. return false;
  158. }
  159. return IsEqual((Settings)b);
  160. }
  161. bool IsEqual(Settings b)
  162. {
  163. if (rangeSettings != b.rangeSettings)
  164. return false;
  165. if (barCount != b.barCount)
  166. return false;
  167. if (timeRange != b.timeRange)
  168. return false;
  169. if (includeOthers != b.includeOthers)
  170. return false;
  171. if (includeUnaccounted != b.includeUnaccounted)
  172. return false;
  173. return true;
  174. }
  175. public static bool operator==(Settings a, Settings b)
  176. {
  177. // If both are null, or both are same instance, return true.
  178. if (System.Object.ReferenceEquals(a, b))
  179. {
  180. return true;
  181. }
  182. // If one is null, but not both, return false.
  183. if (((object)a == null) || ((object)b == null))
  184. {
  185. return false;
  186. }
  187. return a.IsEqual(b);
  188. }
  189. public static bool operator!=(Settings a, Settings b)
  190. {
  191. return !(a == b);
  192. }
  193. }
  194. internal enum SummaryType
  195. {
  196. Marker,
  197. Other,
  198. Unaccounted
  199. }
  200. internal struct MarkerSummaryEntry
  201. {
  202. public readonly string name;
  203. public readonly float msAtMedian; // At the median frame (Miliseconds)
  204. public readonly float msMedian; // median value for marker over all frames (Miliseconds) on frame medianFrameIndex
  205. public readonly float x;
  206. public readonly float w;
  207. public readonly int medianFrameIndex;
  208. public readonly SummaryType summaryType;
  209. public MarkerSummaryEntry(string name, float msAtMedian, float msMedian, float x, float w, int medianFrameIndex, SummaryType summaryType)
  210. {
  211. this.name = name;
  212. this.msAtMedian = msAtMedian;
  213. this.msMedian = msMedian;
  214. this.x = x;
  215. this.w = w;
  216. this.medianFrameIndex = medianFrameIndex;
  217. this.summaryType = summaryType;
  218. }
  219. }
  220. internal class MarkerSummary
  221. {
  222. public List<MarkerSummaryEntry> entry;
  223. public float totalTime;
  224. public MarkerSummary()
  225. {
  226. entry = new List<MarkerSummaryEntry>();
  227. totalTime = 0f;
  228. }
  229. }
  230. Settings m_CurrentSettings; // Current settings, including latest RangeSettings
  231. RangeSettings m_RequestedRangeSettings; // Next requested range setting set by SetData
  232. float m_TimeRange;
  233. bool m_TimeRangeDirty; // Set when renquested range settings change
  234. MarkerSummary m_MarkerSummary;
  235. internal static class Styles
  236. {
  237. public static readonly GUIContent menuItemSelectFramesInAll = new GUIContent("Select Frames that contain this marker (within whole data set)", "");
  238. public static readonly GUIContent menuItemSelectFramesInCurrent = new GUIContent("Select Frames that contain this marker (within current selection)", "");
  239. //public static readonly GUIContent menuItemClearSelection = new GUIContent("Clear Selection");
  240. public static readonly GUIContent menuItemSelectFramesAll = new GUIContent("Select All");
  241. public static readonly GUIContent menuItemAddToIncludeFilter = new GUIContent("Add to Include Filter", "");
  242. public static readonly GUIContent menuItemAddToExcludeFilter = new GUIContent("Add to Exclude Filter", "");
  243. public static readonly GUIContent menuItemRemoveFromIncludeFilter = new GUIContent("Remove from Include Filter", "");
  244. public static readonly GUIContent menuItemRemoveFromExcludeFilter = new GUIContent("Remove from Exclude Filter", "");
  245. public static readonly GUIContent menuItemSetAsParentMarkerFilter = new GUIContent("Set as Parent Marker Filter", "");
  246. public static readonly GUIContent menuItemClearParentMarkerFilter = new GUIContent("Clear Parent Marker Filter", "");
  247. public static readonly GUIContent menuItemCopyToClipboard = new GUIContent("Copy to Clipboard", "");
  248. }
  249. private static class Content
  250. {
  251. public static readonly string frameTime = L10n.Tr("{0} Frame time on median frame");
  252. public static readonly string multipleThreads = L10n.Tr("Multiple threads selected\nSelect a single thread for an overview");
  253. public static readonly string totalTimeAllDepths = L10n.Tr("{0} Total time of all markers at all depths");
  254. public static readonly string totalTimeAtSpecificDepth = L10n.Tr("{0} Total time of all markers at Depth {1}");
  255. public static readonly string selectSelf = L10n.Tr("For an overview select Analysis Type Self");
  256. public static readonly string selectTotal = L10n.Tr("To include child times select Analysis Type Total");
  257. public static readonly string selfTimeAllDepths = L10n.Tr("{0} Self time of markers at all depths");
  258. public static readonly string selfTimeAtSpecificDepth = L10n.Tr("{0} Self time of markers at Depth {1}");
  259. public static readonly string tooltip = L10n.Tr("{0}\n{1:f2}% ({2} on median frame {3})\n\nMedian marker time (in currently selected frames)\n{4} on frame {5}");
  260. }
  261. ProfileAnalyzerWindow m_ProfileAnalyzerWindow;
  262. Draw2D m_2D;
  263. Color m_BackgroundColor;
  264. Color m_TextColor;
  265. public TopMarkers(ProfileAnalyzerWindow profileAnalyzerWindow, Draw2D draw2D, Color backgroundColor, Color textColor)
  266. {
  267. m_ProfileAnalyzerWindow = profileAnalyzerWindow;
  268. m_2D = draw2D;
  269. m_BackgroundColor = backgroundColor;
  270. m_TextColor = textColor;
  271. m_CurrentSettings = new Settings(new RangeSettings(null, 0, null, null, TimingOptions.TimingOption.Time, 0), 0, 0, false, false);
  272. m_TimeRangeDirty = true;
  273. }
  274. string ToDisplayUnits(float ms, bool showUnits = false, int limitToDigits = 5)
  275. {
  276. return m_ProfileAnalyzerWindow.ToDisplayUnits(ms, showUnits, limitToDigits);
  277. }
  278. public void SetData(ProfileDataView dataView, int depthFilter, List<string> nameFilters, List<string> nameExcludes, TimingOptions.TimingOption timingOption, int threadSelectionCount)
  279. {
  280. m_RequestedRangeSettings = new RangeSettings(dataView, depthFilter, nameFilters, nameExcludes, timingOption, threadSelectionCount);
  281. if (m_CurrentSettings.rangeSettings != m_RequestedRangeSettings)
  282. m_TimeRangeDirty = true;
  283. }
  284. float CalculateTopMarkerTimeRange(RangeSettings rangeSettings)
  285. {
  286. if (rangeSettings == null)
  287. return 0.0f;
  288. if (rangeSettings.dataView == null)
  289. return 0.0f;
  290. ProfileAnalysis analysis = rangeSettings.dataView.analysis;
  291. if (analysis == null)
  292. return 0.0f;
  293. var frameSummary = analysis.GetFrameSummary();
  294. if (frameSummary == null)
  295. return 0.0f;
  296. int depthFilter = rangeSettings.depthFilter;
  297. List<string> nameFilters = rangeSettings.nameFilters;
  298. List<string> nameExcludes = rangeSettings.nameExcludes;
  299. var markers = analysis.GetMarkers();
  300. float range = 0;
  301. foreach (var marker in markers)
  302. {
  303. if (depthFilter != ProfileAnalyzer.kDepthAll && marker.minDepth != depthFilter)
  304. {
  305. continue;
  306. }
  307. if (nameFilters.Count > 0)
  308. {
  309. if (!m_ProfileAnalyzerWindow.NameInFilterList(marker.name, nameFilters))
  310. continue;
  311. }
  312. if (nameExcludes.Count > 0)
  313. {
  314. if (m_ProfileAnalyzerWindow.NameInExcludeList(marker.name, nameExcludes))
  315. continue;
  316. }
  317. range += marker.msAtMedian;
  318. }
  319. // Minimum is the frame time range
  320. // As we can have unaccounted markers
  321. if (range < frameSummary.msMedian)
  322. range = frameSummary.msMedian;
  323. return range;
  324. }
  325. public float GetTopMarkerTimeRange()
  326. {
  327. if (m_TimeRangeDirty)
  328. {
  329. Profiler.BeginSample("CalculateTopMarkerTimeRange");
  330. // Use latest requested rather than current (as current may not yet be updated)
  331. m_TimeRange = CalculateTopMarkerTimeRange(m_RequestedRangeSettings);
  332. m_TimeRangeDirty = false;
  333. Profiler.EndSample();
  334. }
  335. return m_TimeRange;
  336. }
  337. public MarkerSummary CalculateTopMarkers()
  338. {
  339. if (m_CurrentSettings.rangeSettings.dataView == null)
  340. return null;
  341. ProfileAnalysis analysis = m_CurrentSettings.rangeSettings.dataView.analysis;
  342. if (analysis == null)
  343. return null;
  344. FrameSummary frameSummary = analysis.GetFrameSummary();
  345. if (frameSummary == null)
  346. return new MarkerSummary();
  347. var markers = analysis.GetMarkers();
  348. if (markers == null)
  349. return new MarkerSummary();
  350. float timeRange = m_CurrentSettings.timeRange;
  351. int depthFilter = m_CurrentSettings.rangeSettings.depthFilter;
  352. List<string> nameFilters = m_CurrentSettings.rangeSettings.nameFilters;
  353. List<string> nameExcludes = m_CurrentSettings.rangeSettings.nameExcludes;
  354. // Show marker graph
  355. float x = 0;
  356. float width = 1.0f;
  357. int max = m_CurrentSettings.barCount;
  358. int at = 0;
  359. float other = 0.0f;
  360. if (timeRange <= 0.0f)
  361. timeRange = frameSummary.msMedian;
  362. float msToWidth = width / timeRange;
  363. float totalMarkerTime = 0;
  364. MarkerSummary markerSummary = new MarkerSummary();
  365. foreach (var marker in markers)
  366. {
  367. float msAtMedian = MarkerData.GetMsAtMedian(marker);
  368. totalMarkerTime += msAtMedian;
  369. if (depthFilter != ProfileAnalyzer.kDepthAll && marker.minDepth != depthFilter)
  370. {
  371. continue;
  372. }
  373. if (nameFilters.Count > 0)
  374. {
  375. if (!m_ProfileAnalyzerWindow.NameInFilterList(marker.name, nameFilters))
  376. continue;
  377. }
  378. if (nameExcludes.Count > 0)
  379. {
  380. if (m_ProfileAnalyzerWindow.NameInExcludeList(marker.name, nameExcludes))
  381. continue;
  382. }
  383. if (at < max)
  384. {
  385. float w = CaculateWidth(x, msAtMedian, msToWidth, width);
  386. float msMedian = MarkerData.GetMsMedian(marker);
  387. int medianFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.medianFrameIndex, m_CurrentSettings.rangeSettings.dataView);
  388. markerSummary.entry.Add(new MarkerSummaryEntry(marker.name, msAtMedian, msMedian, x, w, medianFrameIndex, SummaryType.Marker));
  389. x += w;
  390. }
  391. else
  392. {
  393. other += msAtMedian;
  394. if (!m_CurrentSettings.includeOthers)
  395. break;
  396. }
  397. at++;
  398. }
  399. if (m_CurrentSettings.includeOthers && other > 0.0f)
  400. {
  401. float w = CaculateWidth(x, other, msToWidth, width);
  402. markerSummary.entry.Add(new MarkerSummaryEntry("Other", other, 0f, x, w, -1, SummaryType.Other));
  403. x += w;
  404. }
  405. if (m_CurrentSettings.includeUnaccounted && totalMarkerTime < frameSummary.msMedian)
  406. {
  407. float unaccounted = frameSummary.msMedian - totalMarkerTime;
  408. float w = CaculateWidth(x, unaccounted, msToWidth, width);
  409. markerSummary.entry.Add(new MarkerSummaryEntry("Unaccounted", unaccounted, 0f, x, w, -1, SummaryType.Unaccounted));
  410. x += w;
  411. }
  412. markerSummary.totalTime = totalMarkerTime;
  413. return markerSummary;
  414. }
  415. GenericMenu GenerateActiveContextMenu(string markerName, Event evt)
  416. {
  417. GenericMenu menu = new GenericMenu();
  418. menu.AddItem(Styles.menuItemSelectFramesInAll, false, () => m_ProfileAnalyzerWindow.SelectFramesContainingMarker(markerName, false));
  419. menu.AddItem(Styles.menuItemSelectFramesInCurrent, false, () => m_ProfileAnalyzerWindow.SelectFramesContainingMarker(markerName, true));
  420. if (m_ProfileAnalyzerWindow.AllSelected())
  421. menu.AddDisabledItem(Styles.menuItemSelectFramesAll);
  422. else
  423. menu.AddItem(Styles.menuItemSelectFramesAll, false, () => m_ProfileAnalyzerWindow.SelectAllFrames());
  424. menu.AddSeparator("");
  425. if (!m_CurrentSettings.rangeSettings.nameFilters.Contains(markerName))
  426. menu.AddItem(Styles.menuItemAddToIncludeFilter, false, () => m_ProfileAnalyzerWindow.AddToIncludeFilter(markerName));
  427. else
  428. menu.AddItem(Styles.menuItemRemoveFromIncludeFilter, false, () => m_ProfileAnalyzerWindow.RemoveFromIncludeFilter(markerName));
  429. if (!m_CurrentSettings.rangeSettings.nameExcludes.Contains(markerName))
  430. menu.AddItem(Styles.menuItemAddToExcludeFilter, false, () => m_ProfileAnalyzerWindow.AddToExcludeFilter(markerName));
  431. else
  432. menu.AddItem(Styles.menuItemRemoveFromExcludeFilter, false, () => m_ProfileAnalyzerWindow.RemoveFromExcludeFilter(markerName));
  433. menu.AddSeparator("");
  434. menu.AddItem(Styles.menuItemSetAsParentMarkerFilter, false, () => m_ProfileAnalyzerWindow.SetAsParentMarkerFilter(markerName));
  435. menu.AddItem(Styles.menuItemClearParentMarkerFilter, false, () => m_ProfileAnalyzerWindow.SetAsParentMarkerFilter(""));
  436. menu.AddSeparator("");
  437. menu.AddItem(Styles.menuItemCopyToClipboard, false, () => CopyToClipboard(evt, markerName));
  438. return menu;
  439. }
  440. GenericMenu GenerateDisabledContextMenu(string markerName)
  441. {
  442. GenericMenu menu = new GenericMenu();
  443. menu.AddDisabledItem(Styles.menuItemSelectFramesInAll);
  444. menu.AddDisabledItem(Styles.menuItemSelectFramesInCurrent);
  445. menu.AddDisabledItem(Styles.menuItemSelectFramesAll);
  446. menu.AddSeparator("");
  447. if (!m_CurrentSettings.rangeSettings.nameFilters.Contains(markerName))
  448. menu.AddDisabledItem(Styles.menuItemAddToIncludeFilter);
  449. else
  450. menu.AddDisabledItem(Styles.menuItemRemoveFromIncludeFilter);
  451. if (!m_CurrentSettings.rangeSettings.nameExcludes.Contains(markerName))
  452. menu.AddDisabledItem(Styles.menuItemAddToExcludeFilter);
  453. else
  454. menu.AddDisabledItem(Styles.menuItemRemoveFromExcludeFilter);
  455. menu.AddSeparator("");
  456. menu.AddDisabledItem(Styles.menuItemSetAsParentMarkerFilter);
  457. menu.AddDisabledItem(Styles.menuItemClearParentMarkerFilter);
  458. menu.AddSeparator("");
  459. menu.AddDisabledItem(Styles.menuItemCopyToClipboard);
  460. return menu;
  461. }
  462. public GUIContent ConstructTimeRangeText()
  463. {
  464. StringBuilder sb = new StringBuilder();
  465. ProfileAnalysis analysis = m_CurrentSettings.rangeSettings.dataView.analysis;
  466. int depthFilter = m_CurrentSettings.rangeSettings.depthFilter;
  467. FrameSummary frameSummary = analysis.GetFrameSummary();
  468. string frameTimeString = ToDisplayUnits(frameSummary.msMedian, true, 0);
  469. string accountedTimeString = ToDisplayUnits(m_MarkerSummary.totalTime, true, 0);
  470. sb.AppendFormat(Content.frameTime, frameTimeString);
  471. // Note m_CurrentSettings.rangeSettings.dataView.analysis.GetThreads contains all thread names, not just the filtered threads
  472. bool singleThread = m_CurrentSettings.rangeSettings.threadSelectionCount == 1;
  473. if (depthFilter == ProfileAnalyzer.kDepthAll)
  474. {
  475. if (m_CurrentSettings.rangeSettings.timingOption == TimingOptions.TimingOption.Time)
  476. {
  477. sb.Append("\n");
  478. sb.AppendFormat(Content.totalTimeAllDepths, accountedTimeString);
  479. if (singleThread)
  480. {
  481. sb.Append("\n\n");
  482. sb.Append(Content.selectSelf);
  483. }
  484. }
  485. else
  486. {
  487. sb.Append("\n");
  488. sb.AppendFormat(Content.selfTimeAllDepths,accountedTimeString);
  489. }
  490. }
  491. else
  492. {
  493. if (m_CurrentSettings.rangeSettings.timingOption == TimingOptions.TimingOption.Self)
  494. {
  495. sb.Append("\n");
  496. sb.AppendFormat(Content.selfTimeAtSpecificDepth,accountedTimeString, depthFilter);
  497. if (singleThread)
  498. {
  499. sb.Append("\n\n");
  500. sb.Append(Content.selectTotal);
  501. }
  502. }
  503. else
  504. {
  505. sb.Append("\n");
  506. sb.AppendFormat(Content.totalTimeAtSpecificDepth, accountedTimeString, depthFilter);
  507. }
  508. }
  509. if (!singleThread)
  510. {
  511. sb.Append("\n\n");
  512. sb.Append(Content.multipleThreads);
  513. }
  514. string timeRangeString = ToDisplayUnits(m_CurrentSettings.timeRange, true);
  515. return new GUIContent(timeRangeString, sb.ToString());
  516. }
  517. public void Draw(Rect rect, Color barColor, int barCount, float timeRange, Color selectedBackground, Color selectedBorder, Color selectedText, bool includeOthers, bool includeUnaccounted)
  518. {
  519. Settings newSettings = new Settings(m_RequestedRangeSettings, barCount, timeRange, includeOthers, includeUnaccounted);
  520. if (m_CurrentSettings != newSettings)
  521. {
  522. Profiler.BeginSample("CalculateTopMarkers");
  523. m_CurrentSettings = newSettings;
  524. m_MarkerSummary = CalculateTopMarkers();
  525. Profiler.EndSample();
  526. }
  527. if (m_CurrentSettings.rangeSettings == null)
  528. return;
  529. if (m_CurrentSettings.rangeSettings.dataView == null)
  530. return;
  531. if (m_CurrentSettings.rangeSettings.dataView.analysis == null)
  532. return;
  533. if (m_MarkerSummary == null || m_MarkerSummary.entry == null)
  534. return;
  535. ProfileAnalysis analysis = m_CurrentSettings.rangeSettings.dataView.analysis;
  536. FrameSummary frameSummary = analysis.GetFrameSummary();
  537. if (frameSummary == null)
  538. return;
  539. if (frameSummary.count <= 0)
  540. return;
  541. var markers = analysis.GetMarkers();
  542. if (markers == null)
  543. return;
  544. Profiler.BeginSample("DrawHeader");
  545. int rangeLabelWidth = 60;
  546. // After the marker graph we want an indication of the time range
  547. if (frameSummary.count > 0)
  548. {
  549. Rect rangeLabelRect = new Rect(rect.x + rect.width - rangeLabelWidth, rect.y, rangeLabelWidth, rect.height);
  550. GUIContent timeRangeText = ConstructTimeRangeText();
  551. GUI.Label(rangeLabelRect, timeRangeText);
  552. }
  553. // Reduce the size of the marker graph for the button/label we just added
  554. rect.width -= rangeLabelWidth;
  555. // Show marker graph
  556. float y = 0;
  557. float width = rect.width;
  558. float height = rect.height;
  559. var selectedPairingMarkerName = m_ProfileAnalyzerWindow.GetSelectedMarkerName();
  560. if (timeRange <= 0.0f)
  561. timeRange = frameSummary.msMedian;
  562. Profiler.EndSample();
  563. if (m_2D.DrawStart(rect, Draw2D.Origin.BottomLeft))
  564. {
  565. Profiler.BeginSample("DrawBars");
  566. m_2D.DrawFilledBox(0, y, width, height, m_BackgroundColor);
  567. foreach (MarkerSummaryEntry entry in m_MarkerSummary.entry)
  568. {
  569. String name = entry.name;
  570. float x = entry.x * width;
  571. float w = entry.w * width;
  572. if (entry.summaryType == SummaryType.Marker)
  573. {
  574. if (name == selectedPairingMarkerName)
  575. {
  576. DrawBar(x, y, w, height, selectedBackground, selectedBorder, true);
  577. }
  578. else
  579. {
  580. DrawBar(x, y, w, height, barColor, selectedBorder, false);
  581. }
  582. }
  583. else
  584. {
  585. // Others / Unaccounted
  586. Color color = entry.summaryType == SummaryType.Unaccounted ? new Color(barColor.r * 0.5f, barColor.g * 0.5f, barColor.b * 0.5f, barColor.a) : barColor;
  587. DrawBar(x, y, w, height, color, selectedBorder, false);
  588. }
  589. }
  590. Profiler.EndSample();
  591. m_2D.DrawEnd();
  592. }
  593. GUIStyle centreAlignStyle = new GUIStyle(GUI.skin.label);
  594. centreAlignStyle.alignment = TextAnchor.MiddleCenter;
  595. centreAlignStyle.normal.textColor = m_TextColor;
  596. GUIStyle leftAlignStyle = new GUIStyle(GUI.skin.label);
  597. leftAlignStyle.alignment = TextAnchor.MiddleLeft;
  598. leftAlignStyle.normal.textColor = m_TextColor;
  599. Color contentColor = GUI.contentColor;
  600. int frameSummaryMedianFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(frameSummary.medianFrameIndex, m_CurrentSettings.rangeSettings.dataView);
  601. Profiler.BeginSample("DrawText");
  602. foreach (MarkerSummaryEntry entry in m_MarkerSummary.entry)
  603. {
  604. String name = entry.name;
  605. float x = entry.x * width;
  606. float w = entry.w * width;
  607. float msAtMedian = entry.msAtMedian;
  608. if (entry.summaryType == SummaryType.Marker)
  609. {
  610. Rect labelRect = new Rect(rect.x + x, rect.y, w, rect.height);
  611. GUIStyle style = centreAlignStyle;
  612. String displayName = "";
  613. if (w >= 20)
  614. {
  615. displayName = name;
  616. Vector2 size = centreAlignStyle.CalcSize(new GUIContent(name));
  617. if (size.x > w)
  618. {
  619. var words = name.Split('.');
  620. displayName = words[words.Length - 1];
  621. style = leftAlignStyle;
  622. }
  623. }
  624. float percentAtMedian = msAtMedian * 100 / timeRange;
  625. string tooltip = string.Format(
  626. Content.tooltip,
  627. name,
  628. percentAtMedian, ToDisplayUnits(msAtMedian, true, 0), frameSummaryMedianFrameIndex,
  629. ToDisplayUnits(entry.msMedian, true, 0), entry.medianFrameIndex);
  630. if (name == selectedPairingMarkerName)
  631. style.normal.textColor = selectedText;
  632. else
  633. style.normal.textColor = m_TextColor;
  634. GUI.Label(labelRect, new GUIContent(displayName, tooltip), style);
  635. Event current = Event.current;
  636. if (labelRect.Contains(current.mousePosition))
  637. {
  638. if (current.type == EventType.ContextClick)
  639. {
  640. GenericMenu menu;
  641. if (!m_ProfileAnalyzerWindow.IsAnalysisRunning())
  642. menu = GenerateActiveContextMenu(name, current);
  643. else
  644. menu = GenerateDisabledContextMenu(name);
  645. menu.ShowAsContext();
  646. current.Use();
  647. }
  648. if (current.type == EventType.MouseDown)
  649. {
  650. m_ProfileAnalyzerWindow.SelectMarker(name);
  651. m_ProfileAnalyzerWindow.RequestRepaint();
  652. }
  653. }
  654. }
  655. else
  656. {
  657. DrawBarText(rect, x, w, msAtMedian, name, timeRange, leftAlignStyle, frameSummaryMedianFrameIndex);
  658. }
  659. }
  660. Profiler.EndSample();
  661. }
  662. static float CaculateWidth(float x, float msTime, float msToWidth, float width)
  663. {
  664. float w = msTime * msToWidth;
  665. if (x + w > width)
  666. w = width - x;
  667. return w;
  668. }
  669. float DrawBar(float x, float y, float w, float height, Color barColor, Color selectedBorder, bool withBorder)
  670. {
  671. if (withBorder)
  672. m_2D.DrawFilledBox(x + 1, y + 1, w, height - 2, selectedBorder);
  673. m_2D.DrawFilledBox(x + 2, y + 2, w - 2, height - 4, barColor);
  674. return w;
  675. }
  676. float DrawBarText(Rect rect, float x, float w, float msTime, string name, float timeRange, GUIStyle leftAlignStyle, int medianFrameIndex)
  677. {
  678. float width = rect.width;
  679. Rect labelRect = new Rect(rect.x + x, rect.y, w, rect.height);
  680. float percent = msTime / timeRange * 100;
  681. GUIStyle style = leftAlignStyle;
  682. string tooltip = string.Format("{0}\n{1:f2}% ({2} on median frame {3})",
  683. name,
  684. percent,
  685. ToDisplayUnits(msTime, true, 0),
  686. medianFrameIndex);
  687. GUI.Label(labelRect, new GUIContent("", tooltip), style);
  688. Event current = Event.current;
  689. if (labelRect.Contains(current.mousePosition))
  690. {
  691. if (current.type == EventType.ContextClick)
  692. {
  693. GenericMenu menu = new GenericMenu();
  694. if (!m_ProfileAnalyzerWindow.IsAnalysisRunning())
  695. menu.AddItem(Styles.menuItemSelectFramesAll, false, m_ProfileAnalyzerWindow.SelectAllFrames);
  696. else
  697. menu.AddDisabledItem(Styles.menuItemSelectFramesAll);
  698. menu.ShowAsContext();
  699. current.Use();
  700. }
  701. if (current.type == EventType.MouseDown)
  702. {
  703. m_ProfileAnalyzerWindow.SelectMarker(null);
  704. m_ProfileAnalyzerWindow.RequestRepaint();
  705. }
  706. }
  707. return w;
  708. }
  709. void CopyToClipboard(Event current, string text)
  710. {
  711. EditorGUIUtility.systemCopyBuffer = text;
  712. }
  713. }
  714. }