/* wydawca - automatic release submission daemon
Copyright (C) 2008-2013 Sergey Poznyakoff
Wydawca is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
Wydawca is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with wydawca. If not, see . */
#include
#include
#include
#include
#include
#include
struct timer_slot {
char *name;
double real;
double self_user; /* user time in sec */
double self_system; /* system time in sec */
double children_user; /* user time in sec */
double children_system; /* system time in sec */
struct timeval real_mark;
struct rusage self_mark;
struct rusage children_mark;
};
static struct grecs_symtab *timer_table;
static size_t _timer_count;
static unsigned
hash_string_ci(const char *string, unsigned long n_buckets)
{
size_t value = 0;
unsigned char ch;
for (; (ch = *string); string++)
value = (value * 31 + tolower(ch)) % n_buckets;
return value;
}
static unsigned
timer_hasher(void *ptr, unsigned long n_buckets)
{
struct timer_slot *tp = ptr;
return hash_string_ci(tp->name, n_buckets);
}
/* Lookup a timer by its name. If it does not exist, create it. */
wydawca_timer_t
timer_get(const char *name)
{
struct timer_slot key, *ret;
int install = 1;
key.name = (char *)name;
if (!timer_table) {
timer_table = grecs_symtab_create(sizeof(key),
timer_hasher,
NULL, NULL, NULL, NULL);
if (!timer_table)
grecs_alloc_die();
}
ret = grecs_symtab_lookup_or_install(timer_table, &key, &install);
if (!ret)
grecs_alloc_die();
if (install)
_timer_count++;
return ret;
}
wydawca_timer_t
timer_start(const char *name)
{
wydawca_timer_t t = timer_get(name);
gettimeofday(&t->real_mark, NULL);
getrusage(RUSAGE_SELF, &t->self_mark);
getrusage(RUSAGE_CHILDREN, &t->children_mark);
return t;
}
#define DIFFTIME(now,then)\
(((now).tv_sec - (then).tv_sec) \
+ ((double)((now).tv_usec - (then).tv_usec))/1000000)
static void
_timer_compute(wydawca_timer_t t)
{
struct timeval real;
struct rusage rusage;
gettimeofday(&real, NULL);
t->real = DIFFTIME(real, t->real_mark);
getrusage(RUSAGE_SELF, &rusage);
t->self_user = DIFFTIME(rusage.ru_utime, t->self_mark.ru_utime);
t->self_system = DIFFTIME(rusage.ru_stime, t->self_mark.ru_stime);
getrusage(RUSAGE_CHILDREN, &rusage);
t->children_user = DIFFTIME(rusage.ru_utime, t->children_mark.ru_utime);
t->children_system =
DIFFTIME(rusage.ru_stime, t->children_mark.ru_stime);
}
wydawca_timer_t
timer_stop(const char *name)
{
wydawca_timer_t t = timer_get(name);
_timer_compute(t);
return t;
}
wydawca_timer_t
timer_reset(const char *name)
{
wydawca_timer_t t = timer_get(name);
t->real = 0.0;
t->self_user = 0.0;
t->self_system = 0.0;
t->children_user = 0.0;
t->children_system = 0.0;
return t;
}
double
timer_get_real(wydawca_timer_t t)
{
return t->real;
}
double
timer_get_user(wydawca_timer_t t)
{
return t->self_user + t->children_user;
}
double
timer_get_system(wydawca_timer_t t)
{
return t->self_system + t->children_system;
}
char *
timer_format_time(double t)
{
char *str = NULL;
size_t size = 0;
if (t < 600)
grecs_asprintf(&str, &size, "%0.3f", t);
else {
long int s, m, h, d;
s = (long int)t;
d = s / (3600 * 24);
s -= d * 3600 * 24;
h = s / 3600;
s -= h * 3600;
m = s / 60;
s -= m * 60;
if (d)
grecs_asprintf(&str, &size, "%ld+%02ld:%02ld:%02ld", d,
h, m, s);
else if (h)
grecs_asprintf(&str, &size, "%02ld:%02ld:%02ld", h, m,
s);
else
grecs_asprintf(&str, &size, "%02ld:%02ld", m, s);
}
if (!str)
grecs_alloc_die();
return str;
}
size_t
timer_get_count()
{
return _timer_count;
}
struct timer_data {
struct wy_metadef *def;
size_t num;
};
int
_fill_meta(void *sym, void *data)
{
struct timer_slot *slot = sym;
struct timer_data *tp = data;
#define CREATE_DEF(arg) \
if (tp->num) { \
char *buf = NULL; \
size_t size = 0; \
grecs_asprintf(&buf, &size, "timer:%s:%s", slot->name, #arg); \
if (!buf) \
grecs_alloc_die(); \
tp->def->kw = buf; \
tp->def->storage = \
timer_format_time(wy_s_cat2(timer_get_,arg)(slot)); \
tp->def->value = tp->def->storage; \
tp->def->expand = NULL; \
tp->def++; \
tp->num--; \
}
CREATE_DEF(system);
CREATE_DEF(real);
CREATE_DEF(user);
return tp->num <= 0;
}
void
timer_fill_meta(struct wy_metadef *def, size_t num)
{
struct timer_data td;
if (!timer_table)
return;
td.def = def;
td.num = num;
grecs_symtab_enumerate(timer_table, _fill_meta, &td);
}
void
timer_free_meta(struct wy_metadef *def, size_t num)
{
while (num--) {
free(def->kw);
def++;
}
}