mirror of
https://github.com/schoebel/mars
synced 2024-12-25 08:02:26 +00:00
all: distinguish *_ops_* from *_amount_* at limiter
This commit is contained in:
parent
b5209337a9
commit
628c636dff
@ -61,8 +61,10 @@ int mars_limit(struct mars_limiter *lim, int amount)
|
||||
* They will intentionally wrap around.
|
||||
* Userspace must take care of that.
|
||||
*/
|
||||
lim->lim_total_ops++;
|
||||
lim->lim_total_sum += amount;
|
||||
if (likely(amount > 0)) {
|
||||
lim->lim_total_amount += amount;
|
||||
lim->lim_total_ops++;
|
||||
}
|
||||
|
||||
/* Only use incremental accumulation at repeated calls, but
|
||||
* never after longer pauses.
|
||||
@ -71,26 +73,48 @@ int mars_limit(struct mars_limiter *lim, int amount)
|
||||
window < (long long)lim->lim_max_window * (LIMITER_TIME_RESOLUTION / 1000))) {
|
||||
long long rate_raw;
|
||||
int rate;
|
||||
int max_rate;
|
||||
|
||||
/* Races are possible, but taken into account.
|
||||
* There is no real harm from rarely lost updates.
|
||||
*/
|
||||
if (likely(amount > 0)) {
|
||||
lim->lim_accu += amount;
|
||||
lim->lim_cumul += amount;
|
||||
lim->lim_count++;
|
||||
lim->lim_amount_accu += amount;
|
||||
lim->lim_amount_cumul += amount;
|
||||
lim->lim_ops_accu++;
|
||||
lim->lim_ops_cumul++;
|
||||
}
|
||||
|
||||
rate_raw = lim->lim_accu * LIMITER_TIME_RESOLUTION / window;
|
||||
|
||||
/* compute amount values */
|
||||
rate_raw = lim->lim_amount_accu * LIMITER_TIME_RESOLUTION / window;
|
||||
rate = rate_raw;
|
||||
if (unlikely(rate_raw > INT_MAX)) {
|
||||
rate = INT_MAX;
|
||||
}
|
||||
lim->lim_rate = rate;
|
||||
lim->lim_amount_rate = rate;
|
||||
|
||||
// limit exceeded?
|
||||
if (lim->lim_max_rate > 0 && rate > lim->lim_max_rate) {
|
||||
int this_delay = (window * rate / lim->lim_max_rate - window) / (LIMITER_TIME_RESOLUTION / 1000);
|
||||
/* amount limit exceeded? */
|
||||
max_rate = lim->lim_max_amount_rate;
|
||||
if (max_rate > 0 && rate > max_rate) {
|
||||
int this_delay = (window * rate / max_rate - window) / (LIMITER_TIME_RESOLUTION / 1000);
|
||||
// compute maximum
|
||||
if (this_delay > delay && this_delay > 0)
|
||||
delay = this_delay;
|
||||
}
|
||||
|
||||
/* compute ops values */
|
||||
rate_raw = lim->lim_ops_accu * LIMITER_TIME_RESOLUTION / window;
|
||||
rate = rate_raw;
|
||||
if (unlikely(rate_raw > INT_MAX)) {
|
||||
rate = INT_MAX;
|
||||
}
|
||||
lim->lim_ops_rate = rate;
|
||||
|
||||
/* ops limit exceeded? */
|
||||
max_rate = lim->lim_max_ops_rate;
|
||||
if (max_rate > 0 && rate > max_rate) {
|
||||
int this_delay = (window * rate / max_rate - window) / (LIMITER_TIME_RESOLUTION / 1000);
|
||||
|
||||
// compute maximum
|
||||
if (this_delay > delay && this_delay > 0)
|
||||
delay = this_delay;
|
||||
@ -100,30 +124,41 @@ int mars_limit(struct mars_limiter *lim, int amount)
|
||||
*/
|
||||
window -= lim->lim_min_window * (LIMITER_TIME_RESOLUTION / 1000);
|
||||
if (window > 0) {
|
||||
long long used_up = (long long)lim->lim_rate * window / LIMITER_TIME_RESOLUTION;
|
||||
long long used_up = (long long)lim->lim_amount_rate * window / LIMITER_TIME_RESOLUTION;
|
||||
if (used_up > 0) {
|
||||
lamport_time_add_ns(&lim->lim_stamp, window);
|
||||
lim->lim_accu -= used_up;
|
||||
if (unlikely(lim->lim_accu < 0))
|
||||
lim->lim_accu = 0;
|
||||
lim->lim_amount_accu -= used_up;
|
||||
if (unlikely(lim->lim_amount_accu < 0))
|
||||
lim->lim_amount_accu = 0;
|
||||
}
|
||||
used_up = (long long)lim->lim_ops_rate * window / LIMITER_TIME_RESOLUTION;
|
||||
if (used_up > 0) {
|
||||
lamport_time_add_ns(&lim->lim_stamp, window);
|
||||
lim->lim_ops_accu -= used_up;
|
||||
if (unlikely(lim->lim_ops_accu < 0))
|
||||
lim->lim_ops_accu = 0;
|
||||
}
|
||||
}
|
||||
} else { // reset, start over with new measurement cycle
|
||||
struct lamport_time sub = ns_to_lamport_time(lim->lim_min_window * (LIMITER_TIME_RESOLUTION / 1000));
|
||||
|
||||
if (unlikely(amount < 0))
|
||||
amount = 0;
|
||||
lim->lim_ops_accu = 1;
|
||||
lim->lim_amount_accu = amount;
|
||||
lim->lim_stamp = lamport_time_sub(now, sub);
|
||||
lim->lim_accu = amount;
|
||||
lim->lim_rate = 0;
|
||||
lim->lim_ops_rate = 0;
|
||||
lim->lim_amount_rate = 0;
|
||||
}
|
||||
lim = lim->lim_father;
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mars_limit);
|
||||
|
||||
void mars_limit_sleep(struct mars_limiter *lim, int amount)
|
||||
{
|
||||
int sleep = mars_limit(lim, amount);
|
||||
|
||||
if (sleep > 0) {
|
||||
if (unlikely(lim->lim_max_delay <= 0))
|
||||
lim->lim_max_delay = 1000;
|
||||
@ -132,7 +167,6 @@ void mars_limit_sleep(struct mars_limiter *lim, int amount)
|
||||
brick_msleep(sleep);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mars_limit_sleep);
|
||||
|
||||
void mars_limit_reset(struct mars_limiter *lim)
|
||||
{
|
||||
|
@ -33,19 +33,22 @@ struct mars_limiter {
|
||||
/* hierarchy tree */
|
||||
struct mars_limiter *lim_father;
|
||||
/* tunables */
|
||||
int lim_max_rate;
|
||||
int lim_max_ops_rate;
|
||||
int lim_max_amount_rate;
|
||||
int lim_max_delay;
|
||||
int lim_min_window;
|
||||
int lim_max_window;
|
||||
/* readable */
|
||||
int lim_rate;
|
||||
int lim_cumul;
|
||||
int lim_count;
|
||||
int lim_ops_rate;
|
||||
int lim_amount_rate;
|
||||
int lim_ops_cumul;
|
||||
int lim_amount_cumul;
|
||||
int lim_total_ops;
|
||||
int lim_total_sum;
|
||||
int lim_total_amount;
|
||||
struct lamport_time lim_stamp;
|
||||
/* internal */
|
||||
long long lim_accu;
|
||||
long long lim_ops_accu;
|
||||
long long lim_amount_accu;
|
||||
};
|
||||
|
||||
extern int mars_limit(struct mars_limiter *lim, int amount);
|
||||
|
@ -1161,7 +1161,7 @@ EXPORT_SYMBOL_GPL(client_brick_type);
|
||||
////////////////// module init stuff /////////////////////////
|
||||
|
||||
struct mars_limiter client_limiter = {
|
||||
.lim_max_rate = 0,
|
||||
/* Let all be zero */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(client_limiter);
|
||||
|
||||
|
@ -78,7 +78,7 @@ int if_throttle_start_size = 0; // in kb
|
||||
EXPORT_SYMBOL_GPL(if_throttle_start_size);
|
||||
|
||||
struct mars_limiter if_throttle = {
|
||||
.lim_max_rate = 10000,
|
||||
.lim_max_amount_rate = 10000,
|
||||
};
|
||||
|
||||
///////////////////////// own type definitions ////////////////////////
|
||||
|
@ -936,7 +936,7 @@ static int _server_thread(void *data)
|
||||
////////////////// module init stuff /////////////////////////
|
||||
|
||||
struct mars_limiter server_limiter = {
|
||||
.lim_max_rate = 0,
|
||||
/* Let all be zero */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(server_limiter);
|
||||
|
||||
|
@ -1606,10 +1606,19 @@ void _show_status_all(struct mars_global *global)
|
||||
}
|
||||
|
||||
static
|
||||
void _show_rate(struct mars_rotate *rot, struct mars_limiter *limiter, const char *name)
|
||||
void _show_rate(struct mars_rotate *rot, struct mars_limiter *limiter, const char *basename)
|
||||
{
|
||||
char *name;
|
||||
|
||||
mars_limit(limiter, 0);
|
||||
__show_actual(rot->parent_path, name, limiter->lim_rate);
|
||||
|
||||
name = path_make("ops-%s", basename);
|
||||
__show_actual(rot->parent_path, name, limiter->lim_ops_rate);
|
||||
brick_string_free(name);
|
||||
|
||||
name = path_make("amount-%s", basename);
|
||||
__show_actual(rot->parent_path, name, limiter->lim_amount_rate);
|
||||
brick_string_free(name);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@ -1758,7 +1767,8 @@ int __make_copy(
|
||||
"from = '%s' to = '%s'"
|
||||
" on = %d start_pos = %lld end_pos = %lld"
|
||||
" actual_pos = %lld actual_stamp = %ld.%09ld"
|
||||
" rate = %d read_fly = %d write_fly = %d error_code = %d nr_errors = %d",
|
||||
" ops_rate = %d amount_rate = %d"
|
||||
" read_fly = %d write_fly = %d error_code = %d nr_errors = %d",
|
||||
argv[0],
|
||||
argv[1],
|
||||
_copy->power.led_on,
|
||||
@ -1766,7 +1776,8 @@ int __make_copy(
|
||||
_copy->copy_end,
|
||||
_copy->copy_last,
|
||||
_copy->copy_last_stamp.tv_sec, _copy->copy_last_stamp.tv_nsec,
|
||||
_copy->copy_limiter ? _copy->copy_limiter->lim_rate : 0,
|
||||
_copy->copy_limiter ? _copy->copy_limiter->lim_ops_rate : 0,
|
||||
_copy->copy_limiter ? _copy->copy_limiter->lim_amount_rate : 0,
|
||||
atomic_read(&_copy->copy_read_flight),
|
||||
atomic_read(&_copy->copy_write_flight),
|
||||
_copy->copy_error,
|
||||
|
@ -240,15 +240,17 @@ done:
|
||||
VEC_ENTRY(NAME, VAR, MODE, 1)
|
||||
|
||||
#define LIMITER_ENTRIES(VAR, PREFIX, SUFFIX) \
|
||||
INT_ENTRY(PREFIX "_total_ops_" SUFFIX, (VAR)->lim_total_ops, 0400), \
|
||||
INT_ENTRY(PREFIX "_total_sum_" SUFFIX, (VAR)->lim_total_sum, 0400), \
|
||||
INT_ENTRY(PREFIX "_ratelimit_" SUFFIX, (VAR)->lim_max_rate, 0600), \
|
||||
INT_ENTRY(PREFIX "_total_ops", (VAR)->lim_total_ops, 0400), \
|
||||
INT_ENTRY(PREFIX "_total_" SUFFIX, (VAR)->lim_total_amount, 0400), \
|
||||
INT_ENTRY(PREFIX "_ratelimit_ops", (VAR)->lim_max_ops_rate, 0600), \
|
||||
INT_ENTRY(PREFIX "_ratelimit_" SUFFIX, (VAR)->lim_max_amount_rate, 0600), \
|
||||
INT_ENTRY(PREFIX "_maxdelay_ms", (VAR)->lim_max_delay,0600), \
|
||||
INT_ENTRY(PREFIX "_minwindow_ms", (VAR)->lim_min_window,0600), \
|
||||
INT_ENTRY(PREFIX "_maxwindow_ms", (VAR)->lim_max_window,0600), \
|
||||
INT_ENTRY(PREFIX "_cumul_" SUFFIX, (VAR)->lim_cumul, 0600), \
|
||||
INT_ENTRY(PREFIX "_count_ops", (VAR)->lim_count, 0600), \
|
||||
INT_ENTRY(PREFIX "_rate_" SUFFIX, (VAR)->lim_rate, 0400) \
|
||||
INT_ENTRY(PREFIX "_cumul_ops", (VAR)->lim_ops_cumul, 0600), \
|
||||
INT_ENTRY(PREFIX "_cumul_" SUFFIX, (VAR)->lim_amount_cumul, 0600), \
|
||||
INT_ENTRY(PREFIX "_rate_ops", (VAR)->lim_ops_rate, 0400), \
|
||||
INT_ENTRY(PREFIX "_rate_" SUFFIX, (VAR)->lim_amount_rate, 0400) \
|
||||
|
||||
#define THRESHOLD_ENTRIES(VAR, PREFIX) \
|
||||
INT_ENTRY(PREFIX "_threshold_us", (VAR)->thr_limit, 0600), \
|
||||
|
@ -5418,7 +5418,7 @@ sub eval_fn {
|
||||
my $lnk = $$env{"resdir"} . "/actual-" . $$env{"host"} . "/replay-code";
|
||||
return get_link($lnk, 2);
|
||||
}
|
||||
if (/^(sync|fetch|replay|work)[-_]?(rate|remain)$/) {
|
||||
if (/^(sync|fetch|replay|work)[-_]?(rate|ops[-_]?rate|amount[-_]?rate|remain)$/) {
|
||||
my $what = $1;
|
||||
my $select = $2;
|
||||
if ($what eq "work") {
|
||||
@ -5433,22 +5433,34 @@ sub eval_fn {
|
||||
return $val1 if $val1 > $val2;
|
||||
return $val2;
|
||||
}
|
||||
my $name = $select;
|
||||
$name = "amount_rate" if ($name eq "rate" || $name eq "remain");
|
||||
$name =~ s/-/_/;
|
||||
my %names =
|
||||
(
|
||||
"sync" => "sync_rate",
|
||||
"fetch" => "file_rate",
|
||||
"replay" => "replay_rate",
|
||||
"sync" => "sync",
|
||||
"fetch" => "file",
|
||||
"replay" => "replay",
|
||||
);
|
||||
my $lnk = $$env{"resdir"} . "/actual-" . $$env{"host"} . "/" . $names{$what};
|
||||
$name =~ s/_/-$names{$what}_/;
|
||||
my $lnk = $$env{"resdir"} . "/actual-" . $$env{"host"} . "/$name";
|
||||
my $rate = get_link($lnk, 2);
|
||||
return "" if !defined($rate) || $rate eq "" || $rate < 0;
|
||||
return $rate * 1024 if $select eq "rate";
|
||||
# deprecated: compatibility with old version
|
||||
if (!defined($rate) || $rate eq "") {
|
||||
$lnk =~ s:/amount-:/:;
|
||||
$rate = get_link($lnk, 2);
|
||||
}
|
||||
if ($select eq "remain") {
|
||||
my $rest = make_numeric(eval_fn($env, "$what-rest", ""));
|
||||
return 0 if $rest <= 0;
|
||||
return -1 if ($rate <= 0);
|
||||
return -1 if (!defined($rate) || $rate eq "" || $rate <= 0);
|
||||
return $rest / 1024 / $rate;
|
||||
}
|
||||
if ($select =~ /rate/) {
|
||||
return 0 if (!defined($rate) || !$rate || $rate <= 0);
|
||||
return $rate if $select =~ /^ops-/;
|
||||
return $rate * 1024;
|
||||
}
|
||||
ldie "unknown macro $_\n";
|
||||
}
|
||||
if (/^sync[-_]?size$/) {
|
||||
@ -6431,7 +6443,7 @@ my %trivial_globs =
|
||||
=> "",
|
||||
"writeback-rest"
|
||||
=> "",
|
||||
"{sync,fetch,replay}-{rate,remain}"
|
||||
"{sync,fetch,replay}-{ops-rate,amount-rate,rate,remain}"
|
||||
=> "",
|
||||
"replay-basenr"
|
||||
=> "",
|
||||
|
Loading…
Reference in New Issue
Block a user