/* $Id: stopper.c,v 10.1 92/10/06 23:07:12 ca Exp $ */ /* * MaRS Maryland Routing Simulator * Copyright (c) 1991 University of Maryland * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: Cengiz Alaettinoglu, Klaudia Dussa-Zieger, Ibrahim Matta * Systems Design and Analysis Group * Department of Computer Science * University of Maryland at College Park. */ #include #include #include #include "sim.h" #include "simx.h" #include "q.h" #include "list.h" #include "component.h" #include "log.h" #include "comptypes.h" #include "packet.h" #include "eventdefs.h" #include "event.h" #include "perf.h" #include "stopper.h" #ifndef NoX #ifndef MOTIF #include "controls.h" #endif #endif #ifdef DEBUG extern Log debug_log; #endif extern int doXstuff; extern list *comps; extern char snapname[]; static Stopper *stopper_adr; extern Pmt *pm_adr; /* address of the performance monitor */ static caddr_t stopper_create(), stopper_start(), stopper_delete(), stopper_reset(), stopper_perf_update(), check_stop(); caddr_t stopper_action(src, g, type, pkt, arg) Component *src; register Stopper *g; int type; Packet *pkt; caddr_t arg; { caddr_t result = NULL; dbg_set_level(DBG_ERR); /* Just a big switch on type of event */ switch (type) { case EV_RESET: #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "reset"); #endif result = stopper_reset(g); break; case EV_CREATE: /* Minor sanity check first-- g should be NULL when initializing. */ #ifdef DEBUG if (g) dbg_write(debug_log, DBG_INFO, (Component *)NULL, "STOPPER Generator initialization called with non-null pointer."); #endif result = stopper_create((char *)arg); break; case EV_DEL: result = (caddr_t) stopper_delete(g); break; case EV_NEIGHBOR: result = (caddr_t) NULL; break; case EV_UNEIGHBOR: result = (caddr_t) NULL; break; case EV_MK_PEER: result = (caddr_t) NULL; break; case EV_START: result = stopper_start(g); break; case EV_STOP: result = (caddr_t) NULL; break; /********** The preceding were the commands. Following are the actual events that the application/transport module expects to receive. */ case EV_CHECK_STOP: result = check_stop(g); break; default: #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "got unexpected event of type %x", type); #endif break; } return(result); } static caddr_t stopper_create(name) register char *name; { Stopper *g; extern int doXstuff; if (!pm_adr) { #ifndef NoX if (doXstuff) { printx("Stopper needs performance monitor to run..."); sleep (3); xprintclear(); } #endif /* NoX */ fprintf(stderr, "Stopper needs performance monitor to run...\n"); return (caddr_t) NULL; } if (stopper_adr) { return (caddr_t) NULL; } /* Memory for the component structure. */ stopper_adr = g = (Stopper *)sim_malloc(sizeof(Stopper)); /* First things first-- copy name into the new structure. */ strncpy(g->name, "Stopper", 40); g->neighbors = l_create(); /* have to create a neighbor list */ g->params = q_create(); g->class = AUXILIARY_CLASS; g->type = STOPPER; g->action = stopper_action; g->menu_up = FALSE; /* Initialize the parameters */ (void)param_init((Component *)g, "Stopper", (PFD)NULL, make_name_text, make_short_name_text, (PFI)NULL, 0, DisplayMask, 0.0); g->no_of_intervals_to_stop = param_init((Component *)g, "No of intervals to stop", int_calc, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); g->no_of_intervals_to_stop->u.i = MAX_NO_OF_INTERVALS_TO_STOP; g->interval_length_to_stop = param_init((Component *)g, "Interval length to stop (usec)", int_calc, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); g->interval_length_to_stop->u.i = 10000000; g->percentage_to_stop = param_init((Component *)g, "Within this percentage stop", int_calc, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); g->percentage_to_stop->u.i = 2; #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "Stopper initialized"); #endif return((caddr_t)g); } static caddr_t stopper_start(g) register Stopper *g; { ev_enqueue(EV_CHECK_STOP, (Component *)g, (Component *)g, ev_now() + g->interval_length_to_stop->u.i / USECS_PER_TICK, g->action, (Packet *)NULL, (caddr_t)NULL); return((caddr_t)g); } static caddr_t stopper_delete(g) register Stopper *g; { comp_delete((Component *)g); stopper_adr = (Stopper *) NULL; return((caddr_t)g); } static caddr_t stopper_reset(g) Stopper *g; { g->stop_set.tail = -1; g->stop_set.front = -1; g->stop_set.total = 0; g->stop_set.old_total_data = 0; return (caddr_t) g; } static caddr_t check_stop(g) register Stopper *g; { double average, lower, upper; int index; char dummy[10]; g->stop_set.tail = ((g->stop_set.tail)+1) % g->no_of_intervals_to_stop->u.i; if (g->stop_set.tail == g->stop_set.front) { g->stop_set.total-= g->stop_set.values[g->stop_set.front]; g->stop_set.front = ((g->stop_set.front)+1) % g->no_of_intervals_to_stop->u.i; } g->stop_set.values[g->stop_set.tail] = pm_adr->tot_bytes_acked - g->stop_set.old_total_data; g->stop_set.old_total_data = pm_adr->tot_bytes_acked; g->stop_set.total += g->stop_set.values[g->stop_set.tail]; if (g->stop_set.front == -1) g->stop_set.front = 0; if ((g->stop_set.tail+1) % g->no_of_intervals_to_stop->u.i == g->stop_set.front) { /* we have enough points */ average = g->stop_set.total / g->no_of_intervals_to_stop->u.i; lower = average * (1 - (double) g->percentage_to_stop->u.i / 100.0); upper = average * (1 + (double) g->percentage_to_stop->u.i / 100.0); for (index = 0; index < g->no_of_intervals_to_stop->u.i && g->stop_set.values[index] >= lower && g->stop_set.values[index] <= upper ; index++) ; if (index >= g->no_of_intervals_to_stop->u.i) { if (doXstuff) { the_environment.single_step = 1; #ifndef NoX #ifdef MOTIF SetOperatingModeButtons(EVENT_STEP_MODE); #else set_control_name(RUN_STEP, "EVENT STEP"); /* XClearWindow(the_environment.the_display, control_types[RUN_STEP].window); */ paint_controls(RUN_STEP); #endif printx("Stopper: Condition true, changing to EVENT STEP mode."); sleep(5); xprintclear(); #endif /* NoX */ return((caddr_t)g); } else { (void) save_snapshot(comps, snapname); sim_stop(comps); exit(0); } } } ev_enqueue(EV_CHECK_STOP, (Component *)g, (Component *)g, ev_now() + g->interval_length_to_stop->u.i / USECS_PER_TICK, g->action, (Packet *)NULL, (caddr_t)NULL); return((caddr_t)g); }