File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / proto / perf / perf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (5 years, 5 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    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>