mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
6.1 KiB
C
242 lines
6.1 KiB
C
/* 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 = "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()
|
|
{
|
|
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;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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(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 %-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()
|
|
{
|
|
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
|
|
|