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>