Skip to content

Commit

Permalink
split tile queue into per-canonical-viewid queues
Browse files Browse the repository at this point in the history
handle the queue associated with the least inactive session first.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: Ib14932b20f90d634dca35e9eacef8b005a4a20b7
  • Loading branch information
caolanm committed Feb 27, 2025
1 parent 65655b5 commit 89aaaef
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 37 deletions.
4 changes: 0 additions & 4 deletions kit/ChildSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1285,10 +1285,6 @@ float ChildSession::getTilePriority(const std::chrono::steady_clock::time_point
if (tile.intersects(_cursorPosition))
score *= 2.0;

// interacted with the keyboard/mouse recently ?
if (getInactivityMS(now) < 200 /* ms */) // typing etc.
score *= 2.0;

// pre-loading near the viewing area is also more important than far away
Util::Rectangle r = tile.toAABBox();
// grow in each direction
Expand Down
31 changes: 30 additions & 1 deletion kit/Kit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,35 @@ float Document::getTilePriority(const std::chrono::steady_clock::time_point &now
return maxPrio;
}

std::vector<TilePrioritizer::ViewIdInactivity> Document::getViewIdsByInactivity() const
{
std::vector<TilePrioritizer::ViewIdInactivity> viewIds;

assert(_sessions.size() > 0);
for (const auto& it : _sessions)
{
const std::shared_ptr<ChildSession> &session = it.second;

double sessionInactivity = session->getInactivityMS();
int viewId = session->getCanonicalViewId();

auto found = std::find_if(viewIds.begin(), viewIds.end(),
[viewId](const auto& entry)->bool {
return entry.first == viewId;
});
if (found == viewIds.end())
viewIds.emplace_back(viewId, sessionInactivity);
else if (sessionInactivity < found->second)
found->second = sessionInactivity;
}

std::sort(viewIds.begin(), viewIds.end(), [](const auto& a, const auto& b) {
return a.second < b.second;
});

return viewIds;
}

// poll is idle, are we ?
void Document::checkIdle()
{
Expand Down Expand Up @@ -2460,7 +2489,7 @@ void Document::drainQueue()
if (canRenderTiles())
{
float prio = 8; // visible & intersect with an active viewport
while (_queue->getTileQueueSize() > 0 && prio >= 8)
while (!_queue->isTileQueueEmpty() && prio >= 8)
{
TileCombined tileCombined = _queue->popTileQueue(prio);
LOG_TRC("Tile priority is " << prio << " for " << tileCombined.serialize());
Expand Down
3 changes: 2 additions & 1 deletion kit/Kit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ class Document final : public std::enable_shared_from_this<Document>, private Ti

/// Calculate tile rendering priority from a TileDesc
virtual float getTilePriority(const std::chrono::steady_clock::time_point &now, const TileDesc &desc) const override;
virtual std::vector<ViewIdInactivity> getViewIdsByInactivity() const override;

public:
/// Request loading a document, or a new view, if one exists,
Expand Down Expand Up @@ -343,7 +344,7 @@ class Document final : public std::enable_shared_from_this<Document>, private Ti
bool canRenderTiles() const {
return processInputEnabled() && !isLoadOngoing() &&
!isBackgroundSaveProcess() && _queue &&
_queue->getTileQueueSize() > 0;
!_queue->isTileQueueEmpty();
}
bool hasCallbacks() const { return _queue && _queue->callbackSize() > 0; }

Expand Down
147 changes: 121 additions & 26 deletions kit/KitQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,37 @@ void KitQueue::put(const Payload& value)
_queue.emplace_back(value);
}

std::vector<TileDesc>* KitQueue::getTileQueue(int viewid)
{
for (auto& queue : _tileQueues)
{
if (queue.first == viewid)
return &queue.second;
}
return nullptr;
}

std::vector<TileDesc>& KitQueue::ensureTileQueue(int viewid)
{
std::vector<TileDesc>* tileQueue = getTileQueue(viewid);
if (tileQueue)
return *tileQueue;
return _tileQueues.emplace_back(viewid, std::vector<TileDesc>()).second;
}

void KitQueue::removeTileDuplicate(const TileDesc &desc)
{
for (size_t i = 0; i < _tileQueue.size(); ++i)
std::vector<TileDesc>* viewQueue = getTileQueue(desc.getNormalizedViewId());
if (!viewQueue)
return;
for (size_t i = 0; i < viewQueue->size(); ++i)
{
auto& it = _tileQueue[i];
auto& it = (*viewQueue)[i];
if (it == desc)
{
LOG_TRC("Remove duplicate tile request: " << it.serialize() <<
" -> " << desc.serialize());
_tileQueue.erase(_tileQueue.begin() + i);
viewQueue->erase(viewQueue->begin() + i);
break;
}
}
Expand Down Expand Up @@ -387,16 +408,20 @@ bool KitQueue::elideDuplicateCallback(int view, int type, const std::string &pay
// we process all previews in the same batch of rendering
void KitQueue::deprioritizePreviews()
{
for (size_t i = 0; i < _tileQueue.size(); ++i)
for (auto& queue : _tileQueues)
{
const TileDesc front = _tileQueue.front();
std::vector<TileDesc>& tileQueue = queue.second;
for (size_t i = 0; i < tileQueue.size(); ++i)
{
const TileDesc front = tileQueue.front();

// stop at the first non-tile or non-'id' (preview) message
if (!front.isPreview())
break;
// stop at the first non-tile or non-'id' (preview) message
if (!front.isPreview())
break;

_tileQueue.erase(_tileQueue.begin());
_tileQueue.push_back(front);
tileQueue.erase(tileQueue.begin());
tileQueue.push_back(front);
}
}
}

Expand All @@ -417,13 +442,54 @@ KitQueue::Payload KitQueue::pop()

TileCombined KitQueue::popTileQueue(float &priority)
{
assert(!_tileQueue.empty());
assert(!isTileQueueEmpty());

std::vector<TileDesc>* tileQueue(nullptr);

// canonical viewIds in order of least inactive to highest
auto viewIdsByPrio = _prio.getViewIdsByInactivity();

// find which queue has tiles for the least inactive canonical viewId
for (const auto& viewIdEntry : viewIdsByPrio)
{
auto found = std::find_if(_tileQueues.begin(), _tileQueues.end(),
[viewIdEntry](const auto& queue) {
return viewIdEntry.first == queue.first && !queue.second.empty();
});
if (found != _tileQueues.end())
{
tileQueue = &found->second;
break;
}
}

// This shouldn't happen, but if it does, pick something to pop from
if (!tileQueue)
{
LOG_ERR("No existing session for any tiles in queue.");
for (auto& queue : _tileQueues)
{
if (queue.second.empty())
continue;
tileQueue = &queue.second;
break;
}
}

assert(tileQueue);

return popTileQueue(*tileQueue, priority);
}

TileCombined KitQueue::popTileQueue(std::vector<TileDesc>& tileQueue, float &priority)
{
assert(!tileQueue.empty());

const auto now = std::chrono::steady_clock::now();

LOG_TRC("KitQueue depth: " << _tileQueue.size());
LOG_TRC("KitQueue depth: " << tileQueue.size());

TileDesc msg = _tileQueue.front();
TileDesc msg = tileQueue.front();

// vector of tiles we will render
std::vector<TileDesc> tiles;
Expand All @@ -432,9 +498,9 @@ TileCombined KitQueue::popTileQueue(float &priority)
// position, otherwise handle the one that is at the front
int prioritized = 0;
float prioritySoFar = -1000.0;
for (size_t i = 0; i < _tileQueue.size(); ++i)
for (size_t i = 0; i < tileQueue.size(); ++i)
{
auto& prio = _tileQueue[i];
auto& prio = tileQueue[i];

const float p = _prio.getTilePriority(now, prio);
if (p > prioritySoFar)
Expand All @@ -446,30 +512,30 @@ TileCombined KitQueue::popTileQueue(float &priority)
}

// remove highest priority tile from the queue
_tileQueue.erase(_tileQueue.begin() + prioritized);
tileQueue.erase(tileQueue.begin() + prioritized);
priority = prioritySoFar;

// and add it to the render list
tiles.emplace_back(msg);

// Combine as many tiles as possible with this tile.
for (size_t i = 0; i < _tileQueue.size(); )
for (size_t i = 0; i < tileQueue.size(); )
{
auto& it = _tileQueue[i];
auto& it = tileQueue[i];

LOG_TRC("Combining candidate: " << it.serialize());

// Check if it's on the same row.
if (tiles[0].canCombine(it))
{
tiles.emplace_back(it);
_tileQueue.erase(_tileQueue.begin() + i);
tileQueue.erase(tileQueue.begin() + i);
}
else
++i;
}

LOG_TRC("Combined " << tiles.size() << " tiles, leaving " << _tileQueue.size() << " in queue.");
LOG_TRC("Combined " << tiles.size() << " tiles, leaving " << tileQueue.size() << " in queue.");

if (tiles.size() == 1)
{
Expand Down Expand Up @@ -549,10 +615,12 @@ void KitQueue::pushTileCombineRequest(const Payload &value)
// the tiles inside popTileQueue() again)
const std::string msg = std::string(value.data(), value.size());
const TileCombined tileCombined = TileCombined::parse(msg);

std::vector<TileDesc>& tileQueue = ensureTileQueue(tileCombined.getNormalizedViewId());
for (const auto& tile : tileCombined.getTiles())
{
removeTileDuplicate(tile);
_tileQueue.emplace_back(tile);
tileQueue.emplace_back(tile);
}
}

Expand All @@ -561,7 +629,28 @@ void KitQueue::pushTileQueue(const Payload &value)
const std::string msg = std::string(value.data(), value.size());
const TileDesc desc = TileDesc::parse(msg);
removeTileDuplicate(desc);
_tileQueue.push_back(desc);
std::vector<TileDesc>& tileQueue = ensureTileQueue(desc.getNormalizedViewId());
tileQueue.push_back(desc);
}

size_t KitQueue::getTileQueueSize() const
{
size_t queuedTiles(0);

for (const auto& queue : _tileQueues)
queuedTiles += queue.second.size();

return queuedTiles;
}

bool KitQueue::isTileQueueEmpty() const
{
for (const auto& queue : _tileQueues)
{
if (!queue.second.empty())
return false;
}
return true;
}

std::string KitQueue::combineRemoveText(const StringVector& tokens)
Expand Down Expand Up @@ -627,10 +716,16 @@ void KitQueue::dumpState(std::ostream& oss)
for (Payload &it : _queue)
oss << "\t\t" << i++ << ": " << COOLProtocol::getFirstLine(it) << "\n";

oss << "\tTile Queue size: " << _tileQueue.size() << "\n";
i = 0;
for (TileDesc &it : _tileQueue)
oss << "\t\t" << i++ << ": " << it.serialize() << "\n";
oss << "\tTile Queues count: " << _tileQueues.size() << "\n";
for (auto& queue : _tileQueues)
{
int viewId = queue.first;
const std::vector<TileDesc>& tileQueue = queue.second;
oss << "\t\tTile Queue size: " << tileQueue.size() << " viewId: " << viewId << "\n";
i = 0;
for (const TileDesc &it : tileQueue)
oss << "\t\t\t" << i++ << ": " << it.serialize() << "\n";
}

oss << "\tCallbacks size: " << _callbacks.size() << "\n";
i = 0;
Expand Down
18 changes: 13 additions & 5 deletions kit/KitQueue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class TilePrioritizer
public:
virtual ~TilePrioritizer() {}
virtual float getTilePriority(const std::chrono::steady_clock::time_point &, const TileDesc &) const { return 0.0; }
typedef std::pair<int, float> ViewIdInactivity;
virtual std::vector<ViewIdInactivity> getViewIdsByInactivity() const { return {}; }
};

/// Queue for handling the Kit's messaging needs
Expand Down Expand Up @@ -83,14 +85,15 @@ class KitQueue
Payload pop();
Payload get() { return pop(); }

/// Tiles are special manage a separate queue of them
void clearTileQueue() { _tileQueue.clear(); }
/// Tiles are special manage separate queues of them
void clearTileQueue() { _tileQueues.clear(); }
void pushTileQueue(const Payload &value);
void pushTileCombineRequest(const Payload &value);
/// Pops the highest priority TileCombined from the
/// render queue, with it's priority.
TileCombined popTileQueue(float &priority);
size_t getTileQueueSize() const { return _tileQueue.size(); }
size_t getTileQueueSize() const;
bool isTileQueueEmpty() const;

/// Obtain the next callback
Callback getCallback()
Expand Down Expand Up @@ -168,12 +171,17 @@ class KitQueue
/// the queue.
void deprioritizePreviews();

std::vector<TileDesc>* getTileQueue(int viewid);
std::vector<TileDesc>& ensureTileQueue(int viewid);
TileCombined popTileQueue(std::vector<TileDesc>& tileQueue, float &priority);

private:
/// Queue of incoming messages from coolwsd
std::vector<Payload> _queue;

/// Queue of incoming tile requests from coolwsd
std::vector<TileDesc> _tileQueue;
/// Queues of incoming tile requests from coolwsd
typedef std::pair<int, std::vector<TileDesc>> viewTileQueue;
std::vector<viewTileQueue> _tileQueues;

/// Queue of callbacks from Kit to send out to coolwsd
std::vector<Callback> _callbacks;
Expand Down

0 comments on commit 89aaaef

Please sign in to comment.