commit: c096a5d5d07c464d787a77c44725ac22f2ea731b
Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Fri Nov 28 19:13:54 2025 +0000
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Fri Nov 28 19:13:54 2025 +0000
URL: https://gitweb.gentoo.org/proj/steve.git/commit/?id=c096a5d5
Add a --min-jobs option for --load-average
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>
steve.cxx | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/steve.cxx b/steve.cxx
index 50d9f50..4c49e3f 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -68,6 +68,7 @@ struct steve_process {
struct steve_state {
bool verbose;
size_t jobs;
+ size_t min_jobs;
double max_load_avg{-1}; /* < 0 implies no load average */
double load_avg;
size_t tokens;
@@ -93,6 +94,8 @@ static steve_token_availability
steve_can_give_token(steve_state *state)
if (state->tokens == 0)
return steve_token_availability::no_tokens;
if (state->max_load_avg > 0) {
+ if (state->jobs < state->min_jobs + state->tokens)
+ return steve_token_availability::available;
if (getloadavg(&state->load_avg, 1) == -1) {
static bool warned = false;
if (!warned) {
@@ -112,7 +115,7 @@ static void steve_give_token(steve_state *state, fuse_req_t
req, uint64_t pid)
state->processes[pid].tokens_held++;
if (state->verbose) {
if (state->max_load_avg > 0)
- std::print(stderr, "Giving job token to PID {}, {}
left, {} tokens held by process, load average = {:.3} < {}\n",
+ std::print(stderr, "Giving job token to PID {}, {}
left, {} tokens held by process, load average = {:.3} (limit: {})\n",
pid, state->tokens,
state->processes[pid].tokens_held, state->load_avg, state->max_load_avg);
else
std::print(stderr, "Giving job token to PID {}, {}
left, {} tokens held by process\n",
@@ -169,6 +172,8 @@ static void steve_init(void *userdata, struct
fuse_conn_info *)
std::print(stderr, "steve running on /dev/steve for {} jobs\n",
state->jobs);
if (state->max_load_avg > 0)
std::print(stderr, " tokens will be served with load average <
{:.3}\n", state->max_load_avg);
+ if (state->min_jobs > 0)
+ std::print(stderr, " at least {} jobs will be always
available\n", state->min_jobs);
}
static void steve_destroy(void *userdata)
@@ -427,6 +432,8 @@ static constexpr char steve_usage[] =
" --jobs=JOBS, -j JOBS jobs to use (default: nproc)\n"
" --load-average=LOAD_AVG, -l LOAD_AVG\n"
" do not serve tokens unless load is below
LOAD_AVG\n"
+" --min-jobs=MIN_JOBS, -m MIN_JOBS\n"
+" min. jobs to serve even if load average is
exceeded\n"
" --verbose, -v enable verbose logging\n"
" --debug, -d enable FUSE debug output\n";
@@ -435,12 +442,13 @@ static const struct option steve_long_opts[] = {
{ "version", no_argument, 0, 'V' },
{ "jobs", required_argument, 0, 'j' },
{ "load-average", required_argument, 0, 'l' },
+ { "min-jobs", required_argument, 0, 'm' },
{ "verbose", no_argument, 0, 'v' },
{ "debug", no_argument, 0, 'd' },
{},
};
-static const char *steve_short_opts = "hVj:l:vd";
+static const char *steve_short_opts = "hVj:l:m:vd";
struct fd_guard {
int fd;
@@ -462,6 +470,7 @@ int main(int argc, char **argv)
std::print("steve {}\n", STEVE_VERSION);
return 0;
case 'j':
+ case 'm':
{
char *endptr;
errno = 0;
@@ -470,7 +479,12 @@ int main(int argc, char **argv)
std::print(stderr, "invalid job
number: {}\n", optarg);
return 1;
}
- state.jobs = jobs_arg;
+ if (opt == 'j')
+ state.jobs = jobs_arg;
+ else if (opt == 'm')
+ state.min_jobs = jobs_arg;
+ else
+ assert(0 && "not reached");
}
break;
case 'l':
@@ -497,6 +511,12 @@ int main(int argc, char **argv)
}
}
+ if (state.min_jobs > state.jobs) {
+ std::print(stderr, "--min-jobs ({}) must be smaller than --jobs
({})\n",
+ state.min_jobs, state.jobs);
+ return 1;
+ }
+
std::unique_ptr<struct event_base, std::function<void(struct
event_base*)>>
evb{event_base_new(), event_base_free};
if (!evb) {