mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-16 07:14:09 +02:00
805 lines
21 KiB
Beef
805 lines
21 KiB
Beef
using Beefy.widgets;
|
|
using Beefy.theme.dark;
|
|
using Beefy.gfx;
|
|
using System.Collections;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using Beefy.events;
|
|
using System.Threading;
|
|
using Beefy;
|
|
|
|
namespace BeefPerf
|
|
{
|
|
class ProfilePanel : Widget
|
|
{
|
|
public class ProfileListViewItem : DarkVirtualListViewItem
|
|
{
|
|
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
|
|
{
|
|
((ProfileListView)mListView).mProfilePanel.ItemClicked(this, btn, btnCount, x, y);
|
|
}
|
|
|
|
public override bool Selected
|
|
{
|
|
set
|
|
{
|
|
if (value)
|
|
{
|
|
int32 selectedIdx = mVirtualIdx;
|
|
var profilePanel = ((ProfileListView)mListView).mProfilePanel;
|
|
var result = profilePanel.mProfileCtx.mResults[selectedIdx];
|
|
DeleteAndNullify!(profilePanel.mPerfView.mProfileHiliteZone);
|
|
profilePanel.mPerfView.mProfileHiliteZone = new PerfView.HiliteZone(result.mZoneNameId, result.mUnformattedName);
|
|
|
|
//result.mName
|
|
}
|
|
|
|
base.Selected = value;
|
|
//int32 selectedIdx = item.mVirtualIdx;
|
|
//var foundEntry = mSearchState.mFoundEntries[selectedIdx];
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ProfileListView : DarkVirtualListView
|
|
{
|
|
public ProfilePanel mProfilePanel;
|
|
|
|
public override void ChangeSort(DarkListView.SortType sortType)
|
|
{
|
|
base.ChangeSort(sortType);
|
|
mSortType = sortType;
|
|
mProfilePanel.RefreshList();
|
|
}
|
|
|
|
protected override ListViewItem CreateListViewItem()
|
|
{
|
|
return new ProfileListViewItem();
|
|
}
|
|
|
|
public override void PopulateVirtualItem(DarkVirtualListViewItem listViewItem)
|
|
{
|
|
base.PopulateVirtualItem(listViewItem);
|
|
|
|
var client = mProfilePanel.mPerfView.mSession;
|
|
var perfInfo = mProfilePanel.mProfileCtx.mResults[listViewItem.mVirtualIdx];
|
|
listViewItem.Label = perfInfo.mName;
|
|
|
|
var subItem = listViewItem.CreateSubItem(1);
|
|
subItem.mLabel = new String();
|
|
subItem.mLabel.AppendF("{0}", perfInfo.mCount);
|
|
|
|
subItem = listViewItem.CreateSubItem(2);
|
|
subItem.mLabel = new String();
|
|
client.ElapsedTicksToStr(perfInfo.mTicks, subItem.mLabel);
|
|
|
|
subItem = listViewItem.CreateSubItem(3);
|
|
subItem.mLabel = new String();
|
|
client.ElapsedTicksToStr(perfInfo.mTicks - perfInfo.mChildTicks, subItem.mLabel);
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
base.DrawAll(g);
|
|
|
|
if (((mProfilePanel.mProfileCtx != null) && (!mProfilePanel.mProfileCtx.mDone)) || (mProfilePanel.mSorting))
|
|
{
|
|
using (g.PushColor(0xA0595959))
|
|
g.FillRect(0, 20, mWidth - 20, mHeight - 20);
|
|
BPUtils.DrawWait(g, mWidth / 2, mHeight / 2);
|
|
}
|
|
}
|
|
|
|
public override void KeyDown(KeyCode keyCode, bool isRepeat)
|
|
{
|
|
base.KeyDown(keyCode, isRepeat);
|
|
if (keyCode == .Escape)
|
|
{
|
|
mProfilePanel.RemoveFocus();
|
|
}
|
|
}
|
|
|
|
public void GetSummaryString(String str)
|
|
{
|
|
str.Append("Name____________________________________Count_______Total________Self\n");
|
|
for (var entry in mProfilePanel.mProfileCtx.mResults)
|
|
{
|
|
str.Append(entry.mName);
|
|
str.Append(' ', Math.Max(38 - entry.mName.Length, 1));
|
|
|
|
var entryStr = scope String();
|
|
entry.mCount.ToString(entryStr);
|
|
str.Append(' ', Math.Max(7 - entryStr.Length, 1));
|
|
str.Append(entryStr);
|
|
|
|
entryStr.Clear();
|
|
mProfilePanel.mProfileCtx.mSession.ElapsedTicksToStr(entry.mTicks, entryStr);
|
|
str.Append(' ', Math.Max(12 - entryStr.Length, 1));
|
|
str.Append(entryStr);
|
|
|
|
entryStr.Clear();
|
|
mProfilePanel.mProfileCtx.mSession.ElapsedTicksToStr(entry.mTicks - entry.mChildTicks, entryStr);
|
|
str.Append(' ', Math.Max(12 - entryStr.Length, 1));
|
|
str.Append(entryStr);
|
|
str.Append('\n');
|
|
}
|
|
|
|
str.Append("---------------------------------------------------------------------\n");
|
|
str.Append("Total Time: ");
|
|
|
|
mProfilePanel.mProfileCtx.mSession.ElapsedTicksToStr(mProfilePanel.mSelection.mTickEnd - mProfilePanel.mSelection.mTickStart, str);
|
|
}
|
|
|
|
public void AddStaticMenu(Menu menu)
|
|
{
|
|
var menuItem = menu.AddItem("Copy to Clipboard");
|
|
menuItem.mOnMenuItemSelected.Add(new (item) =>
|
|
{
|
|
String str = scope String();
|
|
GetSummaryString(str);
|
|
gApp.SetClipboardText(str);
|
|
//Debug.WriteLine(str);
|
|
|
|
});
|
|
}
|
|
|
|
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
|
|
{
|
|
base.MouseDown(x, y, btn, btnCount);
|
|
|
|
GetRoot().SelectItemExclusively(null);
|
|
if (btn == 1)
|
|
{
|
|
Menu menu = new Menu();
|
|
AddStaticMenu(menu);
|
|
MenuWidget menuWidget = DarkTheme.sDarkTheme.CreateMenuWidget(menu);
|
|
menuWidget.Init(this, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
DarkCheckBox mFormatCheckbox;
|
|
ProfileListView mListView;
|
|
DarkButton mGetButton;
|
|
|
|
PerfView mPerfView;
|
|
BPSelection mSelection;
|
|
bool mSelectionDirty;
|
|
int64 mActiveLastCurTick;
|
|
|
|
ProfileContext mProfileCtx ~ delete _;
|
|
public WaitEvent mSortDoneHandle = new WaitEvent() ~ delete _;
|
|
public bool mSorting;
|
|
|
|
public this()
|
|
{
|
|
mFormatCheckbox = new DarkCheckBox();
|
|
mFormatCheckbox.Checked = true;
|
|
mFormatCheckbox.Label = "Format Strings";
|
|
mFormatCheckbox.mOnMouseClick.Add(new [&] (evt) => { mSelectionDirty = true; } );
|
|
AddWidget(mFormatCheckbox);
|
|
|
|
mListView = new ProfileListView();
|
|
mListView.mProfilePanel = this;
|
|
mListView.mOnLostFocus.Add(new (evt) => { RemoveFocus(); });
|
|
mListView.mSortType.mColumn = 2;
|
|
mListView.mSortType.mReverse = true;
|
|
AddWidget(mListView);
|
|
|
|
mListView.AddColumn(200, "Name");
|
|
mListView.AddColumn(100, "Count");
|
|
mListView.AddColumn(150, "Total");
|
|
mListView.AddColumn(150, "Self");
|
|
mListView.InitScrollbars(false, true);
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
FinishSorting();
|
|
}
|
|
|
|
void FinishSorting()
|
|
{
|
|
if (mSorting)
|
|
{
|
|
mSortDoneHandle.WaitFor();
|
|
mSorting = false;
|
|
mSortDoneHandle.Reset();
|
|
}
|
|
}
|
|
|
|
public void RemoveFocus()
|
|
{
|
|
mListView.GetRoot().SelectItemExclusively(null);
|
|
if (mPerfView != null)
|
|
DeleteAndNullify!(mPerfView.mProfileHiliteZone);
|
|
}
|
|
|
|
public override void Resize(float x, float y, float width, float height)
|
|
{
|
|
base.Resize(x, y, width, height);
|
|
|
|
mListView.ResizeClamped(0, 20, width, height - 20);
|
|
mFormatCheckbox.Resize(0, 0, 20, 20);
|
|
}
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
|
|
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
|
|
if (mProfileCtx != null)
|
|
{
|
|
String str = scope String();
|
|
str.Append("Total Time: ");
|
|
mProfileCtx.mSession.ElapsedTicksToStr(mSelection.mTickEnd - mSelection.mTickStart, str);
|
|
g.DrawString(str, 150, 0);
|
|
}
|
|
//g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Bkg), 0, 0, mWidth, mHeight);
|
|
}
|
|
|
|
public override void DrawAll(Graphics g)
|
|
{
|
|
base.DrawAll(g);
|
|
}
|
|
|
|
public void Show(PerfView perfView, BPSelection selection)
|
|
{
|
|
Debug.Assert(perfView != null);
|
|
mPerfView = perfView;
|
|
mSelection = selection;
|
|
mSelectionDirty = true;
|
|
}
|
|
|
|
void GetData()
|
|
{
|
|
mListView.GetRoot().Clear();
|
|
|
|
}
|
|
|
|
struct PerfInfo
|
|
{
|
|
public String mName;
|
|
public int32 mCount;
|
|
public int64 mTicks;
|
|
public int64 mChildTicks;
|
|
public int32 mStackCount; // Number of times this entry appears in entryStack
|
|
|
|
public int32 mZoneNameId;
|
|
public String mUnformattedName;
|
|
}
|
|
|
|
struct BPPerfEntry
|
|
{
|
|
public int32 mZoneNameId;
|
|
public int64 mTickStart;
|
|
public int64 mChildTicks;
|
|
public int32 mParamsReadPos;
|
|
public PerfInfo* mPerfInfo;
|
|
}
|
|
|
|
class ProfileContext
|
|
{
|
|
BumpAllocator mAlloc = new BumpAllocator() ~ delete _;
|
|
public BpSession mSession;
|
|
public Dictionary<String, PerfInfo*> mPerfDict = new .() ~ delete _;
|
|
String mTempStr = new String() ~ delete _;
|
|
String mTempDynStr = new String() ~ delete _;
|
|
public List<PerfInfo*> mResults = new List<PerfInfo*>() ~ delete _;
|
|
public List<PerfInfo*> mSortingResults = new List<PerfInfo*>() ~ delete _;
|
|
public int32 mStreamDataIdx;
|
|
public bool mDone;
|
|
public bool mFormatStrings;
|
|
public bool mHasSelectionEndChanged;
|
|
|
|
public PerfInfo* GetPerfInfo(BPPerfEntry entry, BPStateContext stateCtx)
|
|
{
|
|
int32 paramsSize;
|
|
|
|
String str;
|
|
if (entry.mZoneNameId < 0)
|
|
{
|
|
int32 nameLen = -entry.mZoneNameId;
|
|
str = mTempDynStr;
|
|
str.Reference((char8*)stateCtx.mReadStart + entry.mParamsReadPos - nameLen, nameLen, 0);
|
|
paramsSize = -1;
|
|
}
|
|
else
|
|
{
|
|
let zoneName = mSession.mZoneNames[entry.mZoneNameId];
|
|
str = zoneName.mName;
|
|
paramsSize = zoneName.mParamsSize;
|
|
}
|
|
|
|
//bool dbgStr = str == "DeepStack0 %d";
|
|
|
|
String unformattedStr = str;
|
|
|
|
if ((paramsSize != 0) && (mFormatStrings))
|
|
{
|
|
mTempStr.Clear();
|
|
stateCtx.FormatStr(entry.mParamsReadPos, paramsSize, str, mTempStr);
|
|
str = mTempStr;
|
|
}
|
|
|
|
String* keyPtr;
|
|
PerfInfo* perfInfo;
|
|
PerfInfo** perfInfoPtr;
|
|
if (mPerfDict.TryAdd(str, out keyPtr, out perfInfoPtr))
|
|
{
|
|
perfInfo = new:mAlloc PerfInfo();
|
|
*perfInfoPtr = perfInfo;
|
|
|
|
if (str == (Object)mTempStr)
|
|
{
|
|
String heapStr = new:mAlloc String(str);
|
|
*keyPtr = heapStr;
|
|
perfInfo.mName = heapStr;
|
|
}
|
|
else
|
|
perfInfo.mName = str;
|
|
|
|
if ((unformattedStr == (Object)mTempDynStr) && (unformattedStr != (Object)mTempStr))
|
|
{
|
|
String heapStr = new:mAlloc String(unformattedStr);
|
|
perfInfo.mUnformattedName = heapStr;
|
|
}
|
|
else
|
|
perfInfo.mUnformattedName = unformattedStr;
|
|
perfInfo.mZoneNameId = entry.mZoneNameId;
|
|
}
|
|
else
|
|
{
|
|
perfInfo = *perfInfoPtr;
|
|
if ((entry.mZoneNameId > 0) && (perfInfo.mZoneNameId < 0))
|
|
{
|
|
// Set to a valid zoneNameId if the inserting entry was a dynamic string but this one isn't
|
|
perfInfo.mZoneNameId = entry.mZoneNameId;
|
|
}
|
|
}
|
|
|
|
return perfInfo;
|
|
}
|
|
}
|
|
|
|
void UpdateProfileCtx()
|
|
{
|
|
Stopwatch stopwatch = scope Stopwatch();
|
|
stopwatch.Start();
|
|
|
|
var client = mPerfView.mSession;
|
|
var thread = client.mThreads[mSelection.mThreadIdx];
|
|
|
|
bool isRecording = false;
|
|
bool isFirstDrawn = mProfileCtx.mStreamDataIdx == 0;
|
|
|
|
bool isManualSelection = mSelection.mDepth == -1;
|
|
|
|
StreamLoop: while (mProfileCtx.mStreamDataIdx < thread.mStreamDataList.Count)
|
|
{
|
|
int streamDataListIdx = mProfileCtx.mStreamDataIdx++;
|
|
var streamData = thread.mStreamDataList[streamDataListIdx];
|
|
|
|
if ((streamData.mSplitTick > 0) && (streamData.mSplitTick < mSelection.mTickStart))
|
|
continue; // All data is to the left
|
|
|
|
BPStateContext stateCtx = scope BPStateContext(client, streamData);
|
|
|
|
List<BPPerfEntry> entryStack = scope List<BPPerfEntry>();
|
|
int32 stackDepth = 0;
|
|
|
|
CmdLoop: while (true)
|
|
{
|
|
switch (stateCtx.GetNextEvent())
|
|
{
|
|
case let .Enter(startTick, strIdx):
|
|
int stackPos = stackDepth++;
|
|
|
|
if (((mSelection.mDepth == -1) && (startTick >= mSelection.mTickStart)) ||
|
|
((startTick == mSelection.mTickStart) && (stackPos == mSelection.mDepth)))
|
|
{
|
|
isRecording = true;
|
|
}
|
|
|
|
if (isRecording)
|
|
{
|
|
BPPerfEntry entry;
|
|
entry.mTickStart = startTick;
|
|
entry.mZoneNameId = strIdx;
|
|
entry.mChildTicks = 0;
|
|
//stateCtx.MoveToParamData();
|
|
entry.mParamsReadPos = stateCtx.ReadPos;
|
|
entry.mPerfInfo = null;
|
|
entry.mPerfInfo = mProfileCtx.GetPerfInfo(entry, stateCtx);
|
|
entry.mPerfInfo.mStackCount++;
|
|
entryStack.Add(entry);
|
|
}
|
|
case let .Leave(endTick):
|
|
stackDepth--;
|
|
if (isRecording)
|
|
{
|
|
let entry = entryStack.PopBack();
|
|
entry.mPerfInfo.mStackCount--;
|
|
|
|
if ((entry.mTickStart == mSelection.mTickStart) && (stackDepth == mSelection.mDepth))
|
|
{
|
|
if (client.mCurTick == endTick)
|
|
{
|
|
mProfileCtx.mHasSelectionEndChanged = true;
|
|
mSelection.mTickEnd = endTick;
|
|
}
|
|
}
|
|
|
|
int64 ticks = endTick - entry.mTickStart;
|
|
|
|
if (isManualSelection)
|
|
{
|
|
int64 tickStart = Math.Max(entry.mTickStart, mSelection.mTickStart);
|
|
int64 tickEnd = Math.Min(endTick, mSelection.mTickEnd);
|
|
ticks = tickEnd - tickStart;
|
|
if (ticks <= 0)
|
|
continue;
|
|
}
|
|
|
|
//PerfInfo* perfInfo = mProfileCtx.GetPerfInfo(entry, stateCtx);
|
|
PerfInfo* perfInfo = entry.mPerfInfo;
|
|
|
|
bool isOld = ((entry.mTickStart <= streamData.mStartTick) && (stackDepth < stateCtx.mSplitCarryoverCount));
|
|
|
|
// Is this a duplicate spanned entry? If so, we don't add it's stats but we still
|
|
// must process it as a parent to keep track of mChildTicks for new children
|
|
if ((isFirstDrawn) || (!isOld))
|
|
{
|
|
perfInfo.mCount++;
|
|
if (perfInfo.mStackCount != 0)
|
|
{
|
|
// Total time is already handled by outer scope
|
|
}
|
|
else
|
|
perfInfo.mTicks += ticks;
|
|
}
|
|
|
|
if (entryStack.Count > 0)
|
|
{
|
|
var prevEntry = entryStack[entryStack.Count - 1];
|
|
|
|
//bool prevIsOld = ((prevEntry.mTickStart <= streamData.mStartTick) && (stackDepth - 1 < stateCtx.mSplitCarryoverCount));
|
|
//if ((isFirstDrawn) || (!prevIsOld))
|
|
if (!isOld)
|
|
{
|
|
//PerfInfo* prevPerfInfo = mProfileCtx.GetPerfInfo(prevEntry, stateCtx);
|
|
|
|
PerfInfo* prevPerfInfo = prevEntry.mPerfInfo;
|
|
prevPerfInfo.mChildTicks += ticks;
|
|
|
|
if (perfInfo.mStackCount != 0)
|
|
{
|
|
// We have an instance of ourselves on an outer scope, so time we thought was child time actually isn't
|
|
perfInfo.mChildTicks -= ticks;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isManualSelection)
|
|
{
|
|
if ((stackDepth == 0) && (endTick >= mSelection.mTickEnd))
|
|
{
|
|
if (endTick <= streamData.mSplitTick)
|
|
break StreamLoop;
|
|
}
|
|
//isRecording = false;
|
|
}
|
|
|
|
if (stackDepth <= mSelection.mDepth)
|
|
{
|
|
if (endTick <= streamData.mSplitTick)
|
|
break StreamLoop;
|
|
isRecording = false;
|
|
}
|
|
}
|
|
case .EndOfStream:
|
|
break CmdLoop;
|
|
default:
|
|
}
|
|
}
|
|
|
|
isFirstDrawn = false;
|
|
|
|
if (stopwatch.ElapsedMilliseconds > (int)(gApp.mTimePerFrame * 1000))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
mProfileCtx.mDone = true;
|
|
|
|
for (var value in mProfileCtx.mPerfDict.Keys)
|
|
{
|
|
var perfInfo = @value.Value;
|
|
Debug.Assert(perfInfo.mName != null);
|
|
mProfileCtx.mResults.Add(perfInfo);
|
|
}
|
|
|
|
RefreshList();
|
|
}
|
|
|
|
void RefreshData()
|
|
{
|
|
mListView.GetRoot().Clear();
|
|
|
|
if (mPerfView == null)
|
|
return;
|
|
|
|
var session = mPerfView.mSession;
|
|
|
|
delete mProfileCtx;
|
|
mProfileCtx = new ProfileContext();
|
|
mProfileCtx.mFormatStrings = mFormatCheckbox.Checked;
|
|
mProfileCtx.mSession = session;
|
|
}
|
|
|
|
public void ItemClicked(ProfileListViewItem clickedItem, int32 btn, int32 btnCount, float x, float y)
|
|
{
|
|
if (clickedItem.mParentItem == null)
|
|
return;
|
|
ProfileListViewItem item = (ProfileListViewItem)clickedItem.GetSubItem(0);
|
|
mListView.GetRoot().SelectItemExclusively(item);
|
|
mListView.SetFocus();
|
|
|
|
if (btn == 1)
|
|
{
|
|
Menu menu = new Menu();
|
|
|
|
var menuItem = menu.AddItem("Find Instances");
|
|
menuItem.mOnMenuItemSelected.Add(new (selectedItem) =>
|
|
{
|
|
var find = gApp.mFindPanel;
|
|
var str = scope String();
|
|
var client = mPerfView.mSession;
|
|
|
|
var thread = client.mThreads[mSelection.mThreadIdx];
|
|
|
|
str.Clear();
|
|
var perfInfo = mProfileCtx.mResults[item.mVirtualIdx];
|
|
str.Append('=');
|
|
str.Append(perfInfo.mName);
|
|
if (str.Contains(' '))
|
|
{
|
|
str.Insert(1, '\"');
|
|
str.Append('"');
|
|
}
|
|
|
|
if (mSelection.mDepth > 0)
|
|
{
|
|
str.Append(" Depth>");
|
|
mSelection.mDepth.ToString(str);
|
|
}
|
|
find.mEntryEdit.SetText(str);
|
|
|
|
str.Clear();
|
|
str.Append('=');
|
|
thread.GetName(str);
|
|
if (str.Contains(' '))
|
|
{
|
|
str.Insert(1, '\"');
|
|
str.Append('"');
|
|
}
|
|
find.mTrackEdit.mEditWidget.SetText(str);
|
|
|
|
str.Clear();
|
|
client.TicksToStr(mSelection.mTickStart, str);
|
|
find.mTimeFromEdit.mEditWidget.SetText(str);
|
|
|
|
str.Clear();
|
|
client.TicksToStr(mSelection.mTickEnd, str);
|
|
find.mTimeToEdit.mEditWidget.SetText(str);
|
|
|
|
find.mFormatCheckbox.Checked = true;
|
|
find.mZonesCheckbox.Checked = true;
|
|
find.mEventsCheckbox.Checked = false;
|
|
|
|
find.mNeedsRestartSearch = true;
|
|
});
|
|
|
|
menu.AddItem();
|
|
mListView.AddStaticMenu(menu);
|
|
|
|
MenuWidget menuWidget = DarkTheme.sDarkTheme.CreateMenuWidget(menu);
|
|
menuWidget.Init(clickedItem, x, y);
|
|
}
|
|
}
|
|
|
|
public void ValueClicked(MouseEvent theEvent)
|
|
{
|
|
DarkVirtualListViewItem clickedItem = (DarkVirtualListViewItem)theEvent.mSender;
|
|
DarkVirtualListViewItem item = (DarkVirtualListViewItem)clickedItem.GetSubItem(0);
|
|
|
|
mListView.GetRoot().SelectItemExclusively(item);
|
|
mListView.SetFocus();
|
|
|
|
if ((theEvent.mBtn == 0) && (theEvent.mBtnCount > 1))
|
|
{
|
|
for (int32 childIdx = 1; childIdx < mListView.GetRoot().GetChildCount(); childIdx++)
|
|
{
|
|
var checkListViewItem = mListView.GetRoot().GetChildAtIndex(childIdx);
|
|
checkListViewItem.IconImage = null;
|
|
}
|
|
|
|
/*int32 selectedIdx = item.mVirtualIdx;
|
|
var foundEntry = mSearchState.mFoundEntries[selectedIdx];
|
|
mPerfView.ZoomTo(foundEntry.mStartTick, foundEntry.mEndTick);
|
|
BPSelection selection;
|
|
selection.mStartTick = foundEntry.mStartTick;
|
|
selection.mEndTick = foundEntry.mEndTick;
|
|
selection.mDepth = foundEntry.mDepth;
|
|
selection.mThreadIdx = foundEntry.mTrackIdx;
|
|
|
|
mPerfView.mSelection = selection;*/
|
|
}
|
|
|
|
if (theEvent.mBtn == 1)
|
|
{
|
|
Menu menu = new Menu();
|
|
|
|
#unwarn
|
|
var menuItem = menu.AddItem("Set Track Color ...");
|
|
MenuWidget menuWidget = DarkTheme.sDarkTheme.CreateMenuWidget(menu);
|
|
menuWidget.Init(this, theEvent.mX, theEvent.mY);
|
|
}
|
|
}
|
|
|
|
int EntryCompare(PerfInfo* lhs, PerfInfo* rhs)
|
|
{
|
|
int64 result = 0;
|
|
if (mListView.mSortType.mColumn == 0)
|
|
{
|
|
result = String.Compare(lhs.mName, rhs.mName, true);
|
|
if (result == 0)
|
|
result = lhs.mTicks - rhs.mTicks;
|
|
}
|
|
else if (mListView.mSortType.mColumn == 1)
|
|
{
|
|
result = lhs.mCount - rhs.mCount;
|
|
}
|
|
else if (mListView.mSortType.mColumn == 2)
|
|
{
|
|
result = lhs.mTicks - rhs.mTicks;
|
|
}
|
|
else
|
|
{
|
|
result = (lhs.mTicks - lhs.mChildTicks) - (rhs.mTicks - rhs.mChildTicks);
|
|
}
|
|
if (mListView.mSortType.mReverse)
|
|
result = -result;
|
|
return (int)result;
|
|
}
|
|
|
|
void SortList()
|
|
{
|
|
mProfileCtx.mSortingResults.Sort(scope => EntryCompare);
|
|
mSortDoneHandle.Set(true);
|
|
}
|
|
|
|
void CheckSorting(int32 waitMS = 0)
|
|
{
|
|
if (mSorting)
|
|
{
|
|
if (mSortDoneHandle.WaitFor(waitMS))
|
|
{
|
|
mSorting = false;
|
|
mSortDoneHandle.Reset();
|
|
|
|
Debug.Assert(mProfileCtx.mResults.Count == mProfileCtx.mSortingResults.Count);
|
|
Swap!(mProfileCtx.mResults, mProfileCtx.mSortingResults);
|
|
|
|
mListView.GetRoot().Clear();
|
|
|
|
if (mProfileCtx.mResults.Count > 0)
|
|
{
|
|
var listViewItem = (DarkVirtualListViewItem)mListView.GetRoot().CreateChildItem();
|
|
listViewItem.mVirtualHeadItem = listViewItem;
|
|
listViewItem.mVirtualCount = (int32)mProfileCtx.mResults.Count;
|
|
mListView.PopulateVirtualItem(listViewItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RefreshList()
|
|
{
|
|
if (mPerfView == null)
|
|
{
|
|
mListView.GetRoot().Clear();
|
|
return;
|
|
}
|
|
|
|
FinishSorting();
|
|
|
|
mSorting = true;
|
|
|
|
mProfileCtx.mSortingResults.Clear();
|
|
mProfileCtx.mSortingResults.GrowUnitialized(mProfileCtx.mResults.Count);
|
|
for (int i < mProfileCtx.mResults.Count)
|
|
mProfileCtx.mSortingResults[i] = mProfileCtx.mResults[i];
|
|
|
|
ThreadPool.QueueUserWorkItem(new => SortList);
|
|
CheckSorting(20);
|
|
|
|
/*for (var strId in iList)
|
|
{
|
|
var childItem = mListView.GetRoot().CreateChildItem();
|
|
childItem.Label = strId;
|
|
|
|
var perfInfo = ref perfDict[strId];
|
|
|
|
var subItem = childItem.CreateSubItem(1);
|
|
subItem.mLabel = new String();
|
|
subItem.mLabel.FormatInto("{0}", perfInfo.mCount);
|
|
subItem.mMouseDownHandler.Add(new => ValueClicked);
|
|
|
|
subItem = childItem.CreateSubItem(2);
|
|
subItem.mLabel = new String();
|
|
client.ElapsedTicksToStr(perfInfo.mTicks, subItem.mLabel);
|
|
subItem.mMouseDownHandler.Add(new => ValueClicked);
|
|
|
|
subItem = childItem.CreateSubItem(3);
|
|
subItem.mLabel = new String();
|
|
client.ElapsedTicksToStr(perfInfo.mTicks - perfInfo.mChildTicks, subItem.mLabel);
|
|
subItem.mMouseDownHandler.Add(new => ValueClicked);
|
|
}*/
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
if (mPerfView == null)
|
|
return;
|
|
|
|
// Were we awaiting more data to refresh
|
|
var client = mPerfView.mSession;
|
|
if ((mActiveLastCurTick != 0) && (mActiveLastCurTick != client.mCurTick))
|
|
{
|
|
mActiveLastCurTick = 0;
|
|
mSelectionDirty = true;
|
|
}
|
|
|
|
if (mSorting)
|
|
{
|
|
CheckSorting();
|
|
}
|
|
else
|
|
{
|
|
if ((mSelectionDirty) && (gApp.mIsUpdateBatchStart) &&
|
|
((mProfileCtx == null) || (mProfileCtx.mDone)))
|
|
{
|
|
mSelectionDirty = false;
|
|
RefreshData();
|
|
}
|
|
|
|
if ((mProfileCtx != null) && (!mProfileCtx.mDone))
|
|
{
|
|
if (gApp.mIsUpdateBatchStart)
|
|
UpdateProfileCtx();
|
|
|
|
if (mProfileCtx.mDone)
|
|
{
|
|
if (mProfileCtx.mHasSelectionEndChanged)
|
|
{
|
|
mActiveLastCurTick = client.mCurTick;
|
|
}
|
|
else
|
|
mActiveLastCurTick = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
mListView.GetRoot().Clear();
|
|
DeleteAndNullify!(mProfileCtx);
|
|
mActiveLastCurTick = 0;
|
|
mPerfView = null;
|
|
}
|
|
}
|
|
}
|