blob: 252ca9b0cf4391465b9fd16269a9b628b854ccea [file] [log] [blame]
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\Profiler;
13
14/**
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17final class Profile implements \IteratorAggregate, \Serializable
18{
19 public const ROOT = 'ROOT';
20 public const BLOCK = 'block';
21 public const TEMPLATE = 'template';
22 public const MACRO = 'macro';
23
24 private $template;
25 private $name;
26 private $type;
27 private $starts = [];
28 private $ends = [];
29 private $profiles = [];
30
31 public function __construct(string $template = 'main', string $type = self::ROOT, string $name = 'main')
32 {
33 $this->template = $template;
34 $this->type = $type;
35 $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name;
36 $this->enter();
37 }
38
39 public function getTemplate(): string
40 {
41 return $this->template;
42 }
43
44 public function getType(): string
45 {
46 return $this->type;
47 }
48
49 public function getName(): string
50 {
51 return $this->name;
52 }
53
54 public function isRoot(): bool
55 {
56 return self::ROOT === $this->type;
57 }
58
59 public function isTemplate(): bool
60 {
61 return self::TEMPLATE === $this->type;
62 }
63
64 public function isBlock(): bool
65 {
66 return self::BLOCK === $this->type;
67 }
68
69 public function isMacro(): bool
70 {
71 return self::MACRO === $this->type;
72 }
73
74 /**
75 * @return Profile[]
76 */
77 public function getProfiles(): array
78 {
79 return $this->profiles;
80 }
81
82 public function addProfile(self $profile): void
83 {
84 $this->profiles[] = $profile;
85 }
86
87 /**
88 * Returns the duration in microseconds.
89 */
90 public function getDuration(): float
91 {
92 if ($this->isRoot() && $this->profiles) {
93 // for the root node with children, duration is the sum of all child durations
94 $duration = 0;
95 foreach ($this->profiles as $profile) {
96 $duration += $profile->getDuration();
97 }
98
99 return $duration;
100 }
101
102 return isset($this->ends['wt']) && isset($this->starts['wt']) ? $this->ends['wt'] - $this->starts['wt'] : 0;
103 }
104
105 /**
106 * Returns the memory usage in bytes.
107 */
108 public function getMemoryUsage(): int
109 {
110 return isset($this->ends['mu']) && isset($this->starts['mu']) ? $this->ends['mu'] - $this->starts['mu'] : 0;
111 }
112
113 /**
114 * Returns the peak memory usage in bytes.
115 */
116 public function getPeakMemoryUsage(): int
117 {
118 return isset($this->ends['pmu']) && isset($this->starts['pmu']) ? $this->ends['pmu'] - $this->starts['pmu'] : 0;
119 }
120
121 /**
122 * Starts the profiling.
123 */
124 public function enter(): void
125 {
126 $this->starts = [
127 'wt' => microtime(true),
128 'mu' => memory_get_usage(),
129 'pmu' => memory_get_peak_usage(),
130 ];
131 }
132
133 /**
134 * Stops the profiling.
135 */
136 public function leave(): void
137 {
138 $this->ends = [
139 'wt' => microtime(true),
140 'mu' => memory_get_usage(),
141 'pmu' => memory_get_peak_usage(),
142 ];
143 }
144
145 public function reset(): void
146 {
147 $this->starts = $this->ends = $this->profiles = [];
148 $this->enter();
149 }
150
151 public function getIterator(): \Traversable
152 {
153 return new \ArrayIterator($this->profiles);
154 }
155
156 public function serialize(): string
157 {
158 return serialize($this->__serialize());
159 }
160
161 public function unserialize($data): void
162 {
163 $this->__unserialize(unserialize($data));
164 }
165
166 /**
167 * @internal
168 */
169 public function __serialize(): array
170 {
171 return [$this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles];
172 }
173
174 /**
175 * @internal
176 */
177 public function __unserialize(array $data): void
178 {
179 list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = $data;
180 }
181}