diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
commit | a0aa2307322cd47bbf416810ac0292925e03be87 (patch) | |
tree | 37076262a026c4b48c8a0e84f44ff9187556ca35 /src/util-profiling-locks.c | |
parent | Initial commit. (diff) | |
download | suricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip |
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/util-profiling-locks.c')
-rw-r--r-- | src/util-profiling-locks.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/util-profiling-locks.c b/src/util-profiling-locks.c new file mode 100644 index 0000000..00f9ef6 --- /dev/null +++ b/src/util-profiling-locks.c @@ -0,0 +1,242 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien <victor@inliniac.net> + * + * An API for profiling locks. + * + */ + +#include "suricata-common.h" +#include "util-profiling-locks.h" + +#ifdef PROFILING +#ifdef PROFILE_LOCKING +#include "threads.h" +#include "util-hashlist.h" +#include "util-debug.h" + +thread_local ProfilingLock locks[PROFILING_MAX_LOCKS]; +thread_local int locks_idx = 0; +thread_local int record_locks = 0; + +int profiling_locks_enabled = 0; +int profiling_locks_output_to_file = 0; +char *profiling_locks_file_name = NULL; +const char *profiling_locks_file_mode = "a"; + +typedef struct LockRecord_ { + char *file; // hash + + char *func; // info + int type; // info + + int line; // hash + + uint32_t cont; + uint32_t ticks_cnt; + uint64_t ticks_total; + uint64_t ticks_max; +} LockRecord; + +HashListTable *lock_records; +pthread_mutex_t lock_records_mutex; + +static uint32_t LockRecordHash(HashListTable *ht, void *buf, uint16_t buflen) +{ + LockRecord *fn = (LockRecord *)buf; + uint32_t hash = strlen(fn->file) + fn->line; + uint16_t u; + + for (u = 0; u < strlen(fn->file); u++) { + hash += fn->file[u]; + } + + return hash % ht->array_size; +} + +static char LockRecordCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) +{ + LockRecord *fn1 = (LockRecord *)buf1; + LockRecord *fn2 = (LockRecord *)buf2; + + if (fn1->line != fn2->line) + return 0; + + if (fn1->file == fn2->file) + return 1; + + return 0; +} + +static void LockRecordFree(void *data) +{ + LockRecord *fn = (LockRecord *)data; + + if (fn == NULL) + return; + SCFree(fn); +} + +int LockRecordInitHash(void) +{ + pthread_mutex_init(&lock_records_mutex, NULL); + pthread_mutex_lock(&lock_records_mutex); + + lock_records = HashListTableInit(512, LockRecordHash, LockRecordCompare, LockRecordFree); + BUG_ON(lock_records == NULL); + + pthread_mutex_unlock(&lock_records_mutex); + + return 0; +} + +static void LockRecordAdd(ProfilingLock *l) +{ + LockRecord fn = { NULL, NULL, 0,0,0,0,0,0}, *ptr = &fn; + fn.file = l->file; + fn.line = l->line; + + LockRecord *lookup_fn = (LockRecord *)HashListTableLookup(lock_records, (void *)ptr, 0); + if (lookup_fn == NULL) { + LockRecord *new = SCMalloc(sizeof(LockRecord)); + BUG_ON(new == NULL); + + new->file = l->file; + new->line = l->line; + new->type = l->type; + new->cont = l->cont; + new->func = l->func; + new->ticks_max = l->ticks; + new->ticks_total = l->ticks; + new->ticks_cnt = 1; + + HashListTableAdd(lock_records, (void *)new, 0); + } else { + lookup_fn->ticks_total += l->ticks; + if (l->ticks > lookup_fn->ticks_max) + lookup_fn->ticks_max = l->ticks; + lookup_fn->ticks_cnt++; + lookup_fn->cont += l->cont; + } + + return; +} + +/** \param p void ptr to Packet struct */ +void SCProfilingAddPacketLocks(void *p) +{ + int i; + + if (profiling_locks_enabled == 0) + return; + + for (i = 0; i < locks_idx; i++) { + pthread_mutex_lock(&lock_records_mutex); + LockRecordAdd(&locks[i]); + pthread_mutex_unlock(&lock_records_mutex); + } +} + +static void SCProfilingListLocks(void) +{ + FILE *fp = NULL; + + if (profiling_locks_output_to_file == 1) { + fp = fopen(profiling_locks_file_name, profiling_locks_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_locks_file_name, strerror(errno)); + return; + } + } else { + fp = stdout; + } + + fprintf(fp, "\n\nLock Cnt Avg ticks Max ticks Total ticks Cont Func\n"); + fprintf(fp, "------------------ ---------- --------- ------------ ------------ ------- ---------\n"); + + uint64_t total = 0; + uint32_t cont = 0; + uint64_t cnt = 0; + + HashListTableBucket *b = HashListTableGetListHead(lock_records); + while (b) { + LockRecord *r = HashListTableGetListData(b); + + const char *lock; + switch (r->type) { + case LOCK_MUTEX: + lock = "mtx"; + break; + case LOCK_SPIN: + lock = "spn"; + break; + case LOCK_RWW: + lock = "rww"; + break; + case LOCK_RWR: + lock = "rwr"; + break; + default: + lock = "bug"; + break; + } + + char str[128] = ""; + snprintf(str, sizeof(str), "(%s) %s:%d", lock,r->file, r->line); + + fprintf(fp, "%-50s %-10u %-9"PRIu64" %-12"PRIu64" %-12"PRIu64" %-7u %-s\n", + str, r->ticks_cnt, (uint64_t)((uint64_t)r->ticks_total/(uint64_t)r->ticks_cnt), r->ticks_max, r->ticks_total, r->cont, r->func); + + total += r->ticks_total; + cnt += r->ticks_cnt; + cont += r->cont; + + b = HashListTableGetListNext(b); + } + + fprintf(fp, "\nOverall: locks %"PRIu64", average cost %"PRIu64", contentions %"PRIu32", total ticks %"PRIu64"\n", + cnt, (uint64_t)((uint64_t)total/(uint64_t)cnt), cont, total); + + fclose(fp); +} + +void LockRecordFreeHash(void) +{ + if (profiling_locks_enabled == 0) + return; + + pthread_mutex_lock(&lock_records_mutex); + + SCProfilingListLocks(); + + if (lock_records != NULL) { + HashListTableFree(lock_records); + lock_records = NULL; + } + pthread_mutex_unlock(&lock_records_mutex); + + pthread_mutex_destroy(&lock_records_mutex); +} + +#endif +#endif + |