Annotation of embedaddon/bird2/proto/perf/perf.c, revision 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>