ccnd_stats.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnd_stats.c
00003  *
00004  * Statistics presentation for ccnd.
00005  *
00006  * Part of ccnd - the CCNx Daemon.
00007  *
00008  * Copyright (C) 2008-2011 Palo Alto Research Center, Inc.
00009  *
00010  * This work is free software; you can redistribute it and/or modify it under
00011  * the terms of the GNU General Public License version 2 as published by the
00012  * Free Software Foundation.
00013  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00016  * for more details. You should have received a copy of the GNU General Public
00017  * License along with this program; if not, write to the
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  */
00021 
00022 #include <sys/types.h>
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <stdint.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <sys/time.h>
00030 #include <sys/socket.h>
00031 #include <sys/utsname.h>
00032 #include <time.h>
00033 #include <unistd.h>
00034 #include <ccn/ccn.h>
00035 #include <ccn/ccnd.h>
00036 #include <ccn/charbuf.h>
00037 #include <ccn/coding.h>
00038 #include <ccn/indexbuf.h>
00039 #include <ccn/schedule.h>
00040 #include <ccn/sockaddrutil.h>
00041 #include <ccn/hashtb.h>
00042 #include <ccn/uri.h>
00043 
00044 #include "ccnd_private.h"
00045 
00046 #define CRLF "\r\n"
00047 #define NL   "\n"
00048 
00049 /**
00050  * Provide a way to monitor rates.
00051  */
00052 struct ccnd_meter {
00053     uintmax_t total;
00054     char what[8];
00055     unsigned rate; /** a scale factor applies */
00056     unsigned lastupdate;
00057 };
00058 
00059 struct ccnd_stats {
00060     long total_interest_counts;
00061     long total_flood_control;      /* done propagating, still recorded */
00062 };
00063 
00064 static int ccnd_collect_stats(struct ccnd_handle *h, struct ccnd_stats *ans);
00065 static struct ccn_charbuf *collect_stats_html(struct ccnd_handle *h);
00066 static void send_http_response(struct ccnd_handle *h, struct face *face,
00067                                const char *mime_type,
00068                                struct ccn_charbuf *response);
00069 static struct ccn_charbuf *collect_stats_html(struct ccnd_handle *h);
00070 static struct ccn_charbuf *collect_stats_xml(struct ccnd_handle *h);
00071 
00072 /* HTTP */
00073 
00074 static const char *resp404 =
00075     "HTTP/1.1 404 Not Found" CRLF
00076     "Connection: close" CRLF CRLF;
00077 
00078 static const char *resp405 =
00079     "HTTP/1.1 405 Method Not Allowed" CRLF
00080     "Connection: close" CRLF CRLF;
00081 
00082 static void
00083 ccnd_stats_http_set_debug(struct ccnd_handle *h, struct face *face, int level)
00084 {
00085     struct ccn_charbuf *response = ccn_charbuf_create();
00086     
00087     h->debug = 1;
00088     ccnd_msg(h, "CCND_DEBUG=%d", level);
00089     h->debug = level;
00090     ccn_charbuf_putf(response, "<title>CCND_DEBUG=%d</title><tt>CCND_DEBUG=%d</tt>" CRLF, level, level);
00091     send_http_response(h, face, "text/html", response);
00092     ccn_charbuf_destroy(&response);
00093 }
00094 
00095 int
00096 ccnd_stats_handle_http_connection(struct ccnd_handle *h, struct face *face)
00097 {
00098     struct ccn_charbuf *response = NULL;
00099     char rbuf[16];
00100     int i;
00101     int nspace;
00102     int n;
00103     
00104     if (face->inbuf->length < 4)
00105         return(-1);
00106     if ((face->flags & CCN_FACE_NOSEND) != 0) {
00107         ccnd_destroy_face(h, face->faceid);
00108         return(-1);
00109     }
00110     n = sizeof(rbuf) - 1;
00111     if (face->inbuf->length < n)
00112         n = face->inbuf->length;
00113     for (i = 0, nspace = 0; i < n && nspace < 2; i++) {
00114         rbuf[i] = face->inbuf->buf[i];
00115         if (rbuf[i] == ' ')
00116             nspace++;
00117     }
00118     rbuf[i] = 0;
00119     if (nspace < 2 && i < sizeof(rbuf) - 1)
00120         return(-1);
00121     if (0 == strcmp(rbuf, "GET / ") ||
00122         0 == strcmp(rbuf, "GET /? ")) {
00123         response = collect_stats_html(h);
00124         send_http_response(h, face, "text/html", response);
00125     }
00126     else if (0 == strcmp(rbuf, "GET /?l=none ")) {
00127         ccnd_stats_http_set_debug(h, face, 0);
00128     }
00129     else if (0 == strcmp(rbuf, "GET /?l=low ")) {
00130         ccnd_stats_http_set_debug(h, face, 1);
00131     }
00132     else if (0 == strcmp(rbuf, "GET /?l=co ")) {
00133         ccnd_stats_http_set_debug(h, face, 4);
00134     }
00135     else if (0 == strcmp(rbuf, "GET /?l=med ")) {
00136         ccnd_stats_http_set_debug(h, face, 71);
00137     }
00138     else if (0 == strcmp(rbuf, "GET /?l=high ")) {
00139         ccnd_stats_http_set_debug(h, face, -1);
00140     }
00141     else if (0 == strcmp(rbuf, "GET /?f=xml ")) {
00142         response = collect_stats_xml(h);
00143         send_http_response(h, face, "text/xml", response);
00144     }
00145     else if (0 == strcmp(rbuf, "GET "))
00146         ccnd_send(h, face, resp404, strlen(resp404));
00147     else
00148         ccnd_send(h, face, resp405, strlen(resp405));
00149     face->flags |= (CCN_FACE_NOSEND | CCN_FACE_CLOSING);
00150     ccn_charbuf_destroy(&response);
00151     return(0);
00152 }
00153 
00154 static void
00155 send_http_response(struct ccnd_handle *h, struct face *face,
00156                    const char *mime_type, struct ccn_charbuf *response)
00157 {
00158     struct linger linger = { .l_onoff = 1, .l_linger = 1 };
00159     char buf[128];
00160     int hdrlen;
00161 
00162     /* Set linger to prevent quickly resetting the connection on close.*/
00163     setsockopt(face->recv_fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
00164     hdrlen = snprintf(buf, sizeof(buf),
00165                       "HTTP/1.1 200 OK" CRLF
00166                       "Content-Type: %s; charset=utf-8" CRLF
00167                       "Connection: close" CRLF
00168                       "Content-Length: %jd" CRLF CRLF,
00169                       mime_type,
00170                       (intmax_t)response->length);
00171     ccnd_send(h, face, buf, hdrlen);
00172     ccnd_send(h, face, response->buf, response->length);
00173 }
00174 
00175 /* Common statistics collection */
00176 
00177 static int
00178 ccnd_collect_stats(struct ccnd_handle *h, struct ccnd_stats *ans)
00179 {
00180     struct hashtb_enumerator ee;
00181     struct hashtb_enumerator *e = &ee;
00182     long sum;
00183     unsigned i;
00184     for (sum = 0, hashtb_start(h->nameprefix_tab, e);
00185          e->data != NULL; hashtb_next(e)) {
00186         struct nameprefix_entry *npe = e->data;
00187         struct ielinks *head = &npe->ie_head;
00188         struct ielinks *ll;
00189         for (ll = head->next; ll != head; ll = ll->next) {
00190             struct interest_entry *ie = (struct interest_entry *)ll;
00191             struct pit_face_item *p;
00192             for (p = ie->pfl; p != NULL; p = p->next)
00193                 if ((p->pfi_flags & CCND_PFI_PENDING) != 0)
00194                     if (ccnd_face_from_faceid(h, p->faceid) != NULL)
00195                         sum += 1;
00196         }
00197     }
00198     ans->total_interest_counts = sum;
00199     hashtb_end(e);
00200     ans->total_flood_control = 0; /* N/A */
00201     /* Do a consistency check on pending interest counts */
00202     for (sum = 0, i = 0; i < h->face_limit; i++) {
00203         struct face *face = h->faces_by_faceid[i];
00204         if (face != NULL)
00205             sum += face->pending_interests;
00206     }
00207     if (sum != ans->total_interest_counts)
00208         ccnd_msg(h, "ccnd_collect_stats found inconsistency %ld != %ld\n",
00209                  (long)sum, (long)ans->total_interest_counts);
00210     ans->total_interest_counts = sum;
00211     return(0);
00212 }
00213 
00214 /* HTML formatting */
00215 
00216 static void
00217 collect_faces_html(struct ccnd_handle *h, struct ccn_charbuf *b)
00218 {
00219     int i;
00220     struct ccn_charbuf *nodebuf;
00221     int port;
00222     
00223     nodebuf = ccn_charbuf_create();
00224     ccn_charbuf_putf(b, "<h4>Faces</h4>" NL);
00225     ccn_charbuf_putf(b, "<ul>");
00226     for (i = 0; i < h->face_limit; i++) {
00227         struct face *face = h->faces_by_faceid[i];
00228         if (face != NULL && (face->flags & CCN_FACE_UNDECIDED) == 0) {
00229             ccn_charbuf_putf(b, " <li>");
00230             ccn_charbuf_putf(b, "<b>face:</b> %u <b>flags:</b> 0x%x",
00231                              face->faceid, face->flags);
00232             ccn_charbuf_putf(b, " <b>pending:</b> %d",
00233                              face->pending_interests);
00234             if (face->recvcount != 0)
00235                 ccn_charbuf_putf(b, " <b>activity:</b> %d",
00236                                  face->recvcount);
00237             nodebuf->length = 0;
00238             port = ccn_charbuf_append_sockaddr(nodebuf, face->addr);
00239             if (port > 0) {
00240                 const char *node = ccn_charbuf_as_string(nodebuf);
00241                 int chk = CCN_FACE_MCAST | CCN_FACE_UNDECIDED |
00242                 CCN_FACE_NOSEND | CCN_FACE_GG | CCN_FACE_PASSIVE;
00243                 if ((face->flags & chk) == 0)
00244                     ccn_charbuf_putf(b,
00245                                      " <b>remote:</b> "
00246                                      "<a href='http://%s:%s/'>"
00247                                      "%s:%d</a>",
00248                                      node, CCN_DEFAULT_UNICAST_PORT,
00249                                      node, port);
00250                 else if ((face->flags & CCN_FACE_PASSIVE) == 0)
00251                     ccn_charbuf_putf(b, " <b>remote:</b> %s:%d",
00252                                      node, port);
00253                 else
00254                     ccn_charbuf_putf(b, " <b>local:</b> %s:%d",
00255                                      node, port);
00256                 if (face->sendface != face->faceid &&
00257                     face->sendface != CCN_NOFACEID)
00258                     ccn_charbuf_putf(b, " <b>via:</b> %u", face->sendface);
00259             }
00260             ccn_charbuf_putf(b, "</li>" NL);
00261         }
00262     }
00263     ccn_charbuf_putf(b, "</ul>");
00264     ccn_charbuf_destroy(&nodebuf);
00265 }
00266 
00267 static void
00268 collect_face_meter_html(struct ccnd_handle *h, struct ccn_charbuf *b)
00269 {
00270     int i;
00271     ccn_charbuf_putf(b, "<h4>Face Activity Rates</h4>");
00272     ccn_charbuf_putf(b, "<table cellspacing='0' cellpadding='0' class='tbl' summary='face activity rates'>");
00273     ccn_charbuf_putf(b, "<tbody>" NL);
00274     ccn_charbuf_putf(b, " <tr><td>        </td>\t"
00275                         " <td>Bytes/sec In/Out</td>\t"
00276                         " <td>recv data/intr sent</td>\t"
00277                         " <td>sent data/intr recv</td></tr>" NL);
00278     for (i = 0; i < h->face_limit; i++) {
00279         struct face *face = h->faces_by_faceid[i];
00280         if (face != NULL && (face->flags & (CCN_FACE_UNDECIDED|CCN_FACE_PASSIVE)) == 0) {
00281             ccn_charbuf_putf(b, " <tr>");
00282             ccn_charbuf_putf(b, "<td><b>face:</b> %u</td>\t",
00283                              face->faceid);
00284             ccn_charbuf_putf(b, "<td>%6u / %u</td>\t\t",
00285                                  ccnd_meter_rate(h, face->meter[FM_BYTI]),
00286                                  ccnd_meter_rate(h, face->meter[FM_BYTO]));
00287             ccn_charbuf_putf(b, "<td>%9u / %u</td>\t\t",
00288                                  ccnd_meter_rate(h, face->meter[FM_DATI]),
00289                                  ccnd_meter_rate(h, face->meter[FM_INTO]));
00290             ccn_charbuf_putf(b, "<td>%9u / %u</td>",
00291                                  ccnd_meter_rate(h, face->meter[FM_DATO]),
00292                                  ccnd_meter_rate(h, face->meter[FM_INTI]));
00293             ccn_charbuf_putf(b, "</tr>" NL);
00294         }
00295     }
00296     ccn_charbuf_putf(b, "</tbody>");
00297     ccn_charbuf_putf(b, "</table>");
00298 }
00299 
00300 static void
00301 collect_forwarding_html(struct ccnd_handle *h, struct ccn_charbuf *b)
00302 {
00303     struct hashtb_enumerator ee;
00304     struct hashtb_enumerator *e = &ee;
00305     struct ccn_forwarding *f;
00306     int res;
00307     struct ccn_charbuf *name = ccn_charbuf_create();
00308     
00309     ccn_charbuf_putf(b, "<h4>Forwarding</h4>" NL);
00310     ccn_charbuf_putf(b, "<ul>");
00311     hashtb_start(h->nameprefix_tab, e);
00312     for (; e->data != NULL; hashtb_next(e)) {
00313         struct nameprefix_entry *ipe = e->data;
00314         ccn_name_init(name);
00315         res = ccn_name_append_components(name, e->key, 0, e->keysize);
00316         if (res < 0)
00317             abort();
00318         if (0) {
00319             ccn_charbuf_putf(b, " <li>");
00320             ccn_uri_append(b, name->buf, name->length, 1);
00321             ccn_charbuf_putf(b, "</li>" NL);
00322         }
00323         for (f = ipe->forwarding; f != NULL; f = f->next) {
00324             if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0) {
00325                 ccn_name_init(name);
00326                 ccn_name_append_components(name, e->key, 0, e->keysize);
00327                 ccn_charbuf_putf(b, " <li>");
00328                 ccn_uri_append(b, name->buf, name->length, 1);
00329                 ccn_charbuf_putf(b,
00330                                  " <b>face:</b> %u"
00331                                  " <b>flags:</b> 0x%x"
00332                                  " <b>expires:</b> %d",
00333                                  f->faceid,
00334                                  f->flags & CCN_FORW_PUBMASK,
00335                                  f->expires);
00336                 ccn_charbuf_putf(b, "</li>" NL);
00337             }
00338         }
00339     }
00340     hashtb_end(e);
00341     ccn_charbuf_destroy(&name);
00342     ccn_charbuf_putf(b, "</ul>");
00343 }
00344 
00345 static unsigned
00346 ccnd_colorhash(struct ccnd_handle *h)
00347 {
00348     unsigned const char *a = h->ccnd_id;
00349     unsigned v;
00350     
00351     v = (a[0] << 16) + (a[1] << 8) + a[2];
00352     return (v | 0xC0C0C0);
00353 }
00354 
00355 static struct ccn_charbuf *
00356 collect_stats_html(struct ccnd_handle *h)
00357 {
00358     struct ccnd_stats stats = {0};
00359     struct ccn_charbuf *b = ccn_charbuf_create();
00360     int pid;
00361     struct utsname un;
00362     const char *portstr;
00363     
00364     portstr = getenv(CCN_LOCAL_PORT_ENVNAME);
00365     if (portstr == NULL || portstr[0] == 0 || strlen(portstr) > 10)
00366         portstr = CCN_DEFAULT_UNICAST_PORT;
00367     uname(&un);
00368     pid = getpid();
00369     
00370     ccnd_collect_stats(h, &stats);
00371     ccn_charbuf_putf(b,
00372         "<html xmlns='http://www.w3.org/1999/xhtml'>"
00373         "<head>"
00374         "<title>%s ccnd[%d]</title>"
00375         //"<meta http-equiv='refresh' content='3'>"
00376         "<style type='text/css'>"
00377         "/*<![CDATA[*/"
00378         "p.header {color: white; background-color: blue; width: 100%%} "
00379         "table.tbl {border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: black} "
00380         "td {border-style: solid; "
00381             "border-width: 1.0px 1.0px 1.0px 1.0px; "
00382             "border-color: #808080 #808080 #808080 #808080; "
00383             "padding: 6px 6px 6px 6px; "
00384             "margin-left: auto; margin-right: auto; "
00385             "text-align: center"
00386             "} "
00387         "td.left {text-align: left} "
00388         "/*]]>*/"
00389         "</style>"
00390         "</head>" NL
00391         "<body bgcolor='#%06X'>"
00392         "<p class='header'>%s ccnd[%d] local port %s api %d start %ld.%06u now %ld.%06u</p>" NL
00393         "<div><b>Content items:</b> %llu accessioned,"
00394         " %d stored, %lu stale, %d sparse, %lu duplicate, %lu sent</div>" NL
00395         "<div><b>Interests:</b> %d names,"
00396         " %ld pending, %ld propagating, %ld noted</div>" NL
00397         "<div><b>Interest totals:</b> %lu accepted,"
00398         " %lu dropped, %lu sent, %lu stuffed</div>" NL,
00399         un.nodename,
00400         pid,
00401         ccnd_colorhash(h),
00402         un.nodename,
00403         pid,
00404         portstr,
00405         (int)CCN_API_VERSION,
00406         h->starttime, h->starttime_usec,
00407         h->sec,
00408         h->usec,
00409         (unsigned long long)h->accession,
00410         hashtb_n(h->content_tab),
00411         h->n_stale,
00412         hashtb_n(h->sparse_straggler_tab),
00413         h->content_dups_recvd,
00414         h->content_items_sent,
00415         hashtb_n(h->nameprefix_tab), stats.total_interest_counts,
00416         hashtb_n(h->interest_tab) - stats.total_flood_control,
00417         stats.total_flood_control,
00418         h->interests_accepted, h->interests_dropped,
00419         h->interests_sent, h->interests_stuffed);
00420     if (0)
00421         ccn_charbuf_putf(b,
00422                          "<div><b>Active faces and listeners:</b> %d</div>" NL,
00423                          hashtb_n(h->faces_by_fd) + hashtb_n(h->dgram_faces));
00424     collect_faces_html(h, b);
00425     collect_face_meter_html(h, b);
00426     collect_forwarding_html(h, b);
00427     ccn_charbuf_putf(b,
00428         "</body>"
00429         "</html>" NL);
00430     return(b);
00431 }
00432 
00433 /* XML formatting */
00434 
00435 static void
00436 collect_meter_xml(struct ccnd_handle *h, struct ccn_charbuf *b, struct ccnd_meter *m)
00437 {
00438     uintmax_t total;
00439     unsigned rate;
00440     
00441     if (m == NULL)
00442         return;
00443     total = ccnd_meter_total(m);
00444     rate = ccnd_meter_rate(h, m);
00445     ccn_charbuf_putf(b, "<%s><total>%ju</total><persec>%u</persec></%s>",
00446         m->what, total, rate, m->what);
00447 }
00448 
00449 static void
00450 collect_faces_xml(struct ccnd_handle *h, struct ccn_charbuf *b)
00451 {
00452     int i;
00453     int m;
00454     int port;
00455     struct ccn_charbuf *nodebuf;
00456     
00457     nodebuf = ccn_charbuf_create();
00458     ccn_charbuf_putf(b, "<faces>");
00459     for (i = 0; i < h->face_limit; i++) {
00460         struct face *face = h->faces_by_faceid[i];
00461         if (face != NULL && (face->flags & CCN_FACE_UNDECIDED) == 0) {
00462             ccn_charbuf_putf(b, "<face>");
00463             ccn_charbuf_putf(b,
00464                              "<faceid>%u</faceid>"
00465                              "<faceflags>%04x</faceflags>",
00466                              face->faceid, face->flags);
00467             ccn_charbuf_putf(b, "<pending>%d</pending>",
00468                              face->pending_interests);
00469             ccn_charbuf_putf(b, "<recvcount>%d</recvcount>",
00470                              face->recvcount);
00471             nodebuf->length = 0;
00472             port = ccn_charbuf_append_sockaddr(nodebuf, face->addr);
00473             if (port > 0) {
00474                 const char *node = ccn_charbuf_as_string(nodebuf);
00475                 ccn_charbuf_putf(b, "<ip>%s:%d</ip>", node, port);
00476             }
00477             if (face->sendface != face->faceid &&
00478                 face->sendface != CCN_NOFACEID)
00479                 ccn_charbuf_putf(b, "<via>%u</via>", face->sendface);
00480             if (face != NULL && (face->flags & CCN_FACE_PASSIVE) == 0) {
00481                 ccn_charbuf_putf(b, "<meters>");
00482                 for (m = 0; m < CCND_FACE_METER_N; m++)
00483                     collect_meter_xml(h, b, face->meter[m]);
00484                 ccn_charbuf_putf(b, "</meters>");
00485             }
00486             ccn_charbuf_putf(b, "</face>" NL);
00487         }
00488     }
00489     ccn_charbuf_putf(b, "</faces>");
00490     ccn_charbuf_destroy(&nodebuf);
00491 }
00492 
00493 static void
00494 collect_forwarding_xml(struct ccnd_handle *h, struct ccn_charbuf *b)
00495 {
00496     struct hashtb_enumerator ee;
00497     struct hashtb_enumerator *e = &ee;
00498     struct ccn_forwarding *f;
00499     int res;
00500     struct ccn_charbuf *name = ccn_charbuf_create();
00501     
00502     ccn_charbuf_putf(b, "<forwarding>");
00503     hashtb_start(h->nameprefix_tab, e);
00504     for (; e->data != NULL; hashtb_next(e)) {
00505         struct nameprefix_entry *ipe = e->data;
00506         for (f = ipe->forwarding, res = 0; f != NULL && !res; f = f->next) {
00507             if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0)
00508                 res = 1;
00509         }
00510         if (res) {
00511             ccn_name_init(name);
00512             ccn_name_append_components(name, e->key, 0, e->keysize);
00513             ccn_charbuf_putf(b, "<fentry>");
00514             ccn_charbuf_putf(b, "<prefix>");
00515             ccn_uri_append(b, name->buf, name->length, 1);
00516             ccn_charbuf_putf(b, "</prefix>");
00517             for (f = ipe->forwarding; f != NULL; f = f->next) {
00518                 if ((f->flags & (CCN_FORW_ACTIVE | CCN_FORW_PFXO)) != 0) {
00519                     ccn_charbuf_putf(b,
00520                                      "<dest>"
00521                                      "<faceid>%u</faceid>"
00522                                      "<flags>%x</flags>"
00523                                      "<expires>%d</expires>"
00524                                      "</dest>",
00525                                      f->faceid,
00526                                      f->flags & CCN_FORW_PUBMASK,
00527                                      f->expires);
00528                 }
00529             }
00530             ccn_charbuf_putf(b, "</fentry>");
00531         }
00532     }
00533     hashtb_end(e);
00534     ccn_charbuf_destroy(&name);
00535     ccn_charbuf_putf(b, "</forwarding>");
00536 }
00537 
00538 static struct ccn_charbuf *
00539 collect_stats_xml(struct ccnd_handle *h)
00540 {
00541     struct ccnd_stats stats = {0};
00542     struct ccn_charbuf *b = ccn_charbuf_create();
00543     int i;
00544         
00545     ccnd_collect_stats(h, &stats);
00546     ccn_charbuf_putf(b,
00547         "<ccnd>"
00548         "<identity>"
00549         "<ccndid>");
00550     for (i = 0; i < sizeof(h->ccnd_id); i++)
00551         ccn_charbuf_putf(b, "%02X", h->ccnd_id[i]);
00552     ccn_charbuf_putf(b, "</ccndid>"
00553         "<apiversion>%d</apiversion>"
00554         "<starttime>%ld.%06u</starttime>"
00555         "<now>%ld.%06u</now>"
00556         "</identity>",
00557         (int)CCN_API_VERSION,
00558         h->starttime, h->starttime_usec,
00559         h->sec,
00560         h->usec);
00561     ccn_charbuf_putf(b,
00562         "<cobs>"
00563         "<accessioned>%llu</accessioned>"
00564         "<stored>%d</stored>"
00565         "<stale>%lu</stale>"
00566         "<sparse>%d</sparse>"
00567         "<duplicate>%lu</duplicate>"
00568         "<sent>%lu</sent>"
00569         "</cobs>"
00570         "<interests>"
00571         "<names>%d</names>"
00572         "<pending>%ld</pending>"
00573         "<propagating>%ld</propagating>"
00574         "<noted>%ld</noted>"
00575         "<accepted>%lu</accepted>"
00576         "<dropped>%lu</dropped>"
00577         "<sent>%lu</sent>"
00578         "<stuffed>%lu</stuffed>"
00579         "</interests>",
00580         (unsigned long long)h->accession,
00581         hashtb_n(h->content_tab),
00582         h->n_stale,
00583         hashtb_n(h->sparse_straggler_tab),
00584         h->content_dups_recvd,
00585         h->content_items_sent,
00586         hashtb_n(h->nameprefix_tab), stats.total_interest_counts,
00587         hashtb_n(h->interest_tab) - stats.total_flood_control,
00588         stats.total_flood_control,
00589         h->interests_accepted, h->interests_dropped,
00590         h->interests_sent, h->interests_stuffed);
00591     collect_faces_xml(h, b);
00592     collect_forwarding_xml(h, b);
00593     ccn_charbuf_putf(b, "</ccnd>" NL);
00594     return(b);
00595 }
00596 
00597 /**
00598  * create and initialize separately allocated meter.
00599  */
00600 struct ccnd_meter *
00601 ccnd_meter_create(struct ccnd_handle *h, const char *what)
00602 {
00603     struct ccnd_meter *m;
00604     m = calloc(1, sizeof(*m));
00605     if (m == NULL)
00606         return(NULL);
00607     ccnd_meter_init(h, m, what);
00608     return(m);
00609 }
00610 
00611 /**
00612  * Destroy a separately allocated meter.
00613  */
00614 void
00615 ccnd_meter_destroy(struct ccnd_meter **pm)
00616 {
00617     if (*pm != NULL) {
00618         free(*pm);
00619         *pm = NULL;
00620     }
00621 }
00622 
00623 /**
00624  * Initialize a meter.
00625  */
00626 void
00627 ccnd_meter_init(struct ccnd_handle *h, struct ccnd_meter *m, const char *what)
00628 {
00629     if (m == NULL)
00630         return;
00631     memset(m, 0, sizeof(m));
00632     if (what != NULL)
00633         strncpy(m->what, what, sizeof(m->what)-1);
00634     ccnd_meter_bump(h, m, 0);
00635 }
00636 
00637 static const unsigned meterHz = 7; /* 1/ln(8/7) would give RC const of 1 sec */
00638 
00639 /**
00640  * Count something (messages, packets, bytes), and roll up some kind of
00641  * statistics on it.
00642  */
00643 void
00644 ccnd_meter_bump(struct ccnd_handle *h, struct ccnd_meter *m, unsigned amt)
00645 {
00646     unsigned now; /* my ticks, wrap OK */
00647     unsigned t;
00648     unsigned r;
00649     if (m == NULL)
00650         return;
00651     now = (((unsigned)(h->sec)) * meterHz) + (h->usec * meterHz / 1000000U);
00652     t = m->lastupdate;
00653     m->total += amt;
00654     if (now - t > 166U)
00655         m->rate = amt; /* history has decayed away */
00656     else {
00657         /* Decay the old rate exponentially based on time since last sample. */
00658         for (r = m->rate; t != now && r != 0; t++)
00659             r = r - ((r + 7U) / 8U); /* multiply by 7/8, truncating */
00660         m->rate = r + amt;
00661     }
00662     m->lastupdate = now;
00663 }
00664 
00665 /**
00666  * Return the average rate (units per second) of a metered quantity.
00667  *
00668  * m may be NULL.
00669  */
00670 unsigned
00671 ccnd_meter_rate(struct ccnd_handle *h, struct ccnd_meter *m)
00672 {
00673     unsigned denom = 8;
00674     if (m == NULL)
00675         return(0);
00676     ccnd_meter_bump(h, m, 0);
00677     if (m->rate > 0x0FFFFFFF)
00678         return(m->rate / denom * meterHz);
00679     return ((m->rate * meterHz + (denom - 1)) / denom);
00680 }
00681 
00682 /**
00683  * Return the grand total for a metered quantity.
00684  *
00685  * m may be NULL.
00686  */
00687 uintmax_t
00688 ccnd_meter_total(struct ccnd_meter *m)
00689 {
00690     if (m == NULL)
00691         return(0);
00692     return (m->total);
00693 }
Generated on Tue Aug 21 14:54:15 2012 for Content-Centric Networking in C by  doxygen 1.6.3