suricata
util-profiling-locks.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2012 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * An API for profiling locks.
24  *
25  */
26 
27 #include "suricata-common.h"
28 #include "util-profiling-locks.h"
29 #include "util-hashlist.h"
30 
31 #ifdef PROFILING
32 #ifdef PROFILE_LOCKING
33 
35 __thread int locks_idx = 0;
36 __thread int record_locks = 0;
37 
40 char *profiling_locks_file_name = NULL;
41 const char *profiling_locks_file_mode = "a";
42 
43 typedef struct LockRecord_ {
44  char *file; // hash
45 
46  char *func; // info
47  int type; // info
48 
49  int line; // hash
50 
51  uint32_t cont;
52  uint32_t ticks_cnt;
53  uint64_t ticks_total;
54  uint64_t ticks_max;
55 } LockRecord;
56 
57 HashListTable *lock_records;
58 pthread_mutex_t lock_records_mutex;
59 
60 static uint32_t LockRecordHash(HashListTable *ht, void *buf, uint16_t buflen)
61 {
62  LockRecord *fn = (LockRecord *)buf;
63  uint32_t hash = strlen(fn->file) + fn->line;
64  uint16_t u;
65 
66  for (u = 0; u < strlen(fn->file); u++) {
67  hash += fn->file[u];
68  }
69 
70  return hash % ht->array_size;
71 }
72 
73 static char LockRecordCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2)
74 {
75  LockRecord *fn1 = (LockRecord *)buf1;
76  LockRecord *fn2 = (LockRecord *)buf2;
77 
78  if (fn1->line != fn2->line)
79  return 0;
80 
81  if (fn1->file == fn2->file)
82  return 1;
83 
84  return 0;
85 }
86 
87 static void LockRecordFree(void *data)
88 {
89  LockRecord *fn = (LockRecord *)data;
90 
91  if (fn == NULL)
92  return;
93  SCFree(fn);
94 }
95 
97 {
98  pthread_mutex_init(&lock_records_mutex, NULL);
99  pthread_mutex_lock(&lock_records_mutex);
100 
101  lock_records = HashListTableInit(512, LockRecordHash, LockRecordCompare, LockRecordFree);
102  BUG_ON(lock_records == NULL);
103 
104  pthread_mutex_unlock(&lock_records_mutex);
105 
106  return 0;
107 }
108 
109 static void LockRecordAdd(ProfilingLock *l)
110 {
111  LockRecord fn = { NULL, NULL, 0,0,0,0,0,0}, *ptr = &fn;
112  fn.file = l->file;
113  fn.line = l->line;
114 
115  LockRecord *lookup_fn = (LockRecord *)HashListTableLookup(lock_records, (void *)ptr, 0);
116  if (lookup_fn == NULL) {
117  LockRecord *new = SCMalloc(sizeof(LockRecord));
118  BUG_ON(new == NULL);
119 
120  new->file = l->file;
121  new->line = l->line;
122  new->type = l->type;
123  new->cont = l->cont;
124  new->func = l->func;
125  new->ticks_max = l->ticks;
126  new->ticks_total = l->ticks;
127  new->ticks_cnt = 1;
128 
129  HashListTableAdd(lock_records, (void *)new, 0);
130  } else {
131  lookup_fn->ticks_total += l->ticks;
132  if (l->ticks > lookup_fn->ticks_max)
133  lookup_fn->ticks_max = l->ticks;
134  lookup_fn->ticks_cnt++;
135  lookup_fn->cont += l->cont;
136  }
137 
138  return;
139 }
140 
141 /** \param p void ptr to Packet struct */
142 void SCProfilingAddPacketLocks(void *p)
143 {
144  int i;
145 
146  if (profiling_locks_enabled == 0)
147  return;
148 
149  for (i = 0; i < locks_idx; i++) {
150  pthread_mutex_lock(&lock_records_mutex);
151  LockRecordAdd(&locks[i]);
152  pthread_mutex_unlock(&lock_records_mutex);
153  }
154 }
155 
156 static void SCProfilingListLocks(void)
157 {
158  FILE *fp = NULL;
159 
162 
163  if (fp == NULL) {
164  SCLogError(SC_ERR_FOPEN, "failed to open %s: %s",
165  profiling_locks_file_name, strerror(errno));
166  return;
167  }
168  } else {
169  fp = stdout;
170  }
171 
172  fprintf(fp, "\n\nLock Cnt Avg ticks Max ticks Total ticks Cont Func\n");
173  fprintf(fp, "------------------ ---------- --------- ------------ ------------ ------- ---------\n");
174 
175  uint64_t total = 0;
176  uint32_t cont = 0;
177  uint64_t cnt = 0;
178 
180  while (b) {
181  LockRecord *r = HashListTableGetListData(b);
182 
183  const char *lock;
184  switch (r->type) {
185  case LOCK_MUTEX:
186  lock = "mtx";
187  break;
188  case LOCK_SPIN:
189  lock = "spn";
190  break;
191  case LOCK_RWW:
192  lock = "rww";
193  break;
194  case LOCK_RWR:
195  lock = "rwr";
196  break;
197  default:
198  lock = "bug";
199  break;
200  }
201 
202  char str[128] = "";
203  snprintf(str, sizeof(str), "(%s) %s:%d", lock,r->file, r->line);
204 
205  fprintf(fp, "%-50s %-10u %-9"PRIu64" %-12"PRIu64" %-12"PRIu64" %-7u %-s\n",
206  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);
207 
208  total += r->ticks_total;
209  cnt += r->ticks_cnt;
210  cont += r->cont;
211 
213  }
214 
215  fprintf(fp, "\nOverall: locks %"PRIu64", average cost %"PRIu64", contentions %"PRIu32", total ticks %"PRIu64"\n",
216  cnt, (uint64_t)((uint64_t)total/(uint64_t)cnt), cont, total);
217 
218  fclose(fp);
219 }
220 
221 void LockRecordFreeHash()
222 {
223  if (profiling_locks_enabled == 0)
224  return;
225 
226  pthread_mutex_lock(&lock_records_mutex);
227 
228  SCProfilingListLocks();
229 
230  if (lock_records != NULL) {
231  HashListTableFree(lock_records);
232  lock_records = NULL;
233  }
234  pthread_mutex_unlock(&lock_records_mutex);
235 
236  pthread_mutex_destroy(&lock_records_mutex);
237 }
238 
239 #endif
240 #endif
241 
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
const char * profiling_locks_file_mode
#define BUG_ON(x)
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
int LockRecordInitHash(void)
HRLOCK_TYPE lock
Definition: host.h:732
void LockRecordFreeHash(void)
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
void SCProfilingAddPacketLocks(void *)
__thread int record_locks
__thread ProfilingLock locks[PROFILING_MAX_LOCKS]
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
#define str(s)
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
uint8_t type
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
__thread int locks_idx
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
char * profiling_locks_file_name
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCFree(a)
Definition: util-mem.h:228
int profiling_locks_output_to_file
int profiling_locks_enabled
uint32_t array_size
Definition: util-hashlist.h:41
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
#define PROFILING_MAX_LOCKS