wxgui: Optimizations and improvements to the console logger's threading model.

git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1535 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-07-17 03:43:45 +00:00
parent 539a35fe80
commit ccdb5d84b9
7 changed files with 206 additions and 93 deletions

View File

@ -29,6 +29,9 @@ namespace Threading
///////////////////////////////////////////////////////////////
// Define some useful object handles - wait events, mutexes.
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
#if 0
struct WaitEvent
{
pthread_cond_t cond;
@ -40,6 +43,7 @@ namespace Threading
void Set();
void Wait();
};
#endif
struct Semaphore
{

View File

@ -49,37 +49,19 @@ namespace Console
return false;
}
// ------------------------------------------------------------------------
bool __fastcall WriteLn( const char* fmt )
{
Write( fmt );
Newline();
return false;
}
bool __fastcall WriteLn( Colors color, const char* fmt )
{
SetColor( color );
Write( fmt );
Newline();
WriteLn( fmt );
ClearColor();
return false;
}
// ------------------------------------------------------------------------
bool __fastcall WriteLn( const wxString& fmt )
{
Write( fmt );
Newline();
return false;
}
bool __fastcall WriteLn( Colors color, const wxString& fmt )
{
SetColor( color );
Write( fmt );
Newline();
WriteLn( fmt );
ClearColor();
return false;
}
@ -94,8 +76,10 @@ namespace Console
__forceinline void __fastcall _WriteLn( const char* fmt, va_list args )
{
_Write( fmt, args );
Newline();
ScopedLock locker( m_writelock );
vssprintf( m_format_buffer, fmt, args );
m_format_buffer += "\n";
Write( m_format_buffer.c_str() );
}
__forceinline void __fastcall _WriteLn( Colors color, const char* fmt, va_list args )

View File

@ -25,6 +25,8 @@
#include "System.h"
using namespace Threading;
class MainEmuFrame;
class IniInterface;
@ -32,7 +34,7 @@ extern wxFileHistory* g_RecentIsoList;
class LogWriteEvent;
DECLARE_EVENT_TYPE(wxEVT_DockConsole, -1)
DECLARE_EVENT_TYPE(wxEVT_DockConsole, -1);
//////////////////////////////////////////////////////////////////////////////////////////
//
@ -66,7 +68,15 @@ public:
ConsoleLogFrame(MainEmuFrame *pParent, const wxString& szTitle);
virtual ~ConsoleLogFrame();
virtual void OnCloseWindow(wxCloseEvent& event);
virtual void Write( const wxString& text );
virtual void SetColor( Console::Colors color );
virtual void ClearColor();
virtual void DockedMove();
void Write( Console::Colors color, const wxString& text );
void Newline();
void CountMessage();
void DoMessage();
protected:
@ -75,6 +85,7 @@ protected:
virtual void OnClose(wxMenuEvent& event);
virtual void OnSave (wxMenuEvent& event);
virtual void OnClear(wxMenuEvent& event);
virtual void OnCloseWindow(wxCloseEvent& event);
void OnWrite( wxCommandEvent& event );
void OnNewline( wxCommandEvent& event );
@ -86,10 +97,6 @@ protected:
void OnMoveAround( wxMoveEvent& evt );
void OnResize( wxSizeEvent& evt );
virtual void Write( const wxString& text );
void SetColor( Console::Colors color );
void ClearColor();
};
@ -173,6 +180,22 @@ public:
return *m_MainFrame;
}
ConsoleLogFrame* GetProgramLog()
{
return m_ProgramLogBox;
}
ConsoleLogFrame* GetConsoleLog()
{
return m_Ps2ConLogBox;
}
void ProgramLog_CountMsg()
{
if( m_ProgramLogBox == NULL ) return;
m_ProgramLogBox->CountMessage();
}
void ProgramLog_PostEvent( wxEvent& evt )
{
if( m_ProgramLogBox == NULL ) return;

View File

@ -90,16 +90,20 @@ ConsoleLogFrame::ColorArray::ColorArray() :
m_table( 8 )
{
// Standard R, G, B format:
new (&m_table[Color_Black]) wxTextAttr( wxColor( 0, 0, 0 ) );
new (&m_table[Color_Red]) wxTextAttr( wxColor( 128, 0, 0 ) );
new (&m_table[Color_Green]) wxTextAttr( wxColor( 0, 128, 0 ) );
new (&m_table[Color_Blue]) wxTextAttr( wxColor( 0, 0, 128 ) );
new (&m_table[Color_Yellow])wxTextAttr( wxColor( 180, 180, 0 ) );
new (&m_table[Color_Cyan]) wxTextAttr( wxColor( 0, 160, 160 ) );
new (&m_table[Color_Magenta])wxTextAttr( wxColor( 160, 0, 160 ) );
new (&m_table[Color_White]) wxTextAttr( wxColor( 160, 160, 160 ) );
new (&m_table[Color_Black]) wxTextAttr( wxColor( 0, 0, 0 ) );
new (&m_table[Color_Red]) wxTextAttr( wxColor( 128, 0, 0 ) );
new (&m_table[Color_Green]) wxTextAttr( wxColor( 0, 128, 0 ) );
new (&m_table[Color_Blue]) wxTextAttr( wxColor( 0, 0, 128 ) );
new (&m_table[Color_Yellow]) wxTextAttr( wxColor( 180, 180, 0 ) );
new (&m_table[Color_Cyan]) wxTextAttr( wxColor( 0, 160, 160 ) );
new (&m_table[Color_Magenta]) wxTextAttr( wxColor( 160, 0, 160 ) );
new (&m_table[Color_White]) wxTextAttr( wxColor( 160, 160, 160 ) );
}
// ------------------------------------------------------------------------
// Threading: this function may employ the use of GDI objects in Win32, which means it's
// not safe to be clled from anything but the main gUI thread.
//
void ConsoleLogFrame::ColorArray::SetFont( const wxFont& font )
{
for( int i=0; i<8; ++i )
@ -170,7 +174,7 @@ void ConsoleLogFrame::OnMoveAround( wxMoveEvent& evt )
wxRect snapzone( topright - wxSize( 8,8 ), wxSize( 16,16 ) );
g_Conf->ConLogBox.AutoDock = snapzone.Contains( GetPosition() );
Console::WriteLn( "DockCheck: %d", params g_Conf->ConLogBox.AutoDock );
//Console::WriteLn( "DockCheck: %d", params g_Conf->ConLogBox.AutoDock );
if( g_Conf->ConLogBox.AutoDock )
{
SetPosition( topright + wxSize( 1,0 ) );
@ -246,27 +250,26 @@ void ConsoleLogFrame::OnClear(wxMenuEvent& WXUNUSED(event))
void ConsoleLogFrame::SetColor( Colors color )
{
m_TextCtrl.SetDefaultStyle( m_ColorTable[color] );
if( color != m_curcolor )
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=color] );
}
void ConsoleLogFrame::ClearColor()
{
m_curcolor = Color_Black;
m_TextCtrl.SetDefaultStyle( m_ColorTable.Default() );
}
void ConsoleLogFrame::OnWrite( wxCommandEvent& event )
{
Colors color = (Colors)event.GetExtraLong();
if( color != m_curcolor )
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=color] );
Write( event.GetString() );
Write( (Colors)event.GetExtraLong(), event.GetString() );
DoMessage();
}
void ConsoleLogFrame::OnNewline( wxCommandEvent& event )
{
Write( L"\n" );
Newline();
DoMessage();
}
void ConsoleLogFrame::OnSetTitle( wxCommandEvent& event )
@ -276,7 +279,11 @@ void ConsoleLogFrame::OnSetTitle( wxCommandEvent& event )
void ConsoleLogFrame::OnDockedMove( wxCommandEvent& event )
{
Console::Error( "Dock Message: %d, %d", params g_Conf->ConLogBox.DisplayPosition.x, g_Conf->ConLogBox.DisplayPosition.y );
DockedMove();
}
void ConsoleLogFrame::DockedMove()
{
if( g_Conf != NULL )
SetPosition( g_Conf->ConLogBox.DisplayPosition );
}
@ -284,21 +291,85 @@ void ConsoleLogFrame::OnDockedMove( wxCommandEvent& event )
void ConsoleLogFrame::Write( const wxString& text )
{
// remove selection (WriteText is in fact ReplaceSelection)
#ifdef __WXMSW__
wxTextPos nLen = m_TextCtrl.GetLastPosition();
m_TextCtrl.SetSelection(nLen, nLen);
#endif
m_TextCtrl.AppendText( text );
// cap at 256k for now:
if( m_TextCtrl.GetLastPosition() > 0x40000 )
{
m_TextCtrl.AppendText( L"************************ REMOVING BUFFER CRAP *****************\n" );
m_TextCtrl.Remove( 0, 0x8000 );
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Implementation note: Calls SetColor and Write( text ). Override those virtuals
// and this one will magically follow suite. :)
void ConsoleLogFrame::Write( Colors color, const wxString& text )
{
SetColor( color );
Write( text );
}
void ConsoleLogFrame::Newline()
{
Write( L"\n" );
}
static volatile long counter = 0;
// ------------------------------------------------------------------------
// Deadlock protection: High volume logs will over-tax our message pump and cause the
// GUI to become inaccessible. The cool solution would be a threaded log window, but wx
// is entirely un-safe for that kind of threading. So instead I use a message counter
// that stalls non-GUI threads when they attempt to over-tax an already burdened log.
// If too many messages get queued up, non-gui threads are stalled to allow the gui to
// catch up.
void ConsoleLogFrame::CountMessage()
{
_InterlockedIncrement( &counter );
if( counter > 0x10 ) // 0x10 -- arbitrary value that seems to work well on my C2Q 3.2ghz
{
if( !wxThread::IsMain() )
{
// fixme : It'd be swell if this could be replaced with something that uses
// pthreads semaphores instead of Sleep, but I haven't been able to conjure up
// such an alternative yet.
while( counter > 1 ) { Sleep(1); }
Sleep(1); // give the main thread more time to catch up. :|
}
}
}
void ConsoleLogFrame::DoMessage()
{
int cur = _InterlockedDecrement( &counter );
if( m_TextCtrl.IsFrozen() )
{
if( cur <= 1 && wxThread::IsMain() )
m_TextCtrl.Thaw();
}
else if( cur >= 4 && wxThread::IsMain() )
{
m_TextCtrl.Freeze();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
namespace Console
{
// thread-local console color storage.
__threadlocal Colors th_CurrentColor = Color_Black;
// ------------------------------------------------------------------------
void __fastcall SetTitle( const wxString& title )
{
wxCommandEvent evt( wxEVT_SetTitleText );
@ -306,36 +377,35 @@ namespace Console
wxGetApp().ProgramLog_PostEvent( evt );
}
// ------------------------------------------------------------------------
void __fastcall SetColor( Colors color )
{
th_CurrentColor = color;
}
// ------------------------------------------------------------------------
void ClearColor()
{
th_CurrentColor = Color_Black;
}
// ------------------------------------------------------------------------
bool Newline()
{
if( emuLog != NULL )
fputs( "\n", emuLog );
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Newline );
wxGetApp().ProgramLog_PostEvent( evt );
return false;
}
// ------------------------------------------------------------------------
bool __fastcall Write( const char* fmt )
{
if( emuLog != NULL )
fputs( fmt, emuLog );
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( wxString::FromAscii( fmt ) );
evt.SetExtraLong( th_CurrentColor );
@ -344,12 +414,13 @@ namespace Console
return false;
}
// ------------------------------------------------------------------------
bool __fastcall Write( const wxString& fmt )
{
if( emuLog != NULL )
fputs( fmt.ToAscii().data(), emuLog );
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( fmt );
evt.SetExtraLong( th_CurrentColor );
@ -357,6 +428,48 @@ namespace Console
return false;
}
bool __fastcall WriteLn( const char* fmt )
{
// Implementation note: I've duplicated Write+Newline behavior here to avoid polluting
// the message pump with lots of erroneous messages (Newlines can be bound into Write message).
if( emuLog != NULL )
{
fputs( fmt, emuLog );
fputs( "\n", emuLog );
}
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( wxString::FromAscii( fmt ) + L"\n" );
evt.SetExtraLong( th_CurrentColor );
wxGetApp().ProgramLog_PostEvent( evt );
return false;
}
bool __fastcall WriteLn( const wxString& fmt )
{
// Implementation note: I've duplicated Write+Newline behavior here to avoid polluting
// the message pump with lots of erroneous messages (Newlines can be bound into Write message).
if( emuLog != NULL )
{
fputs( fmt.ToAscii().data(), emuLog );
fputs( "\n", emuLog );
}
wxGetApp().ProgramLog_CountMsg();
wxCommandEvent evt( wxEVT_LOG_Write );
evt.SetString( fmt + L"\n" );
evt.SetExtraLong( th_CurrentColor );
wxGetApp().ProgramLog_PostEvent( evt );
return false;
}
}
namespace Msgbox

View File

@ -78,44 +78,6 @@ wxMenu* MainEmuFrame::MakeIsoMenu()
wxMenu* mnuIso = new wxMenu();
mnuIso->Append( Menu_IsoBrowse, _("Browse..."), _("Select an Iso image from your hard drive.") );
//mnuIso->AppendSeparator();
// Add in the recent files!
/*const StringListNode* cruise = g_Conf->RecentIsos;
int i = 0;
int threshold = 15;
while( cruise != NULL && (--threshold >= 0) )
{
wxString ellipsized;
if( cruise->item->Length() > 64 )
{
// Ellipsize it!
wxFileName src( *cruise->item );
ellipsized = src.GetVolume() + wxFileName::GetVolumeSeparator() + wxFileName::GetPathSeparator() + L"...";
const wxArrayString& dirs( src.GetDirs() );
int totalLen = ellipsized.Length();
int i=dirs.Count()-1;
for( ; i; --i )
{
if( totalLen + dirs[i].Length() < 56 )
totalLen += dirs[i];
}
for( ; i<dirs.Count(); ++i )
ellipsized += wxFileName::GetPathSeparator() + dirs[i];
ellipsized += wxFileName::GetPathSeparator() + src.GetFullName();
}
else
ellipsized = *cruise->item;
mnuIso->Append( Menu_Iso_Recent+i, Path::GetFilename( ellipsized ), *cruise->item );
}*/
if( g_RecentIsoList != NULL )
{
@ -180,16 +142,21 @@ void MainEmuFrame::OnMoveAround( wxMoveEvent& evt )
static wxPoint lastpos( wxDefaultCoord, wxDefaultCoord );
Console::Status( "Mess o' crashiness? It can't be!" );
if( lastpos == evt.GetPosition() ) return;
lastpos = evt.GetPosition();
if( g_Conf->ConLogBox.AutoDock )
{
g_Conf->ConLogBox.DisplayPosition = GetRect().GetTopRight();
//if( ConsoleLogFrame* frame = wxGetApp().GetProgramLog() )
// frame->DockedMove();
wxCommandEvent conevt( wxEVT_DockConsole );
wxGetApp().ProgramLog_PostEvent( conevt );
}
Console::Error( "XWindows Messages Suck: %d, %d", params GetPosition().x, GetPosition().y );
//Console::Error( "XWindows Messages Suck: %d, %d", params GetPosition().x, GetPosition().y );
g_Conf->MainGuiPosition = evt.GetPosition();
//evt.Skip();

View File

@ -126,6 +126,26 @@ bool Pcsx2App::OnCmdLineParsed(wxCmdLineParser& parser)
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// ConsoleThreadTest -- useful class for unit testing the thread safety and general performance
// of the console logger.
#if 0
class ConsoleTestThread : public Thread
{
int Callback()
{
static int numtrack = 0;
while( true )
{
Console::WriteLn( wxsFormat( L"This is a threaded logging test. Something bad could happen... %d", ++numtrack ) );
Sleep( 0 );
}
}
};
#endif
// ------------------------------------------------------------------------
bool Pcsx2App::OnInit()
{
wxInitAllImageHandlers();
@ -170,6 +190,8 @@ bool Pcsx2App::OnInit()
SetExitOnFrameDelete( true );
m_MainFrame->Show();
//ConsoleTestThread* woo = new ConsoleTestThread();
//woo->Start();
// Check to see if the user needs to perform initial setup:

View File

@ -618,6 +618,6 @@ Global
{4639972E-424E-4E13-8B07-CA403C481346} = {88F517F9-CE1C-4005-9BDF-4481FEB55053}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
AMDCaProjectFile = C:\pcsx2dev\pcsx2\CodeAnalyst\pcsx2_suite_2008.caw
AMDCaProjectFile = E:\devpcsx2\fail\wx\CodeAnalyst\pcsx2_suite_2008.caw
EndGlobalSection
EndGlobal