3

Steps to reproduce:
I've been getting frequent temporary beachballs, sometimes over 10 seconds long, while using Orion.
Using Instruments and Frida I've narrowed down the path where this happens:

  • Some function on the main thread posts the notification FaviconDidUpdate.
  • This calls BookmarksBarItem.iconUpdated (synchronously on the same thread).
  • One of the functions called from this eventually executes a SQLite query of the form:
    SELECT ICON_HASH FROM (
    	SELECT
    		favicon.ICON_HASH,
    		REPLACE(REPLACE(REPLACE(favicon.PAGE_URL, 'www.', ''), 'http://', ''), 'https://', '') as _PAGE_URL
    	FROM favicon
    	LEFT JOIN icon_info ON icon_info.HASH = favicon.ICON_HASH
    	WHERE
    		(_PAGE_URL = 'xxx' OR _PAGE_URL = 'xxx/') AND icon_info.ICON_TYPE = 0 AND icon_info.WIDTH >= 0
    	ORDER BY
    		icon_info.WIDTH DESC
    )
    (where xxx is a webpage URL, either from my bookmarks or one that I'm currently visiting.)
  • This query does a linear scan over all rows of the favicon table, which for me has 27,768 rows.
  • Most of the time the query takes around 33ms, but sometimes it takes orders of magnitude longer, up to multiple seconds. I am honestly baffled at this discrepancy, given that it's scanning over the same data. You would think that this would indicate the thread waiting for a lock or not being scheduled or paging from swap, but Instruments suggests that the thread is actively running and spending most of its time taken in replaceFunc, which is a function in libsqlite3.dylib that implements the REPLACE SQL function. Yet I verified that it calls the replaceFunc the same number of times with the same arguments. (And regarding swap specifically, my system has enough memory that it currently shows 0 bytes of swap used, even though I reproduced beachballs recently.) Could it have something to do with P-cores versus E-cores?

Suggestions:

  • Cache the REPLACE output in a different SQL column and add an index for that column, so that you can query for a specific URL without doing a linear scan over all rows in the table.
  • Have the notification handler dispatch the work to a background queue, so that the SQL query doesn't block the main thread even if it is slow.

Orion, OS version; hardware type:
Orion Version 0.99.123.1-beta (WebKit 615.1.16.1)
MacBook Pro (macOS Ventura 13.1 build 22C65)

  • Vlad replied to this.

    comex Do you still have this in 123.2? (great debug info btw)

      7 months later

      Orion has become completely unusable for me because of this issue. It is running the CPU and fans at 100% and spamming the system log several thousand times per second with this message:

      libsqlite3.dylib
      automatic index on favicon(ICON_HASH)

      Orion version: Version 0.99.125-beta (WebKit 616.1.22)
      OS X Version: Catalina

      • Vlad replied to this.
        5 days later

        carl I would suggest resetting Orion. It probably got into a state where it can not resolve it, and ther eis no way you can produce steps to reproduce to get there.

        No one is typing