mirror of
https://github.com/x64dbg/x64dbg.git
synced 2024-11-23 04:50:07 +00:00
Play around with debouncing slow events in the remote table
This commit is contained in:
parent
bc7cae2f28
commit
2c3c3416f2
@ -20,6 +20,7 @@ OverlayFrame::OverlayFrame(QWidget* parent) :
|
|||||||
QFrame(parent),
|
QFrame(parent),
|
||||||
ui(new Ui::OverlayFrame)
|
ui(new Ui::OverlayFrame)
|
||||||
{
|
{
|
||||||
|
// TODO: forward the scroll/key events to the window below
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,36 +43,57 @@ RemoteTable::RemoteTable(QWidget* parent)
|
|||||||
setRowCount(0x2000ull);
|
setRowCount(0x2000ull);
|
||||||
|
|
||||||
mOverlay = OverlayFrame::embed(this, false);
|
mOverlay = OverlayFrame::embed(this, false);
|
||||||
|
mScrollTimer = new QTimer(this);
|
||||||
|
mScrollTimer->setSingleShot(true);
|
||||||
|
mScrollTimer->setInterval(500); // TODO: this interval should probably be the latency
|
||||||
|
connect(mScrollTimer, &QTimer::timeout, this, [this]
|
||||||
|
{
|
||||||
|
qDebug() << "Total scroll for debounce interval: " << mScrollDelta;
|
||||||
|
uint64_t minTime = UINT64_MAX;
|
||||||
|
uint64_t maxTime = 0;
|
||||||
|
dsint totalDelta = 0;
|
||||||
|
for(const auto&[time,delta] : mScrollEvents) {
|
||||||
|
uint64_t timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch()).count();
|
||||||
|
minTime = std::min(minTime, timeMs);
|
||||||
|
maxTime = std::max(maxTime, timeMs);
|
||||||
|
totalDelta += delta;
|
||||||
|
}
|
||||||
|
auto totalMs = maxTime - minTime;
|
||||||
|
auto div = totalMs / 1000.0;
|
||||||
|
qDebug() << "time:" << totalMs << "total:" << totalDelta << "velocity:" << totalDelta / div << "(lines/second)";
|
||||||
|
mScrollEvents.clear();
|
||||||
|
mScrollDelta = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RemoteTable::getCellContent(duint row, duint col)
|
QString RemoteTable::getCellContent(duint row, duint col)
|
||||||
{
|
{
|
||||||
// TODO: get data from a container that's aware of the outgoing requests
|
// Show the real row number for debugging purposes
|
||||||
// (perhaps this should be done transparently in the request/response handling?)
|
|
||||||
auto relativeRow = row - getTableOffset();
|
|
||||||
QString base;
|
QString base;
|
||||||
if(col == 0)
|
if(col == 0)
|
||||||
{
|
{
|
||||||
base = QString("[row: %1] ").arg(row, 5);
|
base = QString("[row: %1] ").arg(row, 5);
|
||||||
}
|
}
|
||||||
if(relativeRow < mRemoteData.size())
|
|
||||||
{
|
// Ignore out of range data
|
||||||
const auto & remoteRow = mRemoteData[relativeRow];
|
dsint relativeRow = row - mRemoteTableOffset;
|
||||||
QString data;
|
if(relativeRow < 0 || relativeRow >= mRemoteData.size())
|
||||||
if(col < remoteRow.size())
|
|
||||||
{
|
|
||||||
data = QString::fromStdString(remoteRow[col]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data = "(BAD SERVER)";
|
|
||||||
}
|
|
||||||
return base + data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return base + "(FETCHING DATA...)";
|
return base + "(FETCHING DATA...)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display the data we do have
|
||||||
|
const auto & remoteRow = mRemoteData[relativeRow];
|
||||||
|
QString data;
|
||||||
|
if(col < remoteRow.size())
|
||||||
|
{
|
||||||
|
data = QString::fromStdString(remoteRow[col]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = "(BAD SERVER)";
|
||||||
|
}
|
||||||
|
return base + data;
|
||||||
}
|
}
|
||||||
|
|
||||||
duint RemoteTable::getCellUserdata(duint row, duint column)
|
duint RemoteTable::getCellUserdata(duint row, duint column)
|
||||||
@ -94,6 +115,14 @@ void RemoteTable::sortRows(duint column, bool ascending)
|
|||||||
|
|
||||||
duint RemoteTable::sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta)
|
duint RemoteTable::sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta)
|
||||||
{
|
{
|
||||||
|
// Use a debounce timer to predict the scrolling
|
||||||
|
if(!mScrollTimer->isActive())
|
||||||
|
{
|
||||||
|
mScrollStart = std::chrono::system_clock::now();
|
||||||
|
}
|
||||||
|
mScrollDelta += delta;
|
||||||
|
mScrollTimer->start();
|
||||||
|
|
||||||
auto actionName = [action]()
|
auto actionName = [action]()
|
||||||
{
|
{
|
||||||
switch(action)
|
switch(action)
|
||||||
@ -166,14 +195,23 @@ void RemoteTable::prepareData()
|
|||||||
// TODO: use the average/median/last latency of the connection as a debouncing timer
|
// TODO: use the average/median/last latency of the connection as a debouncing timer
|
||||||
// TODO: use some basic prediction heuristics (scroll direction etc) to anticipate
|
// TODO: use some basic prediction heuristics (scroll direction etc) to anticipate
|
||||||
// the scroll (request a bigger range)
|
// the scroll (request a bigger range)
|
||||||
// TODO: measure the ping
|
|
||||||
// TODO: implement partial reuse of the data
|
|
||||||
|
|
||||||
TableRequest r;
|
TableRequest r;
|
||||||
r.offset = offset;
|
r.offset = offset;
|
||||||
r.lines = linesToPrint;
|
r.lines = linesToPrint;
|
||||||
r.scroll = 0; // TODO: unused for now, used to scroll up in disassembly (variable size)
|
r.scroll = 0; // TODO: unused for now, used to scroll up in disassembly (variable size)
|
||||||
|
|
||||||
|
if(mScrollDelta < 0)
|
||||||
|
{
|
||||||
|
// TODO: set scroll to -100 to get 100 extra line up
|
||||||
|
}
|
||||||
|
else if(mScrollDelta > 0)
|
||||||
|
{
|
||||||
|
// TODO: increase the lines based on scroll velocity
|
||||||
|
//r.lines *= 2;
|
||||||
|
}
|
||||||
|
//qDebug() << "scrollDelta:" << mScrollDelta;
|
||||||
|
|
||||||
if(!mCurrentSent)
|
if(!mCurrentSent)
|
||||||
{
|
{
|
||||||
assert(!mNextRequired);
|
assert(!mNextRequired);
|
||||||
@ -193,6 +231,14 @@ void RemoteTable::prepareData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteTable::wheelEvent(QWheelEvent* event)
|
||||||
|
{
|
||||||
|
dsint prevScrollDelta = mScrollDelta;
|
||||||
|
AbstractStdTable::wheelEvent(event);
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
mScrollEvents.emplace_back(now, mScrollDelta - prevScrollDelta);
|
||||||
|
}
|
||||||
|
|
||||||
void RemoteTable::handleTableResponse(const TableResponse & response)
|
void RemoteTable::handleTableResponse(const TableResponse & response)
|
||||||
{
|
{
|
||||||
// Calculate response time statistics
|
// Calculate response time statistics
|
||||||
@ -230,6 +276,8 @@ void RemoteTable::handleTableResponse(const TableResponse & response)
|
|||||||
|
|
||||||
qDebug() << "[response time] now:" << elapsedMs << "min:" << mMinResponseTime << "max:" << mMaxResponseTime << "avg:" << mAvgResponseTime << "med:" << mMedResponseTime;
|
qDebug() << "[response time] now:" << elapsedMs << "min:" << mMinResponseTime << "max:" << mMaxResponseTime << "avg:" << mAvgResponseTime << "med:" << mMedResponseTime;
|
||||||
|
|
||||||
|
// TODO: use these statistics to send a deferred request a bit earlier
|
||||||
|
|
||||||
// Handle deferred request
|
// Handle deferred request
|
||||||
if(mNextRequired)
|
if(mNextRequired)
|
||||||
{
|
{
|
||||||
@ -269,6 +317,7 @@ void RemoteTable::handleTableResponse(const TableResponse & response)
|
|||||||
mOverlay->setVisible(false);
|
mOverlay->setVisible(false);
|
||||||
|
|
||||||
// Update the displayed data with the final response
|
// Update the displayed data with the final response
|
||||||
|
mRemoteTableOffset = mCurrentRequest.offset;
|
||||||
mRemoteData = std::move(response.rows);
|
mRemoteData = std::move(response.rows);
|
||||||
updateViewport();
|
updateViewport();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <QWebSocket>
|
#include <QWebSocket>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QTimer>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
class RemoteTable : public AbstractStdTable, public MagicMenu<RemoteTable>
|
class RemoteTable : public AbstractStdTable, public MagicMenu<RemoteTable>
|
||||||
@ -24,6 +25,7 @@ protected:
|
|||||||
void sortRows(duint column, bool ascending) override;
|
void sortRows(duint column, bool ascending) override;
|
||||||
duint sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta) override;
|
duint sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta) override;
|
||||||
void prepareData() override;
|
void prepareData() override;
|
||||||
|
void wheelEvent(QWheelEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum ColumnIndex
|
enum ColumnIndex
|
||||||
@ -32,15 +34,18 @@ private:
|
|||||||
ColData,
|
ColData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Epoch = std::chrono::time_point<std::chrono::system_clock>;
|
||||||
|
|
||||||
|
duint mRemoteTableOffset = 0;
|
||||||
std::vector<std::vector<std::string>> mRemoteData;
|
std::vector<std::vector<std::string>> mRemoteData;
|
||||||
std::chrono::time_point<std::chrono::system_clock> mLastPrepare;
|
Epoch mLastPrepare;
|
||||||
|
|
||||||
QWebSocket mSocket;
|
QWebSocket mSocket;
|
||||||
JsonRpcClient mRpc;
|
JsonRpcClient mRpc;
|
||||||
|
|
||||||
TableRequest mCurrentRequest;
|
TableRequest mCurrentRequest;
|
||||||
bool mCurrentSent = false;
|
bool mCurrentSent = false;
|
||||||
std::chrono::time_point<std::chrono::system_clock> mCurrentSentTime;
|
Epoch mCurrentSentTime;
|
||||||
|
|
||||||
TableRequest mNextRequest;
|
TableRequest mNextRequest;
|
||||||
bool mNextRequired = false;
|
bool mNextRequired = false;
|
||||||
@ -53,6 +58,11 @@ private:
|
|||||||
uint64_t mAvgResponseTime = 100;
|
uint64_t mAvgResponseTime = 100;
|
||||||
uint64_t mMedResponseTime = 100;
|
uint64_t mMedResponseTime = 100;
|
||||||
|
|
||||||
|
QTimer* mScrollTimer = nullptr;
|
||||||
|
dsint mScrollDelta = 0;
|
||||||
|
Epoch mScrollStart;
|
||||||
|
std::deque<std::pair<Epoch, dsint>> mScrollEvents;
|
||||||
|
|
||||||
void handleTableResponse(const TableResponse & response);
|
void handleTableResponse(const TableResponse & response);
|
||||||
void setupMenu();
|
void setupMenu();
|
||||||
void setupConnection();
|
void setupConnection();
|
||||||
|
Loading…
Reference in New Issue
Block a user