00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00040 #include <stdbool.h>
00041 #include <string.h>
00042 #include "stats.h"
00043 #include "chhash.h"
00044 #include "util.h"
00045 #include "debug.h"
00046
00047 m_statsmgr_t *m_g_statsmgr;
00048
00049 #define M_STATS_THREADSTAT_HASHTABLE_SIZE 128
00050
00051 #define MIN(A, B) (((A) < (B)) ? (A) : (B))
00052 #define MAX(A, B) (((A) > (B)) ? (A) : (B))
00053
00054 #define ACTION(name) #name,
00055 char *stats_strings[] = {
00056 FOREACH_STAT(ACTION)
00057 };
00058 #undef ACTION
00059
00060 static const char __whitespaces[] = " ";
00061
00062 #define WHITESPACE(len) &__whitespaces[sizeof(__whitespaces) - (len) -1]
00063
00065 struct m_stats_threadstat_s {
00066 unsigned int tid;
00067 m_stats_statset_t summary_statset;
00068 m_chhash_t *stats_table;
00069 struct m_stats_threadstat_s *next;
00070 struct m_stats_threadstat_s *prev;
00071 };
00072
00073
00075 struct m_statsmgr_s {
00076 m_mutex_t mutex;
00077 char *output_file;
00078 unsigned int alloc_threadstat_num;
00079 m_stats_threadstat_t *alloc_threadstat_list_head;
00080 m_stats_threadstat_t *alloc_threadstat_list_tail;
00081 };
00082
00083
00084 m_result_t
00085 m_statsmgr_create(m_statsmgr_t **statsmgrp, char *output_file)
00086 {
00087 *statsmgrp = (m_statsmgr_t *) MALLOC(sizeof(m_statsmgr_t));
00088 if (*statsmgrp == NULL) {
00089 return M_R_NOMEMORY;
00090 }
00091 (*statsmgrp)->output_file = output_file;
00092 (*statsmgrp)->alloc_threadstat_num = 0;
00093 (*statsmgrp)->alloc_threadstat_list_head = (*statsmgrp)->alloc_threadstat_list_tail = NULL;
00094 M_MUTEX_INIT(&(*statsmgrp)->mutex, NULL);
00095
00096 return M_R_SUCCESS;
00097 }
00098
00099
00100 m_result_t
00101 m_statsmgr_destroy(m_statsmgr_t **statsmgrp)
00102 {
00103 m_stats_threadstat_t *threadstat;
00104 m_stats_threadstat_t *threadstat_next;
00105 m_statsmgr_t *statsmgr = *statsmgrp;
00106
00107
00108 for (threadstat=statsmgr->alloc_threadstat_list_head;
00109 threadstat != NULL;
00110 threadstat = threadstat_next)
00111 {
00112 threadstat_next = threadstat->next;
00113 FREE(threadstat);
00114 }
00115
00116 FREE(statsmgr);
00117 *statsmgrp = NULL;
00118
00119 return M_R_SUCCESS;
00120 }
00121
00122
00123 m_result_t
00124 m_stats_threadstat_create(m_statsmgr_t *statsmgr,
00125 unsigned int tid,
00126 m_stats_threadstat_t **threadstatp)
00127 {
00128 m_stats_threadstat_t *threadstat;
00129 int i;
00130
00131 threadstat = (m_stats_threadstat_t *) MALLOC(sizeof(m_stats_threadstat_t));
00132
00133 M_MUTEX_LOCK(&(statsmgr->mutex));
00134 if (statsmgr->alloc_threadstat_list_head == NULL) {
00135 M_ASSERT(statsmgr->alloc_threadstat_list_tail == NULL);
00136 statsmgr->alloc_threadstat_list_head = threadstat;
00137 statsmgr->alloc_threadstat_list_tail = threadstat;
00138 threadstat->next = NULL;
00139 threadstat->prev = NULL;
00140 } else {
00141 statsmgr->alloc_threadstat_list_tail->next = threadstat;
00142 threadstat->prev = statsmgr->alloc_threadstat_list_tail;
00143 statsmgr->alloc_threadstat_list_tail = threadstat;
00144 }
00145 statsmgr->alloc_threadstat_num++;
00146 M_MUTEX_UNLOCK(&(statsmgr->mutex));
00147
00148 m_stats_statset_init(&(threadstat->summary_statset), NULL);
00149 threadstat->tid = tid;
00150 m_chhash_create(&threadstat->stats_table,
00151 M_STATS_THREADSTAT_HASHTABLE_SIZE,
00152 false);
00153 *threadstatp = threadstat;
00154 return M_R_SUCCESS;
00155 }
00156
00157
00158 m_result_t
00159 m_stats_statset_create(m_stats_statset_t **statsetp)
00160 {
00161 m_stats_statset_t *statset;
00162
00163 statset = (m_stats_statset_t *) MALLOC(sizeof(m_stats_statset_t));
00164 statset->count = 0;
00165 *statsetp = statset;
00166
00167 return M_R_SUCCESS;
00168 }
00169
00170
00171 m_result_t
00172 m_stats_statset_destroy(m_stats_statset_t **statsetp)
00173 {
00174 FREE(*statsetp);
00175 *statsetp = NULL;
00176
00177 return M_R_SUCCESS;
00178 }
00179
00180
00181 static
00182 void
00183 stats_statset_reset(m_stats_statset_t *statset)
00184 {
00185 #define RESETSTAT(name) \
00186 statset->stats[m_stats_##name##_stat].total = 0; \
00187 statset->stats[m_stats_##name##_stat].min = 0xFFFFFFFF; \
00188 statset->stats[m_stats_##name##_stat].max = 0;
00189
00190 FOREACH_STAT (RESETSTAT)
00191
00192 #undef RESETSTAT
00193 }
00194
00195
00196 m_result_t
00197 m_stats_statset_init(m_stats_statset_t *statset,
00198 const char *name)
00199 {
00200 statset->count = 0;
00201 statset->name = name;
00202 stats_statset_reset(statset);
00203 return M_R_SUCCESS;
00204 }
00205
00206
00207 static
00208 m_result_t
00209 stats_get_statset(m_chhash_t *stats_table,
00210 const char *name,
00211 m_stats_statset_t **statsetp)
00212 {
00213 m_chhash_key_t key;
00214 m_chhash_value_t value;
00215 m_stats_statset_t *statset;
00216 key = (m_chhash_key_t) name;
00217 if (m_chhash_lookup(stats_table, key, &value) == M_R_SUCCESS)
00218 {
00219 statset = (m_stats_statset_t *) value;
00220 *statsetp = statset;
00221 return M_R_SUCCESS;
00222 }
00223 return M_R_FAILURE;
00224 }
00225
00226
00227
00228
00229
00230 void
00231 stats_aggregate(m_stats_statset_t *dest_statset,
00232 m_stats_statset_t *source_statset)
00233 {
00234 int i;
00235
00236 dest_statset->count++;
00237 for (i=0; i<m_stats_numofstats; i++) {
00238 dest_statset->stats[i].total += source_statset->stats[i].total;
00239 dest_statset->stats[i].min = MIN(dest_statset->stats[i].min,
00240 source_statset->stats[i].total);
00241 dest_statset->stats[i].max = MAX(dest_statset->stats[i].max,
00242 source_statset->stats[i].total);
00243 }
00244 }
00245
00246
00247 void
00248 m_stats_threadstat_aggregate(m_stats_threadstat_t *threadstat, m_stats_statset_t *source_statset)
00249 {
00250 m_stats_statset_t *statset_all;
00251 m_result_t result;
00252
00253
00254 result = stats_get_statset(threadstat->stats_table, source_statset->name, &statset_all);
00255 if (result != M_R_SUCCESS) {
00256 m_stats_statset_create(&statset_all);
00257 m_stats_statset_init(statset_all, source_statset->name);
00258 m_chhash_add(threadstat->stats_table,
00259 (m_chhash_key_t) source_statset->name,
00260 (m_chhash_value_t) (statset_all));
00261 }
00262
00263
00264 stats_aggregate(statset_all, source_statset);
00265 stats_aggregate(&threadstat->summary_statset, source_statset);
00266 }
00267
00268
00269
00270 static
00271 void
00272 m_stats_statset_print(FILE *fout,
00273 m_stats_statset_t *statset,
00274 int shiftlen,
00275 int print_header)
00276 {
00277 int i;
00278 char header[512];
00279 double mean;
00280 m_stats_statcounter_t max;
00281 m_stats_statcounter_t min;
00282 m_stats_statcounter_t total;
00283 m_stats_statcounter_t count;
00284
00285 if (print_header) {
00286 sprintf(header, "Transaction: %s", statset->name);
00287 fprintf(fout, "%s%s\n\n", WHITESPACE(shiftlen), header);
00288 }
00289
00290 fprintf(fout, "%s%s%s:%13s%13s%13s%13s\n",
00291 WHITESPACE(shiftlen+2),
00292 "",
00293 WHITESPACE(25),
00294 "Min",
00295 "Mean",
00296 "Max",
00297 "Total");
00298
00299 count = statset->count;
00300
00301 fprintf(fout, "%s%s%s:%13s%13s%13s%13u\n",
00302 WHITESPACE(shiftlen+2),
00303 "Transactions",
00304 WHITESPACE(25 - strlen("Transactions")),
00305 "",
00306 "",
00307 "",
00308 count);
00309
00310 for (i=0; i<m_stats_numofstats; i++) {
00311 total = statset->stats[i].total;
00312 min = statset->stats[i].min;
00313 max = statset->stats[i].max;
00314 mean = (double) total / (double) count;
00315 fprintf(fout, "%s%s%s:%13u%13.2f%13u%13u\n",
00316 WHITESPACE(shiftlen+2),
00317 stats_strings[i],
00318 WHITESPACE(25 - strlen(stats_strings[i])),
00319 min,
00320 mean,
00321 max,
00322 total);
00323 }
00324 }
00325
00326
00327 static
00328 void
00329 stats_threadstat_print(FILE *fout,
00330 m_stats_threadstat_t *threadstat)
00331 {
00332 m_chhash_iter_t iter;
00333 m_chhash_key_t key;
00334 m_chhash_value_t value;
00335 m_stats_statset_t *statset;
00336 m_stats_statset_t statset_all;
00337 int i;
00338
00339 fprintf(fout, "Thread %u\n", threadstat->tid);
00340 m_stats_statset_print(fout, &threadstat->summary_statset, 0, false);
00341 fprintf(fout, "\n");
00342 fprintf(fout, " Transactions for thread %u\n\n", threadstat->tid);
00343
00344 m_chhash_iter_init(threadstat->stats_table, &iter);
00345 while(M_R_SUCCESS == m_chhash_iter_next(&iter, &key, &value)) {
00346 statset = (m_stats_statset_t *) value;
00347 m_stats_statset_print(fout, statset, 4, true);
00348 fprintf(fout, "\n");
00349 }
00350 }
00351
00352
00353 static
00354 void
00355 stats_summarize_all(m_statsmgr_t *statsmgr, m_stats_threadstat_t *summary)
00356 {
00357 m_stats_threadstat_t *threadstat;
00358 m_chhash_iter_t iter;
00359 m_stats_statset_t *statset;
00360 m_stats_statset_t *statset_summary;
00361 m_chhash_key_t key;
00362 m_chhash_value_t value;
00363 int i;
00364 m_result_t result;
00365
00366
00367 for (threadstat=statsmgr->alloc_threadstat_list_head;
00368 threadstat;
00369 threadstat = threadstat->next)
00370 {
00371 m_chhash_iter_init(threadstat->stats_table, &iter);
00372 while(M_R_SUCCESS == m_chhash_iter_next(&iter, &key, &value)) {
00373 statset = (m_stats_statset_t *) value;
00374 result = stats_get_statset(summary->stats_table,
00375 statset->name, &statset_summary);
00376 if (result != M_R_SUCCESS) {
00377 m_stats_statset_create(&statset_summary);
00378 m_stats_statset_init(statset_summary, statset->name);
00379 m_chhash_add(summary->stats_table,
00380 (m_chhash_key_t) statset->name,
00381 (m_chhash_value_t) (statset_summary));
00382 }
00383 statset_summary->count += statset->count;
00384 summary->summary_statset.count += statset->count;
00385 for (i=0; i<m_stats_numofstats; i++) {
00386 statset_summary->stats[i].total += statset->stats[i].total;
00387 statset_summary->stats[i].min = MIN(statset_summary->stats[i].min,
00388 statset->stats[i].min);
00389 statset_summary->stats[i].max = MAX(statset_summary->stats[i].max,
00390 statset->stats[i].max);
00391
00392 summary->summary_statset.stats[i].total += statset->stats[i].total;
00393 summary->summary_statset.stats[i].min = MIN(summary->summary_statset.stats[i].min,
00394 statset->stats[i].min);
00395 summary->summary_statset.stats[i].max = MAX(summary->summary_statset.stats[i].max,
00396 statset->stats[i].max);
00397 }
00398 }
00399 }
00400 }
00401
00402
00414 void
00415 m_stats_print(m_statsmgr_t *statsmgr)
00416 {
00417 m_chhash_iter_t iter;
00418 m_stats_threadstat_t *threadstat;
00419 m_stats_threadstat_t summary;
00420 m_chhash_key_t key;
00421 m_chhash_value_t value;
00422 m_stats_statset_t *statset;
00423 m_stats_statset_t statset_grand_total;
00424 int i;
00425 FILE *fout;
00426
00427 if (statsmgr->output_file) {
00428 printf("OUTPUT STATS >> %s\n", statsmgr->output_file);
00429 fout = fopen(statsmgr->output_file, "w");
00430 } else {
00431 fout = stderr;
00432 }
00433
00434
00435 fprintf(fout, "STATS REPORT\n");
00436 fprintf(fout, "THREAD TOTALS\n\n");
00437
00438 for (threadstat=statsmgr->alloc_threadstat_list_head;
00439 threadstat;
00440 threadstat = threadstat->next)
00441 {
00442 stats_threadstat_print(fout, threadstat);
00443 fprintf(fout, "\n");
00444 }
00445
00446
00447 fprintf(fout, "TRANSACTION TOTALS\n\n");
00448 m_chhash_create(&(summary.stats_table),
00449 M_STATS_THREADSTAT_HASHTABLE_SIZE,
00450 false);
00451 m_stats_statset_init(&summary.summary_statset, NULL);
00452 stats_summarize_all(statsmgr, &summary);
00453 m_chhash_iter_init(summary.stats_table, &iter);
00454 while(M_R_SUCCESS == m_chhash_iter_next(&iter, &key, &value)) {
00455 statset = (m_stats_statset_t *) value;
00456 m_stats_statset_print(fout, statset, 0, true);
00457 fprintf(fout, "\n");
00458 }
00459
00460
00461 fprintf(fout, "GRAND TOTAL (all transactions, all threads)\n\n");
00462 statset_grand_total.count = summary.summary_statset.count;
00463 for (i=0; i<m_stats_numofstats; i++) {
00464 statset_grand_total.stats[i] = summary.summary_statset.stats[i];
00465 }
00466 m_stats_statset_print(fout, &statset_grand_total, 0, false);
00467 if (statsmgr->output_file) {
00468 fclose(fout);
00469 }
00470 }