From 0fe8ac8b484335a828818611792790b4ab6e4fd4 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sun, 6 Aug 2017 16:23:22 -0400 Subject: [PATCH] Debugger: Improved trace logger look & performance --- Core/TraceLogger.cpp | 41 +++--- Core/TraceLogger.h | 7 +- GUI.NET/Config/DebugInfo.cs | 1 + .../Controls/ctrlScrollableTextbox.cs | 29 +++- GUI.NET/Debugger/Controls/ctrlTextbox.cs | 40 +++++- GUI.NET/Debugger/frmDebugger.Designer.cs | 46 +++--- GUI.NET/Debugger/frmDebugger.cs | 4 +- GUI.NET/Debugger/frmTraceLogger.Designer.cs | 133 +++++++++--------- GUI.NET/Debugger/frmTraceLogger.cs | 103 +++++++++++--- 9 files changed, 265 insertions(+), 139 deletions(-) diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index 18ec7f83..43fcd37f 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -48,30 +48,27 @@ void TraceLogger::SetOptions(TraceLoggerOptions options) void TraceLogger::StartLogging(string filename) { + _outputBuffer.clear(); _outputFile.open(filename, ios::out | ios::binary); _logToFile = true; - _firstLine = true; } void TraceLogger::StopLogging() { if(_logToFile) { - Console::Pause(); + _logToFile = false; if(_outputFile) { if(!_outputBuffer.empty()) { _outputFile << _outputBuffer; } _outputFile.close(); } - Console::Resume(); - _logToFile = false; } } - void TraceLogger::LogStatic(string log) { - if(_instance && _instance->_logToFile && _instance->_options.ShowExtraInfo && !_instance->_firstLine) { + if(_instance && _instance->_logToFile && _instance->_options.ShowExtraInfo) { //Flush current buffer _instance->_outputFile << _instance->_outputBuffer; _instance->_outputBuffer.clear(); @@ -105,15 +102,11 @@ void TraceLogger::GetStatusFlag(string &output, uint8_t ps) } } -void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &ppuState, DisassemblyInfo &disassemblyInfo, bool firstLine) +void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &ppuState, DisassemblyInfo &disassemblyInfo, bool forceByteCode) { - if(!firstLine) { - output += "\n"; - } - output += HexUtilities::ToHex(cpuState.DebugPC) + " "; - if(_options.ShowByteCode) { + if(_options.ShowByteCode || forceByteCode) { string byteCode; disassemblyInfo.GetByteCode(byteCode); output += byteCode + std::string(13 - byteCode.size(), ' '); @@ -159,6 +152,7 @@ void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &pp if(_options.ShowCpuCycles) { output += " CPU Cycle:" + std::to_string(cpuState.CycleCount); } + output += "\n"; } bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo) @@ -191,13 +185,11 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state) } if(_logToFile) { - GetTraceRow(_outputBuffer, state.CPU, state.PPU, disassemblyInfo, _firstLine); + GetTraceRow(_outputBuffer, state.CPU, state.PPU, disassemblyInfo, false); if(_outputBuffer.size() > 32768) { _outputFile << _outputBuffer; _outputBuffer.clear(); } - - _firstLine = false; } } @@ -221,15 +213,22 @@ void TraceLogger::Log(DebugState &state, DisassemblyInfo &disassemblyInfo, Opera const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) { + int startPos; + _executionTrace.clear(); - auto lock = _lock.AcquireSafe(); - lineCount = std::min(lineCount, _logCount); - int startPos = _currentPos + ExecutionLogSize - lineCount; - bool firstLine = true; + { + auto lock = _lock.AcquireSafe(); + lineCount = std::min(lineCount, _logCount); + memcpy(_cpuStateCacheCopy, _cpuStateCache, sizeof(_cpuStateCache)); + memcpy(_ppuStateCacheCopy, _ppuStateCache, sizeof(_ppuStateCache)); + memcpy(_disassemblyCacheCopy, _disassemblyCache, sizeof(_disassemblyCache)); + startPos = _currentPos + ExecutionLogSize - lineCount; + } + for(int i = 0; i < (int)lineCount; i++) { int index = (startPos + i) % ExecutionLogSize; - GetTraceRow(_executionTrace, _cpuStateCache[index], _ppuStateCache[index], _disassemblyCache[index], firstLine); - firstLine = false; + GetTraceRow(_executionTrace, _cpuStateCacheCopy[index], _ppuStateCacheCopy[index], _disassemblyCacheCopy[index], true); } + return _executionTrace.c_str(); } \ No newline at end of file diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index 1316ed22..f5030e90 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -41,7 +41,6 @@ private: string _outputFilepath; string _outputBuffer; ofstream _outputFile; - bool _firstLine; shared_ptr _memoryManager; shared_ptr _labelManager; @@ -60,6 +59,10 @@ private: PPUDebugState _ppuStateCache[ExecutionLogSize] = {}; DisassemblyInfo _disassemblyCache[ExecutionLogSize]; + State _cpuStateCacheCopy[ExecutionLogSize] = {}; + PPUDebugState _ppuStateCacheCopy[ExecutionLogSize] = {}; + DisassemblyInfo _disassemblyCacheCopy[ExecutionLogSize]; + SimpleLock _lock; string _executionTrace; @@ -67,7 +70,7 @@ private: void AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state); bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo); - void GetTraceRow(string &output, State &cpuState, PPUDebugState &ppuState, DisassemblyInfo &disassemblyInfo, bool firstLine); + void GetTraceRow(string &output, State &cpuState, PPUDebugState &ppuState, DisassemblyInfo &disassemblyInfo, bool forceByteCode); public: TraceLogger(Debugger* debugger, shared_ptr memoryManager, shared_ptr labelManager); diff --git a/GUI.NET/Config/DebugInfo.cs b/GUI.NET/Config/DebugInfo.cs index 65d87725..938dd08c 100644 --- a/GUI.NET/Config/DebugInfo.cs +++ b/GUI.NET/Config/DebugInfo.cs @@ -157,6 +157,7 @@ namespace Mesen.GUI.Config public bool TraceAutoRefresh = true; public int TraceLineCount = 1000; public bool TraceIndentCode = false; + public Size TraceLoggerSize = new Size(0, 0); public DebugInfo() { diff --git a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs index 455b17cb..9a87c8b5 100644 --- a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs @@ -104,10 +104,16 @@ namespace Mesen.GUI.Debugger this.vScrollBar.Value = this.ctrlTextbox.ScrollPosition; this.hScrollBar.Value = this.ctrlTextbox.HorizontalScrollPosition; UpdateHorizontalScrollbar(); + UpdateVerticalScrollbar(); ScrollPositionChanged?.Invoke(null, null); } + private void UpdateVerticalScrollbar() + { + this.vScrollBar.Maximum = Math.Max(0, this.ctrlTextbox.LineCount + this.vScrollBar.LargeChange - this.ctrlTextbox.GetNumberVisibleLines() + 1); + } + private void UpdateHorizontalScrollbar() { this.hScrollBar.Visible = this.ctrlTextbox.HorizontalScrollWidth > 0; @@ -187,7 +193,7 @@ namespace Mesen.GUI.Debugger case Keys.Down: case Keys.Right: - this.ctrlTextbox.SelectionStart++; + this.ctrlTextbox.SelectionStart = this.ctrlTextbox.SelectedLine + 1; this.ctrlTextbox.SelectionLength = 0; return true; @@ -198,10 +204,23 @@ namespace Mesen.GUI.Debugger case Keys.Up: case Keys.Left: - this.ctrlTextbox.SelectionStart--; + this.ctrlTextbox.SelectionStart = this.ctrlTextbox.SelectedLine - 1; this.ctrlTextbox.SelectionLength = 0; return true; + case Keys.Home | Keys.Shift: + this.ctrlTextbox.MoveSelectionUp(this.ctrlTextbox.LineCount); + break; + + case Keys.End | Keys.Shift: + this.ctrlTextbox.MoveSelectionDown(this.ctrlTextbox.LineCount); + break; + + case Keys.A | Keys.Control: + this.ctrlTextbox.SelectionStart = 0; + this.ctrlTextbox.SelectionLength = this.ctrlTextbox.LineCount; + break; + case Keys.Home: this.ctrlTextbox.SelectionStart = 0; this.ctrlTextbox.SelectionLength = 0; @@ -276,7 +295,7 @@ namespace Mesen.GUI.Debugger set { this.ctrlTextbox.TextLines = value; - this.vScrollBar.Maximum = this.ctrlTextbox.LineCount + this.vScrollBar.LargeChange; + UpdateVerticalScrollbar(); UpdateHorizontalScrollbar(); } } @@ -337,6 +356,10 @@ namespace Mesen.GUI.Debugger set { this.ctrlTextbox.ShowSingleLineLineNumberNotes = value; } } + public int LineCount { get { return this.ctrlTextbox.LineCount; } } + public int SelectionStart { get { return this.ctrlTextbox.SelectionStart; } } + public int SelectionLength { get { return this.ctrlTextbox.SelectionLength; } } + public string Header { set diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs index 91cf2aa9..2f872063 100644 --- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs @@ -39,6 +39,7 @@ namespace Mesen.GUI.Debugger public partial class ctrlTextbox : Control { public event EventHandler ScrollPositionChanged; + private bool _disableScrollPositionChangedEvent; private const float HorizontalScrollFactor = 8; private const int CommentSpacingCharCount = 25; @@ -115,12 +116,16 @@ namespace Mesen.GUI.Debugger } } + //Cache Font.Height value because accessing it is slow + private int FontHeight { get; set; } + public override Font Font { get { return base.Font; } set { base.Font = value; + this.FontHeight = value.Height; _noteFont = new Font(value.FontFamily, value.Size * 0.75f); UpdateHorizontalScrollWidth(); } @@ -538,7 +543,7 @@ namespace Mesen.GUI.Debugger } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - private int SelectedLine + public int SelectedLine { get { return this._selectedLine; } set @@ -556,13 +561,22 @@ namespace Mesen.GUI.Debugger public void MoveSelectionDown(int lines = 1) { + _disableScrollPositionChangedEvent = true; while(lines > 0) { bool singleLineSelection = this.SelectionLength == 0; if(singleLineSelection) { + if(this.SelectionStart + this.SelectionLength >= this._contents.Length - 1) { + //End of document reached + break; + } this.SelectedLine = this.SelectionStart + 1; this.SelectionLength++; } else if(this.SelectionStart + this.SelectionLength == this.SelectedLine) { + if(this.SelectionStart + this.SelectionLength >= this._contents.Length - 1) { + //End of document reached + break; + } this.SelectedLine++; this.SelectionLength++; } else { @@ -572,18 +586,29 @@ namespace Mesen.GUI.Debugger } lines--; } + _disableScrollPositionChangedEvent = false; + ScrollPositionChanged?.Invoke(this, null); } public void MoveSelectionUp(int lines = 1) { + _disableScrollPositionChangedEvent = true; while(lines > 0) { bool singleLineSelection = this.SelectionLength == 0; if(singleLineSelection) { + if(this.SelectionStart == 0) { + //Top of document reached + break; + } this.SelectionStart--; this.SelectedLine = this.SelectionStart; this.SelectionLength++; } else if(this.SelectionStart == this.SelectedLine) { + if(this.SelectionStart == 0) { + //Top of document reached + break; + } this.SelectionStart--; this.SelectedLine--; this.SelectionLength++; @@ -593,6 +618,8 @@ namespace Mesen.GUI.Debugger } lines--; } + _disableScrollPositionChangedEvent = false; + ScrollPositionChanged?.Invoke(this, null); } public int CurrentLine @@ -612,9 +639,9 @@ namespace Mesen.GUI.Debugger get { return _scrollPosition; } set { - value = Math.Max(0, Math.Min(value, this._contents.Length-1)); + value = Math.Max(0, Math.Min(value, this._contents.Length-this.GetNumberVisibleLines())); _scrollPosition = value; - if(this.ScrollPositionChanged != null) { + if(!_disableScrollPositionChangedEvent && this.ScrollPositionChanged != null) { ScrollPositionChanged(this, null); } this.Invalidate(); @@ -629,7 +656,7 @@ namespace Mesen.GUI.Debugger set { _horizontalScrollPosition = value; - if(this.ScrollPositionChanged != null) { + if(!_disableScrollPositionChangedEvent && this.ScrollPositionChanged != null) { ScrollPositionChanged(this, null); } this.Invalidate(); @@ -651,6 +678,7 @@ namespace Mesen.GUI.Debugger protected override void OnResize(EventArgs e) { base.OnResize(e); + this.ScrollPosition = this.ScrollPosition; UpdateHorizontalScrollWidth(); ScrollPositionChanged?.Invoke(this, e); } @@ -672,9 +700,9 @@ namespace Mesen.GUI.Debugger get { if(this.ShowLineNumberNotes && !this.ShowSingleLineLineNumberNotes || this.ShowContentNotes && !this.ShowSingleContentLineNotes) { - return (int)(this.Font.Height * 1.60); + return (int)(this.FontHeight * 1.60); } else { - return this.Font.Height - 1; + return this.FontHeight - 1; } } } diff --git a/GUI.NET/Debugger/frmDebugger.Designer.cs b/GUI.NET/Debugger/frmDebugger.Designer.cs index b9d52bbc..17444ce9 100644 --- a/GUI.NET/Debugger/frmDebugger.Designer.cs +++ b/GUI.NET/Debugger/frmDebugger.Designer.cs @@ -185,14 +185,14 @@ namespace Mesen.GUI.Debugger // splitContainer.Panel1 // this.splitContainer.Panel1.Controls.Add(this.ctrlSplitContainerTop); - this.splitContainer.Panel1MinSize = 390; + this.splitContainer.Panel1MinSize = 400; // // splitContainer.Panel2 // this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10); this.splitContainer.Panel2MinSize = 100; this.splitContainer.Size = new System.Drawing.Size(1172, 573); - this.splitContainer.SplitterDistance = 453; + this.splitContainer.SplitterDistance = 450; this.splitContainer.SplitterWidth = 7; this.splitContainer.TabIndex = 1; this.splitContainer.TabStop = false; @@ -215,8 +215,8 @@ namespace Mesen.GUI.Debugger // this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists); this.ctrlSplitContainerTop.Panel2MinSize = 150; - this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1172, 453); - this.ctrlSplitContainerTop.SplitterDistance = 932; + this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1172, 450); + this.ctrlSplitContainerTop.SplitterDistance = 929; this.ctrlSplitContainerTop.SplitterWidth = 7; this.ctrlSplitContainerTop.TabIndex = 3; this.ctrlSplitContainerTop.PanelCollapsed += new System.EventHandler(this.ctrlSplitContainerTop_PanelCollapsed); @@ -237,7 +237,7 @@ namespace Mesen.GUI.Debugger this.tlpTop.Name = "tlpTop"; this.tlpTop.RowCount = 1; this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpTop.Size = new System.Drawing.Size(932, 453); + this.tlpTop.Size = new System.Drawing.Size(929, 450); this.tlpTop.TabIndex = 2; // // ctrlDebuggerCode @@ -246,7 +246,7 @@ namespace Mesen.GUI.Debugger this.ctrlDebuggerCode.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlDebuggerCode.Location = new System.Drawing.Point(3, 3); this.ctrlDebuggerCode.Name = "ctrlDebuggerCode"; - this.ctrlDebuggerCode.Size = new System.Drawing.Size(468, 447); + this.ctrlDebuggerCode.Size = new System.Drawing.Size(465, 444); this.ctrlDebuggerCode.TabIndex = 2; this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); this.ctrlDebuggerCode.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement); @@ -255,10 +255,10 @@ namespace Mesen.GUI.Debugger // ctrlConsoleStatus // this.ctrlConsoleStatus.Dock = System.Windows.Forms.DockStyle.Fill; - this.ctrlConsoleStatus.Location = new System.Drawing.Point(474, 0); + this.ctrlConsoleStatus.Location = new System.Drawing.Point(471, 0); this.ctrlConsoleStatus.Margin = new System.Windows.Forms.Padding(0); this.ctrlConsoleStatus.Name = "ctrlConsoleStatus"; - this.ctrlConsoleStatus.Size = new System.Drawing.Size(458, 453); + this.ctrlConsoleStatus.Size = new System.Drawing.Size(458, 450); this.ctrlConsoleStatus.TabIndex = 3; this.ctrlConsoleStatus.OnGotoLocation += new System.EventHandler(this.ctrlConsoleStatus_OnGotoLocation); // @@ -266,9 +266,9 @@ namespace Mesen.GUI.Debugger // this.ctrlDebuggerCodeSplit.Code = null; this.ctrlDebuggerCodeSplit.Dock = System.Windows.Forms.DockStyle.Fill; - this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(477, 3); + this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(474, 3); this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit"; - this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 447); + this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 444); this.ctrlDebuggerCodeSplit.TabIndex = 4; this.ctrlDebuggerCodeSplit.Visible = false; this.ctrlDebuggerCodeSplit.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); @@ -288,16 +288,16 @@ namespace Mesen.GUI.Debugger this.tlpFunctionLabelLists.RowCount = 2; this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tlpFunctionLabelLists.Size = new System.Drawing.Size(233, 453); + this.tlpFunctionLabelLists.Size = new System.Drawing.Size(236, 450); this.tlpFunctionLabelLists.TabIndex = 5; // // grpLabels // this.grpLabels.Controls.Add(this.ctrlLabelList); this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill; - this.grpLabels.Location = new System.Drawing.Point(3, 229); + this.grpLabels.Location = new System.Drawing.Point(3, 228); this.grpLabels.Name = "grpLabels"; - this.grpLabels.Size = new System.Drawing.Size(227, 221); + this.grpLabels.Size = new System.Drawing.Size(230, 219); this.grpLabels.TabIndex = 6; this.grpLabels.TabStop = false; this.grpLabels.Text = "Labels"; @@ -307,7 +307,7 @@ namespace Mesen.GUI.Debugger this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlLabelList.Location = new System.Drawing.Point(3, 16); this.ctrlLabelList.Name = "ctrlLabelList"; - this.ctrlLabelList.Size = new System.Drawing.Size(221, 202); + this.ctrlLabelList.Size = new System.Drawing.Size(224, 200); this.ctrlLabelList.TabIndex = 0; this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence); this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected); @@ -318,7 +318,7 @@ namespace Mesen.GUI.Debugger this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill; this.grpFunctions.Location = new System.Drawing.Point(3, 3); this.grpFunctions.Name = "grpFunctions"; - this.grpFunctions.Size = new System.Drawing.Size(227, 220); + this.grpFunctions.Size = new System.Drawing.Size(230, 219); this.grpFunctions.TabIndex = 5; this.grpFunctions.TabStop = false; this.grpFunctions.Text = "Functions"; @@ -328,7 +328,7 @@ namespace Mesen.GUI.Debugger this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16); this.ctrlFunctionList.Name = "ctrlFunctionList"; - this.ctrlFunctionList.Size = new System.Drawing.Size(221, 201); + this.ctrlFunctionList.Size = new System.Drawing.Size(224, 200); this.ctrlFunctionList.TabIndex = 0; this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence); this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected); @@ -349,7 +349,7 @@ namespace Mesen.GUI.Debugger this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel10.Size = new System.Drawing.Size(1172, 113); + this.tableLayoutPanel10.Size = new System.Drawing.Size(1172, 116); this.tableLayoutPanel10.TabIndex = 0; // // grpWatch @@ -359,7 +359,7 @@ namespace Mesen.GUI.Debugger this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.grpWatch.Location = new System.Drawing.Point(3, 3); this.grpWatch.Name = "grpWatch"; - this.grpWatch.Size = new System.Drawing.Size(384, 107); + this.grpWatch.Size = new System.Drawing.Size(384, 110); this.grpWatch.TabIndex = 2; this.grpWatch.TabStop = false; this.grpWatch.Text = "Watch"; @@ -379,7 +379,7 @@ namespace Mesen.GUI.Debugger this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlWatch.Location = new System.Drawing.Point(3, 16); this.ctrlWatch.Name = "ctrlWatch"; - this.ctrlWatch.Size = new System.Drawing.Size(378, 88); + this.ctrlWatch.Size = new System.Drawing.Size(378, 91); this.ctrlWatch.TabIndex = 0; // // grpBreakpoints @@ -388,7 +388,7 @@ namespace Mesen.GUI.Debugger this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.grpBreakpoints.Location = new System.Drawing.Point(393, 3); this.grpBreakpoints.Name = "grpBreakpoints"; - this.grpBreakpoints.Size = new System.Drawing.Size(384, 107); + this.grpBreakpoints.Size = new System.Drawing.Size(384, 110); this.grpBreakpoints.TabIndex = 3; this.grpBreakpoints.TabStop = false; this.grpBreakpoints.Text = "Breakpoints"; @@ -398,7 +398,7 @@ namespace Mesen.GUI.Debugger this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16); this.ctrlBreakpoints.Name = "ctrlBreakpoints"; - this.ctrlBreakpoints.Size = new System.Drawing.Size(378, 88); + this.ctrlBreakpoints.Size = new System.Drawing.Size(378, 91); this.ctrlBreakpoints.TabIndex = 0; this.ctrlBreakpoints.BreakpointNavigation += new System.EventHandler(this.ctrlBreakpoints_BreakpointNavigation); // @@ -408,7 +408,7 @@ namespace Mesen.GUI.Debugger this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill; this.grpCallstack.Location = new System.Drawing.Point(783, 3); this.grpCallstack.Name = "grpCallstack"; - this.grpCallstack.Size = new System.Drawing.Size(386, 107); + this.grpCallstack.Size = new System.Drawing.Size(386, 110); this.grpCallstack.TabIndex = 4; this.grpCallstack.TabStop = false; this.grpCallstack.Text = "Call Stack"; @@ -418,7 +418,7 @@ namespace Mesen.GUI.Debugger this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlCallstack.Location = new System.Drawing.Point(3, 16); this.ctrlCallstack.Name = "ctrlCallstack"; - this.ctrlCallstack.Size = new System.Drawing.Size(380, 88); + this.ctrlCallstack.Size = new System.Drawing.Size(380, 91); this.ctrlCallstack.TabIndex = 0; this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected); // diff --git a/GUI.NET/Debugger/frmDebugger.cs b/GUI.NET/Debugger/frmDebugger.cs index 7fa0cf2d..9f7548d7 100644 --- a/GUI.NET/Debugger/frmDebugger.cs +++ b/GUI.NET/Debugger/frmDebugger.cs @@ -560,8 +560,8 @@ namespace Mesen.GUI.Debugger InteropEmu.DebugRelease(); - ConfigManager.Config.DebugInfo.WindowWidth = this.Width; - ConfigManager.Config.DebugInfo.WindowHeight = this.Height; + ConfigManager.Config.DebugInfo.WindowWidth = this.WindowState == FormWindowState.Maximized ? this.RestoreBounds.Width : this.Width; + ConfigManager.Config.DebugInfo.WindowHeight = this.WindowState == FormWindowState.Maximized ? this.RestoreBounds.Height : this.Height; ConfigManager.Config.DebugInfo.TopPanelHeight = this.splitContainer.GetSplitterDistance(); ConfigManager.Config.DebugInfo.LeftPanelWidth = this.ctrlSplitContainerTop.GetSplitterDistance(); ConfigManager.ApplyChanges(); diff --git a/GUI.NET/Debugger/frmTraceLogger.Designer.cs b/GUI.NET/Debugger/frmTraceLogger.Designer.cs index f26f9376..9bb03f00 100644 --- a/GUI.NET/Debugger/frmTraceLogger.Designer.cs +++ b/GUI.NET/Debugger/frmTraceLogger.Designer.cs @@ -46,11 +46,13 @@ this.chkShowEffectiveAddresses = new System.Windows.Forms.CheckBox(); this.chkShowExtraInfo = new System.Windows.Forms.CheckBox(); this.cboStatusFlagFormat = new System.Windows.Forms.ComboBox(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.picHelp = new System.Windows.Forms.PictureBox(); + this.picExpressionWarning = new System.Windows.Forms.PictureBox(); this.lblCondition = new System.Windows.Forms.Label(); this.txtCondition = new System.Windows.Forms.TextBox(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); this.grpExecutionLog = new System.Windows.Forms.GroupBox(); - this.txtTraceLog = new System.Windows.Forms.TextBox(); this.tmrUpdateLog = new System.Windows.Forms.Timer(this.components); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.showToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -62,18 +64,16 @@ this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem(); - this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); - this.picExpressionWarning = new System.Windows.Forms.PictureBox(); - this.picHelp = new System.Windows.Forms.PictureBox(); + this.txtTraceLog = new Mesen.GUI.Debugger.ctrlScrollableTextbox(); this.tableLayoutPanel1.SuspendLayout(); this.grpLogOptions.SuspendLayout(); this.tableLayoutPanel2.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picHelp)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).BeginInit(); this.tableLayoutPanel3.SuspendLayout(); this.grpExecutionLog.SuspendLayout(); this.menuStrip1.SuspendLayout(); - this.tableLayoutPanel4.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.picHelp)).BeginInit(); this.SuspendLayout(); // // tableLayoutPanel1 @@ -310,6 +310,48 @@ this.cboStatusFlagFormat.Size = new System.Drawing.Size(121, 21); this.cboStatusFlagFormat.TabIndex = 13; // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 4; + this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel4, 4); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.Controls.Add(this.picHelp, 3, 0); + this.tableLayoutPanel4.Controls.Add(this.picExpressionWarning, 2, 0); + this.tableLayoutPanel4.Controls.Add(this.lblCondition, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.txtCondition, 1, 0); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 73); + this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 1; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(769, 25); + this.tableLayoutPanel4.TabIndex = 16; + // + // picHelp + // + this.picHelp.Image = global::Mesen.GUI.Properties.Resources.Help; + this.picHelp.Location = new System.Drawing.Point(748, 5); + this.picHelp.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3); + this.picHelp.Name = "picHelp"; + this.picHelp.Size = new System.Drawing.Size(18, 17); + this.picHelp.TabIndex = 17; + this.picHelp.TabStop = false; + // + // picExpressionWarning + // + this.picExpressionWarning.Image = global::Mesen.GUI.Properties.Resources.Warning; + this.picExpressionWarning.Location = new System.Drawing.Point(724, 5); + this.picExpressionWarning.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3); + this.picExpressionWarning.Name = "picExpressionWarning"; + this.picExpressionWarning.Size = new System.Drawing.Size(18, 17); + this.picExpressionWarning.TabIndex = 16; + this.picExpressionWarning.TabStop = false; + this.picExpressionWarning.Visible = false; + // // lblCondition // this.lblCondition.Anchor = System.Windows.Forms.AnchorStyles.Left; @@ -355,18 +397,6 @@ this.grpExecutionLog.TabStop = false; this.grpExecutionLog.Text = "Execution Log"; // - // txtTraceLog - // - this.txtTraceLog.BackColor = System.Drawing.SystemColors.Window; - this.txtTraceLog.Dock = System.Windows.Forms.DockStyle.Fill; - this.txtTraceLog.Location = new System.Drawing.Point(3, 16); - this.txtTraceLog.Multiline = true; - this.txtTraceLog.Name = "txtTraceLog"; - this.txtTraceLog.ReadOnly = true; - this.txtTraceLog.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.txtTraceLog.Size = new System.Drawing.Size(775, 246); - this.txtTraceLog.TabIndex = 1; - // // tmrUpdateLog // this.tmrUpdateLog.Interval = 150; @@ -457,47 +487,19 @@ this.mnuRefresh.Text = "Refresh"; this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click); // - // tableLayoutPanel4 + // txtTraceLog // - this.tableLayoutPanel4.ColumnCount = 4; - this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel4, 4); - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel4.Controls.Add(this.picHelp, 3, 0); - this.tableLayoutPanel4.Controls.Add(this.picExpressionWarning, 2, 0); - this.tableLayoutPanel4.Controls.Add(this.lblCondition, 0, 0); - this.tableLayoutPanel4.Controls.Add(this.txtCondition, 1, 0); - this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 73); - this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); - this.tableLayoutPanel4.Name = "tableLayoutPanel4"; - this.tableLayoutPanel4.RowCount = 1; - this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel4.Size = new System.Drawing.Size(769, 25); - this.tableLayoutPanel4.TabIndex = 16; - // - // picExpressionWarning - // - this.picExpressionWarning.Image = global::Mesen.GUI.Properties.Resources.Warning; - this.picExpressionWarning.Location = new System.Drawing.Point(724, 5); - this.picExpressionWarning.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3); - this.picExpressionWarning.Name = "picExpressionWarning"; - this.picExpressionWarning.Size = new System.Drawing.Size(18, 17); - this.picExpressionWarning.TabIndex = 16; - this.picExpressionWarning.TabStop = false; - this.picExpressionWarning.Visible = false; - // - // picHelp - // - this.picHelp.Image = global::Mesen.GUI.Properties.Resources.Help; - this.picHelp.Location = new System.Drawing.Point(748, 5); - this.picHelp.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3); - this.picHelp.Name = "picHelp"; - this.picHelp.Size = new System.Drawing.Size(18, 17); - this.picHelp.TabIndex = 17; - this.picHelp.TabStop = false; + this.txtTraceLog.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtTraceLog.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTraceLog.FontSize = 13F; + this.txtTraceLog.Location = new System.Drawing.Point(3, 16); + this.txtTraceLog.Name = "txtTraceLog"; + this.txtTraceLog.ShowContentNotes = false; + this.txtTraceLog.ShowLineNumberNotes = false; + this.txtTraceLog.ShowSingleContentLineNotes = true; + this.txtTraceLog.ShowSingleLineLineNumberNotes = false; + this.txtTraceLog.Size = new System.Drawing.Size(775, 246); + this.txtTraceLog.TabIndex = 0; // // frmTraceLogger // @@ -514,15 +516,14 @@ this.grpLogOptions.ResumeLayout(false); this.tableLayoutPanel2.ResumeLayout(false); this.tableLayoutPanel2.PerformLayout(); - this.tableLayoutPanel3.ResumeLayout(false); - this.grpExecutionLog.ResumeLayout(false); - this.grpExecutionLog.PerformLayout(); - this.menuStrip1.ResumeLayout(false); - this.menuStrip1.PerformLayout(); this.tableLayoutPanel4.ResumeLayout(false); this.tableLayoutPanel4.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.picHelp)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).EndInit(); + this.tableLayoutPanel3.ResumeLayout(false); + this.grpExecutionLog.ResumeLayout(false); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -546,7 +547,6 @@ private System.Windows.Forms.Button btnOpenTrace; private System.Windows.Forms.CheckBox chkShowEffectiveAddresses; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; - private System.Windows.Forms.TextBox txtTraceLog; private System.Windows.Forms.Timer tmrUpdateLog; private System.Windows.Forms.GroupBox grpExecutionLog; private System.Windows.Forms.MenuStrip menuStrip1; @@ -567,5 +567,6 @@ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; private System.Windows.Forms.PictureBox picExpressionWarning; private System.Windows.Forms.PictureBox picHelp; + private ctrlScrollableTextbox txtTraceLog; } } \ No newline at end of file diff --git a/GUI.NET/Debugger/frmTraceLogger.cs b/GUI.NET/Debugger/frmTraceLogger.cs index fb4be0d9..32a55b74 100644 --- a/GUI.NET/Debugger/frmTraceLogger.cs +++ b/GUI.NET/Debugger/frmTraceLogger.cs @@ -20,12 +20,19 @@ namespace Mesen.GUI.Debugger private bool _loggingEnabled = false; private string _lastFilename; private EntityBinder _entityBinder = new EntityBinder(); + private int _previousCycleCount; + private string _previousTrace; + private bool _refreshRunning; public frmTraceLogger() { InitializeComponent(); DebugInfo debugInfo = ConfigManager.Config.DebugInfo; + if(!debugInfo.TraceLoggerSize.IsEmpty) { + this.Size = debugInfo.TraceLoggerSize; + } + mnuAutoRefresh.Checked = debugInfo.TraceAutoRefresh; _lineCount = debugInfo.TraceLineCount; @@ -44,8 +51,9 @@ namespace Mesen.GUI.Debugger _entityBinder.UpdateUI(); UpdateMenu(); - txtTraceLog.Font = new Font(BaseControl.MonospaceFontFamily, 10); + txtTraceLog.FontSize = 10; tmrUpdateLog.Start(); + RefreshLog(true); this.toolTip.SetToolTip(this.picExpressionWarning, "Condition contains invalid syntax or symbols."); this.toolTip.SetToolTip(this.picHelp, "When a condition is given, instructions will only be logged by the trace logger if the condition returns a value not equal to 0 or false." + Environment.NewLine + Environment.NewLine + frmBreakpoint.GetConditionTooltip(false)); @@ -59,6 +67,7 @@ namespace Mesen.GUI.Debugger debugInfo.TraceAutoRefresh = mnuAutoRefresh.Checked; debugInfo.TraceLineCount = _lineCount; debugInfo.TraceIndentCode = chkIndentCode.Checked; + debugInfo.TraceLoggerSize = this.WindowState == FormWindowState.Maximized ? this.RestoreBounds.Size : this.Size; _entityBinder.Entity = debugInfo.TraceLoggerOptions; _entityBinder.UpdateObject(); debugInfo.TraceLoggerOptions = (TraceLoggerOptions)_entityBinder.Entity; @@ -115,16 +124,82 @@ namespace Mesen.GUI.Debugger } catch { } } - private void RefreshLog() - { - SetOptions(); - string newTrace = InteropEmu.DebugGetExecutionTrace((UInt32)_lineCount).Replace("\n", Environment.NewLine); - if(newTrace != txtTraceLog.Text) { - txtTraceLog.Text = newTrace; - txtTraceLog.SelectionStart = txtTraceLog.TextLength; - txtTraceLog.ScrollToCaret(); + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + switch(keyData) { + case Keys.C | Keys.Control: + if(_previousTrace != null) { + string[] lines = _previousTrace.Split('\n'); + StringBuilder sb = new StringBuilder(); + for(int i = txtTraceLog.SelectionStart, end = txtTraceLog.SelectionStart + txtTraceLog.SelectionLength; i <= end; i++) { + sb.AppendLine(lines[i]); + } + Clipboard.SetText(sb.ToString()); + } + return true; } + return base.ProcessCmdKey(ref msg, keyData); + } + + private void RefreshLog(bool scrollToBottom) + { + if(_refreshRunning) { + return; + } + + _refreshRunning = true; + SetOptions(); + Task.Run(() => { + //Update trace log in another thread for performance + DebugState state = new DebugState(); + InteropEmu.DebugGetState(ref state); + if(_previousCycleCount != state.CPU.CycleCount) { + string newTrace = InteropEmu.DebugGetExecutionTrace((UInt32)_lineCount); + _previousCycleCount = state.CPU.CycleCount; + _previousTrace = newTrace; + + int index = 0; + string line = null; + Func readLine = () => { + if(index < newTrace.Length) { + int endOfLineIndex = newTrace.IndexOf('\n', index); + line = newTrace.Substring(index, endOfLineIndex - index); + index = endOfLineIndex + 1; + return true; + } else { + return false; + } + }; + + List programCounter = new List(30000); + List byteCode = new List(30000); + List lineContent = new List(30000); + List indent = new List(30000); + + char[] splitter = new char[] { ' ' }; + while(readLine()) { + programCounter.Add(Int32.Parse(line.Substring(0, 4), System.Globalization.NumberStyles.HexNumber)); + byteCode.Add(line.Substring(6, 11)); + lineContent.Add(line.Substring(19)); + indent.Add(6); + } + this.BeginInvoke((Action)(() => { + txtTraceLog.ShowContentNotes = chkShowByteCode.Checked; + txtTraceLog.ShowSingleContentLineNotes = chkShowByteCode.Checked; + + txtTraceLog.LineIndentations = indent.ToArray(); + txtTraceLog.TextLines = lineContent.ToArray(); + txtTraceLog.LineNumbers = programCounter.ToArray(); + txtTraceLog.TextLineNotes = byteCode.ToArray(); + + if(scrollToBottom) { + txtTraceLog.ScrollToLineIndex(txtTraceLog.LineCount - 1); + } + })); + } + _refreshRunning = false; + }); } private void UpdateMenu() @@ -134,15 +209,11 @@ namespace Mesen.GUI.Debugger mnu1000Lines.Checked = _lineCount == 1000; mnu100Lines.Checked = _lineCount == 100; - if(_lineCount >= 10000) { - mnuAutoRefresh.Checked = false; - } else if(_lineCount == 1000) { + if(_lineCount >= 1000) { tmrUpdateLog.Interval = 250; } else { tmrUpdateLog.Interval = 150; } - - mnuAutoRefresh.Enabled = _lineCount < 10000; } private void tmrUpdateLog_Tick(object sender, EventArgs e) @@ -156,7 +227,7 @@ namespace Mesen.GUI.Debugger } if(mnuAutoRefresh.Checked) { - RefreshLog(); + RefreshLog(false); } } @@ -186,7 +257,7 @@ namespace Mesen.GUI.Debugger private void mnuRefresh_Click(object sender, EventArgs e) { - RefreshLog(); + RefreshLog(false); } } }