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),
|
||||
ui(new Ui::OverlayFrame)
|
||||
{
|
||||
// TODO: forward the scroll/key events to the window below
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
|
@ -43,36 +43,57 @@ RemoteTable::RemoteTable(QWidget* parent)
|
||||
setRowCount(0x2000ull);
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: get data from a container that's aware of the outgoing requests
|
||||
// (perhaps this should be done transparently in the request/response handling?)
|
||||
auto relativeRow = row - getTableOffset();
|
||||
// Show the real row number for debugging purposes
|
||||
QString base;
|
||||
if(col == 0)
|
||||
{
|
||||
base = QString("[row: %1] ").arg(row, 5);
|
||||
}
|
||||
if(relativeRow < mRemoteData.size())
|
||||
{
|
||||
const auto & remoteRow = mRemoteData[relativeRow];
|
||||
QString data;
|
||||
if(col < remoteRow.size())
|
||||
{
|
||||
data = QString::fromStdString(remoteRow[col]);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = "(BAD SERVER)";
|
||||
}
|
||||
return base + data;
|
||||
}
|
||||
else
|
||||
|
||||
// Ignore out of range data
|
||||
dsint relativeRow = row - mRemoteTableOffset;
|
||||
if(relativeRow < 0 || relativeRow >= mRemoteData.size())
|
||||
{
|
||||
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)
|
||||
@ -94,6 +115,14 @@ void RemoteTable::sortRows(duint column, bool ascending)
|
||||
|
||||
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]()
|
||||
{
|
||||
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 some basic prediction heuristics (scroll direction etc) to anticipate
|
||||
// the scroll (request a bigger range)
|
||||
// TODO: measure the ping
|
||||
// TODO: implement partial reuse of the data
|
||||
|
||||
TableRequest r;
|
||||
r.offset = offset;
|
||||
r.lines = linesToPrint;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
|
||||
// TODO: use these statistics to send a deferred request a bit earlier
|
||||
|
||||
// Handle deferred request
|
||||
if(mNextRequired)
|
||||
{
|
||||
@ -269,6 +317,7 @@ void RemoteTable::handleTableResponse(const TableResponse & response)
|
||||
mOverlay->setVisible(false);
|
||||
|
||||
// Update the displayed data with the final response
|
||||
mRemoteTableOffset = mCurrentRequest.offset;
|
||||
mRemoteData = std::move(response.rows);
|
||||
updateViewport();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <QWebSocket>
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include <deque>
|
||||
|
||||
class RemoteTable : public AbstractStdTable, public MagicMenu<RemoteTable>
|
||||
@ -24,6 +25,7 @@ protected:
|
||||
void sortRows(duint column, bool ascending) override;
|
||||
duint sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta) override;
|
||||
void prepareData() override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
private:
|
||||
enum ColumnIndex
|
||||
@ -32,15 +34,18 @@ private:
|
||||
ColData,
|
||||
};
|
||||
|
||||
using Epoch = std::chrono::time_point<std::chrono::system_clock>;
|
||||
|
||||
duint mRemoteTableOffset = 0;
|
||||
std::vector<std::vector<std::string>> mRemoteData;
|
||||
std::chrono::time_point<std::chrono::system_clock> mLastPrepare;
|
||||
Epoch mLastPrepare;
|
||||
|
||||
QWebSocket mSocket;
|
||||
JsonRpcClient mRpc;
|
||||
|
||||
TableRequest mCurrentRequest;
|
||||
bool mCurrentSent = false;
|
||||
std::chrono::time_point<std::chrono::system_clock> mCurrentSentTime;
|
||||
Epoch mCurrentSentTime;
|
||||
|
||||
TableRequest mNextRequest;
|
||||
bool mNextRequired = false;
|
||||
@ -53,6 +58,11 @@ private:
|
||||
uint64_t mAvgResponseTime = 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 setupMenu();
|
||||
void setupConnection();
|
||||
|
Loading…
Reference in New Issue
Block a user