/* 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++; } }