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.
suricata/src/util-profiling-locks.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