Critical performance issue
Closed this issue · 14 comments
After refactoring my app, I'm seeing extreme rendering times, as bad as 14s sometimes. I'm not entirely sure what causes this, but I wanted to report it already, as I believe the issue lies with Stencil.
Here's what I have so far:
- I'm using Stencil 0.11.
- I didn't notice any issue in development. On macOS, 0.11 works fine and render times are < 100ms usually.
- When deploying the same code to IBM Cloud, the render times become horrible (1-15s). This leads me to believe it's a Linux-specific issue. I'm not sure about that however, as I haven't been able to reproduce it on Linux via Docker, only when deploying to cloud.
- I did not have this issue before when I was using 0.10.1.
- I was able to reproduce the issue to a lesser extent on macOS as well. If I use the latest master, my render times jump over 1s as well.
- I've added logging all throughout my handlers as well as Kitura and didn't notice any issues there. Almost all of the delay is caused by Stencil. I went as far as
Template.render
but haven't narrowed it down further yet. - All my templates uses inheritance. I'm having other issues with inheritance on master as well, so perhaps it related?
I would really appreciate any help in tracking down and resolving this issue as I need to release this app in the next few weeks.
I've also tried reverting back to 0.10, but that's giving me a compilation error on Linux I've yet to resolve:
PathKit.swift:299:11: error: cannot convert value of type 'ObjCBool' to expected argument type 'Bool'
I've logged every render separately and came up with the following results:
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
IfNode in 1ms
TextNode in 0ms
BlockNode in 62ms
TextNode in 0ms
VariableNode in 19ms
TextNode in 0ms
VariableNode in 19ms
TextNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
BlockNode in 3ms
TextNode in 0ms
BlockNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 2ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 58ms
TextNode in 0ms
VariableNode in 3ms
TextNode in 0ms
VariableNode in 141ms
TextNode in 0ms
VariableNode in 45ms
TextNode in 0ms
VariableNode in 4ms
TextNode in 0ms
VariableNode in 5ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
IfNode in 16ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 37ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 11ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 267ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 66ms
TextNode in 0ms
VariableNode in 1ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 12ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 22ms
TextNode in 0ms
VariableNode in 2ms
TextNode in 0ms
VariableNode in 1ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 8ms
TextNode in 0ms
VariableNode in 4ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 15ms
TextNode in 0ms
VariableNode in 1ms
TextNode in 0ms
VariableNode in 1ms
TextNode in 0ms
VariableNode in 8ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 35ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 1ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
TextNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
VariableNode in 2ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 3ms
TextNode in 0ms
VariableNode in 1ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
VariableNode in 0ms
TextNode in 0ms
IfNode in 0ms
TextNode in 0ms
ForNode in 1263ms
TextNode in 0ms
IfNode in 1263ms
TextNode in 0ms
BlockNode in 1269ms
TextNode in 0ms
BlockNode in 0ms
TextNode in 0ms
ExtendsNode in 2781ms
So the performance seems to be bad in general.
This is with 0.11, pushed to IBM Cloud, rendering the following template:
{% extends "base.stencil" %}
{% block title %}
{% if sort == "new" %}
{{ block.super }} - Nieuwste spellen
{% elif sort == "upcoming" %}
{{ block.super }} - Binnenkort op de agenda
{% elif sort == "near-me" %}
{{ block.super }} - In mijn buurt
{% endif %}
{% endblock %}
{% block content %}
<div class="d-flex justify-content-center">
<!-- Sort options -->
<ul class="pagination mr-md-5">
{% if sort == "new" %}
<li class="page-item active">
<span class="page-link">
<i class="fa fa-asterisk d-none d-sm-inline"></i> Nieuw
</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="/web/activities?sort=new">
<i class="fa fa-asterisk d-none d-sm-inline"></i> Nieuw
</a>
</li>
{% endif %}
{% if sort == "upcoming" %}
<li class="page-item active">
<span class="page-link">
<i class="fa fa-calendar d-none d-sm-inline"></i> Binnenkort
</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="/web/activities?sort=upcoming">
<i class="fa fa-calendar d-none d-sm-inline"></i> Binnenkort
</a>
</li>
{% endif %}
{% if sort == "near-me" %}
<li class="page-item active">
<span class="page-link">
<i class="fa fa-map-marker d-none d-sm-inline"></i> Dichtbij
</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="/web/activities?sort=near-me">
<i class="fa fa-map-marker d-none d-sm-inline"></i> Dichtbij
</a>
</li>
{% endif %}
</ul>
<!-- View options, only visible in md and above -->
<ul class="pagination d-none d-md-flex">
<li class="page-item">
<a class="page-link" href="/web/activities?view=grid">
<i class="fa fa-th-large"></i> Raster
</a>
</li>
<li class="page-item active">
<span class="page-link">
<i class="fa fa-list"></i> Lijst
</span>
</li>
</ul>
</div>
<!-- Title -->
{% if sort == "new" %}
<h2>Nieuwste spellen</h2>
{% elif sort == "upcoming" %}
<h2>Binnenkort op de agenda</h2>
{% elif sort == "near-me" %}
<h2>In mijn buurt</h2>
{% endif %}
<!-- Link to user activities -->
{% if base.user %}
<div class="alert alert-info">
Spellen die je zelf organiseert worden niet getoond op deze pagina.
Deze spellen zijn te vinden in je persoonlijk menu, onder <a class="alert-link" href="/web/user/activities">Mijn spellen</a>.
</div>
{% endif %}
<!-- Check if a location is set when showing activities near the user -->
{% if sort == "near-me" and not base.user.location %}
<div class="alert alert-warning">
{% if base.user %}
Om deze functie te activeren moet je een adres ingeven bij <a class="alert-link" href="/web/user/settings">Instellingen</a>.
{% else %}
Om deze functie te activeren moet je eerst <a class="alert-link" href="/authentication/welcome?redirect=%2Fweb%2Factivities">aanmelden</a>.
Daarna kan je een adres ingeven bij <a class="alert-link" href="/web/user/settings">Instellingen</a>.
{% endif %}
</div>
<!-- Activities -->
{% elif activities %}
{% for activity in activities %}
<a class="{% if activity.availableSeats == 0 %} red {% elif activity.availableSeats == 1 %} yellow {% else %} green {% endif %} autoborder item"
href="/web/activity/{{ activity.id }}">
<!-- Separate image sizing for xs, sm and md -->
<img class="d-sm-none align-self-start" width="75" src="{{ activity.thumbnail }}">
<img class="d-none d-sm-flex d-md-none align-self-start" width="150" src="{{ activity.picture }}">
<img class="d-none d-md-flex align-self-start" width="200" src="{{ activity.picture }}">
<div class="body">
<h5>{{ activity.name }}</h5>
<p>
<i class="fa fa-calendar"></i>
<!-- xs shows abbreviated weekday -->
<span class="d-sm-none">{{ activity.shortDate }}</span>
<!-- sm shows the full weekday -->
<span class="d-none d-sm-inline">{{ activity.longDate }}</span>
<!-- md adds the time -->
<span class="d-none d-md-inline">om {{ activity.time }}</span>
<br>
<!-- Show the time separately in xs and sm -->
<span class="d-md-none">
<i class="fa fa-clock-o"></i> {{ activity.time }}<br>
</span>
<i class="fa fa-user"></i> {{ activity.host.name }}<br>
<i class="fa fa-map-marker"></i> {{ activity.location.city }}
{% if base.user.location %}
({{ activity.distance }}km)
{% endif %}
</p>
</div>
</a>
{% endfor %}
<!-- Placeholder -->
{% else %}
<p>Geen spellen gepland.</p>
{% endif %}
{% endblock %}
With the following parent template:
<!DOCTYPE html>
<html lang="nl">
<head>
<title>{% block title %}Rond De Tafel{% endblock %}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="author" content="Steven Van Impe">
<meta name="description" content="Rond De Tafel brengt mensen en spellen samen. Vind spellen, zoek medespelers en maak nieuwe vrienden.">
<meta property="og:site_name" content="Rond De Tafel">
<meta property="og:type" content="website">
<meta property="fb:app_id" content="{{ base.facebook.app }}">
<meta property="og:description" content="Rond De Tafel brengt mensen en spellen samen. Vind spellen, zoek medespelers en maak nieuwe vrienden.">
<meta property="og:url" content="{{ base.opengraph.url }}">
{% block opengraph %}
<meta property="og:title" content="Rond De tafel">
<meta property="og:image" content="{{ base.opengraph.image }}">
{% endblock %}
<link href="/public/img/favicon.png" rel="icon" type="image/png">
<link href="/public/css/bootstrap.min.css" rel="stylesheet">
<link href="/public/css/font-awesome.min.css" rel="stylesheet">
<link href="/public/css/pikaday.min.css" rel="stylesheet">
<style>
.navbar, .btn-primary {
background-color: #2185D0;
}
h2, h3 {
margin-bottom: 1rem;
}
img.avatar {
width: 40px;
height: 40px;
}
/* Pagination, used for sort and view options. */
.page-link {
color: #2185D0;
}
.page-item.active .page-link {
background-color: #2185D0;
border-color: #2185D0;
}
/* Activity cards, used in grid view. */
a.card {
width: 100%;
color: inherit;
text-decoration: none;
}
a.card.green {
box-shadow: 0 1px 0 0 #21BA45;
}
a.card.yellow {
box-shadow: 0 1px 0 0 #FBBD08;
}
a.card.red {
box-shadow: 0 1px 0 0 #DB2828;
}
a.card .card-body {
line-height: 2em;
}
/* Activity items, used in list view. */
a.item {
display: flex;
color: inherit;
text-decoration: none;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
a.item:focus, a.item:hover {
background-color: #f8f9fa;
}
a.item.green {
box-shadow: 1px 0 0 0 #21BA45;
}
a.item.yellow {
box-shadow: 1px 0 0 0 #FBBD08;
}
a.item.red {
box-shadow: 1px 0 0 0 #DB2828;
}
a.item .body {
display: flex;
flex-direction: column;
margin-left: 1rem;
line-height: 2em;
}
@media(min-width:768px) {
a.item.autoborder {
border: 1px solid rgba(0, 0, 0, 0.125);
}
a.item.autoborder .body {
margin-top: 0.5rem;
}
}
/* Conversations and messages */
a.conversation {
display: flex;
color: inherit;
text-decoration: none;
}
a.conversation .body {
display: flex;
flex-direction: column;
margin-left: 1rem;
}
@media(min-width:768px) {
.messages {
margin-left: 2rem;
}
}
/* Margins for icons */
.fa-calendar, .fa-clock-o, .fa-envelope, .fa-hourglass-o, .fa-map-marker, .fa-user, .fa-users {
margin-right: 0.25rem;
}
.fa-home {
margin-left: 0.25rem;
}
/* Don't use margins in input groups or buttons */
button > i.fa, .input-group-text > i.fa {
margin-right: 0;
}
.fa-facebook-official {
color: #29487d;
}
</style>
<!-- jQuery is included in head because it's used by included components in body. -->
<script src="/public/js/jquery.min.js"></script>
{% block additional-head %}{% endblock %}
</head>
<body>
<!-- Collapsed navbar -->
<nav class="d-md-none navbar navbar-dark">
<a class="navbar-brand" href="/web/home">Rond De Tafel</a>
<ul class="navbar-nav ml-auto mr-3">
{% if base.unreadMessageCount > 0 %}
<li class="nav-item">
<a class="nav-link" href="/web/user/messages">
<i class="fa fa-envelope"></i>
</a>
</li>
{% endif %}
</ul>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/web/activities">Spellen</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/web/host">Organiseer</a>
</li>
{% if base.user %}
<li class="nav-item">
<a class="nav-link" href="/web/user/activities">Mijn spellen</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/web/user/messages">
Berichten
{% if base.unreadMessageCount > 0 %}
({{ base.unreadMessageCount }})
{% endif %}
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/web/user/settings">Instellingen</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/authentication/signout">Afmelden</a>
</li>
{% else %}
<li class="nav-item">
<!-- The href will be set in code -->
<a class="global-signin nav-link" href="#">Aanmelden</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="/web/faq">Help</a>
</li>
</ul>
</div>
</nav>
<!-- Full navbar -->
<nav class="d-none d-md-flex navbar navbar-expand navbar-dark">
<a class="navbar-brand" href="/web/home">Rond De Tafel</a>
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/web/activities">Spellen</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/web/host">Organiseer</a>
</li>
</ul>
<ul class="navbar-nav">
{% if base.user %}
{% if base.unreadMessageCount > 0 %}
<li class="nav-item">
<a class="nav-link" href="/web/user/messages">
<i class="fa fa-envelope"></i>
</a>
</li>
{% endif %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown">
{{ base.user.name }}
</a>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="/web/user/activities">Mijn spellen</a>
<a class="dropdown-item" href="/web/user/messages">
Berichten
{% if base.unreadMessageCount > 0 %}
({{ base.unreadMessageCount }})
{% endif %}
</a>
<a class="dropdown-item" href="/web/user/settings">Instellingen</a>
<a class="dropdown-item" href="/authentication/signout">Afmelden</a>
</div>
</li>
{% else %}
<li class="nav-item">
<!-- The href will be set in code -->
<a class="global-signin nav-link" href="#">Aanmelden</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="/web/faq">
<i class="fa fa-question-circle fa-lg"></i>
</a>
</li>
</ul>
</nav>
<!-- Main content -->
<div class="container mt-3">
{% block content %}{% endblock %}
</div>
<!-- Footer -->
<footer class="container py-3 text-center">
© 2018 - Rond De Tafel<br>
Like ons op <a href="https://www.facebook.com/ronddetafel.be" target="_blank">Facebook</a> <i class="fa fa-facebook-official"></i><br>
Broncode beschikbaar op <a href="https://github.com/svanimpe/around-the-table.git" target="_blank">GitHub</a> <i class="fa fa-github"></i>
</footer>
<!-- Scripts -->
<script src="/public/js/popper.min.js"></script>
<script src="/public/js/bootstrap.min.js"></script>
<script>
// Set the href for the sign in link.
var redirect = window.location.pathname;
$(".global-signin").attr("href", "/authentication/welcome?redirect=" + encodeURIComponent(redirect));
</script>
{% block additional-body %}{% endblock %}
</body>
</html>
In the list of render timings, I am going to take a guess the hierachy looks roughly like the following (since extends would include all rendering times of nodes inside it, similiar for block node, for node and ifnode etc):
- ExtendsNode in 2781ms
- BlockNode in 1269ms
- IfNode in 1263ms
- ForNode in 1263ms
- VariableNode in 267ms
- VariableNode in 141ms
- ForNode in 1263ms
- IfNode in 1263ms
- BlockNode in 1269ms
Since the ForNode and IfNode take exactly the same time, I am not sure if one is inside the other and which way round they would be. It would seem the most expensive rendering path could be some variable lookups which are performed multiple times in a loop.
I'd take a guess here there is some specific cases of variable lookups that take far more time than others and identifying which they are should help getting to the underlying problem. The variable lookup may also be done inside ForNode and IfNode to resolve them. It could be that mirroring is the bottleneck etc, since there are different types of variable lookups and certain casting (
Stencil/Sources/Variable.swift
Line 110 in ffe8f9d
Would you be able to add some additional logging to your code that produced the rendering times. I think something like the following:
if let node = node as VariableNode {
print(node.token.contents)
}
So it would be printing out more context on the variable lookups that are slower than others. Then you could identify what kind of lookup is taking so long, if it is due to mirroring, or casting an array etc.
@svanimpe Which version of Swift are you testing with? I know Linux performance of Foundation and similiar isn't great on Linux in comparison to macOS, for example.
@svanimpe Since you've only benchmarked the rendering times. Are the lexer and token parser times pretty low? (Lexer.tokenize()
and TokenParser.parse()
respectively)
@kylef Thanks for taking a look at this.
I am using Swift 4.1.2 on both macOS and Linux.
Your comments made me think of something else: As part of my app refactor, I've adopted Kitura's codable rendering. Previously, I used to build a [String: Any]
dictionary by hand. Now Kitura does this by encoding my context to JSON and converting that to [String: Any]
using JSONSerialization. The folks at IBM have already checked that encoding phase and there is no performance issue there. But perhaps the resulting dictionaries are handled differently by Stencil?
I also checked the parser during one of my earlier tests but didn't notice any issues there, which is why I focused on the rendering.
I'll try to add some more logging and will report back what I find.
Well, I have some more information:
I tried upgrading to Swift 4.1.3 on Linux. When I did, I my requests were still slow, but I wasn't seeing the slow VariableNodes. My other logging, in ExtendsNode.render
(as I first thought this was related to inheritance) showed that the line
let template = try context.environment.loadTemplate(name: templateName)
can take up to two seconds. If this happens twice (parent and child template), that's already 4 seconds. I think this is the main cause of the delay now, as the total request render time is usually twice the time it takes to load a template, plus a few 100ms.
I then tried reverting back to 4.1.2. to try to reproduce my previous results, but failed. This may be due to a IBM Cloud caching issue (which is particularly annoying). I'll try again tomorrow.
Ok, in that case it is likely due to the lexer. Could you try applying the patch from #207. I believe it will apply cleanly onto the last Stencil release.
Aha, success.
I've applied the 3 commits from #207 to my fork (branched at the 0.11 tag). Running that on Swift 4.1.3 on Linux gives me acceptable (< 1s) results:
loadTemplate: 0.0185469388961792
Rendered TextNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
sort context
Rendered TextNode in 0ms
block context
super dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered BlockNode in 0ms
Rendered TextNode in 0ms
base context
facebook dictionary
app dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
base context
opengraph dictionary
url dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
base context
opengraph dictionary
image dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
Rendered BlockNode in 0ms
Rendered TextNode in 0ms
Rendered BlockNode in 0ms
Rendered TextNode in 0ms
base context
unreadMessageCount dictionary
Rendered IfNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
sort context
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
sort context
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
sort context
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
sort context
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
Rendered IfNode in 0ms
Rendered TextNode in 0ms
sort context
activities context
Rendered TextNode in 0ms
activities context
Rendered TextNode in 0ms
activity context
availableSeats dictionary
activity context
availableSeats dictionary
Rendered TextNode in 0ms
Rendered IfNode in 1ms
Rendered TextNode in 0ms
activity context
id dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
thumbnail dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 1ms
Rendered TextNode in 0ms
activity context
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
shortDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
longDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
host dictionary
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
location dictionary
city dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
location nil
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
activity context
availableSeats dictionary
activity context
availableSeats dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
activity context
id dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
thumbnail dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
name dictionary
Rendered VariableNode in 5ms
Rendered TextNode in 0ms
activity context
shortDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
longDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
host dictionary
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
location dictionary
city dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
location nil
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
activity context
availableSeats dictionary
activity context
availableSeats dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
activity context
id dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
thumbnail dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
shortDate dictionary
Rendered VariableNode in 53ms
Rendered TextNode in 0ms
activity context
longDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
host dictionary
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
location dictionary
city dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
location nil
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
activity context
availableSeats dictionary
activity context
availableSeats dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
activity context
id dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
thumbnail dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
shortDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
longDate dictionary
Rendered VariableNode in 1ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
host dictionary
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
location dictionary
city dictionary
Rendered VariableNode in 2ms
Rendered TextNode in 0ms
base context
user dictionary
location nil
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
activity context
availableSeats dictionary
activity context
availableSeats dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
activity context
id dictionary
Rendered VariableNode in 27ms
Rendered TextNode in 0ms
activity context
thumbnail dictionary
Rendered VariableNode in 18ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 4ms
Rendered TextNode in 0ms
activity context
name dictionary
Rendered VariableNode in 6ms
Rendered TextNode in 0ms
activity context
shortDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
longDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
host dictionary
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
location dictionary
city dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
location nil
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered TextNode in 0ms
activity context
availableSeats dictionary
Rendered TextNode in 0ms
Rendered IfNode in 0ms
Rendered TextNode in 0ms
activity context
id dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
thumbnail dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
picture dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
shortDate dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
longDate dictionary
Rendered VariableNode in 47ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
time dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
host dictionary
name dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
activity context
location dictionary
city dictionary
Rendered VariableNode in 0ms
Rendered TextNode in 0ms
base context
user dictionary
location nil
Rendered IfNode in 0ms
Rendered TextNode in 0ms
Rendered ForNode in 263ms
Rendered TextNode in 0ms
Rendered IfNode in 263ms
Rendered TextNode in 0ms
Rendered BlockNode in 264ms
Rendered TextNode in 0ms
Rendered BlockNode in 0ms
Rendered TextNode in 0ms
Rendered ExtendsNode in 292ms
Total render: 0.839139938354492
There are still some slow variable lookups there, but nothing problematic. I've also logged the name of each variable and how it was resolved, if that helps.
I'll try to reproduce the issue with very slow lookups again tomorrow.
See #225. I've done the rebase but I need someone who understands the code to have a look at it and fix bugs.
@svanimpe @yonaskolb I suppose this should be now fixed with #230 or there is still something we should look into?
@ilyapuchka the performance regressions from the error handling look like they have been fixed, though there still some performance issues in Swift 4.1 and perhaps some larger issues in Linux that need to be investigated, and that look they may be fixed in #207 / #225 / #226
We might improve performance further but I think this one is directly related to a regression that was fixed so I'll close this, we can discuss improvements in the PRs that we have open.