-
Notifications
You must be signed in to change notification settings - Fork 284
Add rc-analyze utility #998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
axtloss
wants to merge
2
commits into
OpenRC:master
Choose a base branch
from
axtloss:feat/rc-analyze
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| .\" Copyright (c) 2026 The OpenRC Authors. | ||
| .\" See the Authors file at the top-level directory of this distribution and | ||
| .\" https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS | ||
| .\" | ||
| .\" This file is part of OpenRC. It is subject to the license terms in | ||
| .\" the LICENSE file found in the top-level directory of this | ||
| .\" distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE | ||
| .\" This file may not be copied, modified, propagated, or distributed | ||
| .\" except according to the terms contained in the LICENSE file. | ||
| .\" | ||
| .Dd April 2, 2026 | ||
| .Dt RC-ANALYZE 8 SMM | ||
| .Os OpenRC | ||
| .Sh NAME | ||
| .Nm rc-analyze | ||
| .Nd analyze OpenRC startup performance | ||
| .Sh SYNOPSIS | ||
| .Nm | ||
| .Ar blame | critical-chain | time | ||
| .Sh DESCRIPTION | ||
| The | ||
| .Nm | ||
| utility provides commands to analyze the boot performance of an OpenRC-based | ||
| system. | ||
| .Sh COMMANDS | ||
| The following commands are available: | ||
| .Bl -tag -width ".Fl critical-chain" | ||
| .It Nm blame | ||
| Prints a list of all services that were started, sorted by the time they took | ||
| to start up (longest first). This helps identify the slowest services during | ||
| boot. | ||
| .It Nm critical-chain | ||
| .Op Ar service | ||
| Shows the chain of dependencies that led to the specified | ||
| .Ar service | ||
| starting. If no service is specified, it shows the chain for the last service | ||
| to start in the default runlevel. The output is a tree where each dependency | ||
| is a parent of the service that depends on it. The time at which each service | ||
| became active and the time it took to start are printed. | ||
| .It Nm time | ||
| Prints a summary of the time spent getting to the default runlevel. | ||
| .El | ||
| .Sh SEE ALSO | ||
| .Xr openrc 8 , | ||
| .Sh AUTHORS | ||
| .An The OpenRC Authors <openrc@lists.gentoo.org> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| /* | ||
| * rc-eventlog.c | ||
| * Event logging for OpenRC services and system events | ||
| */ | ||
|
|
||
| /* | ||
| * Copyright (c) 2024 The OpenRC Authors. | ||
| * See the Authors file at the top-level directory of this distribution and | ||
| * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS | ||
| * | ||
| * This file is part of OpenRC. It is subject to the license terms in | ||
| * the LICENSE file found in the top-level directory of this | ||
| * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE | ||
| * This file may not be copied, modified, propagated, or distributed | ||
| * except according to the terms contained in the LICENSE file. | ||
| */ | ||
|
|
||
| #include <errno.h> | ||
| #include <fcntl.h> | ||
| #include <inttypes.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/types.h> | ||
| #include <time.h> | ||
| #include <unistd.h> | ||
|
|
||
| #include "librc.h" | ||
|
|
||
| #define RC_EVENTLOG_DIR "events" | ||
| #define RC_EVENTLOG_SERVICES "events/" | ||
| #define RC_EVENTLOG_GLOBAL "events/rc" | ||
|
|
||
| /* | ||
| * Get the name of a service state. | ||
| */ | ||
| static const char *rc_service_state_name(RC_SERVICE state) | ||
| { | ||
| int i; | ||
|
|
||
| for (i = 0; rc_service_state_names[i].name; i++) { | ||
| if (rc_service_state_names[i].state == state) | ||
| return rc_service_state_names[i].name; | ||
| } | ||
|
|
||
| return "unknown"; | ||
| } | ||
|
|
||
| /* | ||
| * Get the current monotonic time in milliseconds. | ||
| */ | ||
| static int64_t tm_now(void) | ||
| { | ||
| struct timespec tv; | ||
| int64_t sec_to_ms = 1000, round_up = 500000, ns_to_ms = 1000000; | ||
|
|
||
| clock_gettime(CLOCK_MONOTONIC, &tv); | ||
| return (tv.tv_sec * sec_to_ms) + ((tv.tv_nsec + round_up) / ns_to_ms); | ||
| } | ||
|
|
||
| /* | ||
| * Initialize the eventlog system. | ||
| * Creates necessary directories under <RC_DIR_SVCDIR>/events/ | ||
| */ | ||
| int rc_eventlog_init(void) | ||
| { | ||
| int svcfd = rc_dirfd(RC_DIR_SVCDIR); | ||
|
|
||
| if (svcfd < 0) | ||
| return -1; | ||
|
|
||
| if (mkdirat(svcfd, RC_EVENTLOG_DIR, 0755) == -1 && errno != EEXIST) | ||
| return -1; | ||
|
|
||
| if (mkdirat(svcfd, RC_EVENTLOG_SERVICES, 0755) == -1 && errno != EEXIST) | ||
| return -1; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /* | ||
| * Log an event for a specific service. | ||
| */ | ||
| void rc_eventlog_service(const char *service, RC_SERVICE state) | ||
| { | ||
| int svcfd; | ||
| int eventsfd; | ||
| FILE *fp; | ||
| const char *state_name; | ||
|
|
||
| if (!service) | ||
| return; | ||
|
|
||
| svcfd = rc_dirfd(RC_DIR_SVCDIR); | ||
| if (svcfd < 0) | ||
| return; | ||
|
|
||
| if (rc_eventlog_init() != 0) | ||
| return; | ||
|
|
||
| eventsfd = openat(svcfd, RC_EVENTLOG_SERVICES, O_RDONLY | O_DIRECTORY); | ||
| if (eventsfd < 0) | ||
| return; | ||
|
|
||
| service = basename_c(service); | ||
|
|
||
| state_name = rc_service_state_name(state); | ||
|
|
||
| fp = do_fopenat(eventsfd, service, O_WRONLY | O_CREAT | O_APPEND); | ||
| close(eventsfd); | ||
|
|
||
| if (!fp) | ||
| return; | ||
|
|
||
| fprintf(fp, "%" PRId64 " %s\n", tm_now(), state_name); | ||
| fclose(fp); | ||
| } | ||
|
|
||
| /* | ||
| * Log a global system event. | ||
| */ | ||
| void rc_eventlog_global(const char *event_type, const char *message) | ||
| { | ||
| int svcfd; | ||
| FILE *fp; | ||
|
|
||
| if (!event_type || !message) | ||
| return; | ||
|
|
||
| svcfd = rc_dirfd(RC_DIR_SVCDIR); | ||
| if (svcfd < 0) | ||
| return; | ||
|
|
||
| if (rc_eventlog_init() != 0) | ||
| return; | ||
|
|
||
| fp = do_fopenat(svcfd, RC_EVENTLOG_GLOBAL, O_WRONLY | O_CREAT | O_APPEND); | ||
| if (!fp) | ||
| return; | ||
|
|
||
| fprintf(fp, "%" PRId64 " %s %s\n", tm_now(), event_type, message); | ||
| fclose(fp); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| libm = cc.find_library('m', required: true) | ||
|
|
||
| executable('rc-analyze', 'rc-analyze.c', | ||
| dependencies: [rc, einfo, shared, libm], | ||
| include_directories: incdir, | ||
| install: true, | ||
| install_dir: bindir) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You likely want to use
CLOCK_BOOTTIMEin linux (seetimeutils.candopenrc-init.c).What build system issue were you running into anyways? The duplication in
openrc-init.cis already not too good, duplicating this a 3rd time doesn't seem nice.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could turn timeutils/tm_now into a "header only" thing like
src/shared/helpers.hbut I'm not sure how much I like that either.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/shared has stuff that uses librc, so librc can't use it, because meson ordering on subdir()
i am going to move most the shared things into their own individual subprojects i think, so that not only is the split clear but we avoid this going forward
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the manpage for clock_gettime wrong? because i don't think we want to count suspended time on init time analytics? (that is if the user does suspend their device during boot, which is odd)