gauge_t global_rate = 0;
size_t cpu_num = u->states_num / STATE_MAX;
+ gauge_t state_ratio[STATE_MAX] = {0};
for (size_t cpu = 0; cpu < cpu_num; cpu++) {
size_t active_index = (cpu * STATE_MAX) + STATE_ACTIVE;
usage_state_t *active = u->states + active_index;
}
}
+ if (active->has_value) {
+ u->global[STATE_ACTIVE].rate += active->rate;
+ u->global[STATE_ACTIVE].has_value = true;
+ }
+
/* With cpu_rate available, calculate a counter for each state that is
* normalized to microseconds. I.e. all states of one CPU sum up to 1000000
* us per second. */
continue;
}
- gauge_t rate = 1000000.0 * us->rate / cpu_rate;
+ gauge_t ratio = us->rate / cpu_rate;
value_t v = {0};
- int status =
- rate_to_value(&v, rate, &us->to_count, DS_TYPE_DERIVE, u->time);
+ int status = rate_to_value(&v, 1000000.0 * ratio, &us->to_count,
+ DS_TYPE_DERIVE, u->time);
if (status == 0) {
us->count = v.derive;
us->has_count = true;
}
- }
- if (active->has_value) {
- u->global[STATE_ACTIVE].rate += active->rate;
- u->global[STATE_ACTIVE].has_value = true;
+ state_ratio[s] += ratio;
}
}
us->count = -1;
if (!us->has_value) {
+ /* Ensure that us->to_count is initialized. */
+ rate_to_value(&(value_t){0}, 0.0, &us->to_count, DS_TYPE_DERIVE, u->time);
continue;
}
- gauge_t rate = CDTIME_T_TO_DOUBLE(u->interval) * us->rate / global_rate;
value_t v = {0};
- int status =
- rate_to_value(&v, rate, &us->to_count, DS_TYPE_DERIVE, u->time);
+ int status = rate_to_value(&v, 1000000.0 * state_ratio[s], &us->to_count,
+ DS_TYPE_DERIVE, u->time);
if (status == 0) {
us->count = v.derive;
us->has_count = true;
return us->count;
}
+__attribute__((unused)) static derive_t usage_global_count(usage_t *u,
+ state_t state) {
+ usage_finalize(u);
+
+ return u->global[state].count;
+}
+
/* Takes the zero-index number of a CPU and makes sure that the module-global
* cpu_states buffer is large enough. Returne ENOMEM on erorr. */
static int cpu_states_alloc(size_t cpu_num) /* {{{ */
static bool expect_usage_count(derive_t want, derive_t got, size_t cpu,
state_t state) {
+ char prefix[510] = "usage_global_count(";
+ if (cpu != SIZE_MAX) {
+ snprintf(prefix, sizeof(prefix), "usage_count(cpu=%zu, ", cpu);
+ }
+
bool ok = true;
char msg[1024] = {0};
- snprintf(msg, sizeof(msg), "usage_count(cpu=%zu, state=\"%s\") = %" PRId64,
- cpu, cpu_state_names[state], got);
+ snprintf(msg, sizeof(msg), "%sstate=\"%s\") = %" PRId64, prefix,
+ cpu_state_names[state], got);
derive_t diff = got - want;
if (diff < -1 || diff > 1) {
- snprintf(msg, sizeof(msg),
- "usage_count(cpu=%zu, state=\"%s\") = %" PRId64 ", want %" PRId64,
- cpu, cpu_state_names[state], got, want);
+ snprintf(msg, sizeof(msg), "%sstate=\"%s\") = %" PRId64 ", want %" PRId64,
+ prefix, cpu_state_names[state], got, want);
ok = false;
}
return 0;
}
+/* sumup returns the sum of 1 + 2 + ... + n */
+static derive_t sumup(derive_t n) { return n * (n + 1) / 2; }
+
+DEF_TEST(usage_global_count) {
+ int ret = 0;
+ usage_t usage = {0};
+#define CPU_NUM 2
+
+ cdtime_t t0 = TIME_T_TO_CDTIME_T(100);
+ usage_init(&usage, t0);
+ for (size_t cpu = 0; cpu < CPU_NUM; cpu++) {
+ for (state_t s = 0; s < STATE_ACTIVE; s++) {
+ usage_record(&usage, cpu, s, 1000);
+ }
+ }
+ usage_finalize(&usage);
+
+ cdtime_t interval = TIME_T_TO_CDTIME_T(300);
+
+ cdtime_t t1 = t0 + interval;
+ usage_init(&usage, t1);
+ for (size_t cpu = 0; cpu < CPU_NUM; cpu++) {
+ for (state_t s = 0; s < STATE_ACTIVE; s++) {
+ derive_t increment = ((derive_t)cpu * STATE_ACTIVE) + ((derive_t)s);
+ usage_record(&usage, cpu, s, 1000 + increment);
+ }
+ }
+
+ derive_t cpu_increment[CPU_NUM] = {
+ sumup(10),
+ sumup(21) - sumup(10),
+ };
+
+ gauge_t state_ratio[STATE_MAX] = {0};
+ for (size_t cpu = 0; cpu < CPU_NUM; cpu++) {
+ for (state_t s = 0; s < STATE_ACTIVE; s++) {
+ derive_t increment = ((derive_t)cpu * STATE_ACTIVE) + ((derive_t)s);
+ gauge_t ratio = ((gauge_t)increment) / ((gauge_t)cpu_increment[cpu]);
+
+ state_ratio[s] += ratio;
+ if (s != STATE_IDLE) {
+ state_ratio[STATE_ACTIVE] += ratio;
+ }
+ }
+ }
+
+ for (state_t s = 0; s < STATE_MAX; s++) {
+ gauge_t want_time =
+ 1000000.0 * CDTIME_T_TO_DOUBLE(interval) * state_ratio[s];
+ bool ok = expect_usage_count((derive_t)want_time,
+ usage_global_count(&usage, s), SIZE_MAX, s);
+ ret = ret || !ok;
+ }
+
+ gauge_t sum_ratio = 0;
+ for (state_t s = 0; s < STATE_ACTIVE; s++) {
+ sum_ratio += state_ratio[s];
+ }
+ EXPECT_EQ_DOUBLE(CPU_NUM, sum_ratio);
+
+ usage_reset(&usage);
+ return ret;
+}
+
int main(void) {
RUN_TEST(usage_rate);
RUN_TEST(usage_ratio);
RUN_TEST(usage_active_rate);
RUN_TEST(usage_global_rate);
RUN_TEST(usage_global_ratio);
+ RUN_TEST(usage_global_count);
END_TEST;
}