mirror of https://github.com/OISF/suricata
profiling: add per lock location profiling
Add profiling per lock location in the code. Accounts how often a lock is requested, how often it was contended, the max number of ticks spent waiting for it, avg number of ticks waiting for it and the total ticks for that location. Added a new configure flag --enable-profiling-locks to enable this feature.remotes/origin/master
parent
41e9dba20b
commit
d908e707d7
@ -0,0 +1,233 @@
|
|||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef PROFILING
|
||||||
|
#ifdef PROFILE_LOCKING
|
||||||
|
|
||||||
|
#include "suricata-common.h"
|
||||||
|
#include "util-profiling-locks.h"
|
||||||
|
#include "util-hashlist.h"
|
||||||
|
|
||||||
|
__thread ProfilingLock locks[PROFILING_MAX_LOCKS];
|
||||||
|
__thread int locks_idx = 0;
|
||||||
|
__thread int record_locks = 0;
|
||||||
|
|
||||||
|
int profiling_locks_enabled = 0;
|
||||||
|
int profiling_locks_output_to_file = 0;
|
||||||
|
char *profiling_locks_file_name = NULL;
|
||||||
|
char *profiling_locks_file_mode = NULL;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
for (i = 0; i < locks_idx; i++) {
|
||||||
|
pthread_mutex_lock(&lock_records_mutex);
|
||||||
|
LockRecordAdd(&locks[i]);
|
||||||
|
pthread_mutex_unlock(&lock_records_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCProfilingListLocks(void) {
|
||||||
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
if (profiling_locks_output_to_file == 1) {
|
||||||
|
if (strcasecmp(profiling_locks_file_mode, "yes") == 0) {
|
||||||
|
fp = fopen(profiling_locks_file_name, "a");
|
||||||
|
} else {
|
||||||
|
fp = fopen(profiling_locks_file_name, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
|
SCLogError(SC_ERR_FOPEN, "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);
|
||||||
|
|
||||||
|
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 %-9u %-12"PRIu64" %-12"PRIu64" %-7u %-s\n",
|
||||||
|
str, r->ticks_cnt, (int)r->ticks_total/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, total/cnt, cont, total);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LockRecordFreeHash() {
|
||||||
|
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
|
||||||
|
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
/* 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>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UTIL_PROFILE_LOCKS_H__
|
||||||
|
#define __UTIL_PROFILE_LOCKS_H__
|
||||||
|
|
||||||
|
#ifdef PROFILING
|
||||||
|
|
||||||
|
#define PROFILING_MAX_LOCKS 64
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LOCK_MUTEX,
|
||||||
|
LOCK_SPIN,
|
||||||
|
LOCK_RWW, /**< rwlock, writer */
|
||||||
|
LOCK_RWR, /**< rwlock, reader */
|
||||||
|
};
|
||||||
|
|
||||||
|
void SCProfilingAddPacketLocks(void *);
|
||||||
|
|
||||||
|
int LockRecordInitHash();
|
||||||
|
void LockRecordFreeHash();
|
||||||
|
|
||||||
|
#endif /* PROFILING */
|
||||||
|
#endif /* __UTIL_PROFILE_LOCKS_H__ */
|
||||||
|
|
||||||
Loading…
Reference in New Issue