Skip to content

Conversation

@trevnorris
Copy link
Member

@trevnorris trevnorris commented Sep 14, 2022

src: add new metrics APIs

The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

This is a patch we are currently using internally at NodeSource. We have been testing more reliable ways to measure the health of the event loop and have found that tracking the number of events processed, and more importantly, the number of events waiting in the event queue to be processed before the event provider is called is a better measure of event loop health.

Allowing a callback to be called upon completion of the event loop iteration, we can measure how long the individual iteration took. Using this we can calculate the statistical average amount of time each event waited. Not only events that were received by the event handler, but also how long each event waited in the event queue.

As an example, here is a graph that plots number of requests (req/sec), total number of events (poll_events), number of event loop iterations that had events waiting to be handled (loop_w_e), and the total number of events waiting (events_waiting):

event_loop_stats_01

This curvature is similar to almost every HTTP server workload. Using this data we can determine the optimal time to scale the server without knowing the actual processing time the event loop has taken.

In addition to this data we use an exponential moving average using the Poisson window function combined with a time constant adjustment so even though the calculations are done once every loop iteration, the smoothing curve acts as if it was time-series data. The equation for this is:

                       /-ΔT \
                       |----|
                       \ τ  /
s   =  s      + (1 - e       ) * (x  - s     )
 t      (t-1)                      t    (t-1)

ΔT - the difference in time since the last calculation in seconds
τ  - the time constant for the calculation in seconds
x  - new value to add to the exponential rolling avg           

Using the moving average data can be reliably stored in a time series database and used for analysis of the health of an application over more than one process.

Hopefully, these advantages outweigh the burden of adding additional metrics APIs.

@trevnorris
Copy link
Member Author

@cjihrig Thanks for the review. Fixed all comments.

@trevnorris trevnorris marked this pull request as draft September 19, 2022 20:50
@trevnorris
Copy link
Member Author

I'm converting this to a draft and rethinking the implementation to make things simpler. Will ping when the update is complete.

@trevnorris trevnorris force-pushed the more-metrics branch 3 times, most recently from 830d4ca to 75bc9f7 Compare September 19, 2022 21:34
trevnorris added a commit to trevnorris/libuv that referenced this pull request Sep 20, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
trevnorris added a commit to trevnorris/libuv that referenced this pull request Sep 20, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
@trevnorris trevnorris marked this pull request as ready for review September 20, 2022 21:00
@trevnorris
Copy link
Member Author

@cjihrig @santigimeno I've redone the implementation and simplified the API along with adding more tests. PTAL.

@trevnorris
Copy link
Member Author

@santigimeno Everything's taken care of.

trevnorris added a commit to trevnorris/libuv that referenced this pull request Sep 21, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
trevnorris added a commit to trevnorris/libuv that referenced this pull request Sep 26, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
trevnorris added a commit to trevnorris/libuv that referenced this pull request Sep 27, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one minor comment.

The GitHub actions CI is green. I also started a Jenkins CI run: https://ci.nodejs.org/view/libuv/job/libuv-test-commit/2258/

EDIT: None of the failures look related to this PR.

@trevnorris
Copy link
Member Author

Looks like several errors are from the build failing to find stdatomic.h.

trevnorris added a commit to trevnorris/libuv that referenced this pull request Oct 3, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
trevnorris added a commit to trevnorris/libuv that referenced this pull request Oct 27, 2022
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv#3749
@santigimeno
Copy link
Member

@santigimeno
Copy link
Member

CI failures unrelated: #3714

@santigimeno santigimeno merged commit e141586 into libuv:v1.x Nov 11, 2022
@trevnorris trevnorris deleted the more-metrics branch February 14, 2023 21:51
santigimeno added a commit to santigimeno/node that referenced this pull request May 20, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

- Fixes: nodejs#43931
- Fixes: nodejs#42496
santigimeno added a commit to santigimeno/node that referenced this pull request May 24, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: nodejs#43931
Fixes: nodejs#42496
Fixes: nodejs#47715
Fixes: nodejs#47259
Fixes: nodejs#47241
nodejs-github-bot pushed a commit to nodejs/node that referenced this pull request May 24, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: #43931
Fixes: #42496
Fixes: #47715
Fixes: #47259
Fixes: #47241
PR-URL: #48078
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
targos pushed a commit to nodejs/node that referenced this pull request Jun 4, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: #43931
Fixes: #42496
Fixes: #47715
Fixes: #47259
Fixes: #47241
PR-URL: #48078
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: nodejs#43931
Fixes: nodejs#42496
Fixes: nodejs#47715
Fixes: nodejs#47259
Fixes: nodejs#47241
PR-URL: nodejs#48078
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: nodejs#43931
Fixes: nodejs#42496
Fixes: nodejs#47715
Fixes: nodejs#47259
Fixes: nodejs#47241
PR-URL: nodejs#48078
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
arsnyder16 pushed a commit to arsnyder16/node that referenced this pull request Sep 10, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: nodejs#43931
Fixes: nodejs#42496
Fixes: nodejs#47715
Fixes: nodejs#47259
Fixes: nodejs#47241
PR-URL: nodejs#48078
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
ruyadorno pushed a commit to nodejs/node that referenced this pull request Sep 11, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: #43931
Fixes: #42496
Fixes: #47715
Fixes: #47259
Fixes: #47241
PR-URL: #48078
Backport-PR-URL: #49591
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
ruyadorno pushed a commit to nodejs/node that referenced this pull request Sep 13, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: #43931
Fixes: #42496
Fixes: #47715
Fixes: #47259
Fixes: #47241
PR-URL: #48078
Backport-PR-URL: #49591
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
ruyadorno pushed a commit to nodejs/node that referenced this pull request Sep 17, 2023
- linux: introduce io_uring support libuv/libuv#3952
- src: add new metrics APIs libuv/libuv#3749
- unix,win: give thread pool threads an 8 MB stack libuv/libuv#3787
- win,unix: change execution order of timers libuv/libuv#3927

Fixes: #43931
Fixes: #42496
Fixes: #47715
Fixes: #47259
Fixes: #47241
PR-URL: #48078
Backport-PR-URL: #49591
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: Debadree Chatterjee <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Jiawen Geng <[email protected]>
@vcunat
Copy link
Contributor

vcunat commented Jun 19, 2024

uint64_t* reserved[13];

So the structure has three uint64_t and then 13 pointers? That feels really weird on 32-bit platforms. Did you mean to use this?

uint64_t reserved[13];

Or is it too late and the 32-bit ABI set in stone now? (though the struct length will be a PITA to keep when "unreserving" in future)

EDIT: honestly I'm afraid that there may be no good solution to this anymore. Especially as you memcpy with sizeof(uv_metrics_t) in uv_metrics_info().

@bnoordhuis
Copy link
Member

It's released so it's set in stone now, yes.

@vcunat
Copy link
Contributor

vcunat commented Jun 20, 2024

Then I suggest at least a comment in the struct to warn about changing/unreserving, as that won't be easy to do while keeping both 32-bit and 64-bit struct lengths.

@trevnorris
Copy link
Member Author

This fuck up will haunt me to the end of time. I can't believe I made it a pointer. Sorry.

@vcunat
Copy link
Contributor

vcunat commented Jun 25, 2024

You were also discussing it during review but noone seems to have noticed 🤷🏽

though the struct length will be a PITA to keep when "unreserving" in future

Actually, using union is possible to simplify that at least. I even now saw this somewhere in libuv. (though it won't warn you about getting over)

@trevnorris
Copy link
Member Author

This is ugly, but here's an idea on how to handle this to make it easier to use the reserved space in the future:

struct uv_metrics_s {
  uint64_t loop_count;
  uint64_t events;
  uint64_t events_waiting;
  /* private */
  uint64_t reserved[6];

#if UINTPTR_MAX == 0xffffffff
  uint64_t* dead[1];
#elif UINTPTR_MAX == 0xffffffffffffffff
  uint64_t* dead[7];
#else
#error "Platform not supported"
#endif
};

What ideas did you have in mind for using a union?

@vcunat
Copy link
Contributor

vcunat commented Jun 25, 2024

Testing UINTPTR_MAX feels ugly, but off the top of my head I don't know a better preprocessor symbol.

I meant e.g. b6bf6d2

liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Jul 23, 2025
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv/libuv#3749
liujinye-sys pushed a commit to open-vela/apps_system_libuv that referenced this pull request Dec 16, 2025
The following metrics are now always recorded and available via the new
uv_metrics_info() API.

* loop_count: Number of event loop iterations.
* events: Total number of events processed by the event handler.
* events_waiting: Total number of events waiting in the event queue when
  the event provider request was made.

Benchmarking has shown no noticeable impact recording these metrics.

PR-URL: libuv/libuv#3749
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants