PluginProbe
Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution / 1.9.0
Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution v1.9.0
2.0.1 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.9.0 2.0.0
solid-performance / src / Performance / Preload / Limiter / Sleep_Limiter.php

Sleep_Limiter.php in Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution 1.9.0, at src/Performance/Preload/Limiter/Sleep_Limiter.php

141 lines 3.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The Sleep Rate Limiter.
4 *
5 * @package SolidWP\Performance
6 */
7
8 declare( strict_types=1 );
9
10 namespace SolidWP\Performance\Preload\Limiter;
11
12 use InvalidArgumentException;
13 use RuntimeException;
14 use SolidWP\Performance\Preload\Limiter\Load\System_Load_Monitor;
15 use SolidWP\Performance\Psr\Log\LoggerInterface;
16
17 /**
18 * Determines the server load per core to determine the time
19 * to sleep in between batches.
20 *
21 * Sleeping lowers load faster than lowering batch sizes.
22 *
23 * @package SolidWP\Performance
24 */
25 class Sleep_Limiter {
26
27 public const MAX_SLEEP = 10.0;
28
29 public const FALLBACK_SLEEP = 3.0;
30
31 /**
32 * @var System_Load_Monitor
33 */
34 private System_Load_Monitor $load_monitor;
35
36 /**
37 * @var Core_Counter
38 */
39 private Core_Counter $core_counter;
40
41 /**
42 * @var LoggerInterface
43 */
44 private LoggerInterface $logger;
45
46 /**
47 * The maximum server load per core before we
48 * start rate limiting.
49 *
50 * 0-0.7 per core is optimal range, allowing headroom.
51 * 0.7-1.0 per core is high, but manageable.
52 * 1.0+ per core indicates CPU is likely bottle necked.
53 *
54 * @var float
55 */
56 private float $max_load_per_core;
57
58 /**
59 * The delay multiplier to calculate the sleep time.
60 *
61 * @var float
62 */
63 private float $delay;
64
65 /**
66 * @param System_Load_Monitor $load_monitor The system load monitor.
67 * @param Core_Counter $core_counter The core counter.
68 * @param LoggerInterface $logger The logger.
69 * @param float $max_load_per_core The maximum load per core before we start rate limiting.
70 * @param float $delay The delay multiplier to calculate the sleep time.
71 *
72 * @throws InvalidArgumentException If an invalid max_load_per_core or sleep argument is passed.
73 */
74 public function __construct(
75 System_Load_Monitor $load_monitor,
76 Core_Counter $core_counter,
77 LoggerInterface $logger,
78 float $max_load_per_core = 0.5,
79 float $delay = 1.5
80 ) {
81 if ( $max_load_per_core < 0.1 ) {
82 throw new InvalidArgumentException( 'The $max_load_per_core argument cannot be below 0.1' );
83 }
84
85 if ( $delay < 0.1 ) {
86 throw new InvalidArgumentException( 'The $delay argument cannot be below 0.1' );
87 }
88
89 $this->load_monitor = $load_monitor;
90 $this->core_counter = $core_counter;
91 $this->logger = $logger;
92 $this->max_load_per_core = $max_load_per_core;
93 $this->delay = $delay;
94 }
95
96 /**
97 * Get the seconds to sleep.
98 *
99 * Formula:
100 * sleep_time = delay * (load_per_core / max_load_per_core) ^ alpha.
101 *
102 * @return float
103 */
104 public function get_sleep(): float {
105 try {
106 $one_min_load = $this->load_monitor->load()->one_min();
107 } catch ( RuntimeException $e ) {
108 $this->logger->error(
109 'Falling back to default sleep: {fallback_sleep}',
110 [
111 'exception' => $e,
112 'fallback_sleep' => self::FALLBACK_SLEEP,
113 ]
114 );
115
116 // Fall back to a reasonable sleep if we can't determine server load.
117 return self::FALLBACK_SLEEP;
118 }
119
120 $core_count = $this->core_counter->core_count();
121
122 $load_per_core = $one_min_load / $core_count;
123
124 if ( $load_per_core <= $this->max_load_per_core ) {
125 return 0.0;
126 }
127
128 // Exponentially scale sleep based on load per core.
129 $sleep = $this->delay * pow( $load_per_core / $this->max_load_per_core, 2.0 );
130
131 $this->logger->debug(
132 'Calculated Sleep: {sleep}',
133 [
134 'sleep' => $sleep,
135 ]
136 );
137
138 return min( self::MAX_SLEEP, $sleep );
139 }
140 }
141