forked from qt-creator/qt-creator
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:
@@ -22,29 +22,20 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFontDatabase>
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QFontDatabase>
|
||||||
#include <QLibraryInfo>
|
#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 <QMessageBox>
|
||||||
|
#include <QNetworkProxyFactory>
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QScopeGuard>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTemporaryDir>
|
#include <QStyle>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QThreadPool>
|
||||||
|
#include <QTranslator>
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -589,11 +580,12 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
SharedTools::QtSingleApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
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)),
|
std::unique_ptr<SharedTools::QtSingleApplication>
|
||||||
numberofArguments,
|
appPtr(SharedTools::createApplication(QLatin1String(Core::Constants::IDE_DISPLAY_NAME),
|
||||||
options.appArguments.data());
|
numberOfArguments, options.appArguments.data()));
|
||||||
|
SharedTools::QtSingleApplication &app = *appPtr;
|
||||||
QCoreApplication::setApplicationName(Core::Constants::IDE_CASED_ID);
|
QCoreApplication::setApplicationName(Core::Constants::IDE_CASED_ID);
|
||||||
QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG));
|
QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG));
|
||||||
QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR));
|
QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR));
|
||||||
|
|||||||
@@ -148,13 +148,11 @@ void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessag
|
|||||||
disconnect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
|
disconnect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QWidget* QtSingleApplication::activationWindow() const
|
QWidget* QtSingleApplication::activationWindow() const
|
||||||
{
|
{
|
||||||
return actWin;
|
return actWin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void QtSingleApplication::activateWindow()
|
void QtSingleApplication::activateWindow()
|
||||||
{
|
{
|
||||||
if (actWin) {
|
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
|
} // namespace SharedTools
|
||||||
|
|||||||
@@ -46,4 +46,7 @@ private:
|
|||||||
bool block;
|
bool block;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Instantiates Freeze Detector when QTC_FREEZE_DETECTOR env var is set.
|
||||||
|
QtSingleApplication *createApplication(const QString &id, int &argc, char **argv);
|
||||||
|
|
||||||
} // namespace SharedTools
|
} // namespace SharedTools
|
||||||
|
|||||||
Reference in New Issue
Block a user