fix: add back cache for window preview to avoid lag#1240
Conversation
Reviewer's guide (collapsed on small PRs)Reviewer's GuideReintroduce caching for window previews using a static QHash to avoid repeated D-Bus calls and reduce UI lag. The cache is checked before fetching, populated after a successful fetch, and invalidated on window close and model changes. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `panels/dock/taskmanager/x11preview.cpp:132` </location>
<code_context>
::close(fd[0]);
auto pixmap = QPixmap::fromImage(image);
+ if (!pixmap.isNull()) {
+ s_windowPreviewCache.insert(winId, pixmap);
+ }
+
</code_context>
<issue_to_address>
Consider cache invalidation strategy for window previews.
The cache may become outdated if window contents change without triggering rowsRemoved or window close. Consider adding more invalidation triggers if this could cause issues.
</issue_to_address>
### Comment 2
<location> `panels/dock/taskmanager/x11preview.cpp:429` </location>
<code_context>
if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [this]() {
+ // 当窗口被移除时,清理相关缓存
+ s_windowPreviewCache.clear();
// 延迟调用,确保视图完全更新后再计算大小
QTimer::singleShot(0, this, [this]() {
</code_context>
<issue_to_address>
Clearing the entire cache on rowsRemoved may be excessive.
Instead of clearing the entire cache, remove only the entries for the windows that were actually removed to prevent unnecessary cache misses for remaining windows.
Suggested implementation:
```cpp
if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this,
[this](const QModelIndex &parent, int first, int last) {
// 只清理被移除窗口的缓存
if (m_sourceModel) {
for (int row = first; row <= last; ++row) {
QModelIndex idx = m_sourceModel->index(row, 0, parent);
QVariant windowIdVar = m_sourceModel->data(idx, WindowIdRole); // 假设WindowIdRole为窗口ID的role
if (windowIdVar.isValid()) {
s_windowPreviewCache.remove(windowIdVar.toUInt());
}
}
}
// 延迟调用,确保视图完全更新后再计算大小
QTimer::singleShot(0, this, [this]() {
if (m_sourceModel) {
```
- Make sure that `WindowIdRole` is defined and used as the role for window IDs in your model. If your model uses a different role or method to get the window ID, adjust the code accordingly.
- If your model does not provide window IDs via a role, you may need to adapt the cache removal logic to match your data structure.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| if (!pixmap.isNull()) { | ||
| s_windowPreviewCache.insert(winId, pixmap); |
There was a problem hiding this comment.
question: Consider cache invalidation strategy for window previews.
The cache may become outdated if window contents change without triggering rowsRemoved or window close. Consider adding more invalidation triggers if this could cause issues.
| if (sourceModel) { | ||
| connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [this]() { | ||
| // 当窗口被移除时,清理相关缓存 | ||
| s_windowPreviewCache.clear(); |
There was a problem hiding this comment.
suggestion: Clearing the entire cache on rowsRemoved may be excessive.
Instead of clearing the entire cache, remove only the entries for the windows that were actually removed to prevent unnecessary cache misses for remaining windows.
Suggested implementation:
if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this,
[this](const QModelIndex &parent, int first, int last) {
// 只清理被移除窗口的缓存
if (m_sourceModel) {
for (int row = first; row <= last; ++row) {
QModelIndex idx = m_sourceModel->index(row, 0, parent);
QVariant windowIdVar = m_sourceModel->data(idx, WindowIdRole); // 假设WindowIdRole为窗口ID的role
if (windowIdVar.isValid()) {
s_windowPreviewCache.remove(windowIdVar.toUInt());
}
}
}
// 延迟调用,确保视图完全更新后再计算大小
QTimer::singleShot(0, this, [this]() {
if (m_sourceModel) {
- Make sure that
WindowIdRoleis defined and used as the role for window IDs in your model. If your model uses a different role or method to get the window ID, adjust the code accordingly. - If your model does not provide window IDs via a role, you may need to adapt the cache removal logic to match your data structure.
| // 建立模型变化监听(只在模型真正变化时建立) | ||
| if (sourceModel) { | ||
| connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [this]() { | ||
| // 当窗口被移除时,清理相关缓存 |
There was a problem hiding this comment.
这个缓存是不是缓存的时间太长了,导致窗口状态可能不太对,
是不是应该在重新show出来时就把之前的给删掉,
There was a problem hiding this comment.
那应该说是在 hide 的时候就清除掉缓存可能更合适吧?我刚在 callHide() 里加了一个,代码已更新。
a0cd35c to
a561ccb
Compare
| if (!WM_HELPER->hasComposite()) | ||
| return QPixmap(); | ||
|
|
||
| if (s_windowPreviewCache.contains(winId)) { |
There was a problem hiding this comment.
这样加缓存的话,以后就不好用多线程来扩展优化了吧,
这里能不能不用静态变量,在调用这个接口的的地方去做缓存,
旧的实现中,在预览窗口自己持有的模型中缓存了预览图. 改为新模型后, 预览图每次都是重新获取的. 获取预览图是 dbus 调用, 会导致卡顿. 因此 这里把缓存以另一种形式加回来. Log:
a561ccb to
ab753fa
Compare
|
cache的代码弄丢了? |
我可能后来推错分支了。。我下周确认下 |
ab753fa to
2a849f4
Compare
deepin pr auto review我对这个代码变更进行了审查,主要关注了语法逻辑、代码质量、性能和安全性。以下是我的改进建议: 语法逻辑
代码质量
性能
安全性
具体改进建议代码:// 添加缓存大小限制和过期机制
static const int MAX_CACHE_SIZE = 100; // 最大缓存条目数
static const int CACHE_EXPIRY_SECONDS = 300; // 缓存过期时间(秒)
struct CacheEntry {
QPixmap pixmap;
QDateTime timestamp;
};
static QHash<uint32_t, CacheEntry> s_windowPreviewCache;
static QMutex s_cacheMutex; // 用于线程安全
QPixmap fetchWindowPreview(const uint32_t &winId) {
QMutexLocker locker(&s_cacheMutex);
// 检查缓存是否存在且未过期
if (s_windowPreviewCache.contains(winId)) {
auto entry = s_windowPreviewCache.value(winId);
if (entry.timestamp.secsTo(QDateTime::currentDateTime()) < CACHE_EXPIRY_SECONDS) {
return entry.pixmap;
}
s_windowPreviewCache.remove(winId);
}
// 获取新图像...
QPixmap pixmap = ...; // 原有获取图像的代码
// 更新缓存
if (!pixmap.isNull()) {
// 检查缓存大小
if (s_windowPreviewCache.size() >= MAX_CACHE_SIZE) {
// 移除最旧的条目
uint32_t oldestId = 0;
QDateTime oldestTime = QDateTime::currentDateTime();
for (auto it = s_windowPreviewCache.constBegin(); it != s_windowPreviewCache.constEnd(); ++it) {
if (it.value().timestamp < oldestTime) {
oldestTime = it.value().timestamp;
oldestId = it.key();
}
}
s_windowPreviewCache.remove(oldestId);
}
CacheEntry entry{pixmap, QDateTime::currentDateTime()};
s_windowPreviewCache.insert(winId, entry);
}
return pixmap;
}
// 在窗口关闭时只移除特定窗口的缓存
void closeWindow(uint32_t winId) {
QMutexLocker locker(&s_cacheMutex);
s_windowPreviewCache.remove(winId);
X11Utils::instance()->closeWindow(winId);
}这些改进可以提高代码的性能、安全性和可维护性,同时减少内存泄漏和资源浪费的风险。 |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: 18202781743, BLumia The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
旧的实现中,在预览窗口自己持有的模型中缓存了预览图. 改为新模型后,
预览图每次都是重新获取的. 获取预览图是 dbus 调用, 会导致卡顿. 因此
这里把缓存以另一种形式加回来.
Summary by Sourcery
Restore caching of window preview pixmaps to reduce lag from repeated DBus calls and ensure cache consistency by invalidating entries on window close and model changes
Bug Fixes:
Enhancements: