Skip to content

Commit c26921f

Browse files
committed
Skip unnecessary poll() syscall when no I/O watchers are active
1 parent 182bdda commit c26921f

5 files changed

Lines changed: 21 additions & 8 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ run-tests.php
3838
*.swp
3939
*.swo
4040
*~
41+
php_test_results_*.txt
4142
.idea/
4243
.vscode/
4344

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ Revolt v1.0.8 tested with all four available drivers ([StreamSelect, Ev, Event,
196196

197197
| Benchmark | Revolt StreamSelect | Revolt Ev | Revolt Event | Revolt UV | ext-eventloop |
198198
|---|--:|--:|--:|--:|--:|
199-
| `defer()` | 755,979 ops/sec | 726,468 ops/sec | 741,084 ops/sec | 730,488 ops/sec | **3,696,132 ops/sec** |
200-
| `delay(0)` | 245,389 ops/sec | 480,866 ops/sec | 467,362 ops/sec | 185,068 ops/sec | **3,041,443 ops/sec** |
201-
| `repeat(0)` | 694,763 ops/sec | 712,077 ops/sec | 74,929 ops/sec | 73,899 ops/sec | **17,971,855 ops/sec** |
202-
| I/O register + cancel | 2,149,497 ops/sec | 2,056,740 ops/sec | 2,034,001 ops/sec | 2,000,214 ops/sec | **7,642,510 ops/sec** |
203-
| Fiber suspend/resume | 219,349 ops/sec | 217,095 ops/sec | 220,924 ops/sec | 215,305 ops/sec | **242,691 ops/sec** |
199+
| `defer()` | 765,598 ops/sec | 743,057 ops/sec | 733,417 ops/sec | 742,926 ops/sec | **3,658,412 ops/sec** |
200+
| `delay(0)` | 242,383 ops/sec | 486,501 ops/sec | 464,196 ops/sec | 183,585 ops/sec | **3,047,625 ops/sec** |
201+
| `repeat(0)` | 687,196 ops/sec | 707,010 ops/sec | 74,708 ops/sec | 73,491 ops/sec | **17,371,529 ops/sec** |
202+
| I/O register + cancel | 2,114,361 ops/sec | 2,003,474 ops/sec | 1,980,326 ops/sec | 1,953,935 ops/sec | **7,193,404 ops/sec** |
203+
| Fiber suspend/resume | 221,383 ops/sec | 220,659 ops/sec | 218,318 ops/sec | 220,244 ops/sec | **243,242 ops/sec** |
204204

205205
> These benchmarks measure callback dispatch and scheduling throughput. The I/O backend (StreamSelect, Ev, Event, UV) primarily affects polling efficiency at high concurrency, not dispatch speed — that's why all four Revolt drivers show similar numbers here. ext-eventloop moves the entire dispatch path into C, which is where the difference comes from. Fiber performance is nearly identical because `suspend()`/`resume()` is handled by the Zend Engine directly.
206206
>

eventloop.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ ZEND_METHOD(EventLoop_EventLoop, onReadable)
571571
}
572572
}
573573

574+
EVENTLOOP_G(io_watcher_count)++;
574575
RETURN_STR_COPY(cb->id);
575576
}
576577
/* }}} */
@@ -605,6 +606,7 @@ ZEND_METHOD(EventLoop_EventLoop, onWritable)
605606
}
606607
}
607608

609+
EVENTLOOP_G(io_watcher_count)++;
608610
RETURN_STR_COPY(cb->id);
609611
}
610612
/* }}} */
@@ -917,9 +919,13 @@ ZEND_METHOD(EventLoop_EventLoop, run)
917919
}
918920
}
919921

920-
EVENTLOOP_G(driver)->poll(timeout);
921-
if (EVENTLOOP_G(stopped)) {
922-
break;
922+
/* Skip the syscall when there are no I/O watchers — avoids
923+
* unnecessary kevent()/epoll_wait()/poll() overhead on every tick */
924+
if (EVENTLOOP_G(io_watcher_count) > 0 || timeout > 0) {
925+
EVENTLOOP_G(driver)->poll(timeout);
926+
if (EVENTLOOP_G(stopped)) {
927+
break;
928+
}
923929
}
924930

925931
eventloop_process_timers();
@@ -1086,6 +1092,7 @@ PHP_RINIT_FUNCTION(eventloop)
10861092

10871093
EVENTLOOP_G(driver) = NULL;
10881094
EVENTLOOP_G(next_id) = 1;
1095+
EVENTLOOP_G(io_watcher_count) = 0;
10891096
EVENTLOOP_G(running) = false;
10901097
EVENTLOOP_G(stopped) = false;
10911098
ZVAL_NULL(&EVENTLOOP_G(error_handler));

eventloop_cb.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ void eventloop_cb_cancel(eventloop_callback *cb)
118118
return;
119119
}
120120

121+
if (cb->type == EVENTLOOP_CB_READABLE || cb->type == EVENTLOOP_CB_WRITABLE) {
122+
EVENTLOOP_G(io_watcher_count)--;
123+
}
124+
121125
eventloop_cb_disable(cb);
122126
cb->flags |= EVENTLOOP_CB_FLAG_CANCELLED;
123127
cb->flags &= ~EVENTLOOP_CB_FLAG_ENABLED;

php_eventloop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ ZEND_BEGIN_MODULE_GLOBALS(eventloop)
118118
eventloop_driver *driver;
119119

120120
uint64_t next_id;
121+
uint32_t io_watcher_count;
121122
bool running;
122123
bool stopped;
123124

0 commit comments

Comments
 (0)