QtSingleApplication: Introduce QTC_FREEZE_DETECTOR env var

This may help with tracking the freezes in main thread.
By default, when QTC_FREEZE_DETECTOR is set, it detects
freezes above the 100 ms and prints the receiver object
and event type that triggered the freeze.

Change the default 100 ms threshold by setting the
QTC_FREEZE_DETECTOR to some different numeric value.

Change-Id: Ifb68c7648c09a5329f1f2aa39cd7e29e69a76052
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jarek Kobus
2023-05-02 19:47:49 +02:00
parent de247bff2b
commit a059f87754
3 changed files with 81 additions and 22 deletions

View File

@@ -22,29 +22,20 @@
#include <QDebug>
#include <QDir>
#include <QFontDatabase>
#include <QFileInfo>
#include <QFontDatabase>
#include <QLibraryInfo>
#include <QScopeGuard>
#include <QStyle>
#include <QTextStream>
#include <QThreadPool>
#include <QTimer>
#include <QTranslator>
#include <QUrl>
#include <QVariant>
#include <QSysInfo>
#include <QNetworkProxyFactory>
#include <QApplication>
#include <QMessageBox>
#include <QNetworkProxyFactory>
#include <QPixmapCache>
#include <QProcess>
#include <QScopeGuard>
#include <QStandardPaths>
#include <QTemporaryDir>
#include <QStyle>
#include <QTextCodec>
#include <QTextStream>
#include <QThreadPool>
#include <QTranslator>
#include <iterator>
#include <optional>
@@ -589,11 +580,12 @@ int main(int argc, char **argv)
SharedTools::QtSingleApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
int numberofArguments = static_cast<int>(options.appArguments.size());
int numberOfArguments = static_cast<int>(options.appArguments.size());
SharedTools::QtSingleApplication app((QLatin1String(Core::Constants::IDE_DISPLAY_NAME)),
numberofArguments,
options.appArguments.data());
std::unique_ptr<SharedTools::QtSingleApplication>
appPtr(SharedTools::createApplication(QLatin1String(Core::Constants::IDE_DISPLAY_NAME),
numberOfArguments, options.appArguments.data()));
SharedTools::QtSingleApplication &app = *appPtr;
QCoreApplication::setApplicationName(Core::Constants::IDE_CASED_ID);
QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG));
QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR));

View File

@@ -148,13 +148,11 @@ void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessag
disconnect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
}
QWidget* QtSingleApplication::activationWindow() const
{
return actWin;
}
void QtSingleApplication::activateWindow()
{
if (actWin) {
@@ -164,4 +162,70 @@ void QtSingleApplication::activateWindow()
}
}
static const char s_freezeDetector[] = "QTC_FREEZE_DETECTOR";
static std::optional<int> isUsingFreezeDetector()
{
if (!qEnvironmentVariableIsSet(s_freezeDetector))
return {};
bool ok = false;
const int threshold = qEnvironmentVariableIntValue(s_freezeDetector, &ok);
return ok ? threshold : 100; // default value 100ms
}
class ApplicationWithFreezerDetector : public SharedTools::QtSingleApplication
{
public:
ApplicationWithFreezerDetector(const QString &id, int &argc, char **argv)
: QtSingleApplication(id, argc, argv)
, m_align(21, QChar::Space)
{}
void setFreezeTreshold(std::chrono::milliseconds freezeAbove) { m_threshold = freezeAbove; }
bool notify(QObject *receiver, QEvent *event) override {
using namespace std::chrono;
const auto start = system_clock::now();
const QPointer<QObject> p(receiver);
const QString className = QLatin1String(receiver->metaObject()->className());
const QString name = receiver->objectName();
const bool ret = QtSingleApplication::notify(receiver, event);
const auto end = system_clock::now();
const auto freeze = duration_cast<milliseconds>(end - start);
if (freeze > m_threshold) {
const QString time = QTime::currentTime().toString(Qt::ISODateWithMs);
qDebug().noquote() << QString("FREEZE [%1]").arg(time)
<< "of" << freeze.count() << "ms, on:" << event;
const QString receiverMessage = name.isEmpty()
? QString("receiver class: %1").arg(className)
: QString("receiver class: %1, object name: %2").arg(className, name);
qDebug().noquote() << m_align << receiverMessage;
if (!p)
qDebug().noquote() << m_align << "THE RECEIVER GOT DELETED inside the event filter!";
}
return ret;
}
private:
const QString m_align;
std::chrono::milliseconds m_threshold = std::chrono::milliseconds(100);
};
QtSingleApplication *createApplication(const QString &id, int &argc, char **argv)
{
const std::optional<int> freezeDetector = isUsingFreezeDetector();
if (!freezeDetector)
return new SharedTools::QtSingleApplication(id, argc, argv);
qDebug() << s_freezeDetector << "evn var is set. The freezes of main thread, above"
<< *freezeDetector << "ms, will be reported.";
qDebug() << "Change the freeze detection threshold by setting the" << s_freezeDetector
<< "env var to a different numeric value (in ms).";
ApplicationWithFreezerDetector *app = new ApplicationWithFreezerDetector(id, argc, argv);
app->setFreezeTreshold(std::chrono::milliseconds(*freezeDetector));
return app;
}
} // namespace SharedTools

View File

@@ -46,4 +46,7 @@ private:
bool block;
};
// Instantiates Freeze Detector when QTC_FREEZE_DETECTOR env var is set.
QtSingleApplication *createApplication(const QString &id, int &argc, char **argv);
} // namespace SharedTools