Make WordPress Core

Ticket #17817: test.php

File test.php, 5.2 KB (added by cheeserolls, 11 years ago)

Comparison of 3 different methods of looping through actions

Line 
1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="utf-8" />
5<title></title>
6<script src="js/jquery.js" ></script>
7<script type="text/javascript">
8//<![CDATA[
9
10//]]>
11</script>
12</head>
13
14<body>
15<pre>
16<?php
17
18
19// Timer for benchmarking
20class timer {
21  var $start;
22  var $pause_time;
23
24  /*  start the timer  */
25  function timer($start = 0) {
26    if($start) { $this->start(); }
27  }
28
29  /*  start the timer  */
30  function start() {
31    $this->start = $this->get_time();
32    $this->pause_time = 0;
33  }
34
35  /*  pause the timer  */
36  function pause() {
37    $this->pause_time = $this->get_time();
38  }
39
40  /*  unpause the timer  */
41  function unpause() {
42    $this->start += ($this->get_time() - $this->pause_time);
43    $this->pause_time = 0;
44  }
45
46  /*  get the current timer value  */
47  function get($decimals = 8) {
48    return round(($this->get_time() - $this->start),$decimals);
49  }
50
51  /*  format the time in seconds  */
52  function get_time() {
53    list($usec,$sec) = explode(' ', microtime());
54    return ((float)$usec + (float)$sec);
55  }
56}
57
58
59
60
61        // Dummy $wp_filter array with structure to mimick the a real one
62        $wp_filter = array(
63                // actions 1-4 just echo the action name so you can see which actions get executed in which order
64                // action 2 also contains a nested call to the same action to illustrate the bug
65                'show_actions'=>array(
66                        10=>array(
67                                'dfgjsdfl'=>array('function'=>'action1','accepted_args'=>1),
68                                'eoivoddw'=>array('function'=>'action2','accepted_args'=>1)
69                        ),
70                        11=>array(
71                                'egosfdfn'=>array('function'=>'action3','accepted_args'=>1)
72                        ),
73                        20=>array(
74                                'ekragjdt'=>array('function'=>'action4','accepted_args'=>1)
75                        ),
76                        30=>null
77                ),
78                // actions 5-8 calculate the square root of 2 - just for benchmarking purposes
79                // action 6 also contains a nested call to the same action to illustrate the bug
80                'test_times'=>array(
81                        10=>array(
82                                'dfgjsdfl'=>array('function'=>'action5','accepted_args'=>1),
83                                'eoivoddw'=>array('function'=>'action6','accepted_args'=>1)
84                        ),
85                        11=>array(
86                                'egosfdfn'=>array('function'=>'action7','accepted_args'=>1)
87                        ),
88                        20=>array(
89                                'ekragjdt'=>array('function'=>'action8','accepted_args'=>1)
90                        ),
91                        30=>null
92                )
93        );
94       
95        function action1($id) {echo "$id action1\n";}
96        function action2($id) {echo "$id action2\n"; if ($id=='out') {global $do_action; $do_action('show_actions',array('in'));}}
97        function action3($id) {echo "$id action3\n";}
98        function action4($id) {echo "$id action4\n";}
99       
100        function action5($id) {global $n; sqrt(2); $n++;}
101        function action6($id) {global $n; sqrt(2); $n++; if ($id=='out') {global $do_action; $do_action('test_times',array('in'));}}
102        function action7($id) {global $n; sqrt(2); $n++;}
103        function action8($id) {global $n; sqrt(2); $n++;}
104       
105        // Number of times to test
106        $N=10000;
107       
108       
109       
110        // current (broken) implementation of do_action
111        $do_action = function($tag,$args) {
112       
113                global $wp_filter;
114               
115                reset ($wp_filter[$tag]);
116               
117                do {
118                        foreach ( (array) current($wp_filter[$tag]) as $the_ )
119                                if ( !is_null($the_['function']) )
120                                        call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
121               
122                } while ( next($wp_filter[$tag]) !== false );
123       
124        };
125       
126        echo "old implementation\n";
127        $do_action('show_actions',array('out'));
128        $n = 0; $timer = new timer(1);
129        for ($i=0; $i<$N; $i++) {
130                $do_action('test_times',array('out'));
131        }
132        $time_taken = $timer->get(); $average_time = $time_taken/$n;
133        echo "total time: $time_taken sqrts: $n average time: $average_time \n\n\n";
134        // note action3 and action4 don't get called in the outer loop
135       
136       
137       
138
139
140        // working implementation, but $actions_to_execute is a copy of the entire array, so it's expensive
141        $do_action = function($tag,$args) {
142       
143                global $wp_filter;
144               
145                $actions_for_this_tag = $wp_filter[$tag];
146               
147                do {
148                        foreach ( (array) current($actions_for_this_tag) as $the_ )
149                                if ( !is_null($the_['function']) )
150                                        call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
151                } while ( next($actions_to_execute) !== false );
152       
153        };
154       
155
156        echo "copying the array\n";
157        $do_action('show_actions',array('out'));
158        $n = 0; $timer = new timer(1);
159        for ($i=0; $i<$N; $i++) {
160                $do_action('test_times',array('out'));
161        }
162        $time_taken = $timer->get(); $average_time = $time_taken/$n;
163        echo "total time: $time_taken sqrts: $n average time: $average_time \n\n\n";
164        // all actions get called in both inner and outer loop, but it's slower
165
166
167
168
169
170        // working implementation, but uses references to array entries, so performance doesn't suffer
171        $do_action = function($tag,$args) {
172       
173                global $wp_filter;
174               
175                foreach ($wp_filter[$tag] as &$action_to_execute) {
176                        foreach ((array)$action_to_execute as $the_)
177                                if ( !is_null($the_['function']) )
178                                        call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
179                }
180       
181        };
182       
183
184        echo "using array reference\n";
185        $do_action('show_actions',array('out'));
186        $n = 0; $timer = new timer(1);
187        for ($i=0; $i<$N; $i++) {
188                $do_action('test_times',array('out'));
189        }
190        $time_taken = $timer->get(); $average_time = $time_taken/$n;
191        echo "total time: $time_taken sqrts: $n average time: $average_time \n\n\n";
192        // all actions get called in both inner and outer loop, and it's faster than the current implementation
193       
194       
195       
196
197?>
198</pre>
199</body>
200</html>