CPU Time in threads view
This commit is contained in:
parent
886511fdcd
commit
bd8ac511d5
|
@ -690,6 +690,10 @@ typedef struct
|
|||
THREADPRIORITY Priority;
|
||||
THREADWAITREASON WaitReason;
|
||||
DWORD LastError;
|
||||
FILETIME UserTime;
|
||||
FILETIME KernelTime;
|
||||
FILETIME CreationTime;
|
||||
ULONG64 Cycles; // Windows Vista or greater
|
||||
} THREADALLINFO;
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -9,6 +9,15 @@
|
|||
#include "threading.h"
|
||||
|
||||
static std::unordered_map<DWORD, THREADINFO> threadList;
|
||||
// Function pointer for dynamic linking. Do not link statically for Windows XP compatibility.
|
||||
// TODO: move this function definition out of thread.cpp
|
||||
BOOL(WINAPI* QueryThreadCycleTime)(HANDLE ThreadHandle, PULONG64 CycleTime) = nullptr;
|
||||
|
||||
BOOL WINAPI QueryThreadCycleTimeUnsupported(HANDLE ThreadHandle, PULONG64 CycleTime)
|
||||
{
|
||||
*CycleTime = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread)
|
||||
{
|
||||
|
@ -78,6 +87,13 @@ int ThreadGetCount()
|
|||
|
||||
void ThreadGetList(THREADLIST* List)
|
||||
{
|
||||
// Initialize function pointer
|
||||
if(QueryThreadCycleTime == nullptr)
|
||||
{
|
||||
QueryThreadCycleTime = (BOOL(WINAPI*)(HANDLE, PULONG64))GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "QueryThreadCycleTime");
|
||||
if(QueryThreadCycleTime == nullptr)
|
||||
QueryThreadCycleTime = QueryThreadCycleTimeUnsupported;
|
||||
}
|
||||
ASSERT_NONNULL(List);
|
||||
SHARED_ACQUIRE(LockThreads);
|
||||
|
||||
|
@ -97,6 +113,9 @@ void ThreadGetList(THREADLIST* List)
|
|||
// Fill out the list data
|
||||
int index = 0;
|
||||
|
||||
// Unused thread exit time
|
||||
FILETIME threadExitTime;
|
||||
|
||||
for(auto & itr : threadList)
|
||||
{
|
||||
HANDLE threadHandle = itr.second.Handle;
|
||||
|
@ -112,6 +131,8 @@ void ThreadGetList(THREADLIST* List)
|
|||
List->list[index].Priority = ThreadGetPriority(threadHandle);
|
||||
List->list[index].WaitReason = ThreadGetWaitReason(threadHandle);
|
||||
List->list[index].LastError = ThreadGetLastErrorTEB(itr.second.ThreadLocalBase);
|
||||
GetThreadTimes(threadHandle, &List->list[index].CreationTime, &threadExitTime, &List->list[index].KernelTime, &List->list[index].UserTime);
|
||||
QueryThreadCycleTime(threadHandle, &List->list[index].Cycles);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ void CPUDump::setupContextMenu()
|
|||
mMenuBuilder->addAction(makeAction(DIcon("data-copy.png"), tr("Data co&py..."), SLOT(dataCopySlot())));
|
||||
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("sync.png"), tr("&Sync with expression"), SLOT(syncWithExpressionSlot()), "ActionSyncWithExpression"));
|
||||
mMenuBuilder->addAction(makeAction(DIcon("animal-dog.png"), ArchValue(tr("Watch QWORD"), tr("Watch DWORD")), SLOT(watchSlot())));
|
||||
mMenuBuilder->addAction(makeAction(DIcon("animal-dog.png"), ArchValue(tr("Watch DWORD"), tr("Watch QWORD")), SLOT(watchSlot())));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("entropy.png"), tr("Entrop&y..."), SLOT(entropySlot()), "ActionEntropy"));
|
||||
|
||||
MenuBuilder* wGotoMenu = new MenuBuilder(this);
|
||||
|
|
|
@ -202,7 +202,11 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
|
|||
addColumnAt(8 + charwidth * 12, tr("Priority"), false);
|
||||
addColumnAt(8 + charwidth * 12, tr("Wait Reason"), false);
|
||||
addColumnAt(8 + charwidth * 11, tr("Last Error"), false);
|
||||
addColumnAt(0, tr("Name"), false);
|
||||
addColumnAt(8 + charwidth * 12, tr("User Time"), false);
|
||||
addColumnAt(8 + charwidth * 12, tr("Kernel Time"), false);
|
||||
addColumnAt(8 + charwidth * 15, tr("Creation Time"), false);
|
||||
addColumnAt(8 + charwidth * 10, tr("CPU Cycles"), false, "", SortBy::AsInt);
|
||||
addColumnAt(8, tr("Name"), false);
|
||||
loadColumnFromConfig("Thread");
|
||||
|
||||
//setCopyMenuOnly(true);
|
||||
|
@ -223,7 +227,7 @@ void ThreadView::updateThreadList()
|
|||
for(int i = 0; i < threadList.count; i++)
|
||||
{
|
||||
if(!threadList.list[i].BasicInfo.ThreadNumber)
|
||||
setCellContent(i, 0, "Main");
|
||||
setCellContent(i, 0, tr("Main"));
|
||||
else
|
||||
setCellContent(i, 0, ToDecString(threadList.list[i].BasicInfo.ThreadNumber));
|
||||
setCellContent(i, 1, ToHexString(threadList.list[i].BasicInfo.ThreadId));
|
||||
|
@ -380,7 +384,11 @@ void ThreadView::updateThreadList()
|
|||
}
|
||||
setCellContent(i, 7, waitReasonString);
|
||||
setCellContent(i, 8, QString("%1").arg(threadList.list[i].LastError, sizeof(unsigned int) * 2, 16, QChar('0')).toUpper());
|
||||
setCellContent(i, 9, threadList.list[i].BasicInfo.threadName);
|
||||
setCellContent(i, 9, FILETIMEToTime(threadList.list[i].UserTime));
|
||||
setCellContent(i, 10, FILETIMEToTime(threadList.list[i].KernelTime));
|
||||
setCellContent(i, 11, FILETIMEToDate(threadList.list[i].CreationTime));
|
||||
setCellContent(i, 12, ToLongLongHexString(threadList.list[i].Cycles));
|
||||
setCellContent(i, 13, threadList.list[i].BasicInfo.threadName);
|
||||
}
|
||||
mCurrentThreadId = "NONE";
|
||||
if(threadList.count)
|
||||
|
|
|
@ -209,7 +209,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "CallStack", 4);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "SEH", 4);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Script", 3);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Thread", 10);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Thread", 14);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Handle", 5);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "TcpConnection", 3);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Privilege", 2);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdint.h>
|
||||
#include "main.h"
|
||||
#include "StringUtil.h"
|
||||
#include "float128.h"
|
||||
#include "MiscUtil.h"
|
||||
|
@ -208,6 +209,7 @@ QString GetDataTypeString(void* buffer, duint size, ENCODETYPE type)
|
|||
|
||||
QString ToDateString(const QDate & date)
|
||||
{
|
||||
/*
|
||||
static const char* months[] =
|
||||
{
|
||||
"Jan",
|
||||
|
@ -224,4 +226,23 @@ QString ToDateString(const QDate & date)
|
|||
"Dec"
|
||||
};
|
||||
return QString().sprintf("%s %d %d", months[date.month() - 1], date.day(), date.year());
|
||||
*/
|
||||
return QLocale(QString(currentLocale)).toString(date);
|
||||
}
|
||||
|
||||
QString FILETIMEToDate(const FILETIME & date)
|
||||
{
|
||||
FILETIME localdate;
|
||||
FileTimeToLocalFileTime(&date, &localdate);
|
||||
SYSTEMTIME systime;
|
||||
FileTimeToSystemTime(&localdate, &systime);
|
||||
QDate qdate = QDate(systime.wYear, systime.wMonth, systime.wDay);
|
||||
quint64 time100ns = (quint64)localdate.dwHighDateTime << 32 | (quint64)localdate.dwLowDateTime;
|
||||
time100ns %= (1000ull * 60ull * 60ull * 24ull * 10000ull);
|
||||
localdate.dwHighDateTime = time100ns >> 32;
|
||||
localdate.dwLowDateTime = time100ns & 0xFFFFFFFF;
|
||||
if(qdate != QDate::currentDate())
|
||||
return ToDateString(qdate) + FILETIMEToTime(localdate);
|
||||
else // today
|
||||
return FILETIMEToTime(localdate);
|
||||
}
|
||||
|
|
|
@ -17,11 +17,12 @@ static QString ToPtrString(duint Address)
|
|||
// QString::arg():
|
||||
// ((int32)0xFFFF0000) == 0xFFFFFFFFFFFF0000 with sign extension
|
||||
//
|
||||
char temp[32];
|
||||
|
||||
#ifdef _WIN64
|
||||
char temp[33];
|
||||
sprintf_s(temp, "%016llX", Address);
|
||||
#else
|
||||
char temp[17];
|
||||
sprintf_s(temp, "%08X", Address);
|
||||
#endif // _WIN64
|
||||
|
||||
|
@ -30,7 +31,7 @@ static QString ToPtrString(duint Address)
|
|||
|
||||
static QString ToLongLongHexString(unsigned long long Value)
|
||||
{
|
||||
char temp[32];
|
||||
char temp[33];
|
||||
|
||||
sprintf_s(temp, "%llX", Value);
|
||||
|
||||
|
@ -39,7 +40,7 @@ static QString ToLongLongHexString(unsigned long long Value)
|
|||
|
||||
static QString ToHexString(duint Value)
|
||||
{
|
||||
char temp[32];
|
||||
char temp[33];
|
||||
|
||||
#ifdef _WIN64
|
||||
sprintf_s(temp, "%llX", Value);
|
||||
|
@ -112,6 +113,22 @@ static T & ArchValue(T & x32value, T & x64value)
|
|||
#endif //_WIN64
|
||||
}
|
||||
|
||||
// Format : d:hh:mm:ss.1234567
|
||||
static QString FILETIMEToTime(const FILETIME & time)
|
||||
{
|
||||
// FILETIME is in 100ns
|
||||
quint64 time100ns = (quint64)time.dwHighDateTime << 32 | (quint64)time.dwLowDateTime;
|
||||
quint64 milliseconds = time100ns / 10000;
|
||||
quint64 days = milliseconds / (1000 * 60 * 60 * 24);
|
||||
QTime qtime = QTime::fromMSecsSinceStartOfDay(milliseconds % (1000 * 60 * 60 * 24));
|
||||
if(days == 0)
|
||||
return QString().sprintf("%02d:%02d:%02d.%07lld", qtime.hour(), qtime.minute(), qtime.second(), time100ns % 10000000);
|
||||
else
|
||||
return QString().sprintf("%lld:%02d:%02d:%02d.%07lld", days, qtime.hour(), qtime.minute(), qtime.second(), time100ns % 10000000);
|
||||
}
|
||||
|
||||
QString FILETIMEToDate(const FILETIME & date);
|
||||
|
||||
static bool GetCommentFormat(duint addr, QString & comment, bool* autoComment = nullptr)
|
||||
{
|
||||
comment.clear();
|
||||
|
|
|
@ -17,18 +17,16 @@ UpdateChecker::UpdateChecker(QWidget* parent)
|
|||
|
||||
void UpdateChecker::checkForUpdates()
|
||||
{
|
||||
get(QNetworkRequest(QUrl("http://jenkins.x64dbg.com/job/vs13/lastSuccessfulBuild/api/json")));
|
||||
//get(QNetworkRequest(QUrl("http://jenkins.x64dbg.com/job/vs13/lastSuccessfulBuild/api/json")));
|
||||
//jenkins is disabled.
|
||||
SimpleErrorBox(mParent, "Error", "Cannot check for updates because the update server is down.");
|
||||
}
|
||||
|
||||
void UpdateChecker::finishedSlot(QNetworkReply* reply)
|
||||
{
|
||||
if(reply->error() != QNetworkReply::NoError) //error
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Critical, tr("Network Error!"), reply->errorString());
|
||||
msg.setParent(mParent, Qt::Dialog);
|
||||
msg.setWindowIcon(DIcon("compile-error.png"));
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
msg.exec();
|
||||
SimpleErrorBox(mParent, tr("Network Error!"), reply->errorString());
|
||||
return;
|
||||
}
|
||||
bool ok = false;
|
||||
|
@ -40,11 +38,7 @@ void UpdateChecker::finishedSlot(QNetworkReply* reply)
|
|||
reply->close();
|
||||
if(!ok)
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Critical, tr("Error!"), tr("File on server could not be parsed..."));
|
||||
msg.setParent(mParent, Qt::Dialog);
|
||||
msg.setWindowIcon(DIcon("compile-error.png"));
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
msg.exec();
|
||||
SimpleErrorBox(mParent, tr("Error!"), tr("File on server could not be parsed..."));
|
||||
return;
|
||||
}
|
||||
auto server = QDateTime::fromTime_t(timestamp).date();
|
||||
|
|
Loading…
Reference in New Issue