feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: [Factories] Config caching - #7696

Merged
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache
Aug 21, 2023
Merged

feat: [Factories] Config caching#7696
kenjis merged 17 commits into
codeigniter4:4.4from
kenjis:feat-Factories-config-cache

Conversation

@kenjis

@kenjiskenjis commented Jul 12, 2023

Copy link
Copy Markdown
Member

Description
To improve performance.

How It Works:

  • Save the all Config instances in Factories into a cache file before shutdown, if the state of the Config instances in Factories changes.
  • Restore cached Config instances before CodeIgniter initialization if a cache is available.

Precautions:

  • Once cached, the cache is never expired, and not updated unless the state of the Config instances in Factories changes.
  • A change in the state of Config instances in Factories means that a new Config class is instantiated and shared in Factories.
  • Therefore, simply changing a existing Config file (or changing Environment Variables for it) will continue to use the Config instance with the old cached values. In that case, you must manually delete the cache file.
  • By default, every Config class that is cached must implement __set_state() method.

Benchmark:

Requests/sec: 328.50 (Caching off)
Requests/sec: 449.71 (Caching on)
Details
$ php -v
PHP 8.2.8 (cli) (built: Jul 6 2023 11:16:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
$ composer update --no-dev
$ php spark env
CodeIgniter v4.3.6 Command Line Tool - Server Time: 2023-07-12 03:00:54 UTC+00:00
Your environment is currently set as production.
$ symfony server:start
$ wrk -t10 -d5s http://127.0.0.1:8000/

Caching off:

Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.46ms 14.84ms 159.95ms 91.07%
Req/Sec 32.96 8.29 50.00 85.34%
1652 requests in 5.03s, 28.38MB read
Requests/sec: 328.50
Transfer/sec: 5.64MB

Caching on:

--- a/public/index.php+++ b/public/index.php@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
}
// Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();-// $factoriesCache->load('config');+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();+$factoriesCache->load('config');
// ^^^ Uncomment these lines if you want to use Config Caching.
/*
@@ -79,7 +79,7 @@ $app->setContext($context);
$app->run();
// Save Config Cache
-// $factoriesCache->save('config');+$factoriesCache->save('config');
// ^^^ Uncomment this line if you want to use Config Caching.
// Exits the application, setting the exit code for CLI-based applications
Running 5s test @ http://127.0.0.1:8000/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.67ms 14.49ms 171.32ms 92.59%
Req/Sec 45.21 11.09 70.00 70.82%
2258 requests in 5.02s, 38.80MB read
Requests/sec: 449.71
Transfer/sec: 7.73MB

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@kenjiskenjis added enhancement PRs that improve existing functionalities 4.4 labels Jul 12, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 332c8b4 to 3889325CompareJuly 12, 2023 04:13
@kenjiskenjis mentioned this pull request Jul 13, 2023
2 tasks

@iReddsiRedds left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good, but because of the classes, the implementation looks terrible. 🥴
Controversial for me is the point of caching in index.php. I think this would be better:

  • enable/disable caching via CLI command or settings in .env.
  • processing to place in the core.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

Comment threadsystem/Cache/FactoriesCache.php Outdated
Comment threadsystem/Cache/FactoriesCache/FileVarExportHandler.php Outdated
Comment threadapp/Config/Paths.php Outdated
Comment threadpublic/index.php
@kenjis

Copy link
Copy Markdown
MemberAuthor

Controversial for me is the point of caching in index.php.

Not making this caching configurable and not placing the code in the core is intentional for now.
Because this caching is not for everyone, because there are many precautions.

If there is a lot of agreement that it should be included in the core,
I will make it configurable and change it that way.

It would also be nice to have a CLI command that will clear any cache, and not do it manually.

spark cache:clear will clear the cache.

@iRedds

Copy link
Copy Markdown
Collaborator

spark cache:clear will clear the cache.

But this does not affect the proposed caching tool.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch 4 times, most recently from 1d374ab to 3699c47CompareJuly 22, 2023 08:13

@TimexPeachtreeTimexPeachtree left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changing setting in index.php is bit of controversial, feature is awesome 😎.

@kenjiskenjis added the stale Pull requests with conflicts label Jul 29, 2023
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 3699c47 to afbd366CompareJuly 29, 2023 06:22
@kenjiskenjis removed the stale Pull requests with conflicts label Jul 29, 2023
@kenjis

Copy link
Copy Markdown
MemberAuthor

Rebased.

@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from e6dd3c1 to dfa206fCompareJuly 29, 2023 06:50
@kenjis

Copy link
Copy Markdown
MemberAuthor

I got benchmark on Ubuntu 22.04 and Apache.

Off:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.38ms 47.38ms 85.19%
Req/Sec 152.01 38.93 333.00 60.83%
7630 requests in 5.10s, 131.09MB read
Requests/sec: 1496.21
Transfer/sec: 25.71MB

On:

$ wrk -t10 -d5s http://localhost/CodeIgniter4/
Running 5s test @ http://localhost/CodeIgniter4/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.30ms 2.87ms 38.41ms 89.55%
Req/Sec 197.98 46.97 270.00 54.40%
9869 requests in 5.02s, 169.57MB read
Requests/sec: 1967.81
Transfer/sec: 33.81MB
$ php -v
PHP 8.1.2-1ubuntu2.13 (cli) (built: Jun 28 2023 14:01:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.13, Copyright (c), by Zend Technologies

@kenjiskenjis mentioned this pull request Aug 8, 2023
Comment threadpublic/index.php
Comment threadpublic/index.php
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from dfa206f to 6742144CompareAugust 9, 2023 08:49

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very cool feature and impressive performance gain! I would like to see a test verifying the interaction with Registrars. We also need to determine the actual and desires intersection with our Settings library, and particularly context-specific (e.g. per user) Config values. It might just be that these are incompatible but we should be able to state that explicitly one way or another.

@kenjiskenjis mentioned this pull request Aug 13, 2023
22 tasks
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from 6742144 to 4fc5c2bCompareAugust 15, 2023 01:36
@kenjis

Copy link
Copy Markdown
MemberAuthor

Updated the docs.

@MGatnerMGatner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kids interrupted, I will come back to this 😅

Comment threaduser_guide_src/source/changelogs/v4.4.0.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
Comment threaduser_guide_src/source/concepts/factories.rst Outdated
@kenjis
kenjisforce-pushed the feat-Factories-config-cache branch from f564eea to 82328c4CompareAugust 16, 2023 05:24
@kenjis

Copy link
Copy Markdown
MemberAuthor

@MGatner As far as Registrars are concerned, the Registrar works when the Config class is instantiated on the first request. That instance is then cached and used forever.

As far as Settings are concerned, it is another layer on top of the Config class.
So I believe if there are setting data in the database, these are used. If there aren't, the cached Config object is used. So Settings work always.

Comment threadsystem/Config/BaseConfig.php Outdated
@kenjis
kenjis requested a review from MGatnerAugust 17, 2023 01:29
@kenjis
kenjis merged commit f4c17e8 into codeigniter4:4.4Aug 21, 2023
@kenjis
kenjis deleted the feat-Factories-config-cache branch August 21, 2023 01:08
@MGatner

Copy link
Copy Markdown
Member

🥳

@neznaika0

Copy link
Copy Markdown
Contributor

System with SSD:

~$ php -v
PHP 8.2.7 (cli) (built: Jun 9 2023 06:51:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
~$ uname -a
Linux aleksandr-debian 6.4.0-3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.4.11-1 (2023-08-17) x86_64 GNU/Linux

Fisrt installation (> 5 repeats) in CodeIgniter v4.4.0.

DEVELOPMENT:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.69ms 1.77ms 44.64ms 98.45%
Req/Sec 27.14 4.52 30.00 71.40%
1357 requests in 5.01s, 52.06MB read
Socket errors: connect 0, read 1357, write 0, timeout 0
Requests/sec: 271.11
Transfer/sec: 10.40MB

After DEVELOPMENT (fast ~13%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.44ms 1.58ms 40.37ms 96.42%
Req/Sec 30.70 2.63 40.00 92.60%
1535 requests in 5.01s, 58.89MB read
Socket errors: connect 0, read 1535, write 0, timeout 0
Requests/sec: 306.60
Transfer/sec: 11.76MB

PRODUCTION:

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.26ms 1.30ms 35.59ms 97.63%
Req/Sec 37.94 4.05 40.00 79.40%
1897 requests in 5.00s, 32.54MB read
Socket errors: connect 0, read 1897, write 0, timeout 0
Requests/sec: 379.11
Transfer/sec: 6.50MB

After PRODUCTION (fast ~19%):

~$ wrk -t10 -d5s http://localhost:8080/
Running 5s test @ http://localhost:8080/
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.82ms 1.10ms 33.70ms 97.37%
Req/Sec 45.64 4.97 50.00 56.40%
2282 requests in 5.00s, 39.14MB read
Socket errors: connect 0, read 2282, write 0, timeout 0
Requests/sec: 455.97
Transfer/sec: 7.82MB

But your test fasted ~37%

@kenjis

Copy link
Copy Markdown
MemberAuthor

The benchmark results depend on the environments.

My first benchmark was made on macOS (MBA), and it seems mac is much slower than Ubuntu.
See #7696 (comment)
The benchmark on Ubuntu was made on another note PC, but the spec is not much better than the MBA.

After all, if you want to know your truth, you need to check your production server environment.

@neznaika0

Copy link
Copy Markdown
Contributor

I understood. I just wanted to note that optimization does not increase equally

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

Labels

enhancementPRs that improve existing functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@kenjis@iRedds@MGatner@neznaika0@samsonasik@TimexPeachtree