/* * Copyright (c) 2003, 2004 Niels Provos * All rights reserved. * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include #include #include #include #include "histogram.h" #include "keycount.h" /* Keycount related stuff */ int key_compare(const void *a, size_t alen, const void *b, size_t blen) { int keylen = MIN(alen, blen); int res; res = memcmp(a, b, keylen); if (res) return (res); return (alen - blen); } int kc_compare(const struct keycount *a, const struct keycount *b) { return (key_compare(a->key, a->keylen, b->key, b->keylen)); } SPLAY_GENERATE(kctree, keycount, node, kc_compare); struct keycount * keycount_new(const void *key, size_t len, void *(*create)(void), void (*free)(void *)) { struct keycount *keycount; if ((keycount = calloc(1, sizeof(struct keycount))) == NULL) err(1, "%s: calloc"); if ((keycount->key = malloc(len)) == NULL) err(1, "%s: malloc"); keycount->keylen = len; memcpy((void *)keycount->key, key, len); keycount->count = count_new(); if (create != NULL) { keycount->auxilary = (*create)(); keycount->aux_free = free; } return (keycount); } void keycount_free(struct keycount *kc) { if (kc->auxilary != NULL && kc->aux_free != NULL) (*kc->aux_free)(kc->auxilary); free((void *)kc->key); count_free(kc->count); free(kc); } /* Timeseries related functionality */ static int timekey_compare(struct timekey *a, struct timekey *b) { return (key_compare(a->key, a->keylen, b->key, b->keylen)); } SPLAY_PROTOTYPE(timetree, timekey, node, timekey_compare); SPLAY_GENERATE(timetree, timekey, node, timekey_compare); SPLAY_HEAD(timeseriestree, timeseries) timeviews; SPLAY_HEAD(timeupdatetree, timeseries) timeupdates; static int timeseries_compare(struct timeseries *a, struct timeseries *b) { return (strcmp(a->name, b->name)); } SPLAY_PROTOTYPE(timeseriestree, timeseries, node, timeseries_compare); SPLAY_GENERATE(timeseriestree, timeseries, node, timeseries_compare); static int timeupdate_compare(struct timeseries *a, struct timeseries *b) { if (timercmp(&a->tv_next, &b->tv_next, <)) return (-1); if (timercmp(&a->tv_next, &b->tv_next, >)) return (1); if (a < b) return (-1); if (a > b) return (1); return (0); } SPLAY_PROTOTYPE(timeupdatetree, timeseries, update_node, timeupdate_compare); SPLAY_GENERATE(timeupdatetree, timeseries, update_node, timeupdate_compare); void timeseries_init() { SPLAY_INIT(&timeviews); SPLAY_INIT(&timeupdates); } struct timeseries * timeseries_new(char *name, struct kctree *kct, void (*extract)(struct keycount *, void **, size_t *), void (*print)(void *, size_t), struct timeval *update) { struct timeseries tmp, *ts; tmp.name = name; if ((SPLAY_FIND(timeseriestree, &timeviews, &tmp)) != NULL) return (NULL); if ((ts = calloc(1, sizeof(struct timeseries))) == NULL) err(1, "%s: calloc", __func__); if ((ts->name = strdup(name)) == NULL) err(1, "%s: strdup", __func__); ts->extract = ts->extract; ts->print = ts->print; count_get_time(&ts->tv_start); ts->tv_update = *update; timeradd(&ts->tv_start, &ts->tv_update, &ts->tv_next); SPLAY_INIT(&ts->entries); SPLAY_INSERT(timeseriestree, &timeviews, ts); SPLAY_INSERT(timeupdatetree, &timeupdates, ts); return (ts); } struct timekey * timekey_new(const void *key, size_t keylen) { struct timekey *tk; if ((tk = calloc(1, sizeof(struct timekey))) == NULL) err(1, "%s: calloc"); if ((tk->key = malloc(keylen)) == NULL) err(1, "%s: malloc"); memcpy(tk->key, key, keylen); tk->keylen = keylen; TAILQ_INIT(&tk->entries); return (tk); } void timeseries_update_item(struct timeseries *ts) { struct keycount *kc; struct timekey *tk, tmp; SPLAY_FOREACH(kc, kctree, ts->tree) { /* Update the counters to our current time period */ count_internal_increment(kc->count, &ts->tv_next, 0); tmp.key = (void *)kc->key; tmp.keylen = kc->keylen; if ((tk = SPLAY_FIND(timetree, &ts->entries, &tmp)) == NULL) { tk = timekey_new(kc->key, kc->keylen); SPLAY_INSERT(timetree, &ts->entries, tk); } /* Summarize and then record */ } } void timeseries_update(struct timeval *tv) { struct timeseries *ts; for (ts = SPLAY_MIN(timeupdatetree, &timeupdates); ts != NULL && timercmp(&ts->tv_next, tv, >); ts = SPLAY_MIN(timeupdatetree, &timeupdates)) { SPLAY_REMOVE(timeupdatetree, &timeupdates, ts); timeseries_update_item(ts); timeradd(&ts->tv_next, &ts->tv_update, &ts->tv_next); SPLAY_INSERT(timeupdatetree, &timeupdates, ts); } }