usermode/library/common/stats_generic.c

00001 /*
00002     Copyright (C) 2011 Computer Sciences Department, 
00003     University of Wisconsin -- Madison
00004 
00005     ----------------------------------------------------------------------
00006 
00007     This file is part of Mnemosyne: Lightweight Persistent Memory, 
00008     originally developed at the University of Wisconsin -- Madison.
00009 
00010     Mnemosyne was originally developed primarily by Haris Volos
00011     with contributions from Andres Jaan Tack.
00012 
00013     ----------------------------------------------------------------------
00014 
00015     Mnemosyne is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License
00017     as published by the Free Software Foundation, version 2
00018     of the License.
00019  
00020     Mnemosyne is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00028     Boston, MA  02110-1301, USA.
00029 
00030 ### END HEADER ###
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  * Collect the statistics of source_statset into dest_statset.
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         /* Print per THREAD per TRANSACTION totals */
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         /* Print per TRANSACTION totals */
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         /* Print GRAND totals */
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 }       

Generated on Sat Apr 23 11:43:35 2011 for Mnemosyne by  doxygen 1.4.7