123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- {% extends '@WebProfiler/Profiler/layout.html.twig' %}
- {% import _self as helper %}
- {% block toolbar %}
- {% set has_time_events = collector.events|length > 0 %}
- {% set total_time = has_time_events ? '%.0f'|format(collector.duration) : 'n/a' %}
- {% set initialization_time = collector.events|length ? '%.0f'|format(collector.inittime) : 'n/a' %}
- {% set status_color = has_time_events and collector.duration > 1000 ? 'yellow' : '' %}
- {% set icon %}
- {{ include('@WebProfiler/Icon/time.svg') }}
- <span class="sf-toolbar-value">{{ total_time }}</span>
- <span class="sf-toolbar-label">ms</span>
- {% endset %}
- {% set text %}
- <div class="sf-toolbar-info-piece">
- <b>Total time</b>
- <span>{{ total_time }} ms</span>
- </div>
- <div class="sf-toolbar-info-piece">
- <b>Initialization time</b>
- <span>{{ initialization_time }} ms</span>
- </div>
- {% endset %}
- {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, status: status_color }) }}
- {% endblock %}
- {% block menu %}
- <span class="label">
- <span class="icon">{{ include('@WebProfiler/Icon/time.svg') }}</span>
- <strong>Performance</strong>
- </span>
- {% endblock %}
- {% block panel %}
- {% set has_time_events = collector.events|length > 0 %}
- <h2>Performance metrics</h2>
- <div class="metrics">
- <div class="metric">
- <span class="value">{{ '%.0f'|format(collector.duration) }} <span class="unit">ms</span></span>
- <span class="label">Total execution time</span>
- </div>
- <div class="metric">
- <span class="value">{{ '%.0f'|format(collector.inittime) }} <span class="unit">ms</span></span>
- <span class="label">Symfony initialization</span>
- </div>
- {% if profile.collectors.memory %}
- <div class="metric">
- <span class="value">{{ '%.2f'|format(profile.collectors.memory.memory / 1024 / 1024) }} <span class="unit">MiB</span></span>
- <span class="label">Peak memory usage</span>
- </div>
- {% endif %}
- {% if profile.children|length > 0 %}
- <div class="metric-divider"></div>
- <div class="metric">
- <span class="value">{{ profile.children|length }}</span>
- <span class="label">Sub-Request{{ profile.children|length > 1 ? 's' }}</span>
- </div>
- {% if has_time_events %}
- {% set subrequests_time = 0 %}
- {% for child in profile.children %}
- {% set subrequests_time = subrequests_time + child.getcollector('time').events.__section__.duration %}
- {% endfor %}
- {% else %}
- {% set subrequests_time = 'n/a' %}
- {% endif %}
- <div class="metric">
- <span class="value">{{ subrequests_time }} <span class="unit">ms</span></span>
- <span class="label">Sub-Request{{ profile.children|length > 1 ? 's' }} time</span>
- </div>
- {% endif %}
- </div>
- <h2>Execution timeline</h2>
- {% if not collector.isStopwatchInstalled() %}
- <div class="empty">
- <p>The Stopwatch component is not installed. If you want to see timing events, run: <code>composer require symfony/stopwatch</code>.</p>
- </div>
- {% elseif collector.events is empty %}
- <div class="empty">
- <p>No timing events have been recorded. Check that symfony/stopwatch is installed and debugging enabled in the kernel.</p>
- </div>
- {% else %}
- {{ block('panelContent') }}
- {% endif %}
- {% endblock %}
- {% block panelContent %}
- <form id="timeline-control" action="" method="get">
- <input type="hidden" name="panel" value="time">
- <label for="threshold">Threshold</label>
- <input type="number" name="threshold" id="threshold" value="1" min="0" placeholder="1.1"> ms
- <span class="help">(timeline only displays events with a duration longer than this threshold)</span>
- </form>
- {% if profile.parent %}
- <h3 class="dump-inline">
- Sub-Request {{ profiler_dump(profile.getcollector('request').requestattributes.get('_controller')) }}
- <small>
- {{ collector.events.__section__.duration }} ms
- <a class="newline" href="{{ path('_profiler', { token: profile.parent.token, panel: 'time' }) }}">Return to parent request</a>
- </small>
- </h3>
- {% elseif profile.children|length > 0 %}
- <h3>
- Main Request <small>{{ collector.events.__section__.duration }} ms</small>
- </h3>
- {% endif %}
- {{ helper.display_timeline(token, collector.events, collector.events.__section__.origin) }}
- {% if profile.children|length %}
- <p class="help">Note: sections with a striped background correspond to sub-requests.</p>
- <h3>Sub-requests <small>({{ profile.children|length }})</small></h3>
- {% for child in profile.children %}
- {% set events = child.getcollector('time').events %}
- <h4>
- <a href="{{ path('_profiler', { token: child.token, panel: 'time' }) }}">{{ child.getcollector('request').identifier }}</a>
- <small>{{ events.__section__.duration }} ms</small>
- </h4>
- {{ helper.display_timeline(child.token, events, collector.events.__section__.origin) }}
- {% endfor %}
- {% endif %}
- <svg id="timeline-template" width="0" height="0">
- <defs>
- <pattern id="subrequest" class="timeline-subrequest-pattern" patternUnits="userSpaceOnUse" width="20" height="20" viewBox="0 0 40 40">
- <path d="M0 40L40 0H20L0 20M40 40V20L20 40"/>
- </pattern>
- </defs>
- </svg>
- <style type="text/css">
- {% include '@WebProfiler/Collector/time.css.twig' %}
- </style>
- <script>
- {% include '@WebProfiler/Collector/time.js' %}
- </script>
- {% endblock %}
- {% macro dump_request_data(token, events, origin) %}
- {% autoescape 'js' %}
- {% from _self import dump_events %}
- {
- id: "{{ token }}",
- left: {{ "%F"|format(events.__section__.origin - origin) }},
- end: "{{ '%F'|format(events.__section__.endtime) }}",
- events: [ {{ dump_events(events) }} ],
- }
- {% endautoescape %}
- {% endmacro %}
- {% macro dump_events(events) %}
- {% autoescape 'js' %}
- {% for name, event in events %}
- {% if '__section__' != name %}
- {
- name: "{{ name }}",
- category: "{{ event.category }}",
- origin: {{ "%F"|format(event.origin) }},
- starttime: {{ "%F"|format(event.starttime) }},
- endtime: {{ "%F"|format(event.endtime) }},
- duration: {{ "%F"|format(event.duration) }},
- memory: {{ "%.1F"|format(event.memory / 1024 / 1024) }},
- elements: {},
- periods: [
- {%- for period in event.periods -%}
- {
- start: {{ "%F"|format(period.starttime) }},
- end: {{ "%F"|format(period.endtime) }},
- duration: {{ "%F"|format(period.duration) }},
- elements: {}
- },
- {%- endfor -%}
- ],
- },
- {% endif %}
- {% endfor %}
- {% endautoescape %}
- {% endmacro %}
- {% macro display_timeline(token, events, origin) %}
- {% import _self as helper %}
- <div class="sf-profiler-timeline">
- <div id="legend-{{ token }}" class="legends"></div>
- <svg id="timeline-{{ token }}" class="timeline-graph"></svg>
- <script>{% autoescape 'js' %}
- window.addEventListener('load', function onLoad() {
- const theme = new Theme();
- new TimelineEngine(
- theme,
- new SvgRenderer(document.getElementById('timeline-{{ token }}')),
- new Legend(document.getElementById('legend-{{ token }}'), theme),
- document.getElementById('threshold'),
- {{ helper.dump_request_data(token, events, origin) }}
- );
- });
- {% endautoescape %}</script>
- </div>
- {% endmacro %}
|