<html>
    <head>
      <base href="https://bugs.webkit.org/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [GLib] GCActivityCallback::scheduleTimer() keeps pushing dispatch into the future"
   href="https://bugs.webkit.org/show_bug.cgi?id=168363">168363</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[GLib] GCActivityCallback::scheduleTimer() keeps pushing dispatch into the future
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>WebKit
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>WebKit Nightly Build
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>Unspecified
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Unspecified
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>Normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P2
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>JavaScriptCore
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>webkit-unassigned&#64;lists.webkit.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>zan&#64;falconsigh.net
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>bugs-noreply&#64;webkitgtk.org, cgarcia&#64;igalia.com, mcatanzaro&#64;igalia.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>GCActivityCallback::scheduleTimer() accepts a delay argument and, in case it's at most half the amount of the current delay, uses this new value to reschedule the internal timer.
<a href="https://trac.webkit.org/browser/trunk/Source/JavaScriptCore/heap/GCActivityCallback.cpp#L119">https://trac.webkit.org/browser/trunk/Source/JavaScriptCore/heap/GCActivityCallback.cpp#L119</a>

Say the GCActivityCallback is scheduled for the first time in 8 seconds. The timer is then set to dispatch 8 seconds from the current time (marked as CT#0). After the JS heap continues to grow, additional scheduleTimer() calls are done, each time decreasing the delay proportional to the amount of memory that's been allocated so far. This is calculated in GCActivityCallback::didAllocate().
<a href="https://trac.webkit.org/browser/trunk/Source/JavaScriptCore/heap/GCActivityCallback.cpp#L150">https://trac.webkit.org/browser/trunk/Source/JavaScriptCore/heap/GCActivityCallback.cpp#L150</a>

It's possible that the allocations progress in such way that, for example, after CT#0 + 7 seconds the computed delay drops to 4 seconds. At that point the call to scheduleTimer() reschedules the timer, but using the current time as the base, CT#1, which equals to CT#0 + 7, and uses 4 seconds as the delay amount, which means the next dispatch will be at CT#1 + 4 = CT#0 + 11 seconds, three seconds after the time when the first scheduled delay was supposed to dispatch.

This isn't how the USE(CF) implementation works. When the delay is set there for the first time, it's set as the latest time when the callback should be fired. Repeating the previous scenario, if the timer is first scheduled to be dispatched after 8 seconds from the current time (CT#0 + 8), and after 7 seconds the delay is dropped to 4 seconds, the new dispatch time will be CT#0 + 4, which is 3 seconds in the past, meaning the timer will dispatch ASAP.

The current GLib implementation should probably match that. Note that the current delay computation doesn't mean that GC doesn't get triggered at all, as far as I've tested it just means that the dispatch gets delayed long enough for the delay values to become really small and close enough to the present that the timer gets dispatched in the near-future main loop iteration.

The delays here are used to showcase the problem. The initial delays are usually quite large, but then become smaller as the allocations grow.

The USE(CF) implementation still sets m_nextFireTime to currentTime() + delay, just like we do, but note that there appears to be no use of the m_nextFireTime member variable or the GCActivityCallback::nextFireTime() getter.</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>