Annotation of embedaddon/bird2/proto/perf/perf.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
                      3:  *
                      4:  *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
                      5:  *
                      6:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      7:  */
                      8: 
                      9: /**
                     10:  * DOC: Perf
                     11:  *
                     12:  * Run this protocol to measure route import and export times.
                     13:  * Generates a load of dummy routes and measures time to import.
                     14:  */
                     15: 
                     16: #undef LOCAL_DEBUG
                     17: 
                     18: #include "nest/bird.h"
                     19: #include "nest/iface.h"
                     20: #include "nest/protocol.h"
                     21: #include "nest/route.h"
                     22: #include "nest/cli.h"
                     23: #include "conf/conf.h"
                     24: #include "filter/filter.h"
                     25: #include "lib/string.h"
                     26: 
                     27: #include "perf.h"
                     28: 
                     29: #include <stdlib.h>
                     30: #include <time.h>
                     31: 
                     32: #define PLOG(msg, ...) log(L_INFO "Perf %s %s " msg, BIRD_VERSION, p->p.name, ##__VA_ARGS__)
                     33: 
                     34: static inline void
                     35: random_data(void *p, uint len)
                     36: {
                     37:   uint ints = (len + sizeof(int) - 1) / sizeof(int);
                     38:   int *d = alloca(sizeof(uint) * ints);
                     39:   for (uint i=0; i<ints; i++)
                     40:     d[i] = random();
                     41: 
                     42:   memcpy(p, d, len);
                     43: }
                     44: 
                     45: static ip_addr
                     46: random_gw(net_addr *prefix)
                     47: {
                     48:   ASSERT(net_is_ip(prefix));
                     49:   ip_addr px = net_prefix(prefix);
                     50:   ip_addr mask = net_pxmask(prefix);
                     51: 
                     52:   ip_addr out;
                     53:   random_data(&out, sizeof(ip_addr));
                     54: 
                     55:   if (ipa_is_ip4(px))
                     56:     out = ipa_and(out, ipa_from_ip4(ip4_mkmask(32)));
                     57: 
                     58:   return ipa_or(ipa_and(px, mask), ipa_and(out, ipa_not(mask)));
                     59: }
                     60: 
                     61: static net_addr_ip4
                     62: random_net_ip4(void)
                     63: {
                     64:   u32 x; random_data(&x, sizeof(u32));
                     65:   x &= ((1 << 20) - 1);
                     66:   uint pxlen = u32_log2(x) + 5;
                     67: 
                     68:   ip4_addr px; random_data(&px, sizeof(ip4_addr));
                     69: 
                     70:   net_addr_ip4 out = {
                     71:     .type = NET_IP4,
                     72:     .pxlen = pxlen,
                     73:     .length = sizeof(net_addr_ip4),
                     74:     .prefix = ip4_and(ip4_mkmask(pxlen), px),
                     75:   };
                     76: 
                     77:   if (!net_validate((net_addr *) &out))
                     78:     return random_net_ip4();
                     79: 
                     80:   int c = net_classify((net_addr *) &out);
                     81:   if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
                     82:     return random_net_ip4();
                     83: 
                     84:   return out;
                     85: }
                     86: 
                     87: struct perf_random_routes {
                     88:   net_addr net;
                     89:   rte *ep;
                     90:   struct rta a;
                     91: };
                     92: 
                     93: static const uint perf_random_routes_size = sizeof(struct perf_random_routes) + (RTA_MAX_SIZE - sizeof(struct rta));
                     94: 
                     95: static inline s64 timediff(struct timespec *begin, struct timespec *end)
                     96: { return (end->tv_sec - begin->tv_sec) * (s64) 1000000000 + end->tv_nsec - begin->tv_nsec; }
                     97: 
                     98: static void
                     99: perf_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
                    100: {
                    101:   struct perf_proto *p = (struct perf_proto *) P;
                    102: 
                    103:   if (ad->flags & IA_SECONDARY)
                    104:     return;
                    105: 
                    106:   if (p->ifa && p->ifa == ad && (flags & IF_CHANGE_DOWN)) {
                    107:     p->ifa = NULL;
                    108:     if (ev_active(p->loop))
                    109:       ev_postpone(p->loop);
                    110: 
                    111:     return;
                    112:   }
                    113: 
                    114:   if (!p->ifa && (flags & IF_CHANGE_UP)) {
                    115:     p->ifa = ad;
                    116:     ev_schedule(p->loop);
                    117:     PLOG("starting");
                    118:     return;
                    119:   }
                    120: }
                    121: 
                    122: static void
                    123: perf_loop(void *data)
                    124: {
                    125:   struct proto *P = data;
                    126:   struct perf_proto *p = data;
                    127: 
                    128:   const uint N = 1U << p->exp;
                    129:   const uint offset = perf_random_routes_size;
                    130: 
                    131:   if (!p->run) {
                    132:     ASSERT(p->data == NULL);
                    133:     p->data = xmalloc(offset * N);
                    134:     bzero(p->data, offset * N);
                    135:     p->stop = 1;
                    136:   }
                    137: 
                    138:   ip_addr gw = random_gw(&p->ifa->prefix);
                    139: 
                    140:   struct timespec ts_begin, ts_generated, ts_update, ts_withdraw;
                    141: 
                    142:   clock_gettime(CLOCK_MONOTONIC, &ts_begin);
                    143: 
                    144:   struct rta *a = NULL;
                    145: 
                    146:   for (uint i=0; i<N; i++) {
                    147:     struct perf_random_routes *prr = p->data + offset * i;
                    148:     *((net_addr_ip4 *) &prr->net) = random_net_ip4();
                    149: 
                    150:     if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
                    151:       a = &prr->a;
                    152:       bzero(a, RTA_MAX_SIZE);
                    153: 
                    154:       a->src = p->p.main_source;
                    155:       a->source = RTS_PERF;
                    156:       a->scope = SCOPE_UNIVERSE;
                    157:       a->dest = RTD_UNICAST;
                    158: 
                    159:       a->nh.iface = p->ifa->iface;
                    160:       a->nh.gw = gw;
                    161:       a->nh.weight = 1;
                    162: 
                    163:       if (p->attrs_per_rte)
                    164:        a = rta_lookup(a);
                    165:     }
                    166: 
                    167:     ASSERT(a);
                    168: 
                    169:     prr->ep = rte_get_temp(a);
                    170:     prr->ep->pflags = 0;
                    171:   }
                    172: 
                    173:   clock_gettime(CLOCK_MONOTONIC, &ts_generated);
                    174: 
                    175:   for (uint i=0; i<N; i++) {
                    176:     struct perf_random_routes *prr = p->data + offset * i;
                    177:     rte_update(P, &prr->net, prr->ep);
                    178:   }
                    179: 
                    180:   clock_gettime(CLOCK_MONOTONIC, &ts_update);
                    181: 
                    182:   if (!p->keep)
                    183:     for (uint i=0; i<N; i++) {
                    184:       struct perf_random_routes *prr = p->data + offset * i;
                    185:       rte_update(P, &prr->net, NULL);
                    186:     }
                    187: 
                    188:   clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);
                    189: 
                    190:   s64 gentime = timediff(&ts_begin, &ts_generated);
                    191:   s64 updatetime = timediff(&ts_generated, &ts_update);
                    192:   s64 withdrawtime = timediff(&ts_update, &ts_withdraw);
                    193: 
                    194:   if (updatetime NS >= p->threshold_min)
                    195:     PLOG("exp=%u times: gen=%ld update=%ld withdraw=%ld",
                    196:        p->exp, gentime, updatetime, withdrawtime);
                    197: 
                    198:   if (updatetime NS < p->threshold_max)
                    199:     p->stop = 0;
                    200: 
                    201:   if ((updatetime NS < p->threshold_min) || (++p->run == p->repeat)) {
                    202:     xfree(p->data);
                    203:     p->data = NULL;
                    204: 
                    205:     if (p->stop || (p->exp == p->to)) {
                    206:       PLOG("done with exp=%u", p->exp);
                    207:       return;
                    208:     }
                    209: 
                    210:     p->run = 0;
                    211:     p->exp++;
                    212:   }
                    213: 
                    214:   rt_schedule_prune(P->main_channel->table);
                    215:   ev_schedule(p->loop);
                    216: }
                    217: 
                    218: static void
                    219: perf_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net UNUSED, struct rte *new UNUSED, struct rte *old UNUSED)
                    220: {
                    221:   struct perf_proto *p = (struct perf_proto *) P;
                    222:   p->exp++;
                    223:   return;
                    224: }
                    225: 
                    226: static void
                    227: perf_feed_begin(struct channel *c, int initial UNUSED)
                    228: {
                    229:   struct perf_proto *p = (struct perf_proto *) c->proto;
                    230: 
                    231:   p->run++;
                    232:   p->data = xmalloc(sizeof(struct timespec));
                    233:   p->exp = 0;
                    234: 
                    235:   clock_gettime(CLOCK_MONOTONIC, p->data);
                    236: }
                    237: 
                    238: static void
                    239: perf_feed_end(struct channel *c)
                    240: {
                    241:   struct perf_proto *p = (struct perf_proto *) c->proto;
                    242:   struct timespec ts_end;
                    243:   clock_gettime(CLOCK_MONOTONIC, &ts_end);
                    244: 
                    245:   s64 feedtime = timediff(p->data, &ts_end);
                    246: 
                    247:   PLOG("feed n=%lu time=%lu", p->exp, feedtime);
                    248: 
                    249:   if (p->run < p->repeat)
                    250:     channel_request_feeding(c);
                    251:   else
                    252:     PLOG("feed done");
                    253: }
                    254: 
                    255: static struct proto *
                    256: perf_init(struct proto_config *CF)
                    257: {
                    258:   struct proto *P = proto_new(CF);
                    259: 
                    260:   P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
                    261: 
                    262:   struct perf_proto *p = (struct perf_proto *) P;
                    263: 
                    264:   p->loop = ev_new_init(P->pool, perf_loop, p);
                    265: 
                    266:   struct perf_config *cf = (struct perf_config *) CF;
                    267: 
                    268:   p->threshold_min = cf->threshold_min;
                    269:   p->threshold_max = cf->threshold_max;
                    270:   p->from = cf->from;
                    271:   p->to = cf->to;
                    272:   p->repeat = cf->repeat;
                    273:   p->keep = cf->keep;
                    274:   p->mode = cf->mode;
                    275:   p->attrs_per_rte = cf->attrs_per_rte;
                    276: 
                    277:   switch (p->mode) {
                    278:     case PERF_MODE_IMPORT:
                    279:       P->ifa_notify = perf_ifa_notify;
                    280:       break;
                    281:     case PERF_MODE_EXPORT:
                    282:       P->rt_notify = perf_rt_notify;
                    283:       P->feed_begin = perf_feed_begin;
                    284:       P->feed_end = perf_feed_end;
                    285:       break;
                    286:   }
                    287: 
                    288:   return P;
                    289: }
                    290: 
                    291: static int
                    292: perf_start(struct proto *P)
                    293: {
                    294:   struct perf_proto *p = (struct perf_proto *) P;
                    295: 
                    296:   p->ifa = NULL;
                    297:   p->run = 0;
                    298:   p->exp = p->from;
                    299:   ASSERT(p->data == NULL);
                    300: 
                    301:   return PS_UP;
                    302: }
                    303: 
                    304: static int
                    305: perf_reconfigure(struct proto *P UNUSED, struct proto_config *CF UNUSED)
                    306: {
                    307:   return 0;
                    308: }
                    309: 
                    310: static void
                    311: perf_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
                    312: {
                    313: }
                    314: 
                    315: struct protocol proto_perf = {
                    316:   .name =              "Perf",
                    317:   .template =          "perf%d",
                    318:   .class =             PROTOCOL_PERF,
                    319:   .channel_mask =      NB_IP,
                    320:   .proto_size =                sizeof(struct perf_proto),
                    321:   .config_size =       sizeof(struct perf_config),
                    322:   .init =              perf_init,
                    323:   .start =             perf_start,
                    324:   .reconfigure =       perf_reconfigure,
                    325:   .copy_config =       perf_copy_config,
                    326: };

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>