Source

Target

Commits (4)
  • Erik Verbruggen's avatar
    Fix animation benchmark · 17d9a17d
    Erik Verbruggen authored
    This was broken by 49a11e88
    
    .
    
    Change-Id: Ic7f261bce5e35b3dbcbdaf0b8718e08c56e55b39
    Reviewed-by: default avatarLars Knoll <lars.knoll@qt.io>
    17d9a17d
  • Erik Verbruggen's avatar
    Fix holistic benchmark · 0dbdfaa7
    Erik Verbruggen authored
    
    Each test now uses its own QQmlEngine, instead of using a single
    instance across all benchmarks. The effect is that peak heap usage
    (on macos) is now about 77MB, where it previously peaked at 770MB. This
    benchmark would actually crash on some platforms due to excessive
    malloc/mmap usage.
    
    Change-Id: I214f7b9b3d8c5565c0578b82c9c144ec87ed0f2b
    Reviewed-by: default avatarLars Knoll <lars.knoll@qt.io>
    0dbdfaa7
  • Mitch Curtis's avatar
    Allow QQmlComponent::loadUrl() to load absolute URLs with relative paths · 8836896d
    Mitch Curtis authored
    
    Currently, QQmlTypeLoader::getType() will assert if passed a relative
    URL, because it needs absolute URLs in order to ensure that it can use
    them as keys for its cache. After dc6b73390 was merged, URLs like
    QUrl::fromLocalFile("main.qml") (which are currently used in examples
    of how to load a QQmlComponent) started causing the assertion to fail.
    
    As mentioned in the comments of the bug report, some patches have
    already been applied to QQmlComponent's QString-based constructors,
    but both the constructors taking a QUrl and loadUrl() itself need
    fixing.
    
    This patch puts the fix into loadUrl() (the constructors call this
    function) so that every operation
    involving URLs is successful when using the documented methods.
    
    Task-number: QTBUG-58837
    Change-Id: Ib54ca52eddce6e7781cf96015f4c15af604233d3
    Reviewed-by: default avatarDavid Faure <david.faure@kdab.com>
    8836896d
  • Ulf Hermann's avatar
    Qml Profiling: Track signals globally · 529b4484
    Ulf Hermann authored
    
    Previously they were tracked per object sending them. This is not only
    too much overhead, but also confusing.
    
    Task-number: QTBUG-65190
    Change-Id: I4c374f2c3794a19cd825e8681d189107cef23813
    Reviewed-by: default avatarSimon Hausmann <simon.hausmann@qt.io>
    529b4484
Showing with 132 additions and 23 deletions
......@@ -234,9 +234,10 @@ public:
{
// Use the QV4::Function as ID, as that is common among different instances of the same
// component. QQmlBinding is per instance.
// Add 1 to the ID, to make it different from the IDs the V4 profiler produces. The +1 makes
// the pointer point into the middle of the QV4::Function. Thus it still points to valid
// memory but we cannot accidentally create a duplicate key from another object.
// Add 1 to the ID, to make it different from the IDs the V4 and signal handling profilers
// produce. The +1 makes the pointer point into the middle of the QV4::Function. Thus it
// still points to valid memory but we cannot accidentally create a duplicate key from
// another object.
quintptr locationId(id(function) + 1);
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), Binding,
......@@ -263,7 +264,12 @@ public:
void startHandlingSignal(QQmlBoundSignalExpression *expression)
{
quintptr locationId(id(expression));
// Use the QV4::Function as ID, as that is common among different instances of the same
// component. QQmlBoundSignalExpression is per instance.
// Add 2 to the ID, to make it different from the IDs the V4 and binding profilers produce.
// The +2 makes the pointer point into the middle of the QV4::Function. Thus it still points
// to valid memory but we cannot accidentally create a duplicate key from another object.
quintptr locationId(id(expression->function()) + 2);
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), HandlingSignal,
locationId));
......
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
//! [url-note]
Ensure that the URL provided is full and correct, in particular, use
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
Relative paths will be resolved against the engine's
\l {QQmlEngine::baseUrl}{baseUrl()}, which is the current working directory
unless specified.
//! [url-note]
......@@ -496,8 +496,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
Create a QQmlComponent from the given \a url and give it the
specified \a parent and \a engine.
Ensure that the URL provided is full and correct, in particular, use
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
\include qqmlcomponent.qdoc url-note
\sa loadUrl()
*/
......@@ -511,8 +510,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren
specified \a parent and \a engine. If \a mode is \l Asynchronous,
the component will be loaded and compiled asynchronously.
Ensure that the URL provided is full and correct, in particular, use
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
\include qqmlcomponent.qdoc url-note
\sa loadUrl()
*/
......@@ -548,7 +546,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : d->engine->baseUrl().resolved(QUrl(fileName));
const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : QUrl(fileName);
d->loadUrl(url, mode);
}
......@@ -608,8 +606,7 @@ QQmlContext *QQmlComponent::creationContext() const
/*!
Load the QQmlComponent from the provided \a url.
Ensure that the URL provided is full and correct, in particular, use
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
\include qqmlcomponent.qdoc url-note
*/
void QQmlComponent::loadUrl(const QUrl &url)
{
......@@ -621,8 +618,7 @@ void QQmlComponent::loadUrl(const QUrl &url)
Load the QQmlComponent from the provided \a url.
If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
Ensure that the URL provided is full and correct, in particular, use
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
\include qqmlcomponent.qdoc url-note
*/
void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
{
......@@ -635,11 +631,21 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
Q_Q(QQmlComponent);
clear();
if ((newUrl.isRelative() && !newUrl.isEmpty())
|| newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
url = engine->baseUrl().resolved(newUrl);
else
if (newUrl.isRelative()) {
// The new URL is a relative URL like QUrl("main.qml").
url = engine->baseUrl().resolved(QUrl(newUrl.toString()));
} else if (engine->baseUrl().isLocalFile() && newUrl.isLocalFile() && !QDir::isAbsolutePath(newUrl.toLocalFile())) {
// The new URL is a file on disk but it's a relative path; e.g.:
// QUrl::fromLocalFile("main.qml") or QUrl("file:main.qml")
// We need to remove the scheme so that it becomes a relative URL with a relative path:
QUrl fixedUrl(newUrl);
fixedUrl.setScheme(QString());
// Then, turn it into an absolute URL with an absolute path by resolving it against the engine's baseUrl().
// This is a compatibility hack for QTBUG-58837.
url = engine->baseUrl().resolved(fixedUrl);
} else {
url = newUrl;
}
if (newUrl.isEmpty()) {
QQmlError error;
......
import QtQml 2.0
QtObject {}
import QtQml 2.0
QtObject {}
......@@ -8,6 +8,8 @@ SOURCES += tst_qqmlcomponent.cpp \
HEADERS += ../../shared/testhttpserver.h
RESOURCES += data/QtObjectComponent.qml
include (../../shared/util.pri)
TESTDATA = data/*
......
......@@ -117,6 +117,8 @@ private slots:
void recursion();
void recursionContinuation();
void callingContextForInitialProperties();
void relativeUrl_data();
void relativeUrl();
private:
QQmlEngine engine;
......@@ -581,6 +583,28 @@ void tst_qqmlcomponent::callingContextForInitialProperties()
QVERIFY(checker->scopeObject->metaObject()->indexOfProperty("incubatedObject") != -1);
}
void tst_qqmlcomponent::relativeUrl_data()
{
QTest::addColumn<QUrl>("url");
QTest::addRow("fromLocalFile") << QUrl::fromLocalFile("data/QtObjectComponent.qml");
QTest::addRow("fromLocalFileHash") << QUrl::fromLocalFile("data/QtObjectComponent#2.qml");
QTest::addRow("constructor") << QUrl("data/QtObjectComponent.qml");
QTest::addRow("absolute") << QUrl::fromLocalFile(QFINDTESTDATA("data/QtObjectComponent.qml"));
QTest::addRow("qrc") << QUrl("qrc:/data/QtObjectComponent.qml");
}
void tst_qqmlcomponent::relativeUrl()
{
QFETCH(QUrl, url);
QQmlComponent component(&engine);
// Shouldn't assert in QQmlTypeLoader; we want QQmlComponent to assume that
// data/QtObjectComponent.qml refers to the data/QtObjectComponent.qml in the current working directory.
component.loadUrl(url);
QVERIFY2(!component.isError(), qPrintable(component.errorString()));
}
QTEST_MAIN(tst_qqmlcomponent)
#include "tst_qqmlcomponent.moc"
......@@ -125,12 +125,12 @@ void tst_animation::animationelements_data()
void tst_animation::animationelements()
{
QFETCH(QString, type);
QQmlType *t = QQmlMetaType::qmlType(type, 2, 0);
if (!t || !t->isCreatable())
QQmlType t = QQmlMetaType::qmlType(type, 2, 0);
if (!t.isValid() || !t.isCreatable())
QSKIP("Non-creatable type");
QBENCHMARK {
QObject *obj = t->create();
QObject *obj = t.create();
delete obj;
}
}
......
......@@ -107,9 +107,6 @@ private slots:
void typeResolution_data();
void typeResolution();
private:
QQmlEngine engine;
};
tst_holistic::tst_holistic()
......@@ -251,6 +248,8 @@ void tst_holistic::compilation()
Q_ASSERT(files.size() > 0);
Q_ASSERT(repetitions > 0);
QQmlEngine engine;
QBENCHMARK {
engine.clearComponentCache();
for (int i = 0; i < repetitions; ++i) {
......@@ -272,6 +271,8 @@ void tst_holistic::instantiation()
Q_ASSERT(files.size() > 0);
Q_ASSERT(repetitions > 0);
QQmlEngine engine;
QList<QQmlComponent*> components;
for (int i = 0; i < files.size(); ++i) {
QQmlComponent *c = new QQmlComponent(&engine, QUrl::fromLocalFile(files.at(i)));
......@@ -306,6 +307,8 @@ void tst_holistic::creation()
Q_ASSERT(files.size() > 0);
Q_ASSERT(repetitions > 0);
QQmlEngine engine;
QBENCHMARK {
engine.clearComponentCache();
for (int i = 0; i < repetitions; ++i) {
......@@ -369,6 +372,7 @@ void tst_holistic::dynamicity()
QFETCH(QVariant, writeValueTwo);
QFETCH(QString, readProperty);
QQmlEngine engine;
QQmlComponent c(&engine, file);
QObject *obj = c.create();
......@@ -478,6 +482,7 @@ void tst_holistic::cppToJsDirect()
QFETCH(QString, file);
QFETCH(QString, methodName);
QQmlEngine engine;
QQmlComponent c(&engine, file);
QObject *obj = c.create();
......@@ -497,6 +502,7 @@ void tst_holistic::cppToJsIndirect()
// The benchmark deliberately causes change signals to be emitted (and
// modifies the scarce resources) so that the properties are updated.
QQmlEngine engine;
QQmlComponent c(&engine, QString(SRCDIR + QLatin1String("/data/scopeSwitching/ScarceTwo.qml")));
QObject *obj = c.create();
......@@ -560,6 +566,7 @@ void tst_holistic::typeResolution()
Q_ASSERT(propertyNameTwo.size() == propertyValueTwo.size());
Q_ASSERT(repetitions > 0);
QQmlEngine engine;
QQmlComponent c(&engine, file);
QObject *obj = c.create();
......