') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Add script to check performance by almarklein · Pull Request #23 · plotly/dash-slicer · GitHub
Skip to content

Add script to check performance - #23

Merged
almarklein merged 3 commits into
mainfrom
perf
Nov 26, 2020
Merged

Add script to check performance#23
almarklein merged 3 commits into
mainfrom
perf

Conversation

@almarklein

@almarkleinalmarklein commented Nov 24, 2020

Copy link
Copy Markdown
Collaborator

I was looking for ways to improve the performance of the slicer, and decided to do a bit of benchmarking. This adds a script to test the performance of updating an image with Plotly+Dash.

It contains a dcc.Interval that tries to update a figure as fast as it can. The time it costs to do this will slow the interval down, so we can measure fps. Of course this FPS value depends on a lot of factors, but it's valuable to see the differences between methods.

Some observations:

  • Even if the (client-side) callback yields no_update, the FPS does not go beyond 20. Not sure whether this is some rate limit or some overhead in Dash.
  • When the callback returns an empty figure, the FPS is the same as doing noting, so that's good.
  • Heatmap is slow! (about 6-7 FPS for me).
  • The gl heatmap is only a wee bit faster (8 FPS). This makes no sense to me ...
  • The PNG approach (which we now use) is actually pretty fast! (13-14 FPS). It actually looks a lot faster than what I experience with the slicer, so we might gain performance by having a good look at the slicer internals.
  • The PNG approach that does not swap the y-axis grinds to a mere 6 FPS. I'd love to get this fixed ...

In summary, I had hoped the glheatmap would allow us to get more smooth interaction. Alas. On the plus side, we seem to have some internal overhead that we can hopefully fix to make things more smooth!

@emmanuelle

emmanuelle commented Nov 25, 2020

Copy link
Copy Markdown
Contributor

A question about serialization: did you compute the JSON serialization time of the figure? If it's a significant fraction of the time it might explain why the difference between heatmap and heatmapgl is not huge. (and are you using plotly 4.13 which should reduce the serialization time for Heatmap and Heatmapgl ?)

Update: forget what I wrote, since the callback is clientside probably there is no serialization

@emmanuelle

Copy link
Copy Markdown
Contributor

I tried the same benchmark on larger (256x512x512) and random uint8 (worst case for png compresseion) data and

  • png: 8-9 fps
  • heatmap 1 fps
  • heatmapgl: 3-4 fps
  • png not reversed: 1 fps :-(

@emmanuelle

Copy link
Copy Markdown
Contributor

Note that the performace of the noop and empty modes are improved when setting the update_title of the app to None:

app = dash.Dash(__name__, update_title=None)

also see https://dash.plotly.com/external-resources. I think this also slightly improves the png mode.

@almarklein

Copy link
Copy Markdown
CollaboratorAuthor

I added update_title=None. I'm surprised at how much this improves the performance ...

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@almarklein@emmanuelle