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 #include "Main.h"
00030 #include "StatSystem.h"
00031 #include "P_EventSystem.h"
00032 #include "Error.h"
00033 #include "ProcessManager.h"
00034 #include "ProxyConfig.h"
00035 #include "StatPages.h"
00036 #include "HTTP.h"
00037 #include "I_Layout.h"
00038 
00039 
00040 
00041 #define SNAP_USAGE_PERIOD         HRTIME_SECONDS(2)
00042 
00043 
00044 
00045 
00046 #ifdef DEBUG
00047 ink_mutex http_time_lock;
00048 time_t last_http_local_time;
00049 #endif
00050 ink_stat_lock_t global_http_trans_stat_lock;
00051 ink_unprot_global_stat_t global_http_trans_stats[MAX_HTTP_TRANS_STATS];
00052 #ifndef USE_LOCKS_FOR_DYN_STATS
00053 inkcoreapi ink_unprot_global_stat_t global_dyn_stats[MAX_DYN_STATS - DYN_STAT_START];
00054 #else
00055 inkcoreapi ink_prot_global_stat_t global_dyn_stats[MAX_DYN_STATS - DYN_STAT_START];
00056 #endif
00057 
00058 Ptr<ProxyMutex> rusage_snap_mutex;
00059 struct rusage rusage_snap;
00060 struct rusage rusage_snap_old;
00061 ink_hrtime rusage_snap_time;
00062 ink_hrtime rusage_snap_time_old;
00063 int snap_stats_every = 60;
00064 
00065 ink_hrtime http_handler_times[MAX_HTTP_HANDLER_EVENTS];
00066 int http_handler_counts[MAX_HTTP_HANDLER_EVENTS];
00067 
00068 
00069 char snap_filename[PATH_NAME_MAX+1] = DEFAULT_SNAP_FILENAME;
00070 
00071 #define DEFAULT_PERSISTENT
00072 
00073 #ifndef DEFAULT_PERSISTENT
00074 static int persistent_stats[] = {
00075   http_incoming_requests_stat
00076 };
00077 #else
00078 static int non_persistent_stats[] = {
00079 
00080   
00081 
00082   cluster_connections_open_stat,
00083   cluster_connections_openned_stat,
00084   cluster_con_total_time_stat,
00085   cluster_ctrl_msgs_sent_stat,
00086   cluster_slow_ctrl_msgs_sent_stat,
00087   cluster_ctrl_msgs_recvd_stat,
00088   cluster_slow_ctrl_msgs_recvd_stat,
00089   cluster_ctrl_msgs_send_time_stat,
00090   cluster_ctrl_msgs_recv_time_stat,
00091   cluster_read_bytes_stat,
00092   cluster_write_bytes_stat,
00093   cluster_op_delayed_for_lock_stat,
00094   cluster_connections_locked_stat,
00095   cluster_connections_bumped_stat,
00096   cluster_nodes_stat,
00097   cluster_net_backup_stat,
00098   cluster_machines_allocated_stat,
00099   cluster_machines_freed_stat,
00100   cluster_configuration_changes_stat,
00101   cluster_delayed_reads_stat,
00102   cluster_byte_bank_used_stat,
00103   cluster_alloc_data_news_stat,
00104   cluster_write_bb_mallocs_stat,
00105   cluster_partial_reads_stat,
00106   cluster_partial_writes_stat,
00107   cluster_cache_outstanding_stat,
00108   cluster_remote_op_timeouts_stat,
00109   cluster_remote_op_reply_timeouts_stat,
00110   cluster_chan_inuse_stat,
00111   cluster_open_delays_stat,
00112   cluster_open_delay_time_stat,
00113   cluster_cache_callbacks_stat,
00114   cluster_cache_callback_time_stat,
00115   cluster_cache_rmt_callbacks_stat,
00116   cluster_cache_rmt_callback_time_stat,
00117   cluster_cache_lkrmt_callbacks_stat,
00118   cluster_cache_lkrmt_callback_time_stat,
00119   cluster_thread_steal_expires_stat,
00120   cluster_local_connections_closed_stat,
00121   cluster_local_connection_time_stat,
00122   cluster_remote_connections_closed_stat,
00123   cluster_remote_connection_time_stat,
00124   cluster_rdmsg_assemble_time_stat,
00125   cluster_ping_time_stat,
00126   cluster_setdata_no_clustervc_stat,
00127   cluster_setdata_no_tunnel_stat,
00128   cluster_setdata_no_cachevc_stat,
00129   cluster_setdata_no_cluster_stat,
00130   cluster_vc_write_stall_stat,
00131   cluster_no_remote_space_stat,
00132   cluster_level1_bank_stat,
00133   cluster_multilevel_bank_stat,
00134   cluster_vc_cache_insert_lock_misses_stat,
00135   cluster_vc_cache_inserts_stat,
00136   cluster_vc_cache_lookup_lock_misses_stat,
00137   cluster_vc_cache_lookup_hits_stat,
00138   cluster_vc_cache_lookup_misses_stat,
00139   cluster_vc_cache_scans_stat,
00140   cluster_vc_cache_scan_lock_misses_stat,
00141   cluster_vc_cache_purges_stat,
00142   cluster_write_lock_misses_stat,
00143 
00144   
00145 
00146   
00147   
00148 };
00149 #endif
00150 
00151 #define _HEADER \
00152 DynamicStatsString_t DynamicStatsStrings[] = {
00153 
00154 #define _FOOTER };
00155 #define _D(_x) { _x, #_x },
00156 
00157 #include "DynamicStats.h"
00158 #undef _HEADER
00159 #undef _FOOTER
00160 #undef _D
00161 
00162 
00163 
00164 
00165 
00166 static int
00167 persistent_stat(int i)
00168 {
00169 #ifndef DEFAULT_PERSISTENT
00170   for (unsigned j = 0; j < countof(persistent_stats); j++)
00171     if (persistent_stats[j] == i)
00172       return 1;
00173   return 0;
00174 #else
00175   for (unsigned j = 0; j < countof(non_persistent_stats); j++)
00176     if (non_persistent_stats[j] == i)
00177       return 0;
00178   return 1;
00179 #endif
00180 }
00181 
00182 static int
00183 open_stats_snap()
00184 {
00185   int fd = socketManager.open(snap_filename,
00186                               O_CREAT | O_RDWR | _O_ATTRIB_NORMAL);
00187   if (fd < 0) {
00188     Warning("unable to open %s: %s", snap_filename, strerror(-fd));
00189     return -1;
00190   }
00191   return fd;
00192 }
00193 
00194 static void
00195 clear_stats()
00196 {
00197   int i = 0;
00198 
00199   int stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS - 1;
00200   for (i = 0; i < stats_size; i++) {
00201     if (persistent_stat(i + NO_HTTP_TRANS_STATS)) {
00202       global_http_trans_stats[i].sum = 0;
00203       global_http_trans_stats[i].count = 0;
00204     }
00205   }
00206   stats_size = MAX_DYN_STATS - NO_DYN_STATS - 1;
00207   for (i = 0; i < stats_size; i++) {
00208     if (persistent_stat(i + NO_DYN_STATS)) {
00209       global_dyn_stats[i].sum = 0;
00210       global_dyn_stats[i].count = 0;
00211     }
00212   }
00213 
00214   socketManager.unlink(snap_filename);
00215   Debug("stats", "clear_stats: clearing statistics");
00216 }
00217 
00218 static void
00219 read_stats_snap()
00220 {
00221   unsigned int version;
00222   unsigned int version_read;
00223   int count;
00224   int fd = -1;
00225   int i = 0;
00226   int stats_size = -1;
00227 
00228   version = STATS_MAJOR_VERSION;
00229 
00230   if ((fd = open_stats_snap()) < 0)
00231     goto Lmissmatch;
00232 
00233   
00234   if (socketManager.read(fd, (char *) &version_read, sizeof(version_read))
00235       != sizeof(version_read))
00236     goto Lmissmatch;
00237   if (version != version_read)
00238     goto Lmissmatch;
00239   stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS + MAX_DYN_STATS - NO_DYN_STATS;
00240   if (socketManager.read(fd, (char *) &count, sizeof(count)) != sizeof(count))
00241     goto Lmissmatch;
00242   if (count != stats_size)
00243     goto Lmissmatch;
00244 
00245   stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS;
00246   for (i = 0; i < stats_size; i++) {
00247     if (socketManager.read(fd, (char *) &global_http_trans_stats[i].sum, sizeof(global_http_trans_stats[i].sum))
00248         != sizeof(global_http_trans_stats[i].sum))
00249       goto Lmissmatch;
00250     if (socketManager.read(fd, (char *) &global_http_trans_stats[i].count, sizeof(global_http_trans_stats[i].count))
00251         != sizeof(global_http_trans_stats[i].count))
00252       goto Lmissmatch;
00253   }
00254   stats_size = MAX_DYN_STATS - NO_DYN_STATS;
00255   for (i = 0; i < stats_size; i++) {
00256     if (socketManager.read(fd, (char *) &global_dyn_stats[i].sum, sizeof(global_dyn_stats[i].sum))
00257         != sizeof(global_dyn_stats[i].sum))
00258       goto Lmissmatch;
00259     if (socketManager.read(fd, (char *) &global_dyn_stats[i].count, sizeof(global_dyn_stats[i].count))
00260         != sizeof(global_dyn_stats[i].count))
00261       goto Lmissmatch;
00262   }
00263   Debug("stats", "read_stats_snap: read statistics");
00264 
00265   
00266   socketManager.close(fd);
00267   return;
00268 
00269 Lmissmatch:
00270   Note("clearing statistics");
00271   clear_stats();
00272   
00273   socketManager.close(fd);
00274 }
00275 
00276 static void
00277 write_stats_snap()
00278 {
00279   int fd = 0;
00280   int version = STATS_MAJOR_VERSION;
00281   char *buf = NULL;
00282 
00283   if ((fd = open_stats_snap()) < 0) {
00284     Warning("unable to snap statistics");
00285     return;
00286   }
00287 
00288   {
00289     int stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS + MAX_DYN_STATS - NO_DYN_STATS;
00290     int buf_size = sizeof(unsigned int) * 3 + stats_size * (sizeof(global_dyn_stats[0].sum) + sizeof(global_dyn_stats[0].count));
00291     buf = (char *)ats_malloc(buf_size);
00292     char *p = buf;
00293     int i = 0;
00294 
00295     memcpy(p, (char *) &version, sizeof(version));
00296     p += sizeof(version);
00297     memcpy(p, (char *) &stats_size, sizeof(stats_size));
00298     p += sizeof(stats_size);
00299 
00300     stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS;
00301     STAT_LOCK_ACQUIRE(&(global_http_trans_stat_lock));
00302     for (i = 0; i < stats_size; i++) {
00303       memcpy(p, (char *) &global_http_trans_stats[i].sum, sizeof(global_http_trans_stats[i].sum));
00304       p += sizeof(global_http_trans_stats[i].sum);
00305       memcpy(p, (char *) &global_http_trans_stats[i].count, sizeof(global_http_trans_stats[i].count));
00306       p += sizeof(global_http_trans_stats[i].count);
00307     }
00308     STAT_LOCK_RELEASE(&(global_http_trans_stat_lock));
00309     stats_size = MAX_DYN_STATS - NO_DYN_STATS;
00310     for (i = 0; i < stats_size; i++) {
00311       
00312       ink_statval_t count, sum;
00313       READ_GLOBAL_DYN_STAT(i, count, sum);
00314       memcpy(p, (char *) &sum, sizeof(sum));
00315       p += sizeof(sum);
00316       memcpy(p, (char *) &count, sizeof(count));
00317       p += sizeof(count);
00318     }
00319     memcpy(p, (char *) &version, sizeof(version));
00320 
00321     if (socketManager.write(fd, buf, buf_size) != buf_size) {
00322       Warning("unable to snap statistics");
00323       ats_free(buf);
00324       socketManager.close(fd);
00325       return;
00326     }
00327   }
00328   ats_free(buf);
00329   socketManager.close(fd);
00330   Debug("stats", "snapped stats");
00331 }
00332 
00333 struct SnapStatsContinuation: public Continuation
00334 {
00335   int mainEvent(int , Event *e ATS_UNUSED)
00336   {
00337     write_stats_snap();
00338     e->schedule_every(HRTIME_SECONDS(snap_stats_every));
00339     return EVENT_CONT;
00340   }
00341   SnapStatsContinuation():Continuation(new_ProxyMutex())
00342   {
00343     SET_HANDLER(&SnapStatsContinuation::mainEvent);
00344   }
00345 };
00346 
00347 static void
00348 take_rusage_snap()
00349 {
00350   rusage_snap_old = rusage_snap;
00351   rusage_snap_time_old = rusage_snap_time;
00352   int retries = 3;
00353   while (retries--) {
00354     if (getrusage(RUSAGE_SELF, &rusage_snap) < 0) {
00355       if (errno == EINTR)
00356         continue;
00357       Note("getrusage [%d %s]", errno, strerror(errno));
00358     } else
00359       rusage_snap_time = ink_get_hrtime();
00360     break;
00361   }
00362   Debug("rusage", "took rusage snap %" PRId64"", rusage_snap_time);
00363 }
00364 
00365 struct SnapCont;
00366 typedef int (SnapCont::*SnapContHandler) (int, void *);
00367 
00368 struct SnapCont: public Continuation
00369 {
00370   int mainEvent(int , Event * e)
00371   {
00372     take_rusage_snap();
00373     e->schedule_every(SNAP_USAGE_PERIOD);
00374     return EVENT_CONT;
00375   }
00376   SnapCont(ProxyMutex * m):Continuation(m)
00377   {
00378     SET_HANDLER((SnapContHandler) & SnapCont::mainEvent);
00379   }
00380 };
00381 
00382 void
00383 start_stats_snap()
00384 {
00385   eventProcessor.schedule_every(new SnapCont(rusage_snap_mutex), SNAP_USAGE_PERIOD, ET_CALL);
00386   if (snap_stats_every)
00387     eventProcessor.schedule_every(new SnapStatsContinuation(), HRTIME_SECONDS(snap_stats_every), ET_CALL);
00388   else
00389     Warning("disabling statistics snap");
00390 }
00391 
00392 static Action *
00393 stat_callback(Continuation * cont, HTTPHdr * header)
00394 {
00395   URL *url;
00396   int length;
00397   const char *path;
00398   char *result = NULL;
00399   int result_size;
00400   bool empty;
00401 
00402   url = header->url_get();
00403   path = url->path_get(&length);
00404 
00405   char *buffer = NULL;
00406   int buffer_len = 0;
00407   int num_prefix_buffer;
00408 
00409   char *var_prefix = (char *)alloca((length + 1) * sizeof(char));
00410 
00411   memset(var_prefix, 0, ((length + 1) * sizeof(char)));
00412   if (path && length > 0)
00413     ink_strlcpy(var_prefix, path, length + 1);
00414 
00415   num_prefix_buffer = RecGetRecordPrefix_Xmalloc(var_prefix, &buffer, &buffer_len);
00416   empty = (num_prefix_buffer == 0);
00417 
00418   if (!empty) {
00419     result_size = (buffer_len + 16) * sizeof(char);
00420     result = (char *)ats_malloc(result_size);
00421     memset(result, 0, result_size);
00422 
00423     snprintf(result, result_size - 7, "<pre>\n%s", buffer);
00424   }
00425 
00426 
00427   if (!empty) {
00428     StatPageData data;
00429 
00430     ink_strlcat(result, "</pre>\n", result_size);
00431 
00432     data.data = result;
00433     data.length = strlen(result);
00434     cont->handleEvent(STAT_PAGE_SUCCESS, &data);
00435   } else {
00436     ats_free(result);
00437     cont->handleEvent(STAT_PAGE_FAILURE, NULL);
00438   }
00439   ats_free(buffer);
00440 
00441   return ACTION_RESULT_DONE;
00442 }
00443 
00444 static Action *
00445 testpage_callback(Continuation * cont, HTTPHdr *)
00446 {
00447   const int buf_size = 64000;
00448   char *buffer = (char *)ats_malloc(buf_size);
00449 
00450   for (int i = 0; i < buf_size; i++) {
00451     buffer[i] = (char) ('a' + (i % 26));
00452   }
00453   buffer[buf_size - 1] = '\0';
00454 
00455   StatPageData data;
00456 
00457   data.data = buffer;
00458   data.length = strlen(buffer);
00459   cont->handleEvent(STAT_PAGE_SUCCESS, &data);
00460 
00461   return ACTION_RESULT_DONE;
00462 }
00463 
00464 static void
00465 testpage_callback_init()
00466 {
00467   statPagesManager.register_http("test", testpage_callback);
00468 }
00469 
00470 void
00471 initialize_all_global_stats()
00472 {
00473   int istat, i;
00474   char snap_file[PATH_NAME_MAX + 1];
00475   ats_scoped_str rundir(RecConfigReadRuntimeDir());
00476 
00477   if (access(rundir, R_OK | W_OK) == -1) {
00478     Warning("Unable to access() local state directory '%s': %d, %s", (const char *)rundir, errno, strerror(errno));
00479     Warning(" Please set 'proxy.config.local_state_dir' to allow statistics collection");
00480   }
00481   REC_ReadConfigString(snap_file, "proxy.config.stats.snap_file", PATH_NAME_MAX);
00482   Layout::relative_to(snap_filename, sizeof(snap_filename), (const char *)rundir, snap_file);
00483   Debug("stats", "stat snap filename %s", snap_filename);
00484 
00485   statPagesManager.register_http("stat", stat_callback);
00486 
00487   testpage_callback_init();
00488 
00489   read_stats_snap();
00490   rusage_snap_mutex = new_ProxyMutex();
00491   take_rusage_snap();
00492   take_rusage_snap();           
00493 
00494   STAT_LOCK_INIT(&(global_http_trans_stat_lock), "Global Http Stats Lock");
00495 
00496   for (istat = NO_HTTP_TRANS_STATS; istat < MAX_HTTP_TRANS_STATS; istat++) {
00497     if (!persistent_stat(istat)) {
00498       INITIALIZE_GLOBAL_TRANS_STATS(global_http_trans_stats[istat]);
00499     }
00500   }
00501 
00502   for (istat = NO_DYN_STATS; istat < MAX_DYN_STATS; istat++) {
00503     if (!persistent_stat(istat)) {
00504       i = istat - DYN_STAT_START;
00505       INITIALIZE_GLOBAL_DYN_STATS(global_dyn_stats[i], "Dyn Stat Lock");
00506     }
00507   }
00508 
00509   
00510   
00511   
00512   
00513   
00514 
00515 #ifdef DEBUG
00516   ink_mutex_init(&http_time_lock, "Http Time Function Lock");
00517   last_http_local_time = 0;
00518 #endif
00519 
00520   clear_http_handler_times();
00521 }
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 
00535 
00536 
00537 
00538 
00539 
00540 
00541 
00542 
00543 void *
00544 dyn_stats_int_msecs_to_float_seconds_cb(void *data, void *res)
00545 {
00546   ink_statval_t count, sum;
00547   READ_DYN_STAT((long) data, count, sum);
00548 
00549   float r;
00550   if (count == 0) {
00551     r = 0.0;
00552   } else {
00553     r = ((float) sum) / 1000.0;
00554   }
00555   *(float *) res = r;
00556   return res;
00557 }
00558 
00559 void *
00560 dyn_stats_count_cb(void *data, void *res)
00561 {
00562   ink_statval_t count, sum;
00563   READ_DYN_STAT((long) data, count, sum);
00564   (void)sum;
00565   ink_atomic_swap((ink_statval_t *) res, count);
00566   return res;
00567 }
00568 
00569 void *
00570 dyn_stats_sum_cb(void *data, void *res)
00571 {
00572   ink_statval_t count, sum;
00573   READ_DYN_STAT((long) data, count, sum);
00574   (void)count;
00575   ink_atomic_swap((ink_statval_t *) res, sum);
00576   return res;
00577 }
00578 
00579 void *
00580 dyn_stats_avg_cb(void *data, void *res)
00581 {
00582   ink_statval_t count, sum;
00583   READ_DYN_STAT((long) data, count, sum);
00584   if (count == 0) {
00585     *(float *) res = 0.0;
00586   } else {
00587     *(float *) res = (float) sum / (float) count;
00588   }
00589   return res;
00590 }
00591 
00592 void *
00593 dyn_stats_fsum_cb(void *data, void *res)
00594 {
00595   ink_statval_t count, sum;
00596   READ_DYN_STAT((long) data, count, sum);
00597   (void)count;
00598   *(float *) res = (double) sum;
00599   return res;
00600 }
00601 
00602 void *
00603 dyn_stats_favg_cb(void *data, void *res)
00604 {
00605   ink_statval_t count, sum;
00606   READ_DYN_STAT((long) data, count, sum);
00607   if (count == 0) {
00608     *(float *) res = 0.0;
00609   } else {
00610     *(float *) res = (double) sum / (double) count;
00611   }
00612   return res;
00613 }
00614 
00615 void *
00616 dyn_stats_time_seconds_cb(void *data, void *res)
00617 {
00618   ink_statval_t count, sum;
00619   float r;
00620   READ_DYN_STAT((long) data, count, sum);
00621   if (count == 0) {
00622     r = 0.0;
00623   } else {
00624     r = (float) sum / (float) count;
00625     r = r / (float) HRTIME_SECOND;
00626   }
00627   *(float *) res = r;
00628   return res;
00629 }
00630 
00631 void *
00632 dyn_stats_time_mseconds_cb(void *data, void *res)
00633 {
00634   ink_statval_t count, sum;
00635   float r;
00636   READ_DYN_STAT((long) data, count, sum);
00637   if (count == 0) {
00638     r = 0.0;
00639   } else {
00640     r = (float) sum / (float) count;
00641     r = r / (float) HRTIME_MSECOND;
00642   }
00643   *(float *) res = r;
00644   return res;
00645 }
00646 
00647 void *
00648 dyn_stats_time_useconds_cb(void *data, void *res)
00649 {
00650   ink_statval_t count, sum;
00651   float r;
00652   READ_DYN_STAT((long) data, count, sum);
00653   if (count == 0) {
00654     r = 0.0;
00655   } else {
00656     r = (float) sum / (float) count;
00657     r = r / (float) HRTIME_USECOND;
00658   }
00659   *(float *) res = r;
00660   return res;
00661 }
00662 
00663 
00664 
00665 
00666 void *
00667 http_trans_stats_int_msecs_to_float_seconds_cb(void *data, void *res)
00668 {
00669   ink_statval_t count, sum;
00670   READ_HTTP_TRANS_STAT((long) data, count, sum);
00671 
00672   float r;
00673   if (count == 0) {
00674     r = 0.0;
00675   } else {
00676     r = ((float) sum) / 1000.0;
00677   }
00678   *(float *) res = r;
00679   return res;
00680 }
00681 
00682 void *
00683 http_trans_stats_count_cb(void *data, void *res)
00684 {
00685   ink_statval_t count, sum;
00686   READ_HTTP_TRANS_STAT((long) data, count, sum);
00687   (void)sum;
00688   ink_atomic_swap((ink_statval_t *) res, count);
00689   return res;
00690 }
00691 
00692 void *
00693 http_trans_stats_sum_cb(void *data, void *res)
00694 {
00695   ink_statval_t count, sum;
00696   READ_HTTP_TRANS_STAT((long) data, count, sum);
00697   (void)count;
00698   ink_atomic_swap((ink_statval_t *) res, sum);
00699   return res;
00700 }
00701 
00702 void *
00703 http_trans_stats_avg_cb(void *data, void *res)
00704 {
00705   ink_statval_t count, sum;
00706   READ_HTTP_TRANS_STAT((long) data, count, sum);
00707   if (count == 0) {
00708     *(float *) res = 0.0;
00709   } else {
00710     *(float *) res = (float) sum / (float) count;
00711   }
00712   return res;
00713 }
00714 
00715 void *
00716 http_trans_stats_fsum_cb(void *data, void *res)
00717 {
00718   ink_statval_t count, sum;
00719   READ_HTTP_TRANS_STAT((long) data, count, sum);
00720   (void)count;
00721   *(float *) res = (double) sum;
00722   return res;
00723 }
00724 
00725 void *
00726 http_trans_stats_favg_cb(void *data, void *res)
00727 {
00728   ink_statval_t count, sum;
00729   READ_HTTP_TRANS_STAT((long) data, count, sum);
00730   if (count == 0) {
00731     *(float *) res = 0.0;
00732   } else {
00733     *(float *) res = (double) sum / (double) count;
00734   }
00735   return res;
00736 }
00737 
00738 void *
00739 http_trans_stats_time_seconds_cb(void *data, void *res)
00740 {
00741   ink_statval_t count, sum;
00742   float r;
00743   READ_HTTP_TRANS_STAT((long) data, count, sum);
00744   if (count == 0) {
00745     r = 0.0;
00746   } else {
00747     r = (float) sum / (float) count;
00748     r = r / (float) HRTIME_SECOND;
00749   }
00750   *(float *) res = r;
00751   return res;
00752 }
00753 
00754 void *
00755 http_trans_stats_time_mseconds_cb(void *data, void *res)
00756 {
00757   ink_statval_t count, sum;
00758   float r;
00759   READ_HTTP_TRANS_STAT((long) data, count, sum);
00760   if (count == 0) {
00761     r = 0.0;
00762   } else {
00763     r = (float) sum / (float) count;
00764     r = r / (float) HRTIME_MSECOND;
00765   }
00766   *(float *) res = r;
00767   return res;
00768 }
00769 
00770 void *
00771 http_trans_stats_time_useconds_cb(void *data, void *res)
00772 {
00773   ink_statval_t count, sum;
00774   float r;
00775   READ_HTTP_TRANS_STAT((long) data, count, sum);
00776   if (count == 0) {
00777     r = 0.0;
00778   } else {
00779     r = (float) sum / (float) count;
00780     r = r / (float) HRTIME_USECOND;
00781   }
00782   *(float *) res = r;
00783   return res;
00784 }