电脑管家远程功能是使用qt编写的进程,启动耗时过长,导致用户体验较差
qt版本:5.15.2
模块签名时间:2020年11月6日
利用微软官方提供的WPA来进行分析,录制etl打开
Graph Explorer -> Computation -> CPU Usage(Sampled)
这里需要注意区分:
在ETL(Event Tracing for Windows)分析中,CPU Usage(CPU使用率)是用于分析系统CPU性能的一种事件跟踪功能。通过分析CPU Usage事件,可以了解系统中各个进程和线程的CPU使用情况,以及系统整体的CPU负载情况。在ETL中,CPU Usage事件有以下几种类型:
CPU Usage:表示系统整体的CPU使用率。这种事件通常是由系统定时器触发,定期记录系统CPU使用情况。CPU Usage事件包含了系统CPU使用率的总体情况,例如CPU占用率、空闲率、中断率、DPC率等。
CPU Sampling:表示对进程或线程的CPU使用率进行采样。这种事件通常是由性能计数器或其他工具触发,定期对进程或线程的CPU使用率进行采样。CPU Sampling事件包含了进程或线程的CPU使用率、调用栈信息等。
CPU Time:表示进程或线程的CPU使用时间。这种事件通常是由进程或线程自身触发,记录进程或线程的CPU使用时间。CPU Time事件包含了进程或线程的CPU使用时间、调用栈信息等。
在分析CPU Usage事件时,需要注意区分不同类型的事件,以便进行针对性的分析和优化。例如,如果系统整体的CPU使用率过高,可以分析CPU Usage事件,找出占用CPU的进程或线程;如果某个进程或线程的CPU使用率过高,可以分析CPU Sampling或CPU Time事件,找出具体的CPU使用情况和性能瓶颈。
1、进程启动在第4.862秒
2、qwindows.dll!qt_getCanonicalFontNames触发了gdi32full.dll!EnumFontFamiliesExW从5.068s执行到5.824s,约莫耗时0.89s也就是756ms
初步怀疑是qt组件出现bug,导致EnumFontFamiliesExW调用过多,尝试进一步定位
查阅文档知道qt程序会在初次使用字体的组件(例如text)渲染之前,枚举本地的字体库并尝试缓存所有的回退字体列表。
针对qt_getCanonicalFontNames查询源码,参考5.15.2的官方源码
// qtbase\src\platformsupport\fontdatabases\windows\qwindowsfontdatabase.cpp
void QWindowsFontDatabase::populateFamily(const QString &familyName)
{
// ***
EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&sfp), 0);
// ***
}
static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
DWORD type, LPARAM lparam)
{
// ***
addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp);
// keep on enumerating
return 1;
}
static bool addFontToDatabase(QString familyName,
QString styleName,
const LOGFONT &logFont,
const TEXTMETRIC *textmetric,
const FONTSIGNATURE *signature,
int type,
StoreFontPayload *sfp)
{
//
QFontNames canonicalNames = qt_getCanonicalFontNames(logFont);
//
}
// qtbase\src\gui\text\qfontdatabase.cpp
void QtFontFamily::ensurePopulated()
{
if (populated)
return;
QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamily(name);
Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name));
}
// qtbase\src\gui\text\qfontdatabase.cpp
/*!
Returns a list of alternative fonts for the specified \a family and
\a style and \a script using the \a styleHint given.
Default implementation returns a list of fonts for which \a style and \a script support
has been reported during the font database population.
*/
QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
{
// ***
for (int i = 0; i < db->count; ++i) {
QtFontFamily *f = db->families[i];
f->ensurePopulated();
// ****
}
return preferredFallbacks + otherFallbacks;
}
针对fallbacksForFamily进一步查阅qt的bug发现:qtbug-71737
堆栈原因与我们出现的逻辑类似,这是摘取的简介
当从 Qt 4.8.7 切换到 Qt 5.9.7 时,我们注意到 Windows 10 上的应用程序启动存在明显的延迟。根据安装的字体数量,即使在快速工作站上,延迟也在大约 500 毫秒到 1 秒之间。我们可以将问题范围缩小到由 QPlatformFontDatabase::fallbacksForFamily 创建的系列回退缓存,这会导致每个字体系列大约有 500 到 1000 个回退列表。首次创建此大型回退字体列表需要花费大量时间。可以使用测试程序重现该问题:main.cpp。在第一个 paintEvent 中,将创建字体系列回退缓存列表。这会导致在 Windows 10 上显示空白按钮和按钮文本之间出现明显的延迟。
至此,大致上可以确定原因,但是如何修复呢,参考了qt的codereview可以看到此bug已经进行了修复
对于5.15.2版本源码可以看到此修复MR并没有在里面,故可以确定5.15.2版本的qt仍存在此问题
// 5.15.2源码:qtbase\src\gui\text\qfontengine.cpp
void QFontEngineMulti::ensureEngineAt(int at)
{
if (!m_fallbackFamiliesQueried)
ensureFallbackFamiliesQueried();
Q_ASSERT(at < m_engines.size());
if (!m_engines.at(at)) {
QFontEngine *engine = loadEngine(at);
if (!engine)
engine = new QFontEngineBox(fontDef.pixelSize);
Q_ASSERT(engine && engine->type() != QFontEngine::Multi);
engine->ref.ref();
m_engines[at] = engine;
}
}
挑选5.15.2后面的版本,例如5.15.6
查看官方源码:源码
// 5.15.6 \qtbase\src\gui\text\qfontengine.cpp
void QFontEngineMulti::ensureEngineAt(int at)
{
if (!m_fallbackFamiliesQueried && at > 0)
ensureFallbackFamiliesQueried();
Q_ASSERT(at < m_engines.size());
if (!m_engines.at(at)) {
QFontEngine *engine = loadEngine(at);
if (!engine)
engine = new QFontEngineBox(fontDef.pixelSize);
Q_ASSERT(engine && engine->type() != QFontEngine::Multi);
engine->ref.ref();
m_engines[at] = engine;
}
}
了解到5.15.6已经解决此问题,下载此模块32位版本替换:下载链接
替换后重新录制etl,对比EnumFontFamiliesExW执行时间从5.870s执行到6.205s(耗时0.335s),说明模块替换有效
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。