diff --git a/CHANGELOG-5.0.md b/CHANGELOG-5.0.md
index 7624df93fa..e4a7ea861d 100644
--- a/CHANGELOG-5.0.md
+++ b/CHANGELOG-5.0.md
@@ -19,6 +19,7 @@ All notable changes are documented here. The format is based on [Keep a Changelo
### Added
+- Benchmark subjects for Acl, Cache, Config, Flash, Forms, Jwt, Logger, Security, Session and Validation in `tests/benchmarks`. [#17695](https://github.com/phalcon/cphalcon/issues/17695)
### Fixed
diff --git a/tests/benchmarks/Acl/AclBench.php b/tests/benchmarks/Acl/AclBench.php
new file mode 100644
index 0000000000..c471f32c40
--- /dev/null
+++ b/tests/benchmarks/Acl/AclBench.php
@@ -0,0 +1,96 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Acl;
+
+use Phalcon\Acl\Adapter\Memory;
+use Phalcon\Di\Di;
+use PhpBench\Attributes\BeforeMethods;
+use PhpBench\Attributes\Revs;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class AclBench
+{
+ private const ACCESS = ['index', 'view', 'edit', 'delete'];
+
+ private const COMPONENTS = ['posts', 'comments', 'users', 'settings', 'reports'];
+
+ private Memory $acl;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->acl = $this->buildAcl();
+ }
+
+ /**
+ * The ACL with 4 roles and 5 components, as one request makes it.
+ */
+ #[Revs(200)]
+ public function benchBuild(): void
+ {
+ $acl = $this->buildAcl();
+
+ if (true !== $acl->isAllowed('admin', 'settings', 'delete')) {
+ throw new RuntimeException('Unexpected value: false');
+ }
+ }
+
+ public function benchIsAllowed(): void
+ {
+ if (true !== $this->acl->isAllowed('editor', 'posts', 'edit')) {
+ throw new RuntimeException('Unexpected value: false');
+ }
+ }
+
+ /**
+ * The access comes from guest, through user (editor inherits user).
+ */
+ public function benchIsAllowedInherited(): void
+ {
+ if (true !== $this->acl->isAllowed('editor', 'comments', 'view')) {
+ throw new RuntimeException('Unexpected value: false');
+ }
+ }
+
+ public function benchIsDenied(): void
+ {
+ if (false !== $this->acl->isAllowed('guest', 'users', 'delete')) {
+ throw new RuntimeException('Unexpected value: true');
+ }
+ }
+
+ private function buildAcl(): Memory
+ {
+ $acl = new Memory();
+
+ $acl->addRole('guest');
+ $acl->addRole('user', 'guest');
+ $acl->addRole('editor', 'user');
+ $acl->addRole('admin', 'editor');
+
+ foreach (self::COMPONENTS as $component) {
+ $acl->addComponent($component, self::ACCESS);
+ }
+
+ $acl->allow('guest', 'posts', ['index', 'view']);
+ $acl->allow('guest', 'comments', ['index', 'view']);
+ $acl->allow('user', 'comments', 'edit');
+ $acl->allow('editor', 'posts', ['edit', 'delete']);
+ $acl->allow('admin', '*', '*');
+
+ return $acl;
+ }
+}
diff --git a/tests/benchmarks/Cache/CacheBench.php b/tests/benchmarks/Cache/CacheBench.php
new file mode 100644
index 0000000000..7aa90f5423
--- /dev/null
+++ b/tests/benchmarks/Cache/CacheBench.php
@@ -0,0 +1,80 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Cache;
+
+use Phalcon\Cache\AdapterFactory;
+use Phalcon\Cache\Cache;
+use Phalcon\Di\Di;
+use Phalcon\Storage\SerializerFactory;
+use PhpBench\Attributes\BeforeMethods;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class CacheBench
+{
+ private const ROBOTS = ['one', 'two', 'three'];
+
+ private Cache $cache;
+
+ private int $counter = 0;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->cache = $this->newCache();
+ $this->cache->set('robots', self::ROBOTS);
+ }
+
+ /**
+ * The two factories, the memory adapter and the cache, as one request
+ * makes them.
+ */
+ public function benchCreate(): void
+ {
+ $cache = $this->newCache();
+
+ if (false !== $cache->has('missing')) {
+ throw new RuntimeException('Unexpected value: true');
+ }
+ }
+
+ public function benchGet(): void
+ {
+ $actual = $this->cache->get('robots');
+
+ if (self::ROBOTS !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: %s', var_export($actual, true)));
+ }
+ }
+
+ /**
+ * set() of a key that exists, with a new value on each call.
+ */
+ public function benchSet(): void
+ {
+ $this->counter++;
+
+ if (true !== $this->cache->set('counter', $this->counter)) {
+ throw new RuntimeException('Unexpected value: false');
+ }
+ }
+
+ private function newCache(): Cache
+ {
+ $factory = new AdapterFactory(new SerializerFactory());
+
+ return new Cache($factory->newInstance('memory'));
+ }
+}
diff --git a/tests/benchmarks/Config/ConfigBench.php b/tests/benchmarks/Config/ConfigBench.php
new file mode 100644
index 0000000000..856188654b
--- /dev/null
+++ b/tests/benchmarks/Config/ConfigBench.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Config;
+
+use Phalcon\Config\Config;
+use Phalcon\Di\Di;
+use PhpBench\Attributes\BeforeMethods;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class ConfigBench
+{
+ private const DATA = [
+ 'app' => [
+ 'baseUri' => '/',
+ 'name' => 'bench',
+ 'timezone' => 'UTC',
+ ],
+ 'database' => [
+ 'adapter' => 'mysql',
+ 'dbname' => 'phalcon',
+ 'host' => 'localhost',
+ 'options' => [
+ 'charset' => 'utf8mb4',
+ ],
+ 'password' => 'secret',
+ 'port' => 3306,
+ 'username' => 'root',
+ ],
+ 'services' => [
+ 'cache' => 'memory',
+ 'logger' => 'stream',
+ 'mailer' => 'smtp',
+ 'queue' => 'beanstalk',
+ 'session' => 'files',
+ ],
+ ];
+
+ private Config $config;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->config = new Config(self::DATA);
+ }
+
+ /**
+ * A new config from a nested array, as one request makes it: each
+ * nested array becomes a Config object.
+ */
+ public function benchConstruct(): void
+ {
+ $config = new Config(self::DATA);
+
+ $actual = $config->path('database.options.charset');
+ if ('utf8mb4' !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: %s', var_export($actual, true)));
+ }
+ }
+
+ public function benchPath(): void
+ {
+ $actual = $this->config->path('database.host');
+
+ if ('localhost' !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: %s', var_export($actual, true)));
+ }
+ }
+}
diff --git a/tests/benchmarks/Encryption/JwtBench.php b/tests/benchmarks/Encryption/JwtBench.php
new file mode 100644
index 0000000000..d8a755efbf
--- /dev/null
+++ b/tests/benchmarks/Encryption/JwtBench.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Encryption;
+
+use Phalcon\Di\Di;
+use Phalcon\Encryption\Security\JWT\Builder;
+use Phalcon\Encryption\Security\JWT\Signer\Hmac;
+use Phalcon\Encryption\Security\JWT\Token\Parser;
+use PhpBench\Attributes\BeforeMethods;
+use PhpBench\Attributes\Revs;
+use RuntimeException;
+
+/**
+ * The time claims are fixed, so the token is the same on each call.
+ */
+#[BeforeMethods('setUp')]
+#[Revs(200)]
+final class JwtBench
+{
+ private const EXPECTED_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9'
+ . '.eyJhdWQiOlsiaHR0cHM6Ly9waGFsY29uLmlvIl0sImV4cCI6NDEwMjQ0NDgwMCwianRpIjoiYmVuY2gtMSIsImlhdCI6'
+ . 'MTcwMDAwMDAwMCwiaXNzIjoiaHR0cHM6Ly9waGFsY29uLmlvIiwibmJmIjoxNzAwMDAwMDAwLCJzdWIiOiJiZW5jaCJ9'
+ . '.F_CWXOsTMdZz_bXLYj9MxwpfcpXUNZrPCob1zR0AHwWqoHr2yNNTVgji7L7AfVnWAXtxcEn0usXWdxwkKVE3rQ';
+
+ private const PASSPHRASE = 'Phalcon!Bench#Passphrase2026';
+
+ private Parser $parser;
+
+ private Hmac $signer;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->parser = new Parser();
+ $this->signer = new Hmac();
+ }
+
+ public function benchBuild(): void
+ {
+ $builder = new Builder($this->signer);
+ $builder
+ ->setAudience('https://phalcon.io')
+ ->setExpirationTime(4102444800)
+ ->setId('bench-1')
+ ->setIssuedAt(1700000000)
+ ->setIssuer('https://phalcon.io')
+ ->setNotBefore(1700000000)
+ ->setPassphrase(self::PASSPHRASE)
+ ->setSubject('bench');
+
+ $actual = $builder->getToken()->getToken();
+
+ if (self::EXPECTED_TOKEN !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: "%s"', $actual));
+ }
+ }
+
+ public function benchParse(): void
+ {
+ $actual = $this->parser->parse(self::EXPECTED_TOKEN)->getClaims()->get('sub');
+
+ if ('bench' !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: %s', var_export($actual, true)));
+ }
+ }
+}
diff --git a/tests/benchmarks/Encryption/SecurityBench.php b/tests/benchmarks/Encryption/SecurityBench.php
new file mode 100644
index 0000000000..ef08e36596
--- /dev/null
+++ b/tests/benchmarks/Encryption/SecurityBench.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Encryption;
+
+use Phalcon\Di\Di;
+use Phalcon\Encryption\Security;
+use Phalcon\Session\Adapter\Noop;
+use Phalcon\Session\Manager;
+use PhpBench\Attributes\BeforeMethods;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class SecurityBench
+{
+ private Manager $session;
+
+ private string $token = '';
+
+ private string $tokenKey = '';
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->session = new Manager();
+ $this->session->setAdapter(new Noop());
+ $this->session->start();
+
+ if (PHP_SESSION_ACTIVE !== $this->session->status()) {
+ throw new RuntimeException(
+ sprintf('Unexpected session status: %d', $this->session->status())
+ );
+ }
+
+ $this->newToken(new Security($this->session));
+ }
+
+ /**
+ * One form request: check the CSRF token of the previous call, then make
+ * a new key and token for the next form. checkToken() removes the
+ * checked token from the session.
+ */
+ public function benchCsrf(): void
+ {
+ $security = new Security($this->session);
+
+ if (true !== $security->checkToken($this->tokenKey, $this->token)) {
+ throw new RuntimeException(sprintf('Unexpected value: false for token "%s"', $this->token));
+ }
+
+ $this->newToken($security);
+ }
+
+ private function newToken(Security $security): void
+ {
+ $this->tokenKey = (string) $security->getTokenKey();
+ $this->token = (string) $security->getToken();
+ }
+}
diff --git a/tests/benchmarks/Filter/ValidationBench.php b/tests/benchmarks/Filter/ValidationBench.php
new file mode 100644
index 0000000000..845d6edb7e
--- /dev/null
+++ b/tests/benchmarks/Filter/ValidationBench.php
@@ -0,0 +1,71 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Filter;
+
+use Phalcon\Di\Di;
+use Phalcon\Filter\Validation;
+use Phalcon\Filter\Validation\Validator\Email;
+use Phalcon\Filter\Validation\Validator\PresenceOf;
+use Phalcon\Filter\Validation\Validator\StringLength;
+use PhpBench\Attributes\BeforeMethods;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class ValidationBench
+{
+ /**
+ * The name is too short (StringLength) and the email is not valid
+ * (Email): 2 messages.
+ */
+ private const INVALID_DATA = [
+ 'email' => 'bad',
+ 'name' => 'a',
+ ];
+
+ private const VALID_DATA = [
+ 'email' => 'team@phalcon.io',
+ 'name' => 'Phalcon',
+ ];
+
+ private Validation $validation;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->validation = new Validation();
+ $this->validation->add('name', new PresenceOf());
+ $this->validation->add('email', new PresenceOf());
+ $this->validation->add('email', new Email());
+ $this->validation->add('name', new StringLength(['max' => 50, 'min' => 2]));
+ }
+
+ public function benchValidate(): void
+ {
+ $messages = $this->validation->validate(self::VALID_DATA);
+
+ if (0 !== count($messages)) {
+ throw new RuntimeException(sprintf('Unexpected count: %d', count($messages)));
+ }
+ }
+
+ public function benchValidateFails(): void
+ {
+ $messages = $this->validation->validate(self::INVALID_DATA);
+
+ if (2 !== count($messages)) {
+ throw new RuntimeException(sprintf('Unexpected count: %d', count($messages)));
+ }
+ }
+}
diff --git a/tests/benchmarks/Flash/FlashBench.php b/tests/benchmarks/Flash/FlashBench.php
new file mode 100644
index 0000000000..ce10457115
--- /dev/null
+++ b/tests/benchmarks/Flash/FlashBench.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Flash;
+
+use Phalcon\Di\Di;
+use Phalcon\Flash\Direct;
+use Phalcon\Html\Escaper;
+use PhpBench\Attributes\BeforeMethods;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class FlashBench
+{
+ private const EXPECTED_OUTPUT = '
Robot <b>saved</b>
' . PHP_EOL
+ . 'Robot <b>not saved</b>
' . PHP_EOL
+ . 'Robot <b>changed</b>
' . PHP_EOL
+ . 'Robot <b>old</b>
' . PHP_EOL;
+
+ private Direct $flash;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->flash = new Direct(new Escaper());
+ $this->flash->setImplicitFlush(false);
+ }
+
+ /**
+ * 4 messages, one of each type. Each text has HTML, so the escaper runs.
+ */
+ public function benchMessages(): void
+ {
+ $actual = $this->flash->success('Robot saved')
+ . $this->flash->error('Robot not saved')
+ . $this->flash->notice('Robot changed')
+ . $this->flash->warning('Robot old');
+
+ if (self::EXPECTED_OUTPUT !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: "%s"', $actual));
+ }
+ }
+}
diff --git a/tests/benchmarks/Forms/FormBench.php b/tests/benchmarks/Forms/FormBench.php
new file mode 100644
index 0000000000..6694ff3540
--- /dev/null
+++ b/tests/benchmarks/Forms/FormBench.php
@@ -0,0 +1,147 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Forms;
+
+use Phalcon\Di\Di;
+use Phalcon\Filter\Validation\Validator\Email as EmailValidator;
+use Phalcon\Filter\Validation\Validator\PresenceOf;
+use Phalcon\Filter\Validation\Validator\StringLength;
+use Phalcon\Forms\Element\Email;
+use Phalcon\Forms\Element\Password;
+use Phalcon\Forms\Element\Select;
+use Phalcon\Forms\Element\Text;
+use Phalcon\Forms\Element\TextArea;
+use Phalcon\Forms\Form;
+use Phalcon\Html\Escaper;
+use Phalcon\Html\TagFactory;
+use PhpBench\Attributes\BeforeMethods;
+use PhpBench\Attributes\Revs;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+#[Revs(200)]
+final class FormBench
+{
+ private const ELEMENTS = ['name', 'email', 'password', 'country', 'about'];
+
+ private const EXPECTED_HTML = ''
+ . ''
+ . ''
+ . ''
+ . '';
+
+ private const VALID_DATA = [
+ 'about' => 'A full stack PHP framework',
+ 'country' => 'gr',
+ 'email' => 'team@phalcon.io',
+ 'name' => 'Phalcon',
+ 'password' => 'secret123',
+ ];
+
+ private Form $form;
+
+ private TagFactory $tagFactory;
+
+ /**
+ * Select::render() uses Phalcon\Tag, which reads the 'escaper' service
+ * of the default container. The container has only this service.
+ */
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $container = new Di();
+ $container->setShared('escaper', Escaper::class);
+ Di::setDefault($container);
+
+ $this->tagFactory = new TagFactory(new Escaper());
+ $this->form = $this->buildForm();
+ }
+
+ /**
+ * A form with 5 elements and their validators, as one request makes it.
+ */
+ public function benchConstruct(): void
+ {
+ $form = $this->buildForm();
+
+ if (5 !== $form->count()) {
+ throw new RuntimeException(sprintf('Unexpected count: %d', $form->count()));
+ }
+ }
+
+ public function benchIsValid(): void
+ {
+ if (true !== $this->form->isValid(self::VALID_DATA)) {
+ throw new RuntimeException('Unexpected value: false');
+ }
+ }
+
+ public function benchRender(): void
+ {
+ $actual = '';
+ foreach (self::ELEMENTS as $name) {
+ $actual .= $this->form->render($name);
+ }
+
+ if (self::EXPECTED_HTML !== $actual) {
+ throw new RuntimeException(sprintf('Unexpected value: "%s"', $actual));
+ }
+ }
+
+ private function buildForm(): Form
+ {
+ $name = new Text('name');
+ $name->addValidators(
+ [
+ new PresenceOf(),
+ new StringLength(['max' => 50, 'min' => 2]),
+ ]
+ );
+
+ $email = new Email('email');
+ $email->addValidators(
+ [
+ new PresenceOf(),
+ new EmailValidator(),
+ ]
+ );
+
+ $password = new Password('password');
+ $password->addValidator(new StringLength(['min' => 8]));
+
+ $country = new Select(
+ 'country',
+ [
+ 'de' => 'Germany',
+ 'gr' => 'Greece',
+ 'us' => 'USA',
+ ]
+ );
+
+ $form = new Form();
+ $form->setTagFactory($this->tagFactory);
+ $form->add($name);
+ $form->add($email);
+ $form->add($password);
+ $form->add($country);
+ $form->add(new TextArea('about'));
+
+ return $form;
+ }
+}
diff --git a/tests/benchmarks/Logger/LastLineAdapter.php b/tests/benchmarks/Logger/LastLineAdapter.php
new file mode 100644
index 0000000000..44929797b2
--- /dev/null
+++ b/tests/benchmarks/Logger/LastLineAdapter.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Logger;
+
+use Phalcon\Logger\Adapter\AbstractAdapter;
+use Phalcon\Logger\Item;
+
+/**
+ * A logger adapter with no I/O. It keeps the last formatted line, so the
+ * subjects can check it.
+ */
+final class LastLineAdapter extends AbstractAdapter
+{
+ public string $last = '';
+
+ public function close(): bool
+ {
+ return true;
+ }
+
+ public function process(Item $item): void
+ {
+ $this->last = $this->getFormattedItem($item);
+ }
+}
diff --git a/tests/benchmarks/Logger/LoggerBench.php b/tests/benchmarks/Logger/LoggerBench.php
new file mode 100644
index 0000000000..6f3e8a5070
--- /dev/null
+++ b/tests/benchmarks/Logger/LoggerBench.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace Phalcon\Tests\Benchmarks\Logger;
+
+use Phalcon\Di\Di;
+use Phalcon\Logger\Enum;
+use Phalcon\Logger\Logger;
+use PhpBench\Attributes\BeforeMethods;
+use RuntimeException;
+
+#[BeforeMethods('setUp')]
+final class LoggerBench
+{
+ private const CONTEXT = ['name' => 'phalcon'];
+
+ private const MESSAGE = 'User %name% logged in';
+
+ private LastLineAdapter $adapter;
+
+ private Logger $logger;
+
+ private LastLineAdapter $skippedAdapter;
+
+ private Logger $skippedLogger;
+
+ public function setUp(): void
+ {
+ Di::reset();
+
+ $this->adapter = new LastLineAdapter();
+ $this->logger = new Logger('bench', ['main' => $this->adapter]);
+
+ $this->skippedAdapter = new LastLineAdapter();
+ $this->skippedLogger = new Logger('skipped', ['main' => $this->skippedAdapter]);
+ $this->skippedLogger->setLogLevel(Enum::ERROR);
+ }
+
+ /**
+ * debug() on a logger with the level ERROR: no line is written.
+ */
+ public function benchDebugSkipped(): void
+ {
+ $this->skippedLogger->debug(self::MESSAGE, self::CONTEXT);
+
+ if ('' !== $this->skippedAdapter->last) {
+ throw new RuntimeException(sprintf('Unexpected value: "%s"', $this->skippedAdapter->last));
+ }
+ }
+
+ /**
+ * info() with one placeholder, formatted with the default line
+ * formatter (date, level, message).
+ */
+ public function benchInfo(): void
+ {
+ $this->logger->info(self::MESSAGE, self::CONTEXT);
+
+ if (!str_ends_with($this->adapter->last, 'User phalcon logged in')) {
+ throw new RuntimeException(sprintf('Unexpected value: "%s"', $this->adapter->last));
+ }
+ }
+}
diff --git a/tests/benchmarks/README.md b/tests/benchmarks/README.md
index cd1f263db0..7ee2859a74 100644
--- a/tests/benchmarks/README.md
+++ b/tests/benchmarks/README.md
@@ -86,23 +86,35 @@ docker exec cphalcon-bench-8.4 callgrind_annotate --auto=no --inclusive=yes /srv
## Micro subjects
-One subject for each component entry point that the reference apps run (selected with the coverage data).
+One subject for each component entry point that the reference apps run (selected with the coverage data), and
+subjects for components that no reference app uses (Acl, Cache, Config, Encryption, Flash, Forms, Logger,
+Session and Validation).
| Class | Subjects |
|----------------------------|--------------------------------------------------------------------------------|
+| `Acl\AclBench` | `benchBuild`, `benchIsAllowed`, `benchIsAllowedInherited`, `benchIsDenied` |
+| `Cache\CacheBench` | `benchCreate`, `benchGet`, `benchSet` |
+| `Config\ConfigBench` | `benchConstruct`, `benchPath` |
| `Container\ContainerBench` | `benchGet` |
| `Db\PdoBench` | `benchFetchAll`, `benchFetchOneBound` |
| `Di\DiBench` | `benchFactoryDefault`, `benchGetNew`, `benchGetShared`, `benchGetSharedMethod` |
+| `Encryption\JwtBench` | `benchBuild`, `benchParse` |
+| `Encryption\SecurityBench` | `benchCsrf` |
| `Events\ManagerBench` | `benchFire`, `benchFireNoListener` |
| `Filter\FilterBench` | `benchSanitize` |
+| `Filter\ValidationBench` | `benchValidate`, `benchValidateFails` |
+| `Flash\FlashBench` | `benchMessages` |
+| `Forms\FormBench` | `benchConstruct`, `benchIsValid`, `benchRender` |
| `Html\EscaperBench` | `benchHtml` |
| `Http\ResponseBench` | `benchSend`, `benchSetJsonContent` |
+| `Logger\LoggerBench` | `benchDebugSkipped`, `benchInfo` |
| `Mvc\DispatcherBench` | `benchDispatch` |
| `Mvc\ModelBench` | `benchFind`, `benchFindFirst`, `benchQueryJoin`, `benchSave`, `benchToArray` |
| `Mvc\QueryBench` | `benchParseCold`, `benchParseWarm` |
| `Mvc\RouterBench` | `benchDefineAndHandle`, `benchDefineAndHandleMethods`, `benchHandle`, `benchHandleWithEvents` |
| `Mvc\ViewBench` | `benchPartial`, `benchRender` |
| `Mvc\VoltBench` | `benchCompileString` |
+| `Session\SessionBench` | `benchBagSet`, `benchGet`, `benchSet` |
| `Support\CollectionBench` | `benchConstruct`, `benchFilter`, `benchGet`, `benchOffsetGet`, `benchRemove`, `benchSet`, `benchToJson` |
| `Support\JsonBench` | `benchEncode` |
@@ -116,8 +128,12 @@ One subject for each component entry point that the reference apps run (selected
call. `benchRemove` sets the key and then removes it, so each call does the same work.
- `benchParseCold` uses a new PHQL string for each call, so both PHQL caches miss. The caches grow during
the run.
-- For heavy subjects (Router, View, Model, Query, Db, `benchFactoryDefault`), use a smaller k (for example
- 200) with `bin/instr`.
+- The component subjects use no network: Session uses the `Noop` adapter, Cache the `memory` adapter, Logger the
+ bench adapter `LastLineAdapter`.
+- `Forms\FormBench` sets a default container with only `escaper`: `Select::render()` uses `Phalcon\Tag`, which
+ reads this service.
+- For heavy subjects (Router, View, Model, Query, Db, `benchFactoryDefault`, Forms, JWT, `Acl\AclBench::benchBuild`),
+ use a smaller k (for example 200) with `bin/instr`.
## Reference apps
@@ -254,6 +270,17 @@ docker exec cphalcon-bench-8.4 tests/benchmarks/bin/run-all