Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1f77a91

Browse files
committed
feat(uvloop): Support event loop utilization queries
1 parent 0e9ff6c commit 1f77a91

File tree

5 files changed

+53
-0
lines changed

5 files changed

+53
-0
lines changed

‎tests/test_base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,21 @@ def scheduler():
737737

738738
class TestBaseUV(_TestBase, UVTestCase):
739739

740+
def test_event_loop_utilization(self):
741+
self.assertTrue(self.loop.event_loop_utilization() == (0., 0., 0.))
742+
743+
async def run():
744+
await asyncio.sleep(0.2)
745+
time.sleep(0.05)
746+
return self.loop.event_loop_utilization()
747+
748+
i, a, p = self.loop.run_until_complete(run())
749+
self.assertTrue(100 < i < 400)
750+
self.assertTrue(a > 0.)
751+
self.assertTrue(0. < p < 1.)
752+
753+
self.assertTrue(self.loop.event_loop_utilization() == (0., 0., 0.))
754+
740755
def test_loop_create_future(self):
741756
fut = self.loop.create_future()
742757
self.assertTrue(isinstance(fut, asyncio.Future))

‎uvloop/includes/uv.pxd

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ cdef extern from "uv.h" nogil:
202202
UV_REQ_TYPE_PRIVATE,
203203
UV_REQ_TYPE_MAX
204204

205+
ctypedef enum uv_loop_option:
206+
UV_LOOP_BLOCK_SIGNAL = 0,
207+
UV_METRICS_IDLE_TIME
208+
205209
ctypedef enum uv_run_mode:
206210
UV_RUN_DEFAULT = 0,
207211
UV_RUN_ONCE,
@@ -281,6 +285,7 @@ cdef extern from "uv.h" nogil:
281285
int uv_loop_init(uv_loop_t* loop)
282286
int uv_loop_close(uv_loop_t* loop)
283287
int uv_loop_alive(uv_loop_t* loop)
288+
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...)
284289
int uv_loop_fork(uv_loop_t* loop)
285290
int uv_backend_fd(uv_loop_t* loop)
286291

@@ -458,6 +463,10 @@ cdef extern from "uv.h" nogil:
458463
uv_calloc_func calloc_func,
459464
uv_free_func free_func)
460465

466+
# Metrics
467+
468+
uint64_t uv_metrics_idle_time(uv_loop_t* loop)
469+
461470
# Process
462471

463472
ctypedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status,

‎uvloop/loop.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ cdef class Loop:
138138

139139
cdef _close(self)
140140
cdef _stop(self, exc)
141+
cdef uint64_t _event_loop_idle_time(self)
141142
cdef uint64_t _time(self)
142143

143144
cdef inline _queue_write(self, UVStream stream)

‎uvloop/loop.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class Loop:
3737
def call_at(
3838
self, when: float, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
3939
) -> asyncio.TimerHandle: ...
40+
def _event_loop_utilization(self) -> Tuple[float, float, float]: ...
4041
def time(self) -> float: ...
4142
def stop(self) -> None: ...
4243
def run_forever(self) -> None: ...

‎uvloop/loop.pyx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ cdef class Loop:
162162
self._recv_buffer_in_use = 0
163163

164164
err = uv.uv_loop_init(self.uvloop)
165+
if err < 0:
166+
raise convert_error(err)
167+
168+
err = uv.uv_loop_configure(self.uvloop, uv.UV_METRICS_IDLE_TIME)
165169
if err < 0:
166170
raise convert_error(err)
167171
self.uvloop.data = <void*> self
@@ -527,6 +531,7 @@ cdef class Loop:
527531

528532
self._thread_id = PyThread_get_thread_ident()
529533
self._running = 1
534+
self._loop_start_time = self._time()
530535

531536
self.handler_check__exec_writes.start()
532537
self.handler_idle.start()
@@ -628,6 +633,10 @@ cdef class Loop:
628633
self._default_executor = None
629634
executor.shutdown(wait=False)
630635

636+
cdef uint64_t _event_loop_idle_time(self):
637+
"""Returns number of nanoseconds the loop has been idle"""
638+
return uv.uv_metrics_idle_time(self.uvloop)
639+
631640
cdef uint64_t _time(self):
632641
# asyncio doesn't have a time cache, neither should uvloop.
633642
uv.uv_update_time(self.uvloop) # void
@@ -1337,6 +1346,24 @@ cdef class Loop:
13371346
return self.call_later(
13381347
when - self.time(), callback, *args, context=context)
13391348

1349+
def _event_loop_utilization(self):
1350+
"""Returns idle and active time in milliseconds and the percentage of
1351+
time the event loop is active
1352+
"""
1353+
1354+
idle = 0.
1355+
active = 0.
1356+
utilization = 0.
1357+
1358+
if not self._running:
1359+
return idle, active, utilization
1360+
1361+
idle = self._event_loop_idle_time() / 10 ** 6
1362+
active = self._time() - self._loop_start_time - idle
1363+
utilization = active / (active + idle)
1364+
1365+
return idle, active, utilization
1366+
13401367
def time(self):
13411368
"""Return the time according to the event loop's clock.
13421369

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /