Add console.time / console.timeEnd API
authorKai Koehne <kai.koehne@nokia.com>
Thu, 3 Nov 2011 16:58:07 +0000 (17:58 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 9 Nov 2011 07:23:57 +0000 (08:23 +0100)
Implement console.time() / console.timeEnd() as also provided by FireBug
/ Safari.

Task-number: QTBUG-22347
Change-Id: I94fcadbb0c54fdf60dc2559e3ae63d613e29630b
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
doc/src/declarative/globalobject.qdoc
doc/src/declarative/qdeclarativedebugging.qdoc
src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp
src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h
src/declarative/qml/v8/qv8engine.cpp
src/declarative/qml/v8/qv8engine_p.h

index f4e9d0d..ced797b 100644 (file)
@@ -203,7 +203,7 @@ May throw exception with code property SQLException.DATABASE_ERR, SQLException.S
 
 \section1 Logging
 
-\c console.log() and \c console.debug() can be used to print information
+\c console.log(), \c console.debug(), \c console.time(), and \c console.timeEnd() can be used to print information
 to the console. See \l{Debugging QML} for more information.
 
 */
index 189d444..a34c2fa 100644 (file)
@@ -43,6 +43,20 @@ Rectangle {
 }
 \endqml
 
+\c console.time and console.timeEnd log the time (in milliseconds) that was spent between
+the calls. Both take a string argument that identifies the measurement. For example:
+
+\qml
+function f() {
+    console.time("wholeFunction");
+    console.time("firstPart");
+    // first part
+    console.timeEnd("firstPart");
+    // second part
+    console.timeEnd("wholeFunction");
+}
+\endqml
+
 \section1 Debugging Transitions
 
 When a transition doesn't look quite right, it can be helpful to view it in slow
index 96c51da..1ced868 100644 (file)
@@ -92,6 +92,28 @@ v8::Handle<v8::Value> print(const v8::Arguments &args)
     return v8::Undefined();
 }
 
+v8::Handle<v8::Value> consoleTime(const v8::Arguments &args)
+{
+    if (args.Length() != 1)
+        V8THROW_ERROR("console.time(): Invalid arguments");
+    QString name = V8ENGINE()->toString(args[0]);
+    V8ENGINE()->startTimer(name);
+    return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args)
+{
+    if (args.Length() != 1)
+        V8THROW_ERROR("console.time(): Invalid arguments");
+    QString name = V8ENGINE()->toString(args[0]);
+    bool wasRunning;
+    qint64 elapsed = V8ENGINE()->stopTimer(name, &wasRunning);
+    if (wasRunning) {
+        qDebug("%s: %llims", qPrintable(name), elapsed);
+    }
+    return v8::Undefined();
+}
+
 v8::Handle<v8::Value> stringArg(const v8::Arguments &args)
 {
     QString value = V8ENGINE()->toString(args.This()->ToString());
index 847dc66..35ea885 100644 (file)
@@ -91,6 +91,8 @@ v8::Handle<v8::Value> qsTr(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
 v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTime(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args);
 v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
 }
 
index d239f30..6f744e5 100644 (file)
@@ -519,10 +519,14 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
 {
     using namespace QDeclarativeBuiltinFunctions;
     v8::Local<v8::Function> printFn = V8FUNCTION(print, this);
+    v8::Local<v8::Function> consoleTimeFn = V8FUNCTION(consoleTime, this);
+    v8::Local<v8::Function> consoleTimeEndFn = V8FUNCTION(consoleTimeEnd, this);
 
     v8::Local<v8::Object> console = v8::Object::New();
     console->Set(v8::String::New("log"), printFn);
     console->Set(v8::String::New("debug"), printFn);
+    console->Set(v8::String::New("time"), consoleTimeFn);
+    console->Set(v8::String::New("timeEnd"), consoleTimeEndFn);
 
     v8::Local<v8::Object> qt = v8::Object::New();
 
@@ -1398,6 +1402,24 @@ void QV8Engine::emitSignalHandlerException()
     emit q->signalHandlerException(scriptValueFromInternal(uncaughtException()));
 }
 
+void QV8Engine::startTimer(const QString &timerName)
+{
+    if (!m_time.isValid())
+        m_time.start();
+    m_startedTimers[timerName] = m_time.elapsed();
+}
+
+qint64 QV8Engine::stopTimer(const QString &timerName, bool *wasRunning)
+{
+    if (!m_startedTimers.contains(timerName)) {
+        *wasRunning = false;
+        return 0;
+    }
+    *wasRunning = true;
+    qint64 startedAt = m_startedTimers.take(timerName);
+    return m_time.elapsed() - startedAt;
+}
+
 QThreadStorage<QV8GCCallback::ThreadData *> QV8GCCallback::threadData;
 void QV8GCCallback::initializeThreadData()
 {
index 92e6123..7b85cfc 100644 (file)
@@ -59,6 +59,7 @@
 #include <QtCore/qmutex.h>
 #include <QtCore/qstack.h>
 #include <QtCore/qstringlist.h>
+#include <QtCore/QElapsedTimer>
 
 #include <private/qv8_p.h>
 #include <qjsengine.h>
@@ -405,6 +406,10 @@ public:
 
     void emitSignalHandlerException();
 
+    // used for console.time(), console.timeEnd()
+    void startTimer(const QString &timerName);
+    qint64 stopTimer(const QString &timerName, bool *wasRunning);
+
     QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
     QSet<int> visitedConversionObjects;
 protected:
@@ -436,6 +441,9 @@ protected:
 
     Exception m_exception;
 
+    QElapsedTimer m_time;
+    QHash<QString, qint64> m_startedTimers;
+
     QVariant toBasicVariant(v8::Handle<v8::Value>);
 
     void initializeGlobal(v8::Handle<v8::Object>);