Home >Backend Development >PHP Tutorial >PHP Performance Analysis and Experiments: Macroscopic Analysis of Performance
【Editor's Note】I have read a lot of articles about PHP performance analysis before, but they all write rules one by one. Moreover, these rules have no context, and there are no clear experiments to show the advantages of these rules. The discussion also focuses on some grammatical points. This article changes the perspective of PHP performance analysis and uses examples to analyze the points that need attention and improvement in PHP performance.
For the analysis of PHP performance, we start from two levels and divide this article into two parts. One is the macro level. The so-called macro level is the PHP language itself and the environment level. The other is the application. The level is the level of grammar and usage rules, but it not only discusses the rules, but also assists in the analysis of examples.
At the macro level, that is, the performance analysis of the PHP language itself is divided into three aspects:
1. Performance analysis and improvement of PHP as an interpreted language
PHP is a scripting language and an interpreted language, which is the reason why its natural performance is limited, because it is compiled at the same time Unlike type-based languages that are compiled into binary code before running, interpreted languages face the input, parsing, compilation, and then execution of the original script at each run. The following is the execution process of PHP as an interpreted language.
As shown above, you can see from the picture above that each run needs to go through three processes of parsing, compiling and running.
So where is the optimization point? It is conceivable that as long as the code file is determined, the steps from parsing to compilation are determined, because the file no longer changes, and the execution is different due to different input parameters. In the world of performance optimization, the ultimate trick is to reduce operations while obtaining the same results. This is the famous cache. Caching is everywhere, and caching is also a killer feature for performance optimization. So the OpCode cache trick appeared. Only the first time it needs to be parsed and compiled, and in subsequent executions, the script is directly transferred to Opcode, thus achieving performance improvement. The execution process is shown in the figure below:
Compared with each parsing, compilation, and reading of the script, the efficiency of reading bytecode directly from the cache will be greatly improved. How much is the improvement?
Let’s do an experiment without Opcode cache. 20 concurrency, a total of 10,000 requests without opcode cache, and the following results are obtained:
Secondly, we turn on Opcode cache on the server. To implement opcode caching, you only need to install the APC, Zend OPCache, and eAccelerator extensions. Even if multiple are installed, only one of them will be enabled. Note that after modifying the php.ini configuration, you need to reload the php-fpm configuration.
APC and Zend OPCache are enabled here for experiments. APC-enabled version.
You can see that the speed has been greatly improved. Originally, each request was 110ms, and 182 requests were processed per second. After APC was enabled, it was 68ms, and 294 requests were processed per second, which increased the speed by nearly 40%.
In the version with Zend Opcache enabled, the results are roughly equivalent to APC. Processing 291 requests per second, each request takes 68.5ms.
As you can see from the above experiment, more than 40ms of the test page used was spent on syntax parsing and compilation. By caching these two operations, the speed of this process can be greatly improved.
In addition, what exactly is OpCode? For the bytecode compiled by OpCode, we can use tools like bytekit or use the vld PHP extension to compile PHP code. The following is the result of running the vld plug-in parsing code.
You can see that each line of code is compiled into the corresponding OpCode output.
2. Performance analysis and improvement of PHP as a dynamically typed language
The second is that the PHP language is a dynamically typed language. The dynamically typed language itself involves type inference in memory. For example, in PHP, when two integers are added, we can get an integer value, an integer and a character. Adding strings, or even adding two strings, becomes adding integers. Strings and any type of concatenation operations become strings.
<?php $a = 10.11; $b = "30"; var_dump($a+$b); var_dump("10"+$b); var_dump(10+"20"); var_dump("10"+"20");
The running results are as follows:
float(40.11) int(40) int(30) int(30)
The dynamic typing of the language provides convenience to developers, but the language itself will reduce efficiency due to dynamic typing. In Swift, there is a feature called type inference. We can see how big an efficiency difference type inference will bring? For the two pieces of Swift code that require type inference and those that do not, let’s try to compile them and see how they work. The first piece of code is as follows:
This is a piece of Swift code. The dictionary only has 14 key-value pairs. The compilation of this code has not been completed in 9 minutes (5G memory, 2.4GHz CPU). The compilation environment is Swift 1.2, Xcode 6.4.
But if the code is adjusted as follows:
In other words, type qualification is added to avoid the type inference of planeLocation. The compilation process took 2S.
It can be seen that the type inference operation attached as a dynamic type greatly reduces the compilation speed of the program. Of course, this example is a bit extreme, and it may not be appropriate to use Swift to compare PHP, because the Swift language itself is still in the process of evolving. This example only shows that in a programming language, if it is a dynamically typed language, it involves the processing of dynamic types, which will be affected from a compilation perspective.
So how to improve the efficiency of PHP as a dynamic type? There is no solution at the level of the PHP language itself, because no matter how you write code, it is also dynamically typed. The solution is to convert PHP into a static type representation, that is, make it an extension. You can see that many of Brother Niao's projects, such as the Yaf framework, are made into extensions. Of course, this is also because Brother Niao is a C master. Because the extension is written in C or C++, it is no longer a dynamic type. In addition, it is compiled, and the efficiency of the C language itself will be greatly improved. Therefore, the efficiency will be greatly improved.
Let’s take a look at a piece of code. This code only implements simple prime number operations and can calculate the number of prime numbers within a specified value. It uses an ordinary screening method. Now let’s look at the efficiency difference between the extended implementation and PHP’s native implementation. Of course, this difference is not only the difference between dynamic types and compiled types, but also the difference in language efficiency.
The first is an algorithm written in pure PHP to calculate the number of prime numbers within 10 million. It takes about 33 seconds. After three experiments, the results are basically the same.
Secondly, we wrote this process of finding the number of prime numbers into a PHP extension, and implemented the getprimenumbers function in the extension. Input an integer and return a prime number smaller than the integer. The results obtained are as follows. This efficiency improvement is very amazing, and it returns in about 1.4s. More than 20 times faster.
As you can imagine, the efficiency of static and compiled languages has been amazingly improved. The C language code of this program is as follows:
PHP_FUNCTION(get_prime_numbers) { long value; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) { return; } int *numbers = (int *)malloc(sizeof(int)*128*10000); memset(numbers, 0x0, 128*10000); int num = 2; numbers[0] = 2; numbers[1] = 3; bool flag = true; double f = 0; int i = 0; int j = 0; for(i=5; i<=value; i+=2) { flag = true; f = sqrt(i); for(j=0; j<num;j++) { if(i%numbers[j]==0) { flag = false; break; } if(numbers[j]>f) { break; } } if(flag) { numbers[num] = i; num++; } } free(numbers); RETURN_LONG(num); }
3. Improvement of the underlying performance engine of the PHP language itself
The third level of performance optimization is the performance improvement of the language itself, which is beyond what we ordinary developers can do. Before PHP 7, we hoped for improvements in minor versions, but the improvement was not very significant. For example, when comparing the performance of the same piece of code between PHP 5.3, PHP 5.4, PHP 5.5, and PHP 5.5, there was a certain degree of improvement.
The version of PHP 5.3 has been mentioned in the above example and takes about 33 seconds. Let’s look at other PHP versions now. The operations are as follows:
PHP version 5.4 has been improved to a certain extent compared to version 5.3. About 6 seconds faster.
PHP version 5.5 takes another step forward based on PHP 5.4 and is 6S faster.
PHP5.6 is a bit backward.
PHP 7 really has an amazing efficiency improvement, more than 3 times that of PHP5.3.
The above is to find the running speed difference between prime number scripts between various PHP versions. Although only this program was tested, it is not particularly rigorous, but it is on the same machine, and the compile configure parameters are also basic. The same, there is still a certain degree of comparability.
At the macro level, in addition to the above, in the actual deployment process, the optimization of PHP performance is also reflected in reducing the resources consumed during operation. Therefore, FastCGI mode and mod_php mode are also more popular than traditional CGI mode. Because in the traditional CGI mode, all modules need to be loaded every time the script is run. After the program is finished running, the module resources must also be released. As shown in the figure below:
In FastCGI and mod_php modes, this is not necessary. Only when php-fpm or Apache is started, all modules need to be loaded once. During a specific running process, there is no need to load and release related module resources again.
In this way, the efficiency of program performance has been improved. The above is the analysis of performance optimization of PHP at the macro level. In the second part of this article, we will discuss the application-related PHP optimization guidelines. Stay tuned!
The above introduces PHP performance analysis and experiments: macro analysis of performance, including aspects of content. I hope it will be helpful to friends who are interested in PHP tutorials.