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