├── Block └── Adminhtml │ └── Index │ ├── Gui.php │ └── Index.php ├── COPYING.txt ├── Controller └── Adminhtml │ └── Index │ ├── Gui.php │ └── Index.php ├── LICENSE.txt ├── Magento-Opcache-Gui.jpg ├── PHP-performance.jpg ├── README.md ├── composer.json ├── etc ├── acl.xml ├── adminhtml │ ├── menu.xml │ └── routes.xml ├── csp_whitelist.xml └── module.xml ├── registration.php ├── vendor ├── amnuts │ └── opcache-gui │ │ ├── README.md │ │ ├── build │ │ ├── _frontend │ │ │ ├── interface.jsx │ │ │ └── interface.scss │ │ ├── build.php │ │ └── template.phps │ │ ├── composer.json │ │ ├── index.php │ │ ├── package.json │ │ └── src │ │ └── Opcache │ │ └── Service.php ├── autoload.php └── composer │ ├── ClassLoader.php │ ├── LICENSE │ ├── autoload_classmap.php │ ├── autoload_files.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_real.php │ ├── autoload_static.php │ └── installed.json └── view └── adminhtml ├── layout ├── opcache_gui_index_gui.xml └── opcache_gui_index_index.xml └── templates └── index ├── gui.phtml └── index.phtml /Block/Adminhtml/Index/Gui.php: -------------------------------------------------------------------------------- 1 | backendUrl = $backendUrl; 29 | //$this->setData('gui_url', $this->backendUrl->getUrl('opcache_gui/index/gui')); 30 | parent::__construct($context, $data); 31 | } 32 | 33 | public function getGuiUrl(){ 34 | return $this->backendUrl->getUrl('opcache_gui/index/gui'); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2020-present 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /Controller/Adminhtml/Index/Gui.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 26 | parent::__construct($context); 27 | 28 | } 29 | 30 | /** 31 | * Execute view action 32 | * 33 | * @return \Magento\Framework\Controller\ResultInterface 34 | */ 35 | public function execute() 36 | { 37 | 38 | //$this->addData(array('cache_lifetime' => null)); 39 | /*return $this->resultPageFactory->create(false, [ 40 | 'template' => 'Genaker_Opcache::index/gui.phtml' 41 | ]);*/ 42 | require __DIR__ . '/../../../view/adminhtml/templates/index/gui.phtml'; 43 | die(); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Index/Index.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 26 | parent::__construct($context); 27 | } 28 | 29 | /** 30 | * Execute view action 31 | * 32 | * @return \Magento\Framework\Controller\ResultInterface 33 | */ 34 | public function execute() 35 | { 36 | return $this->resultPageFactory->create(); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2020-present 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /Magento-Opcache-Gui.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Genaker/Magento2OPcacheGUI/4a2331beca2dd30fd65dafcce259c97ce3ada97c/Magento-Opcache-Gui.jpg -------------------------------------------------------------------------------- /PHP-performance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Genaker/Magento2OPcacheGUI/4a2331beca2dd30fd65dafcce259c97ce3ada97c/PHP-performance.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magento 2 OPcache GUI PHP Performance Dashboard 2 | 3 | Magento 2 Opcache Control GUI using React Frontend Micro-services. 4 | 5 | ![MAgento 2 Opcache GUI](https://github.com/Genaker/Magento2OPcacheGUI/raw/main/Magento-Opcache-Gui.jpg) 6 | 7 | # Where to find in the Admin Menu 8 | 9 | System -> React -> OpCache GUI 10 | 11 | # Installation 12 | 13 | Copy to App code, Setup, and compile as always. 14 | 15 | This Extension doesn't need static content generation it uses CDN version of React JS. So, you can install with flag *--keep-generated* 16 | 17 | or use composer: 18 | ``` 19 | composer require genaker/module-opcache 20 | ``` 21 | 22 | # Magento 2 Opcache best settings 23 | 24 | The biggest Magento 2 performance issue is the wrong (default) PHP OPcache settings. 25 | 26 | Check your PHP settings with this module: 27 | ``` 28 | opcache.enable = 1 29 | opcache.enable_cli = 0 30 | opcache.memory_consumption = 556 31 | opcache.max_accelerated_files = 1000000 32 | opcache.validate_timestamps = 0 33 | opcache.interned_strings_buffer=64 34 | opcache.max_wasted_percentage=5 35 | opcache.save_comments=1 36 | opcache.fast_shutdown=1 37 | ``` 38 | 39 | # CLI opcache settings 40 | should be a separate cli config file like */etc/php/8.1/cli/conf.d/10-opcache.ini* 41 | ``` 42 | zend_extension=opcache.so 43 | opcache.memory_consumption=1000M 44 | opcache.interned_strings_buffer=8 45 | opcache.max_accelerated_files=10000000 46 | opcache.validate_timestamps=1 47 | ; opcache.revalidate_freq=2 48 | opcache.enable_cli=1 49 | opcache.file_cache=/tmp/ 50 | opcache.file_cache_only=0 51 | opcache.file_cache_consistency_checks=1 52 | ``` 53 | 54 | # PHP BogoMIPS performance measurement 55 | 56 | New feature has been added. Now you will have PHP performance test on GUI open. 57 | 58 | Magento 2 is CPU CPU-intensive platform due to bad framework design. You should use the fastest CPU to achieve a good page rendering performance. If Magento 2 takes a 2GHz processor core 3 seconds to process a request, then the same request would be returned in around 2 seconds by a 3GHz processor core. Test your PHP performance. 59 | 60 | ![Magento 2 PHP performance](https://github.com/Genaker/Magento2OPcacheGUI/raw/main/PHP-performance.jpg) 61 | 62 | AWS C5.large has *0.032* PHP 7.3.23 performance score (less is better).
63 | AWS R5.xlarge has *0.039* PHP 7.2.34 performance score (less is better).
64 | AWS C8.xlarge has *0.029* PHP 8.1 performance score (less is better), CLI performace is: 0.066 for Cli opcache doesn't work it is well known PHP issue
65 | 66 | Two types of BogoMIPS performance are measured from the CLI and from the web interface cached by OPcache. 67 | 68 | # What is BogoMIPS of the Magento Server? 69 | 70 | MIPS stands for Millions of Instructions Per Second. It measures a Magento server code computation speed. Like most such measures, it is more often abused than used properly (it is very difficult to justly compare MIPS for different kinds of computers). 71 | BogoMips are Linus's (Founder of Linux) own invention and Yehor Shytikov adopted this concept to the Magento servers. The linux kernel version 0.99.11 (dated 11 July 1993) needed a timing loop (the time is too short and/or needs to be too exact for a non-busy-loop method of waiting), which must be calibrated to the processor speed of the machine. Hence, the kernel measures at boot time how fast a certain kind of busy loop runs on a computer. "Bogo" comes from "bogus", i.e, something which is a fake. Hence, the BogoMips value gives some indication of the processor speed, but it is way too unscientific to be called anything but BogoMips. 72 | 73 | It is the best way to measure Magento PHP code execution on the server and compare server performance. 74 | 75 | 76 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "genaker/module-opcache", 3 | "description": "PHP Op-cache monitoring ", 4 | "type": "magento2-module", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Yehor Shytikov", 9 | "email": "egorshitikov@gmail.com" 10 | } 11 | ], 12 | "minimum-stability": "dev", 13 | "autoload": { 14 | "psr-4": { 15 | "Genaker\\Opcache\\": "" 16 | }, 17 | "files": [ 18 | "registration.php" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /etc/csp_whitelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | https://unpkg.com 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | handle(); 39 | ``` 40 | 41 | Then you can create whatever view you want with which to show the opcache details. Although there is a pretty neat React-based interface available for you in this repo. 42 | 43 | Alternatively, include `vendor/amnuts/opcache-gui/index.php` directly and this'll give you the same result as just copying/pasting the `index.php` somewhere. 44 | 45 | ```php 46 | true, // show/hide the files tab 68 | 'allow_invalidate' => true, // give a link to invalidate files 69 | 'allow_reset' => true, // give option to reset the whole cache 70 | 'allow_realtime' => true, // give option to enable/disable real-time updates 71 | 'refresh_time' => 5, // how often the data will refresh, in seconds 72 | 'size_precision' => 2, // Digits after decimal point 73 | 'size_space' => false, // have '1MB' or '1 MB' when showing sizes 74 | 'charts' => true, // show gauge chart or just big numbers 75 | 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering 76 | 'per_page' => 200, // How many results per page to show in the file list, false for no pagination 77 | 'cookie_name' => 'opcachegui', // name of cookie 78 | 'cookie_ttl' => 365, // days to store cookie 79 | 'highlight' => [ 80 | 'memory' => true, // show the memory chart/big number 81 | 'hits' => true, // show the hit rate chart/big number 82 | 'keys' => true // show the keys used chart/big number 83 | ] 84 | ]; 85 | ``` 86 | 87 | If you want to change any of the defaults, you can pass in just the ones you want to change if you're happy to keep the rest as-is. Just alter the array at the top of the `index.php` script (or pass in the array differently to the `Service` class). For example, the following would change only the `allow_reset` and `refresh_time` values but keep everything else as the default: 88 | 89 | ```php 90 | $opcache = (new Service([ 91 | 'refresh_time' => 2, 92 | 'allow_reset' => false 93 | ]))->handle(); 94 | ``` 95 | 96 | ### Changing the look 97 | 98 | The interface has been split up to allow you to easily change the colours of the gui, or even the core components, should you wish. 99 | 100 | The CSS for the interface is in the `build/_frontend/interface.scss` file. If you want to change the interface itself, update the `build/_frontend/interface.jsx` file - it's basically a set of ReactJS components. 101 | 102 | If you update those files, you will want to build the interface again and have the new jsx/css put into use. To do that, run the command `php ./build/build.php` from the repo root (you will need `nodejs` and `npm` installed). Once running, you should see the output: 103 | 104 | ``` 105 | 🐢 Installing node modules 106 | 🏗️ Building js and css 107 | 🚀 Creating single build file 108 | 💯 Done! 109 | ``` 110 | 111 | The build script will only need to install the `node_modules` once, so on subsequent builds it should be a fair bit quicker! 112 | 113 | The build process will create a compiled css file at `build/interface.css` and the javascript of the interface will be in `build/interface.js`. You could probably use both of these within your own frameworks and templating systems, should you wish. 114 | 115 | The core PHP template used in the build process, and that acts to pass various bits of data to the ReactJS side of things, is located at `build/template.phps`. If you wanted to update the version of ReactJS used, or how the wrapper html is structured, then this would be the file you'd want to update. 116 | 117 | ### Overview 118 | 119 | The overview will show you all the core information. From here you'll be able to see what host and platform you're running on, what version of OPcache you're using, when it was last reset, the functions that are available, all the directives and all the statistics associated with the OPcache (number of hits, memory used, free and wasted memory, etc.) 120 | 121 | ![Screenshot of the Overview tab](http://amnuts.com/images/opcache/screenshot/overview-v3.0.0.png) 122 | 123 | ### Cached files 124 | 125 | All the files currently in the cache are listed here with their associated statistics. 126 | 127 | You can filter the results to help find the particular scripts you're looking for, and you can optionally set levels of the path to be hidden. From here you can invalidate the cache for individual files or invalidate the cache for all the files matching your search. 128 | 129 | If you do not want to show the file list at all then you can use the `allow_filelist` configuration option; setting it to `false` will suppress the file list altogether. 130 | 131 | If you want to adjust the pagination length you can do so with the `per_page` configuration option. 132 | 133 | ![Screenshot of the Cached files list showing filtered results and pagination](http://amnuts.com/images/opcache/screenshot/cached-v3.png) 134 | 135 | ### Ignored files 136 | 137 | If you have set up a list of files which you don't want cache by supplying an `opcache.blacklist_filename` value, then the list of files will be listed within this tab. 138 | 139 | If you have not supplied that configuration option in the `php.ini` file then this tab will not be displayed. If you set the `allow_filelist` configuration option to `false` then this tab will not be displayed irrespective of your ini setting. 140 | 141 | ### Preloaded files 142 | 143 | PHP 7.4 introduced the ability to pre-load a set of files on server start by way of the `opcache.preload` setting in your `php.ini` file. If you have set that up then the list of files specifically pre-loaded will be listed within this tab. 144 | 145 | As with the ignored file, if you have not supplied the ini setting, or the `allow_filelist` configuration option is `false`, then this tab will not be displayed. 146 | 147 | ### Reset the cache 148 | 149 | You can reset the whole cache as well as force individual files, or groups of files, to become invalidated so that they will be cached again. 150 | 151 | Resetting can be disabled with the use of the configuration options `allow_reset` and `allow_invalidate`. 152 | 153 | ### Real-time updates 154 | 155 | The interface can poll every so often to get a fresh look at the opcache. You can change how often this happens with the configuration option `refresh_time`, which is in seconds. 156 | 157 | When the real-time updates are active the interface will automatically update all the values as needed. Also, if you choose to invalidate any files or reset the cache it will do this without reloading the page, so the search term you've entered, or the page you've navigated to do not get reset. If the real-time update is not on then the page will reload on any invalidation usage. 158 | 159 | ## Releases 160 | 161 | **Version 3.0.1**\ 162 | A minor update that will use http or https to get the javascript libraries, depending on what you're using. 163 | 164 | **Version 3.0.0**\ 165 | Although the interface looks mostly the same, it's had a complete re-write under the hood! Some of the more notable changes are: 166 | * New namespace for the base service class which ensure composer compatibility 167 | * You can now paginate the cached files list to make it easier to render a large file list 168 | * Any scripts that have been preloaded are displayed in a tab 169 | * Any file paths ignored are displayed in a tab 170 | * You can now invalidate all the files matching a search in one go 171 | * jQuery has been removed; the whole interface is now using ReactJS and more modern javascript (so only modern browsers) 172 | * The CSS is now using SASS and is now much easier to change all the colours of the interface as you wish 173 | * SVGs are now used for any icons or gauge graphs 174 | * A more responsive interface when the 'enable real-time' is activated 175 | * Build script added to compile the ReactJS and SASS and put them into the single, simple, gui script 176 | 177 | **Version 2.5.4**\ 178 | Refined placement of initial css namespace to play nicely within Moodle plugin and possibly other systems. Also tweaked some CSS. 179 | 180 | **Version 2.5.3**\ 181 | CSS class names have been added and style rules updated to use them. 182 | 183 | **Version 2.5.2**\ 184 | Hotfix for the optimisation_level values that was put out in v2.5.1. 185 | 186 | **Version 2.5.1**\ 187 | A couple bug fixes and improvement on the optimisation level details. 188 | * optimisation_level now shows the levels of optimisations that will be performed rather than an abstract number 189 | * Fixed issue #43 190 | * Fixed issue #44 191 | 192 | **Version 2.5.0**\ 193 | Added a new highlight chart to show the cached keys percentage with options to turn on/off the individual highlight graphs. 194 | 195 | **Version 2.4.1**\ 196 | Mostly bug fixes 197 | * `memory_consumption` and `max_file_size` config settings now display as human-readable sizes 198 | * four missing directives have been included 199 | * better handling if `file_cache_only` is active 200 | * cache-control header set to not cache the page 201 | 202 | **Version 2.4.0**\ 203 | Adds cookie store for the real-time state allowing real-time to be activated on load. Cookie name and TTL length can be adjusted in the config 204 | 205 | **Version 2.3.0**\ 206 | Adds information for interned strings and PHP 5.4 compatibility 207 | 208 | **Version 2.2.2**\ 209 | Brings in optimisations for the file listing when filtering 210 | 211 | **Version 2.2.1**\ 212 | Has the gauges now updating with the real-time pulse and a couple rounding issues fixed 213 | 214 | **Version 2.2.0**\ 215 | Provides the ability to turn on/off the file list (default is on) 216 | 217 | **Version 2.1.0**\ 218 | Now provides a much easier way to configure some options, be it the poll time, toggling the ability to reset the cache, real-time updates, etc. It also allows you to show the big values (memory usage and hit rate) as gauge graphs instead of big numbers. 219 | 220 | **Version 2.0.0**\ 221 | Introduces the use of React.js provides the ability to seamlessly update more of the information in real-time (well, every five seconds by default) - so now the files as well as the overview get refreshed. There is an updated look, removing the gradients and going for a flatter feel. And the code in general has had an overhaul. 222 | 223 | Releases of the GUI are available at: 224 | 225 | https://github.com/amnuts/opcache-gui/releases/ 226 | 227 | # License 228 | 229 | MIT: http://acollington.mit-license.org/ 230 | -------------------------------------------------------------------------------- /vendor/amnuts/opcache-gui/build/_frontend/interface.jsx: -------------------------------------------------------------------------------- 1 | class Interface extends React.Component { 2 | constructor(props) { 3 | super(props); 4 | this.state = { 5 | realtime: this.getCookie(), 6 | resetting: false, 7 | opstate: props.opstate 8 | } 9 | this.polling = false; 10 | this.isSecure = (window.location.protocol === 'https:'); 11 | if (this.getCookie()) { 12 | this.startTimer(); 13 | } 14 | } 15 | 16 | startTimer = () => { 17 | this.setState({realtime: true}) 18 | this.polling = setInterval(() => { 19 | this.setState({fetching: true, resetting: false}); 20 | axios.get('?', {time: Date.now()}) 21 | .then((response) => { 22 | this.setState({opstate: response.data}); 23 | }); 24 | }, this.props.realtimeRefresh * 1000); 25 | } 26 | 27 | stopTimer = () => { 28 | this.setState({realtime: false, resetting: false}) 29 | clearInterval(this.polling) 30 | } 31 | 32 | realtimeHandler = () => { 33 | const realtime = !this.state.realtime; 34 | if (!realtime) { 35 | this.stopTimer(); 36 | this.removeCookie(); 37 | } else { 38 | this.startTimer(); 39 | this.setCookie(); 40 | } 41 | } 42 | 43 | resetHandler = () => { 44 | if (this.state.realtime) { 45 | this.setState({resetting: true}); 46 | axios.get('?', {params: {reset: 1}}) 47 | .then((response) => { 48 | console.log('success: ', response.data); 49 | }); 50 | } else { 51 | window.location.href = '?reset=1'; 52 | } 53 | } 54 | 55 | setCookie = () => { 56 | let d = new Date(); 57 | d.setTime(d.getTime() + (this.props.cookie.ttl * 86400000)); 58 | document.cookie = `${this.props.cookie.name}=true;expires=${d.toUTCString()};path=/${this.isSecure ? ';secure' : ''}`; 59 | } 60 | 61 | removeCookie = () => { 62 | document.cookie = `${this.props.cookie.name}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/${this.isSecure ? ';secure' : ''}`; 63 | } 64 | 65 | getCookie = () => { 66 | const v = document.cookie.match(`(^|;) ?${this.props.cookie.name}=([^;]*)(;|$)`); 67 | return v ? !!v[2] : false; 68 | }; 69 | 70 | render() { 71 | const { opstate, realtimeRefresh, ...otherProps } = this.props; 72 | return ( 73 | <> 74 |
75 | 82 |
83 |