mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
97c8a29fb9
commit
4383cb5b0c
|
@ -337,4 +337,24 @@ namespace Exception
|
|||
public:
|
||||
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
|
||||
}
|
||||
|
|
|
@ -116,8 +116,10 @@ namespace Threading
|
|||
|
||||
protected:
|
||||
wxString m_name; // diagnostic name for our 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_startup; // startup sync tool
|
||||
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;
|
||||
|
||||
|
||||
public:
|
||||
virtual ~PersistentThread() throw();
|
||||
PersistentThread();
|
||||
PersistentThread( const char* name );
|
||||
|
||||
pthread_t GetId() const { return m_thread; }
|
||||
u64 GetCpuTime() const;
|
||||
|
||||
virtual void Start();
|
||||
virtual void Cancel( bool isBlocking = true );
|
||||
|
@ -204,6 +208,8 @@ namespace Threading
|
|||
// ----------------------------------------------------------------------------
|
||||
// Section of methods for internal use only.
|
||||
|
||||
void _platform_specific_OnStartInThread();
|
||||
void _platform_specific_OnCleanupInThread();
|
||||
bool _basecancel();
|
||||
void _selfRunningTest( const wxChar* name ) const;
|
||||
void _DoSetThreadName( const wxString& name );
|
||||
|
|
|
@ -51,6 +51,8 @@ namespace Threading
|
|||
|
||||
extern PersistentThread* pxGetCurrentThread();
|
||||
extern wxString pxGetCurrentThreadName();
|
||||
extern u64 GetThreadCpuTime();
|
||||
extern u64 GetThreadTicksPerSecond();
|
||||
|
||||
// Yields the current thread and provides cancellation points if the thread is managed by
|
||||
// PersistentThread. Unmanaged threads use standard Sleep.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
|
||||
#include "../PrecompiledHeader.h"
|
||||
#include "Threading.h"
|
||||
#include "PersistentThread.h"
|
||||
#include "x86emitter/tools.h"
|
||||
|
||||
#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
|
||||
|
|
|
@ -16,10 +16,6 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <wx/msw/wrapwin.h> // for thread renaming features
|
||||
#endif
|
||||
|
||||
#ifdef __LINUX__
|
||||
# include <signal.h> // for pthread_kill, which is in pthread.h on w32-pthreads
|
||||
#endif
|
||||
|
@ -67,7 +63,6 @@ static void unmake_curthread_key()
|
|||
curthread_key = NULL;
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
Threading::PersistentThread::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_running = false;
|
||||
|
||||
m_native_id = 0;
|
||||
m_native_handle = NULL;
|
||||
}
|
||||
|
||||
// This destructor performs basic "last chance" cleanup, which is a blocking join
|
||||
|
@ -564,6 +559,8 @@ void Threading::PersistentThread::OnStartInThread()
|
|||
{
|
||||
m_detached = false;
|
||||
m_running = true;
|
||||
|
||||
_platform_specific_OnStartInThread();
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::_internal_execute()
|
||||
|
@ -585,6 +582,9 @@ void Threading::PersistentThread::_internal_execute()
|
|||
// running thread has been canceled or detached.
|
||||
void Threading::PersistentThread::OnStart()
|
||||
{
|
||||
m_native_handle = NULL;
|
||||
m_native_id = 0;
|
||||
|
||||
FrankenMutex( m_lock_InThread );
|
||||
m_sem_event.Reset();
|
||||
m_sem_startup.Reset();
|
||||
|
@ -600,6 +600,11 @@ void Threading::PersistentThread::OnCleanupInThread()
|
|||
pthread_setspecific( curthread_key, NULL );
|
||||
|
||||
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
|
||||
|
@ -620,40 +625,6 @@ void Threading::PersistentThread::_DoSetThreadName( const wxString& name )
|
|||
_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
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "RedtapeWindows.h"
|
||||
#include "x86emitter/tools.h"
|
||||
#include "Threading.h"
|
||||
#include "PersistentThread.h"
|
||||
|
||||
#ifndef __WXMSW__
|
||||
|
||||
|
@ -52,5 +52,89 @@ __forceinline void Threading::DisableHiresScheduler()
|
|||
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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()
|
||||
{
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
}
|
|
@ -326,6 +326,7 @@ GSPanel* GSFrame::GetViewport()
|
|||
return (GSPanel*)FindWindowById( m_id_gspanel );
|
||||
}
|
||||
|
||||
|
||||
void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
|
||||
{
|
||||
double fps = wxGetApp().FpsManager.GetFramerate();
|
||||
|
@ -345,8 +346,15 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
|
|||
}
|
||||
}
|
||||
|
||||
SetTitle( wxsFormat( L"%s | Limiter: %s | fps: %2.02f",
|
||||
fromUTF8(gsDest).c_str(), limiterStr, fps )
|
||||
wxString cpuUsage;
|
||||
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()
|
||||
|
|
|
@ -24,4 +24,3 @@ extern void MSW_ListView_SetIconSpacing( wxListbook& listbook, int width );
|
|||
extern void pxDwm_Load();
|
||||
extern void pxDwm_Unload();
|
||||
extern void pxDwm_SetPresentParams( WXWidget wnd );
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "App.h"
|
||||
#include "AppSaveStates.h"
|
||||
#include "CpuUsageProvider.h"
|
||||
|
||||
enum LimiterModeType
|
||||
{
|
||||
|
@ -85,6 +86,8 @@ protected:
|
|||
wxStaticText* m_label_Disabled;
|
||||
wxStatusBar* m_statusbar;
|
||||
|
||||
CpuUsageProvider m_CpuUsage;
|
||||
|
||||
public:
|
||||
GSFrame(wxWindow* parent, const wxString& title);
|
||||
virtual ~GSFrame() throw();
|
||||
|
|
|
@ -1848,6 +1848,42 @@
|
|||
RelativePath="..\..\gui\ConsoleLogger.cpp"
|
||||
>
|
||||
</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
|
||||
RelativePath="..\..\gui\FrameForGS.cpp"
|
||||
>
|
||||
|
@ -2565,6 +2601,10 @@
|
|||
RelativePath="..\..\gui\ConsoleLogger.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\CpuUsageProvider.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Resources\EmbeddedImage.h"
|
||||
>
|
||||
|
|
|
@ -23,25 +23,6 @@
|
|||
|
||||
#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_ThrowFromErrno( const wxString& streamname, errno_t errcode );
|
||||
|
|
|
@ -19,29 +19,14 @@
|
|||
#include "App.h"
|
||||
#include "ConsoleLogger.h"
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::Win32Error
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
namespace Exception
|
||||
Exception::WinApiError::WinApiError( const char* msg )
|
||||
{
|
||||
class Win32Error : public RuntimeError
|
||||
{
|
||||
public:
|
||||
int ErrorId;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( Win32Error )
|
||||
|
||||
Win32Error( const char* msg="" )
|
||||
{
|
||||
ErrorId = GetLastError();
|
||||
BaseException::InitBaseEx( msg );
|
||||
}
|
||||
}
|
||||
|
||||
wxString GetMsgFromWindows() const
|
||||
{
|
||||
wxString Exception::WinApiError::GetMsgFromWindows() const
|
||||
{
|
||||
if (!ErrorId)
|
||||
return wxString();
|
||||
|
||||
|
@ -51,18 +36,16 @@ namespace Exception
|
|||
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
|
||||
|
||||
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
|
||||
}
|
||||
}
|
||||
|
||||
virtual wxString FormatDisplayMessage() const
|
||||
{
|
||||
wxString Exception::WinApiError::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + L"\n\n" + GetMsgFromWindows();
|
||||
}
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const
|
||||
{
|
||||
wxString Exception::WinApiError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag + L"\n\t" + GetMsgFromWindows();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -119,7 +102,7 @@ protected:
|
|||
continue;
|
||||
}
|
||||
|
||||
throw Exception::Win32Error( "ReadFile from pipe failed." );
|
||||
throw Exception::WinApiError( "ReadFile from pipe failed." );
|
||||
}
|
||||
|
||||
if( u32_Read <= 3 )
|
||||
|
@ -137,7 +120,7 @@ protected:
|
|||
{
|
||||
Yield();
|
||||
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;
|
||||
|
||||
|
@ -207,10 +190,10 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
|||
try
|
||||
{
|
||||
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 ) )
|
||||
throw Exception::Win32Error( "SetStdHandle failed." );
|
||||
throw Exception::WinApiError( "SetStdHandle failed." );
|
||||
|
||||
// Note: Don't use GetStdHandle to "confirm" the handle.
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue