00001
00008 #include <string.h>
00009 #include <core/tx.h>
00010 #include <core/txdesc.h>
00011 #include <core/stats.h>
00012 #include <core/config.h>
00013 #include <misc/hash_table.h>
00014 #include <misc/generic_types.h>
00015 #include <misc/malloc.h>
00016 #include <misc/mutex.h>
00017 #include <misc/debug.h>
00018
00019 txc_statsmgr_t *txc_g_statsmgr;
00020
00021 #define MIN(A, B) (((A) < (B)) ? (A) : (B))
00022 #define MAX(A, B) (((A) > (B)) ? (A) : (B))
00023
00024 #define ACTION(name) #name,
00025 char *stats_strings[] = {
00026 FOREACH_STAT(ACTION)
00027 };
00028 #undef ACTION
00029
00030 static const char __whitespaces[] = " ";
00031
00032 #define WHITESPACE(len) &__whitespaces[sizeof(__whitespaces) - (len) -1]
00033
00035 struct txc_stats_threadstat_s {
00036 txc_stats_statcounter_t count;
00037 txc_stats_stat_t total_stats[txc_stats_numofstats];
00038 txc_hash_table_t *tx_stats;
00039 struct txc_stats_threadstat_s *next;
00040 struct txc_stats_threadstat_s *prev;
00041 txc_tx_t *txd;
00042 };
00043
00044
00046 struct txc_statsmgr_s {
00047 txc_mutex_t mutex;
00048 unsigned int alloc_threadstat_num;
00049 txc_stats_threadstat_t *alloc_threadstat_list_head;
00050 txc_stats_threadstat_t *alloc_threadstat_list_tail;
00051 };
00052
00053
00054 txc_result_t
00055 txc_statsmgr_create(txc_statsmgr_t **statsmgrp)
00056 {
00057 *statsmgrp = (txc_statsmgr_t *) MALLOC(sizeof(txc_statsmgr_t));
00058 if (*statsmgrp == NULL) {
00059 return TXC_R_NOMEMORY;
00060 }
00061
00062 (*statsmgrp)->alloc_threadstat_num = 0;
00063 (*statsmgrp)->alloc_threadstat_list_head = (*statsmgrp)->alloc_threadstat_list_tail = NULL;
00064 TXC_MUTEX_INIT(&(*statsmgrp)->mutex, NULL);
00065
00066 return TXC_R_SUCCESS;
00067 }
00068
00069
00070 txc_result_t
00071 txc_statsmgr_destroy(txc_statsmgr_t **statsmgrp)
00072 {
00073 txc_stats_threadstat_t *threadstat;
00074 txc_stats_threadstat_t *threadstat_next;
00075 txc_statsmgr_t *statsmgr = *statsmgrp;
00076
00077
00078 for (threadstat=statsmgr->alloc_threadstat_list_head;
00079 threadstat != NULL;
00080 threadstat = threadstat_next)
00081 {
00082 threadstat_next = threadstat->next;
00083 FREE(threadstat);
00084 }
00085
00086 FREE(statsmgr);
00087 *statsmgrp = NULL;
00088
00089 return TXC_R_SUCCESS;
00090 }
00091
00092
00093 txc_result_t
00094 txc_stats_threadstat_create(txc_statsmgr_t *statsmgr,
00095 txc_stats_threadstat_t **threadstatp,
00096 txc_tx_t *txd)
00097 {
00098 txc_stats_threadstat_t *threadstat;
00099 int i;
00100
00101 threadstat = (txc_stats_threadstat_t *) MALLOC(sizeof(txc_stats_threadstat_t));
00102
00103 TXC_MUTEX_LOCK(&(statsmgr->mutex));
00104 if (statsmgr->alloc_threadstat_list_head == NULL) {
00105 TXC_ASSERT(statsmgr->alloc_threadstat_list_tail == NULL);
00106 statsmgr->alloc_threadstat_list_head = threadstat;
00107 statsmgr->alloc_threadstat_list_tail = threadstat;
00108 threadstat->next = NULL;
00109 threadstat->prev = NULL;
00110 } else {
00111 statsmgr->alloc_threadstat_list_tail->next = threadstat;
00112 threadstat->prev = statsmgr->alloc_threadstat_list_tail;
00113 statsmgr->alloc_threadstat_list_tail = threadstat;
00114 }
00115 statsmgr->alloc_threadstat_num++;
00116 TXC_MUTEX_UNLOCK(&(statsmgr->mutex));
00117
00118 threadstat->count = 0;
00119 threadstat->txd = txd;
00120 txc_hash_table_create(&threadstat->tx_stats,
00121 TXC_STATS_THREADSTAT_HASHTABLE_SIZE,
00122 TXC_BOOL_FALSE);
00123 for (i=0; i<txc_stats_numofstats; i++) {
00124 threadstat->total_stats[i].total = 0;
00125 threadstat->total_stats[i].min = 0xFFFFFFFF;
00126 threadstat->total_stats[i].max = 0;
00127 }
00128
00129 *threadstatp = threadstat;
00130 return TXC_R_SUCCESS;
00131 }
00132
00133
00134 txc_result_t
00135 txc_stats_txstat_create(txc_stats_txstat_t **txstatp)
00136 {
00137 txc_stats_txstat_t *txstat;
00138
00139 txstat = (txc_stats_txstat_t *) MALLOC(sizeof(txc_stats_txstat_t));
00140 txstat->count = 0;
00141 *txstatp = txstat;
00142
00143 return TXC_R_SUCCESS;
00144 }
00145
00146
00147 txc_result_t
00148 txc_stats_txstat_destroy(txc_stats_txstat_t **txstatp)
00149 {
00150 FREE(*txstatp);
00151 *txstatp = NULL;
00152
00153 return TXC_R_SUCCESS;
00154 }
00155
00156
00157 static
00158 void
00159 stats_txstat_reset(txc_stats_txstat_t *txstat)
00160 {
00161 #define RESETSTAT(name) \
00162 txstat->total_stats[txc_stats_##name##_stat].total = 0; \
00163 txstat->total_stats[txc_stats_##name##_stat].min = 0xFFFFFFFF; \
00164 txstat->total_stats[txc_stats_##name##_stat].max = 0;
00165
00166 FOREACH_STAT (RESETSTAT)
00167
00168 #undef RESETSTAT
00169 }
00170
00171
00172 txc_result_t
00173 txc_stats_txstat_init(txc_stats_txstat_t *txstat,
00174 const char *srcloc_str,
00175 txc_tx_srcloc_t *srcloc)
00176 {
00177 if (txc_runtime_settings.statistics == TXC_BOOL_TRUE) {
00178 txstat->count = 1;
00179 txstat->srcloc_str = srcloc_str;
00180 txstat->srcloc.line = srcloc->line;
00181 txstat->srcloc.fun = srcloc->fun;
00182 txstat->srcloc.file = srcloc->file;
00183 stats_txstat_reset(txstat);
00184 }
00185 return TXC_R_SUCCESS;
00186 }
00187
00188
00189 static
00190 void
00191 stats_get_txstat_container(txc_hash_table_t *tx_stats,
00192 txc_stats_txstat_t *txstat,
00193 txc_stats_txstat_t **txstat_containerp)
00194 {
00195 txc_hash_table_key_t key;
00196 txc_hash_table_value_t value;
00197 txc_stats_txstat_t *txstat_container;
00198
00199
00200
00201
00202
00203 key = (txc_hash_table_key_t) txstat->srcloc_str;
00204 if (txc_hash_table_lookup(tx_stats, key, &value)
00205 == TXC_R_SUCCESS)
00206 {
00207 txstat_container = (txc_stats_txstat_t *) value;
00208 } else {
00209 txstat_container = (txc_stats_txstat_t *) MALLOC(sizeof(txc_stats_txstat_t));
00210 stats_txstat_reset(txstat_container);
00211 txstat_container->count = 0;
00212 txstat_container->srcloc_str = txstat->srcloc_str;
00213 txstat_container->srcloc.line = txstat->srcloc.line;
00214 txstat_container->srcloc.fun = txstat->srcloc.fun;
00215 txstat_container->srcloc.file = txstat->srcloc.file;
00216 txc_hash_table_add(tx_stats,
00217 key,
00218 (txc_hash_table_value_t) (txstat_container));
00219 }
00220
00221 *txstat_containerp = txstat_container;
00222 }
00223
00224
00225 static
00226 void
00227 statsmgr_commit_action(void *args, int *result)
00228 {
00229 txc_tx_t *txd = (txc_tx_t *) args;
00230 txc_stats_txstat_t *txstat = txd->txstat;
00231 txc_stats_txstat_t *txstat_all;
00232 txc_stats_threadstat_t *threadstat = txd->threadstat;
00233 int i;
00234
00235
00236
00237
00238
00239
00240 stats_get_txstat_container(threadstat->tx_stats, txstat, &txstat_all);
00241
00242
00243
00244
00245
00246 txstat_all->count++;
00247 for (i=0; i<txc_stats_numofstats; i++) {
00248 txstat_all->total_stats[i].total += txstat->total_stats[i].total;
00249 txstat_all->total_stats[i].min = MIN(txstat_all->total_stats[i].min,
00250 txstat->total_stats[i].total);
00251 txstat_all->total_stats[i].max = MAX(txstat_all->total_stats[i].max,
00252 txstat->total_stats[i].total);
00253 }
00254
00255
00256
00257
00258
00259 threadstat->count++;
00260 for (i=0; i<txc_stats_numofstats; i++) {
00261 threadstat->total_stats[i].total += txstat->total_stats[i].total;
00262 threadstat->total_stats[i].min = MIN(threadstat->total_stats[i].min,
00263 txstat->total_stats[i].total);
00264 threadstat->total_stats[i].max = MAX(threadstat->total_stats[i].max,
00265 txstat->total_stats[i].total);
00266 }
00267 if (result) {
00268 *result = 0;
00269 }
00270 }
00271
00272
00273 static
00274 void
00275 statsmgr_undo_action(void *args, int *result)
00276 {
00277 txc_tx_t *txd = (txc_tx_t *) args;
00278
00279
00280
00281 stats_txstat_reset(txd->txstat);
00282
00283 if (result) {
00284 *result = 0;
00285 }
00286 }
00287
00288
00289 static inline
00290 void
00291 register_statsmgr_commit_action(txc_tx_t *txd)
00292 {
00293 if (txd->statsmgr_commit_action_registered == 0) {
00294 txc_tx_register_commit_action(txd,
00295 statsmgr_commit_action,
00296 (void *) txd,
00297 NULL,
00298 TXC_STATSMGR_COMMIT_ACTION_ORDER);
00299 txd->statsmgr_commit_action_registered = 1;
00300 }
00301 }
00302
00303
00304 static inline
00305 void
00306 register_statsmgr_undo_action(txc_tx_t *txd)
00307 {
00308 if (txd->statsmgr_undo_action_registered == 0) {
00309 txc_tx_register_undo_action(txd,
00310 statsmgr_undo_action,
00311 (void *) txd,
00312 NULL,
00313 TXC_STATSMGR_UNDO_ACTION_ORDER);
00314 txd->statsmgr_undo_action_registered = 1;
00315 }
00316 }
00317
00318
00319 void
00320 txc_stats_register_statsmgr_commit_action(txc_tx_t *txd)
00321 {
00322 register_statsmgr_commit_action(txd);
00323 }
00324
00325
00326 void
00327 txc_stats_register_statsmgr_undo_action(txc_tx_t *txd)
00328 {
00329 register_statsmgr_undo_action(txd);
00330 }
00331
00332
00333 void
00334 txc_stats_transaction_postbegin(txc_tx_t *txd)
00335 {
00336 if (txc_runtime_settings.statistics == TXC_BOOL_TRUE)
00337 {
00338 register_statsmgr_commit_action(txd);
00339 register_statsmgr_undo_action(txd);
00340 }
00341 }
00342
00343
00344 static
00345 void
00346 stats_txstat_print(FILE *fout,
00347 txc_stats_txstat_t *txstat,
00348 int shiftlen,
00349 txc_bool_t print_srcloc)
00350 {
00351 int i;
00352 char header[512];
00353 double mean;
00354 txc_stats_statcounter_t max;
00355 txc_stats_statcounter_t min;
00356 txc_stats_statcounter_t total;
00357 txc_stats_statcounter_t count;
00358
00359 if (print_srcloc) {
00360 sprintf(header, "Source is line %d in function %s in %s",
00361 txstat->srcloc.line,
00362 txstat->srcloc.fun,
00363 txstat->srcloc.file);
00364 fprintf(fout, "%s%s\n\n", WHITESPACE(shiftlen), header);
00365 }
00366
00367 fprintf(fout, "%s%s%s:%13s%13s%13s%13s\n",
00368 WHITESPACE(shiftlen+2),
00369 "",
00370 WHITESPACE(25),
00371 "Min",
00372 "Mean",
00373 "Max",
00374 "Total");
00375
00376 count = txstat->count;
00377
00378 fprintf(fout, "%s%s%s:%13s%13s%13s%13u\n",
00379 WHITESPACE(shiftlen+2),
00380 "Transactions",
00381 WHITESPACE(25 - strlen("Transactions")),
00382 "",
00383 "",
00384 "",
00385 count);
00386
00387 for (i=0; i<txc_stats_numofstats; i++) {
00388 total = txstat->total_stats[i].total;
00389 min = txstat->total_stats[i].min;
00390 max = txstat->total_stats[i].max;
00391 mean = (double) total / (double) count;
00392 fprintf(fout, "%s%s%s:%13u%13.2f%13u%13u\n",
00393 WHITESPACE(shiftlen+2),
00394 stats_strings[i],
00395 WHITESPACE(25 - strlen(stats_strings[i])),
00396 min,
00397 mean,
00398 max,
00399 total);
00400 }
00401 }
00402
00403
00404 static
00405 void
00406 stats_threadstat_print(FILE *fout,
00407 txc_stats_threadstat_t *threadstat)
00408 {
00409 txc_hash_table_iter_t iter;
00410 txc_hash_table_key_t key;
00411 txc_hash_table_value_t value;
00412 txc_stats_txstat_t *txstat;
00413 txc_stats_txstat_t txstat_all;
00414 int i;
00415
00416 txstat_all.count = threadstat->count;
00417 for (i=0; i<txc_stats_numofstats; i++) {
00418 txstat_all.total_stats[i] = threadstat->total_stats[i];
00419 }
00420 fprintf(fout, "Thread %u\n", threadstat->txd->tid);
00421 stats_txstat_print(fout, &txstat_all, 0, TXC_BOOL_FALSE);
00422 fprintf(fout, "\n");
00423 fprintf(fout, " Transactions for thread %u\n\n", threadstat->txd->tid);
00424
00425 txc_hash_table_iter_init(threadstat->tx_stats, &iter);
00426 while(TXC_R_SUCCESS == txc_hash_table_iter_next(&iter, &key, &value)) {
00427 txstat = (txc_stats_txstat_t *) value;
00428 stats_txstat_print(fout, txstat, 4, TXC_BOOL_TRUE);
00429 fprintf(fout, "\n");
00430 }
00431 }
00432
00433
00434 static
00435 void
00436 stats_summarize_all(txc_statsmgr_t *statsmgr, txc_stats_threadstat_t *summary)
00437 {
00438 txc_stats_threadstat_t *threadstat;
00439 txc_hash_table_iter_t iter;
00440 txc_stats_txstat_t *txstat;
00441 txc_stats_txstat_t *txstat_summary;
00442 txc_hash_table_key_t key;
00443 txc_hash_table_value_t value;
00444 int i;
00445
00446 for (threadstat=statsmgr->alloc_threadstat_list_head;
00447 threadstat;
00448 threadstat = threadstat->next)
00449 {
00450 txc_hash_table_iter_init(threadstat->tx_stats, &iter);
00451 while(TXC_R_SUCCESS == txc_hash_table_iter_next(&iter, &key, &value)) {
00452 txstat = (txc_stats_txstat_t *) value;
00453 stats_get_txstat_container(summary->tx_stats, txstat, &txstat_summary);
00454 txstat_summary->count += txstat->count;
00455 summary->count += txstat->count;
00456 for (i=0; i<txc_stats_numofstats; i++) {
00457 txstat_summary->total_stats[i].total += txstat->total_stats[i].total;
00458 txstat_summary->total_stats[i].min = MIN(txstat_summary->total_stats[i].min,
00459 txstat->total_stats[i].min);
00460 txstat_summary->total_stats[i].max = MAX(txstat_summary->total_stats[i].max,
00461 txstat->total_stats[i].max);
00462
00463 summary->total_stats[i].total += txstat->total_stats[i].total;
00464 summary->total_stats[i].min = MIN(summary->total_stats[i].min,
00465 txstat->total_stats[i].min);
00466 summary->total_stats[i].max = MAX(summary->total_stats[i].max,
00467 txstat->total_stats[i].max);
00468 }
00469 }
00470 }
00471 }
00472
00473
00485 void
00486 txc_stats_print(txc_statsmgr_t *statsmgr)
00487 {
00488 txc_hash_table_iter_t iter;
00489 txc_stats_threadstat_t *threadstat;
00490 txc_stats_threadstat_t summary;
00491 txc_hash_table_key_t key;
00492 txc_hash_table_value_t value;
00493 txc_stats_txstat_t *txstat;
00494 txc_stats_txstat_t txstat_grand_total;
00495 int i;
00496 FILE *fout;
00497
00498 if (txc_runtime_settings.statistics == TXC_BOOL_FALSE) {
00499 return;
00500 }
00501
00502 fout = fopen(txc_runtime_settings.statistics_file, "w");
00503
00504
00505 fprintf(fout, "STATS REPORT\n");
00506 fprintf(fout, "THREAD TOTALS\n\n");
00507
00508 for (threadstat=statsmgr->alloc_threadstat_list_head;
00509 threadstat;
00510 threadstat = threadstat->next)
00511 {
00512 stats_threadstat_print(fout, threadstat);
00513 fprintf(fout, "\n");
00514 }
00515
00516
00517
00518 fprintf(fout, "TRANSACTION TOTALS\n\n");
00519 txc_hash_table_create(&(summary.tx_stats),
00520 TXC_STATS_THREADSTAT_HASHTABLE_SIZE,
00521 TXC_BOOL_FALSE);
00522 for (i=0; i<txc_stats_numofstats; i++) {
00523 summary.total_stats[i].min = 0;
00524 summary.total_stats[i].max = 0;
00525 summary.total_stats[i].total = 0;
00526 summary.count = 0;
00527 }
00528 stats_summarize_all(statsmgr, &summary);
00529 txc_hash_table_iter_init(summary.tx_stats, &iter);
00530 while(TXC_R_SUCCESS == txc_hash_table_iter_next(&iter, &key, &value)) {
00531 txstat = (txc_stats_txstat_t *) value;
00532 stats_txstat_print(fout, txstat, 0, TXC_BOOL_TRUE);
00533 fprintf(fout, "\n");
00534 }
00535
00536
00537 fprintf(fout, "GRAND TOTAL (all transactions, all threads)\n\n");
00538 txstat_grand_total.count = summary.count;
00539 for (i=0; i<txc_stats_numofstats; i++) {
00540 txstat_grand_total.total_stats[i] = summary.total_stats[i];
00541 }
00542 stats_txstat_print(fout, &txstat_grand_total, 0, TXC_BOOL_FALSE);
00543
00544 fclose(fout);
00545 }