Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-69475

10x (and growing) slowdown in populating JS objects

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P1: Critical
    • 5.11.2
    • 5.11.1
    • None
    • Linux/X11, macOS, Windows

    Description

      Consider these two code snippets:

      for (var i = 0; i < n; i++) {
          var message = getMessage(i);
          if (!known[message.id]) known[message.id] = true
      }
      
      var messages = [];
      for (var i = 0; i < n; i++) {
          messages.push(getMessage(i));
      }
      for (i = 0; i < messages.length; i++) {
          var message = messages[i];
          if (!known[message.id]) known[message.id] = true;
      }
      

      I would expect the first to be faster.

      In fact, the first snippet is more than ten times slower than the second one for some reason.

      See the example below:

      import QtQuick 2.11
      
      Item {
        Component.onCompleted: {
          for (var i = 0; i < 4; i++) {
            process(true)
            process(false)
          }
        }
      
        function process(fast) {
          var message, i;
          var start = Date.now()
          var known = {};
          var messages = [];
          for (i = 0; i < 10000; i++) {
            message = Math.random().toString();
            messages.push(message);
            if (!fast && !known[message]) known[message] = true;
          }
          for (i = 0; i < messages.length; i++) {
            message = messages[i];
            if (fast && !known[message]) known[message] = true;
          }
          console.log(fast ? 'fast' : 'slow', (Date.now() - start) / 1000)
        }
      }
      

      For the testcase, messages are just random strings. In the original code, those were unique id strings from the database (also messages were objects, and `known` stored their `.id`s).

      Output on my setup on Qt 5.11.1:

      qml: fast 0.087
      qml: slow 1.178
      qml: fast 0.097
      qml: slow 1.532
      qml: fast 0.117
      qml: slow 2.376
      qml: fast 0.157
      qml: slow 3.7
      

      The following testcase shows that the slowdown grows on subsequent calls (despite all variables being local):

      import QtQuick 2.11
      
      Item {
        Timer {
          id: timer
          interval: 100
          running: true
          onTriggered: process()
        }
      
        function process() {
          var fast = false //true
          var message, i;
          var start = Date.now()
          var known = {};
          var messages = [];
          for (i = 0; i < 10000; i++) {
            message = Math.random().toString().split().join();
            messages.push(message);
            if (!fast && !known[message]) known[message] = true;
          }
          for (i = 0; i < messages.length; i++) {
            message = messages[i];
            if (fast && !known[message]) known[message] = true;
          }
          console.log(fast ? 'fast' : 'slow', (Date.now() - start) / 1000)
          timer.restart()
        }
      }
      

      Result:

      qml: slow 0.638
      qml: slow 1.29
      qml: slow 2.05
      qml: slow 3.034
      qml: slow 4.246
      qml: slow 5.422
      qml: slow 7.219
      qml: slow 9.395
      qml: slow 11.192
      qml: slow 12.359
      qml: slow 12.329
      qml: slow 13.73
      qml: slow 14.954
      

      Even if you change the number of loop iterations (aka the object size) in the testcase from 10000 to 100, it eventually starts to take seconds to do anything.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            laknoll Lars Knoll
            chalker Сковорода Никита
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes