/* wydawca - automatic release submission daemon
Copyright (C) 2008-2011 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 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 (__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 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 metadef *def, size_t num)
{
while (num--)
{
free (def->kw);
def++;
}
}