Added CPU and GPU load readouts (currently Win32 only). Documented possible methods for implementation in linux. (linux project files aren't updated yet, short on time -- sorry!)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2520 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-01-25 15:31:17 +00:00
parent 97c8a29fb9
commit 4383cb5b0c
16 changed files with 714 additions and 115 deletions

View File

@ -337,4 +337,24 @@ namespace Exception
public: public:
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") ); DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") );
}; };
#ifdef __WXMSW__
// --------------------------------------------------------------------------------------
// Exception::WinApiError
// --------------------------------------------------------------------------------------
class WinApiError : public RuntimeError
{
public:
int ErrorId;
public:
DEFINE_EXCEPTION_COPYTORS( WinApiError )
WinApiError( const char* msg="" );
wxString GetMsgFromWindows() const;
virtual wxString FormatDisplayMessage() const;
virtual wxString FormatDiagnosticMessage() const;
};
#endif
} }

View File

@ -116,8 +116,10 @@ namespace Threading
protected: protected:
wxString m_name; // diagnostic name for our thread. wxString m_name; // diagnostic name for our thread.
pthread_t m_thread; pthread_t m_thread;
uptr m_native_id; // typically an id, but implementing platforms can do whatever.
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
Semaphore m_sem_event; // general wait event that's needed by most threads Semaphore m_sem_event; // general wait event that's needed by most threads
Semaphore m_sem_startup; // startup sync tool Semaphore m_sem_startup; // startup sync tool
Mutex m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner Mutex m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner
@ -132,12 +134,14 @@ namespace Threading
EventSource<EventListener_Thread> m_evtsrc_OnDelete; EventSource<EventListener_Thread> m_evtsrc_OnDelete;
public: public:
virtual ~PersistentThread() throw(); virtual ~PersistentThread() throw();
PersistentThread(); PersistentThread();
PersistentThread( const char* name ); PersistentThread( const char* name );
pthread_t GetId() const { return m_thread; } pthread_t GetId() const { return m_thread; }
u64 GetCpuTime() const;
virtual void Start(); virtual void Start();
virtual void Cancel( bool isBlocking = true ); virtual void Cancel( bool isBlocking = true );
@ -204,6 +208,8 @@ namespace Threading
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Section of methods for internal use only. // Section of methods for internal use only.
void _platform_specific_OnStartInThread();
void _platform_specific_OnCleanupInThread();
bool _basecancel(); bool _basecancel();
void _selfRunningTest( const wxChar* name ) const; void _selfRunningTest( const wxChar* name ) const;
void _DoSetThreadName( const wxString& name ); void _DoSetThreadName( const wxString& name );

View File

@ -51,6 +51,8 @@ namespace Threading
extern PersistentThread* pxGetCurrentThread(); extern PersistentThread* pxGetCurrentThread();
extern wxString pxGetCurrentThreadName(); extern wxString pxGetCurrentThreadName();
extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond();
// Yields the current thread and provides cancellation points if the thread is managed by // Yields the current thread and provides cancellation points if the thread is managed by
// PersistentThread. Unmanaged threads use standard Sleep. // PersistentThread. Unmanaged threads use standard Sleep.

View File

@ -15,7 +15,7 @@
#include "../PrecompiledHeader.h" #include "../PrecompiledHeader.h"
#include "Threading.h" #include "PersistentThread.h"
#include "x86emitter/tools.h" #include "x86emitter/tools.h"
#if !defined(__LINUX__) && !defined(__WXMAC__) #if !defined(__LINUX__) && !defined(__WXMAC__)
@ -51,4 +51,45 @@ __forceinline void Threading::DisableHiresScheduler()
{ {
} }
u64 Threading::GetThreadTicksPerSecond()
{
// Returning 0 is like saying "I'm not supported yet!"
return 0;
}
u64 Threading::GetThreadCpuTime()
{
// Get the cpu time for the current thread. Should be a measure of total time the
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
return 0;
}
u64 Threading::PersistentThread::GetCpuTime() const
{
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
// m_native_handle to implement it. Return value should be a measure of total time the
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
return 0;
}
void Threading::PersistentThread::_platform_specific_OnStartInThread()
{
// Obtain linux-specific thread IDs or Handles here, which can be used to query
// kernel scheduler performance information.
}
void Threading::PersistentThread::_platform_specific_OnCleanupInThread()
{
// Cleanup handles here, which were opened above.
}
void Threading::PersistentThread::_DoSetThreadName( const char* name )
{
// dunno if linux has a feature for naming threads ...?
}
#endif #endif

View File

@ -16,10 +16,6 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#ifdef _WIN32
# include <wx/msw/wrapwin.h> // for thread renaming features
#endif
#ifdef __LINUX__ #ifdef __LINUX__
# include <signal.h> // for pthread_kill, which is in pthread.h on w32-pthreads # include <signal.h> // for pthread_kill, which is in pthread.h on w32-pthreads
#endif #endif
@ -67,7 +63,6 @@ static void unmake_curthread_key()
curthread_key = NULL; curthread_key = NULL;
} }
// Returns a handle to the current persistent thread. If the current thread does not belong // Returns a handle to the current persistent thread. If the current thread does not belong
// to the PersistentThread table, NULL is returned. Since the main/ui thread is not created // to the PersistentThread table, NULL is returned. Since the main/ui thread is not created
// through PersistentThread it will also return NULL. Callers can use wxThread::IsMain() to // through PersistentThread it will also return NULL. Callers can use wxThread::IsMain() to
@ -131,15 +126,15 @@ void Threading::PersistentThread::_pt_callback_cleanup( void* handle )
((PersistentThread*)handle)->_ThreadCleanup(); ((PersistentThread*)handle)->_ThreadCleanup();
} }
Threading::PersistentThread::PersistentThread() Threading::PersistentThread::PersistentThread()
: m_name( L"PersistentThread" ) : m_name( L"PersistentThread" )
, m_thread()
, m_sem_event()
, m_lock_InThread()
, m_lock_start()
{ {
m_detached = true; // start out with m_thread in detached/invalid state m_detached = true; // start out with m_thread in detached/invalid state
m_running = false; m_running = false;
m_native_id = 0;
m_native_handle = NULL;
} }
// This destructor performs basic "last chance" cleanup, which is a blocking join // This destructor performs basic "last chance" cleanup, which is a blocking join
@ -564,6 +559,8 @@ void Threading::PersistentThread::OnStartInThread()
{ {
m_detached = false; m_detached = false;
m_running = true; m_running = true;
_platform_specific_OnStartInThread();
} }
void Threading::PersistentThread::_internal_execute() void Threading::PersistentThread::_internal_execute()
@ -585,6 +582,9 @@ void Threading::PersistentThread::_internal_execute()
// running thread has been canceled or detached. // running thread has been canceled or detached.
void Threading::PersistentThread::OnStart() void Threading::PersistentThread::OnStart()
{ {
m_native_handle = NULL;
m_native_id = 0;
FrankenMutex( m_lock_InThread ); FrankenMutex( m_lock_InThread );
m_sem_event.Reset(); m_sem_event.Reset();
m_sem_startup.Reset(); m_sem_startup.Reset();
@ -600,6 +600,11 @@ void Threading::PersistentThread::OnCleanupInThread()
pthread_setspecific( curthread_key, NULL ); pthread_setspecific( curthread_key, NULL );
unmake_curthread_key(); unmake_curthread_key();
_platform_specific_OnCleanupInThread();
m_native_handle = NULL;
m_native_id = 0;
} }
// passed into pthread_create, and is used to dispatch the thread's object oriented // passed into pthread_create, and is used to dispatch the thread's object oriented
@ -620,40 +625,6 @@ void Threading::PersistentThread::_DoSetThreadName( const wxString& name )
_DoSetThreadName( name.ToUTF8() ); _DoSetThreadName( name.ToUTF8() );
} }
void Threading::PersistentThread::_DoSetThreadName( const char* name )
{
// This feature needs Windows headers and MSVC's SEH support:
#if defined(_WINDOWS_) && defined (_MSC_VER)
// This code sample was borrowed form some obscure MSDN article.
// In a rare bout of sanity, it's an actual Microsoft-published hack
// that actually works!
static const int MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
struct THREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
};
#pragma pack(pop)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
__try {
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
} __except(EXCEPTION_EXECUTE_HANDLER) { }
#endif
}
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BaseTaskThread Implementations // BaseTaskThread Implementations
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------

View File

@ -16,7 +16,7 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "RedtapeWindows.h" #include "RedtapeWindows.h"
#include "x86emitter/tools.h" #include "x86emitter/tools.h"
#include "Threading.h" #include "PersistentThread.h"
#ifndef __WXMSW__ #ifndef __WXMSW__
@ -52,5 +52,89 @@ __forceinline void Threading::DisableHiresScheduler()
timeEndPeriod( 1 ); timeEndPeriod( 1 );
} }
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't
// packed (but for any x86 CPU and microsoft compiler, they will be).
union FileTimeSucks
{
FILETIME filetime;
u64 u64time;
};
u64 Threading::GetThreadCpuTime()
{
FileTimeSucks user, kernel;
FILETIME dummy;
GetThreadTimes( GetCurrentThread(), &dummy, &dummy, &user.filetime, &kernel.filetime );
return user.u64time + kernel.u64time;
}
u64 Threading::GetThreadTicksPerSecond()
{
return 10000000;
}
u64 Threading::PersistentThread::GetCpuTime() const
{
if( m_native_handle == NULL ) return 0;
FileTimeSucks user, kernel;
FILETIME dummy;
// Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more),
// however we own our process threads, so shouldn't matter in any case...
if( GetThreadTimes( (HANDLE)m_native_handle, &dummy, &dummy, &user.filetime, &kernel.filetime ) )
return user.u64time + kernel.u64time;
return 0; // thread prolly doesn't exist anymore.
}
void Threading::PersistentThread::_platform_specific_OnStartInThread()
{
m_native_id = (uptr)GetCurrentThreadId();
m_native_handle = (uptr)OpenThread( THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id );
pxAssertDev( m_native_handle != NULL, wxNullChar );
}
void Threading::PersistentThread::_platform_specific_OnCleanupInThread()
{
CloseHandle( (HANDLE)m_native_handle );
}
void Threading::PersistentThread::_DoSetThreadName( const char* name )
{
// This feature needs Windows headers and MSVC's SEH support:
#if defined(_WINDOWS_) && defined(_MSC_VER)
// This code sample was borrowed form some obscure MSDN article.
// In a rare bout of sanity, it's an actual Microsoft-published hack
// that actually works!
static const int MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
struct THREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
};
#pragma pack(pop)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
__try {
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
} __except(EXCEPTION_EXECUTE_HANDLER) { }
#endif
}
#endif #endif

View File

@ -0,0 +1,77 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "CpuUsageProvider.h"
#include "System.h"
#include "SysThreads.h"
#include "GS.h"
DefaultCpuUsageProvider::DefaultCpuUsageProvider()
{
m_lasttime_ee = GetCoreThread().GetCpuTime();
m_lasttime_gs = GetMTGS().GetCpuTime();
m_lasttime_ui = GetThreadCpuTime();
m_lasttime_update = GetCPUTicks();
m_pct_ee = 0;
m_pct_gs = 0;
m_pct_ui = 0;
}
bool DefaultCpuUsageProvider::IsImplemented() const
{
return GetThreadTicksPerSecond() != 0;
}
void DefaultCpuUsageProvider::UpdateStats()
{
u64 curtime = GetCPUTicks();
u64 delta = curtime - m_lasttime_update;
if( delta < (GetTickFrequency() / 16) ) return;
u64 curtime_ee = GetCoreThread().GetCpuTime();
u64 curtime_gs = GetMTGS().GetCpuTime();
u64 curtime_ui = GetThreadCpuTime();
// get the real time passed, scaled to the Thread's tick frequency.
u64 timepass = (delta * GetThreadTicksPerSecond()) / GetTickFrequency();
m_pct_ee = ((curtime_ee - m_lasttime_ee) * 100) / timepass;
m_pct_gs = ((curtime_gs - m_lasttime_gs) * 100) / timepass;
m_pct_ui = ((curtime_ui - m_lasttime_ui) * 100) / timepass;
m_lasttime_update = curtime;
m_lasttime_ee = curtime_ee;
m_lasttime_gs = curtime_gs;
m_lasttime_ui = curtime_ui;
}
int DefaultCpuUsageProvider::GetEEcorePct() const
{
return m_pct_ee;
}
int DefaultCpuUsageProvider::GetGsPct() const
{
return m_pct_gs;
}
int DefaultCpuUsageProvider::GetGuiPct() const
{
return m_pct_ui;
}

View File

@ -0,0 +1,70 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
class BaseCpuUsageProvider
{
public:
BaseCpuUsageProvider() {}
virtual ~BaseCpuUsageProvider() throw() {}
virtual bool IsImplemented() const=0;
virtual void UpdateStats()=0;
virtual int GetEEcorePct() const=0;
virtual int GetGsPct() const=0;
virtual int GetGuiPct() const=0;
};
class CpuUsageProvider : public BaseCpuUsageProvider
{
protected:
ScopedPtr<BaseCpuUsageProvider> m_Implementation;
public:
CpuUsageProvider();
virtual ~CpuUsageProvider() throw();
virtual bool IsImplemented() const { return m_Implementation->IsImplemented(); }
virtual void UpdateStats() { m_Implementation->UpdateStats(); }
virtual int GetEEcorePct() const { return m_Implementation->GetEEcorePct(); }
virtual int GetGsPct() const { return m_Implementation->GetGsPct(); }
virtual int GetGuiPct() const { return m_Implementation->GetGuiPct(); }
};
class DefaultCpuUsageProvider : public BaseCpuUsageProvider
{
protected:
u64 m_lasttime_ee;
u64 m_lasttime_gs;
u64 m_lasttime_ui;
u64 m_lasttime_update;
u32 m_pct_ee;
u32 m_pct_gs;
u32 m_pct_ui;
public:
DefaultCpuUsageProvider();
virtual ~DefaultCpuUsageProvider() throw() {}
bool IsImplemented() const;
void UpdateStats();
int GetEEcorePct() const;
int GetGsPct() const;
int GetGuiPct() const;
};

View File

@ -0,0 +1,33 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "CpuUsageProvider.h"
// CpuUsageProvider under Linux (Doesn't Do Jack, yet!)
//
// Currently this just falls back on the Default, which itself is not implemented under
// linux, as of me writing this. I'm not sure if it'll be easier to implement the
// default provider (see Utilities/LnxThreads.cpp for details) or to use a custom/manual
// implementation here.
CpuUsageProvider::CpuUsageProvider() :
m_Implementation( new DefaultCpuUsageProvider() )
{
}
CpuUsageProvider::~CpuUsageProvider() throw()
{
}

View File

@ -0,0 +1,281 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "CpuUsageProvider.h"
// undef this for compiler errors, code errors, security denies, and total fail.
#define _COM_SUCKS_SHIT_
#ifndef _COM_SUCKS_SHIT_
#include "MswStuff.h"
#include "System.h"
#include "SysThreads.h"
#include "GS.h"
#include <wx/dynlib.h>
#include <wbemcli.h>
#include <wbemprov.h>
#include <comutil.h>
#include <atlcomcli.h>
using namespace Threading;
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "comsuppw.lib")
class CpuUsageProviderMSW : public BaseCpuUsageProvider
{
protected:
bool m_IsImplemented;
CComPtr<IWbemServices> m_WbemServices;
//CComPtr<IWbemRefresher> m_Refresher;
//CComPtr<IWbemHiPerfEnum> m_Enum;
public:
CpuUsageProviderMSW();
virtual ~CpuUsageProviderMSW() throw();
bool IsImplemented() const;
void UpdateStats();
int GetEEcorePct() const;
int GetGsPct() const;
int GetGuiPct() const;
};
CpuUsageProviderMSW::CpuUsageProviderMSW()
{
m_IsImplemented = false;
{
// Test if the OS supports cooked thread performance info...
wxDoNotLogInThisScope please;
wxDynamicLibrary perfinst( L"WmiPerfInst.dll" );
if( !perfinst.IsLoaded() )
{
wxDynamicLibrary cooker( L"Wmicookr.dll" );
if( !cooker.IsLoaded() ) return;
}
}
m_IsImplemented = true;
HRESULT hr;
CComPtr<IWbemLocator> m_IWbemLocator;
// We're pretty well assured COM is Initialized.
CoInitialize(NULL);
if( FAILED (hr = CoInitializeSecurity(
NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0) ) )
{
switch( hr )
{
case RPC_E_TOO_LATE: break; // harmless failure, expected with wxWidgets.
case RPC_E_NO_GOOD_SECURITY_PACKAGES:
throw Exception::RuntimeError( "(CpuUsageProviderMSW) CoInitializeSecurity failed: No good security packages! .. whatever tht means." );
case E_OUTOFMEMORY:
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." );
default:
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) CoInitializeSecurity failed with an unknown error code: %d", hr ), wxEmptyString );
}
}
//BSTR bstrNamespace = L"\\\\.\\root\\cimv2";
BSTR bstrNamespace = L"root\\cimv2";
if( FAILED (hr = CoCreateInstance (
CLSID_WbemAdministrativeLocator,
NULL ,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER ,
IID_IUnknown ,
(LPVOID*)&m_IWbemLocator) ) )
{
return;
}
if( FAILED (hr = m_IWbemLocator->ConnectServer(
bstrNamespace, NULL, NULL, NULL, 0, NULL, NULL, &m_WbemServices) ) )
{
return;
}
/*
HRESULT hr;
CComPtr<IWbemConfigureRefresher> m_Config;
if (FAILED (hr = CoCreateInstance(
CLSID_WbemRefresher,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWbemRefresher,
(void**) &m_Refresher)))
{
return;
}
if (FAILED (hr = m_Refresher->QueryInterface(
IID_IWbemConfigureRefresher,
(void **)&m_Config)))
{
return;
}
long lID = 0; // why?
// Add an enumerator to the refresher.
if (FAILED (hr = m_Config->AddEnum(
m_WbemServices,
L"Win32_PerfRawData_PerfProc_Process",
0,
NULL,
&m_Enum,
&lID)))
{
return;
}*/
}
CpuUsageProviderMSW::~CpuUsageProviderMSW() throw()
{
//CoUninitialize();
}
bool CpuUsageProviderMSW::IsImplemented() const
{
return m_IsImplemented;
}
void CpuUsageProviderMSW::UpdateStats()
{
HRESULT hRes;
BSTR strQuery = L"Select * from Win32_PerfFormattedData_PerfProc_Thread where Name='EEcore'";
BSTR strQL = L"WQL";
CComPtr<IEnumWbemClassObject> m_EnumObject;
hRes = m_WbemServices->ExecQuery(strQL, strQuery, WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &m_EnumObject);
if( FAILED(hRes) )
{
//throw Exception::WinApiError("Could not execute Query");
return;
}
hRes = m_EnumObject->Reset();
if( FAILED(hRes) )
{
//MessageBox("Could not Enumerate");
return;
}
ULONG uCount = 1, uReturned;
IWbemClassObject* pClassObject = NULL;
hRes = m_EnumObject->Next(WBEM_INFINITE,uCount, &pClassObject, &uReturned);
if( FAILED(hRes) )
{
const wxChar* msg = NULL;
switch( hRes )
{
case WBEM_E_INVALID_PARAMETER:
msg = L"One or more invalid parameters were specified in the call.";
break;
case WBEM_E_UNEXPECTED:
msg = L"An object in the enumeration has been deleted, destroying the validity of the enumeration.";
break;
case WBEM_E_TRANSPORT_FAILURE:
msg = L"This indicates the failure of the remote procedure call (RPC) link between the current process and Windows Management.";
break;
case WBEM_S_FALSE:
msg = L"The number of objects returned was less than the number requested. WBEM_S_FALSE is also returned when this method is called with a value of 0 for the uCount parameter.";
break;
case WBEM_S_TIMEDOUT:
msg = L"A time-out occurred before you obtained all the objects.";
break;
case WBEM_E_ACCESS_DENIED:
msg = L"Access Denied to WMI Query.";
break;
case WBEM_E_OUT_OF_MEMORY:
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." );
default:
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) WMI Object Enumeration failed with an unknown error code: %d", hRes ), wxEmptyString );
}
if( msg != NULL )
throw Exception::RuntimeError( wxString("(CpuUsageProviderMSW) ") + msg, wxEmptyString );
return;
}
VARIANT v;
BSTR strClassProp = SysAllocString(L"LoadPercentage");
hRes = pClassObject->Get(strClassProp, 0, &v, 0, 0);
if( FAILED(hRes) )
{
//MessageBox("Could not Get Value");
return;
}
SysFreeString(strClassProp);
_bstr_t bstrPath = &v; //Just to convert BSTR to ANSI
char* strPath=(char*)bstrPath;
/*if (SUCCEEDED(hRes))
MessageBox(strPath);
else
MessageBox("Error in getting object");*/
VariantClear(&v);
}
int CpuUsageProviderMSW::GetEEcorePct() const
{
return 0;
}
int CpuUsageProviderMSW::GetGsPct() const
{
return 0;
}
int CpuUsageProviderMSW::GetGuiPct() const
{
return 0;
}
#endif
CpuUsageProvider::CpuUsageProvider() :
m_Implementation( new DefaultCpuUsageProvider() )
{
}
CpuUsageProvider::~CpuUsageProvider() throw()
{
}

View File

@ -326,6 +326,7 @@ GSPanel* GSFrame::GetViewport()
return (GSPanel*)FindWindowById( m_id_gspanel ); return (GSPanel*)FindWindowById( m_id_gspanel );
} }
void GSFrame::OnUpdateTitle( wxTimerEvent& evt ) void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
{ {
double fps = wxGetApp().FpsManager.GetFramerate(); double fps = wxGetApp().FpsManager.GetFramerate();
@ -345,8 +346,15 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
} }
} }
SetTitle( wxsFormat( L"%s | Limiter: %s | fps: %2.02f", wxString cpuUsage;
fromUTF8(gsDest).c_str(), limiterStr, fps ) if( m_CpuUsage.IsImplemented() )
{
m_CpuUsage.UpdateStats();
cpuUsage = wxsFormat( L" | EE: %d%% | GS: %d%%", m_CpuUsage.GetEEcorePct(), m_CpuUsage.GetGsPct() );
}
SetTitle( wxsFormat( L"%s | Limiter: %s | fps: %2.02f%s",
fromUTF8(gsDest).c_str(), limiterStr, fps, cpuUsage.c_str() )
); );
//States_GetCurrentSlot() //States_GetCurrentSlot()

View File

@ -24,4 +24,3 @@ extern void MSW_ListView_SetIconSpacing( wxListbook& listbook, int width );
extern void pxDwm_Load(); extern void pxDwm_Load();
extern void pxDwm_Unload(); extern void pxDwm_Unload();
extern void pxDwm_SetPresentParams( WXWidget wnd ); extern void pxDwm_SetPresentParams( WXWidget wnd );

View File

@ -21,6 +21,7 @@
#include "App.h" #include "App.h"
#include "AppSaveStates.h" #include "AppSaveStates.h"
#include "CpuUsageProvider.h"
enum LimiterModeType enum LimiterModeType
{ {
@ -79,11 +80,13 @@ class GSFrame : public wxFrame,
typedef wxFrame _parent; typedef wxFrame _parent;
protected: protected:
wxTimer m_timer_UpdateTitle; wxTimer m_timer_UpdateTitle;
wxWindowID m_id_gspanel; wxWindowID m_id_gspanel;
wxWindowID m_id_OutputDisabled; wxWindowID m_id_OutputDisabled;
wxStaticText* m_label_Disabled; wxStaticText* m_label_Disabled;
wxStatusBar* m_statusbar; wxStatusBar* m_statusbar;
CpuUsageProvider m_CpuUsage;
public: public:
GSFrame(wxWindow* parent, const wxString& title); GSFrame(wxWindow* parent, const wxString& title);

View File

@ -1848,6 +1848,42 @@
RelativePath="..\..\gui\ConsoleLogger.cpp" RelativePath="..\..\gui\ConsoleLogger.cpp"
> >
</File> </File>
<File
RelativePath="..\..\gui\CpuUsageProvider.cpp"
>
</File>
<File
RelativePath="..\..\gui\CpuUsageProviderLnx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Devel|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\gui\CpuUsageProviderMSW.cpp"
>
</File>
<File <File
RelativePath="..\..\gui\FrameForGS.cpp" RelativePath="..\..\gui\FrameForGS.cpp"
> >
@ -2565,6 +2601,10 @@
RelativePath="..\..\gui\ConsoleLogger.h" RelativePath="..\..\gui\ConsoleLogger.h"
> >
</File> </File>
<File
RelativePath="..\..\gui\CpuUsageProvider.h"
>
</File>
<File <File
RelativePath="..\..\gui\Resources\EmbeddedImage.h" RelativePath="..\..\gui\Resources\EmbeddedImage.h"
> >

View File

@ -23,25 +23,6 @@
#define COMPILEDATE __DATE__ #define COMPILEDATE __DATE__
//Exception handler for the VTLB-based recompilers.
int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps);
#define PCSX2_MEM_PROTECT_BEGIN() __try {
#define PCSX2_MEM_PROTECT_END() } __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {}
// --->> Patch Browser Stuff (in the event we ever use it)
void ListPatches (HWND hW);
int ReadPatch (HWND hW, char fileName[1024]);
char * lTrim (char *s);
BOOL Save_Patch_Proc( char * filename );
// <<--- END Patch Browser
extern SafeArray<u8>* g_RecoveryState;
extern SafeArray<u8>* g_gsRecoveryState;
extern const char* g_pRunGSState;
extern int g_SaveGSStream;
extern void StreamException_ThrowLastError( const wxString& streamname, HANDLE result=INVALID_HANDLE_VALUE ); extern void StreamException_ThrowLastError( const wxString& streamname, HANDLE result=INVALID_HANDLE_VALUE );
extern void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode ); extern void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode );

View File

@ -19,50 +19,33 @@
#include "App.h" #include "App.h"
#include "ConsoleLogger.h" #include "ConsoleLogger.h"
Exception::WinApiError::WinApiError( const char* msg )
// --------------------------------------------------------------------------------------
// Exception::Win32Error
// --------------------------------------------------------------------------------------
namespace Exception
{ {
class Win32Error : public RuntimeError ErrorId = GetLastError();
{ BaseException::InitBaseEx( msg );
public: }
int ErrorId;
public: wxString Exception::WinApiError::GetMsgFromWindows() const
DEFINE_EXCEPTION_COPYTORS( Win32Error ) {
if (!ErrorId)
return wxString();
Win32Error( const char* msg="" ) const DWORD BUF_LEN = 2048;
{ TCHAR t_Msg[BUF_LEN];
ErrorId = GetLastError(); if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
BaseException::InitBaseEx( msg ); return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
}
wxString GetMsgFromWindows() const return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
{ }
if (!ErrorId)
return wxString();
const DWORD BUF_LEN = 2048; wxString Exception::WinApiError::FormatDisplayMessage() const
TCHAR t_Msg[BUF_LEN]; {
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0)) return m_message_user + L"\n\n" + GetMsgFromWindows();
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg ); }
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId ); wxString Exception::WinApiError::FormatDiagnosticMessage() const
} {
return m_message_diag + L"\n\t" + GetMsgFromWindows();
virtual wxString FormatDisplayMessage() const
{
return m_message_user + L"\n\n" + GetMsgFromWindows();
}
virtual wxString FormatDiagnosticMessage() const
{
return m_message_diag + L"\n\t" + GetMsgFromWindows();
}
};
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -119,7 +102,7 @@ protected:
continue; continue;
} }
throw Exception::Win32Error( "ReadFile from pipe failed." ); throw Exception::WinApiError( "ReadFile from pipe failed." );
} }
if( u32_Read <= 3 ) if( u32_Read <= 3 )
@ -137,7 +120,7 @@ protected:
{ {
Yield(); Yield();
if( !PeekNamedPipe(m_outpipe, 0, 0, 0, &u32_avail, 0) ) if( !PeekNamedPipe(m_outpipe, 0, 0, 0, &u32_avail, 0) )
throw Exception::Win32Error( "Error peeking Pipe." ); throw Exception::WinApiError( "Error peeking Pipe." );
if( u32_avail == 0 ) break; if( u32_avail == 0 ) break;
@ -207,10 +190,10 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
try try
{ {
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) ) if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
throw Exception::Win32Error( "CreatePipe failed." ); throw Exception::WinApiError( "CreatePipe failed." );
if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) ) if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) )
throw Exception::Win32Error( "SetStdHandle failed." ); throw Exception::WinApiError( "SetStdHandle failed." );
// Note: Don't use GetStdHandle to "confirm" the handle. // Note: Don't use GetStdHandle to "confirm" the handle.
// //