void net_event_handler(int event, void *data) { struct net_stack_t *stack = data; struct net_t *net = stack->net; struct net_routing_table_t *routing_table = net->routing_table; struct net_packet_t *pkt= stack->packet; struct net_node_t *src_node = pkt->msg->src_node; struct net_node_t *dst_node = pkt->msg->dst_node; struct net_node_t *node = pkt->node; struct net_buffer_t *buffer = pkt->buffer; long long cycle; /* Get current cycle */ cycle = esim_domain_cycle(net_domain_index); if ((net_snap_period != 0) && (net->last_recorded_cycle < (cycle/net_snap_period ))) net_bandwidth_snapshot(net, cycle); if (event == EV_NET_SEND) { struct net_routing_table_entry_t *entry; struct net_buffer_t *output_buffer; if (net->magicNet) { /* Magic Net work-around */ src_node->bytes_sent += pkt->size; src_node->msgs_sent++; dst_node->bytes_received += pkt->size; dst_node->msgs_received++; pkt->node = dst_node; esim_schedule_event(EV_NET_RECEIVE, stack, net->fixed_delay); } /* Get output buffer */ entry = net_routing_table_lookup(routing_table, src_node, dst_node); output_buffer = entry->output_buffer; if (!output_buffer) fatal("%s: no route from %s to %s.\n%s", net->name, src_node->name, dst_node->name, net_err_no_route); if (pkt->msg->size > output_buffer->size) panic("%s: message does not fit in buffer.\n%s", __FUNCTION__, net_err_can_send); if (output_buffer->count + pkt->size > output_buffer->size) panic("%s: output buffer full.\n%s", __FUNCTION__, net_err_can_send); /* Insert in output buffer (1 cycle latency) */ net_buffer_insert(output_buffer, pkt); output_buffer->write_busy = cycle; pkt->node = src_node; pkt->buffer = output_buffer; pkt->busy = cycle; /* Schedule next event */ esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, 1); } else if (event == EV_NET_OUTPUT_BUFFER) { struct net_buffer_t *input_buffer; int lat; /* Debug */ net_debug("msg " "a=\"obuf\" " "net=\"%s\" " "msg-->pkt=%lld-->%d " "node=\"%s\" " "buf=\"%s\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); /* If message is not at buffer head, process later */ assert(list_count(buffer->msg_list)); if (list_get(buffer->msg_list, 0) != pkt) { net_buffer_wait(buffer, event, stack); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->packet=%lld:%d " "why=\"not output buffer head\"\n", net->name, pkt->msg->id, pkt->session_id); return; } if (buffer->read_busy >= cycle) { esim_schedule_event(event, stack, buffer->read_busy - cycle + 1); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"output buffer busy\" \n", net->name, pkt->msg->id, pkt->session_id); return; } /* If link is busy, wait */ if (buffer->kind == net_buffer_link) { struct net_link_t *link; assert(buffer->link); link = buffer->link; if (link->busy >= cycle) { esim_schedule_event(event, stack, link->busy - cycle + 1); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"link busy\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:link_busy\" " "stg=\"LB\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* If buffer contain the message but doesn't have the * shared link in control, wait */ if (link->virtual_channel > 1) { struct net_buffer_t *temp_buffer; temp_buffer = net_link_arbitrator_vc(link, node); if (temp_buffer != buffer) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"arbitrator sched\"\n", net->name, pkt->msg->id, pkt->session_id); esim_schedule_event(event, stack, 1); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:VC_arbitration_fail\" " "stg=\"VCA\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } } /* If destination input buffer is busy, wait */ assert(buffer == link->src_buffer); input_buffer = link->dst_buffer; if (input_buffer->write_busy >= cycle) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"input buffer busy\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_busy\" " "stg=\"DBB\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); esim_schedule_event(event, stack, input_buffer->write_busy - cycle + 1); return; } /* If destination input buffer is full, wait */ if (pkt->size > input_buffer->size) fatal("%s: packet does not fit in buffer.\n%s", net->name, net_err_large_message); if (input_buffer->count + pkt->size > input_buffer->size) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"input buffer full\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_full\" " "stg=\"DBF\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); net_buffer_wait(input_buffer, event, stack); return; } /* Calculate latency and occupy resources */ lat = (pkt->size - 1) / link->bandwidth + 1; assert(lat > 0); buffer->read_busy = cycle + lat - 1; link->busy = cycle + lat - 1; input_buffer->write_busy = cycle + lat - 1; /* Transfer message to next input buffer */ assert(pkt->busy < cycle); net_buffer_extract(buffer, pkt); net_buffer_insert(input_buffer, pkt); pkt->node = input_buffer->node; pkt->buffer = input_buffer; pkt->busy = cycle + lat - 1; /* Stats */ link->busy_cycles += lat; link->transferred_bytes += pkt->size; link->transferred_msgs++; net->topology_util_bw += pkt->size; node->bytes_sent += pkt->size; node->msgs_sent++; input_buffer->node->bytes_received += pkt->size; input_buffer->node->msgs_received++; net_trace("net.link_transfer net=\"%s\" link=\"%s\" " "transB=%lld last_size=%d busy=%lld\n", net->name, link->name, link->transferred_bytes, pkt->size, link->busy); } else if (buffer->kind == net_buffer_bus) { struct net_bus_t *bus, *updated_bus; struct net_node_t *bus_node; assert(!buffer->link); assert(buffer->bus); bus = buffer->bus; bus_node = bus->node; /* before initiating bus transfer we have to figure out what is the * next input buffer since it is not clear from the * output buffer */ int input_buffer_detection = 0; struct net_routing_table_entry_t *entry; entry = net_routing_table_lookup(routing_table, pkt->node, pkt->msg->dst_node); for (int i = 0; i < list_count(bus_node->dst_buffer_list); i++) { input_buffer = list_get(bus_node->dst_buffer_list, i); if (entry->next_node == input_buffer->node) { input_buffer_detection = 1; break; } } if (input_buffer_detection == 0) fatal("%s: Something went wrong so there is no appropriate input" "buffer for the route between %s and %s \n", net->name, pkt->node->name,entry->next_node->name); /* 1. Check the destination buffer is busy or not */ if (input_buffer->write_busy >= cycle) { esim_schedule_event(event, stack, input_buffer->write_busy - cycle + 1); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"input busy\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_busy\" " "stg=\"DBB\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* 2. Check the destination buffer is full or not */ if (pkt->size > input_buffer->size) fatal("%s: packet does not fit in buffer.\n%s", net->name, net_err_large_message); if (input_buffer->count + pkt->size > input_buffer->size) { net_buffer_wait(input_buffer, event, stack); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"input full\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_full\" " "stg=\"DBF\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* 3. Make sure if any bus is available; return one * that is available the fastest */ updated_bus = net_bus_arbitration(bus_node, buffer); if (updated_bus == NULL) { esim_schedule_event(event, stack, 1); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"bus arbiter\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:BUS_arbit_fail\" " "stg=\"BA\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* 4. assign the bus to the buffer. update the * necessary data ; before here, the bus is not * assign to anything and is not updated so it can be * assign to other buffers as well. If this certain * buffer wins that specific bus_lane the appropriate * fields will be updated. Contains: bus_lane * cin_buffer and cout_buffer and busy time as well as * buffer data itself */ assert(updated_bus); buffer->bus = updated_bus; input_buffer->bus = updated_bus; bus = buffer->bus; assert(bus); /* Calculate latency and occupy resources */ /* Wire delay is introduced when the packet is on transit */ lat = bus->fix_delay + ((pkt->size - 1) / bus->bandwidth + 1) ; assert(lat > 0); buffer->read_busy = cycle + lat - 1; bus->busy = cycle + lat - 1; input_buffer->write_busy = cycle + lat - 1 ; /* Transfer message to next input buffer */ assert(pkt->busy < cycle); net_buffer_extract(buffer, pkt); net_buffer_insert(input_buffer, pkt); pkt->node = input_buffer->node; pkt->buffer = input_buffer; pkt->busy = cycle + lat - 1; /* Stats */ bus->busy_cycles += lat; bus->transferred_bytes += pkt->size; bus->transferred_msgs++; net->topology_util_bw += pkt->size; node->bytes_sent += pkt->size; node->msgs_sent++; input_buffer->node->bytes_received += pkt->size; input_buffer->node->msgs_received++; net_trace("net.bus_transfer net=\"%s\" node=\"%s\" " "lane_index=%d transB=%lld last_size=%d busy=%lld\n", net->name, bus->node->name, bus->index, bus->transferred_bytes, pkt->size, bus->busy); } else if (buffer->kind == net_buffer_photonic) { struct net_bus_t *bus, *updated_bus; struct net_node_t *bus_node; assert(!buffer->link); assert(buffer->bus); bus = buffer->bus; bus_node = bus->node; /* before 1 and 2 we have to figure out what is the * next input buffer since it is not clear from the * output buffer */ int input_buffer_detection = 0; struct net_routing_table_entry_t *entry; entry = net_routing_table_lookup(routing_table, pkt->node, pkt->msg->dst_node); for (int i = 0; i < list_count(bus_node->dst_buffer_list); i++) { input_buffer = list_get(bus_node->dst_buffer_list, i); if (entry->next_node == input_buffer->node) { input_buffer_detection = 1; break; } } if (input_buffer_detection == 0) fatal("%s: Something went wrong so there is no appropriate input" "buffer for the route between %s and %s \n", net->name, pkt->node->name,entry->next_node->name); /* 1. Check the destination buffer is busy or not */ if (input_buffer->write_busy > cycle) { esim_schedule_event(event, stack, input_buffer->write_busy - cycle + 1); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"input busy\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_busy\" " "stg=\"DBB\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* 2. Check the destination buffer is full or not */ if (pkt->size > input_buffer->size) fatal("%s: message does not fit in buffer.\n%s", net->name, net_err_large_message); if (input_buffer->count + pkt->size > input_buffer->size) { net_buffer_wait(input_buffer, event, stack); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"input full\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_full\" " "stg=\"DBF\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* 3. Make sure if any bus is available; return one * that is available the fastest */ updated_bus = net_photo_link_arbitration(bus_node, buffer); if (updated_bus == NULL) { esim_schedule_event(event, stack, 1); net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"bus arbiter\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:photonic_arbitration\" " "stg=\"BA\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); return; } /* 4. assign the bus to the buffer. update the * necessary data ; before here, the bus is not * assign to anything and is not updated so it can be * assign to other buffers as well. If this certain * buffer wins that specific bus_lane the appropriate * fields will be updated. Contains: bus_lane * cin_buffer and cout_buffer and busy time as well as * buffer data itself */ assert(updated_bus); buffer->bus = updated_bus; input_buffer->bus = updated_bus; bus = buffer->bus; assert(bus); /* Calculate latency and occupy resources */ lat = (pkt->size - 1) / bus->bandwidth + 1; assert(lat > 0); buffer->read_busy = cycle + lat - 1; bus->busy = cycle + lat - 1; input_buffer->write_busy = cycle + lat - 1; /* Transfer message to next input buffer */ assert(pkt->busy < cycle); net_buffer_extract(buffer, pkt); net_buffer_insert(input_buffer, pkt); pkt->node = input_buffer->node; pkt->buffer = input_buffer; pkt->busy = cycle + lat - 1; /* Stats */ bus->busy_cycles += lat; bus->transferred_bytes += pkt->size; bus->transferred_msgs++; net->topology_util_bw += pkt->size; node->bytes_sent += pkt->size; node->msgs_sent++; input_buffer->node->bytes_received += pkt->size; input_buffer->node->msgs_received++; net_trace("net.photonic_transfer net=\"%s\" node=\"%s\" " "lane_index=%d transB=%lld last_size=%d busy=%lld\n", net->name, bus->node->name, bus->index, bus->transferred_bytes,pkt->size, bus->busy); net_debug("msg " "a=\"success photonic transmission\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "through = \" %d\"\n", net->name, pkt->msg->id, pkt->session_id, updated_bus->index); } /* Schedule next event */ esim_schedule_event(EV_NET_INPUT_BUFFER, stack, lat); } else if (event == EV_NET_INPUT_BUFFER) { struct net_routing_table_entry_t *entry; struct net_buffer_t *output_buffer; int lat; /* Debug */ net_debug("msg " "a=\"ibuf\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "node=\"%s\" " "buf=\"%s\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); /* If message is not at buffer head, process later */ assert(list_count(buffer->msg_list)); if (list_get(buffer->msg_list, 0) != pkt) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d" "why=\"not-head\"\n", net->name, pkt->msg->id, pkt->session_id); net_buffer_wait(buffer, event, stack); return; } /* If this is the destination node, finish */ if (node == pkt->msg->dst_node) { esim_schedule_event(EV_NET_RECEIVE, stack, 0); return; } /* If source input buffer is busy, wait */ if (buffer->read_busy >= cycle) { net_debug("pkt" "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"src-busy\"\n", net->name, pkt->msg->id, pkt->session_id); esim_schedule_event(event, stack, buffer->read_busy - cycle + 1); return; } /* Get output buffer */ entry = net_routing_table_lookup(routing_table, node, dst_node); output_buffer = entry->output_buffer; if (!output_buffer) fatal("%s: no route from %s to %s.\n%s", net->name, node->name, dst_node->name, net_err_no_route); /* If destination output buffer is busy, wait */ if (output_buffer->write_busy >= cycle) { net_debug("pkt " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"dst-busy\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_busy\" " "stg=\"DBB\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); esim_schedule_event(event, stack, output_buffer->write_busy - cycle + 1); return; } /* If destination output buffer is full, wait */ if (pkt->size > output_buffer->size) fatal("%s: packet does not fit in buffer.\n%s", net->name, net_err_large_message); if (output_buffer->count + pkt->size > output_buffer->size) { net_debug("pkt " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"dst-full\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:Dest_buffer_full\" " "stg=\"DBF\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); net_buffer_wait(output_buffer, event, stack); return; } /* If scheduler says that it is not our turn, try later */ if (net_node_schedule(node, output_buffer) != buffer) { net_debug("pkt " "a=\"stall\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "why=\"sched\"\n", net->name, pkt->msg->id, pkt->session_id); net_trace("net.packet " "net=\"%s\" " "name=\"P-%lld:%d\" " "state=\"%s:%s:switch_arbit_fail\" " "stg=\"SA\"\n", net->name, pkt->msg->id, pkt->session_id, node->name, buffer->name); esim_schedule_event(event, stack, 1); return; } /* Calculate latency and occupy resources */ assert(node->kind != net_node_end); assert(node->bandwidth > 0); lat = (pkt->size - 1) / node->bandwidth + 1; assert(lat > 0); buffer->read_busy = cycle + lat - 1; output_buffer->write_busy = cycle + lat - 1; /* Transfer message to next output buffer */ assert(pkt->busy < cycle); net_buffer_extract(buffer, pkt); net_buffer_insert(output_buffer, pkt); pkt->buffer = output_buffer; pkt->busy = cycle + lat - 1; /* Schedule next event */ esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, lat); } else if (event == EV_NET_RECEIVE) { assert (pkt); struct net_msg_t *msg = pkt->msg; /* Debug */ net_debug("pkt " "a=\"receive\" " "net=\"%s\" " "msg-->pkt=%lld:%d " "node=\"%s\"\n", net->name, pkt->msg->id, pkt->session_id, dst_node->name); if (net_depacketizer(net, node, pkt) == 1) { if (pkt->msg->packet_list_count > 1) net_trace("net.msg net=\"%s\" name=\"M-%lld\" " "state=\"%s:depacketize\"\n", net->name, msg->id, node->name); if (stack->ret_event == ESIM_EV_NONE) { assert (msg); net_receive(net, node, msg); } /* Finish */ net_stack_return(stack); } else /* Freeing packet stack, not the message */ free(stack); } else { panic("%s: unknown event", __FUNCTION__); } }
void net_event_handler(int event, void *data) { struct net_stack_t *stack = data; struct net_t *net = stack->net; struct net_routing_table_t *routing_table = net->routing_table; struct net_msg_t *msg = stack->msg; struct net_node_t *src_node = msg->src_node; struct net_node_t *dst_node = msg->dst_node; struct net_node_t *node = msg->node; struct net_buffer_t *buffer = msg->buffer; if (event == EV_NET_SEND) { struct net_routing_table_entry_t *entry; struct net_buffer_t *output_buffer; /* Debug */ net_debug("msg " "a=\"send\" " "net=\"%s\" " "msg=%lld " "size=%d " "src=\"%s\" " "dst=\"%s\"\n", net->name, msg->id, msg->size, src_node->name, dst_node->name); /* Get output buffer */ entry = net_routing_table_lookup(routing_table, src_node, dst_node); output_buffer = entry->output_buffer; if (!output_buffer) fatal("%s: no route from %s to %s.\n%s", net->name, src_node->name, dst_node->name, net_err_no_route); if (output_buffer->write_busy >= esim_cycle) panic("%s: output buffer busy.\n%s", __FUNCTION__, net_err_can_send); if (msg->size > output_buffer->size) panic("%s: message does not fit in buffer.\n%s", __FUNCTION__, net_err_can_send); if (output_buffer->count + msg->size > output_buffer->size) panic("%s: output buffer full.\n%s", __FUNCTION__, net_err_can_send); /* Insert in output buffer (1 cycle latency) */ net_buffer_insert(output_buffer, msg); output_buffer->write_busy = esim_cycle; msg->node = src_node; msg->buffer = output_buffer; msg->busy = esim_cycle; /* Schedule next event */ esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, 1); } else if (event == EV_NET_OUTPUT_BUFFER) { struct net_link_t *link; struct net_buffer_t *input_buffer; int lat; /* Debug */ net_debug("msg " "a=\"obuf\" " "net=\"%s\" " "msg=%lld " "node=\"%s\" " "buf=\"%s\"\n", net->name, msg->id, node->name, buffer->name); /* If message is not at buffer head, process later */ assert(list_count(buffer->msg_list)); if (list_get(buffer->msg_list, 0) != msg) { net_buffer_wait(buffer, event, stack); return; } /* If source output buffer is busy, wait */ if (buffer->read_busy >= esim_cycle) { esim_schedule_event(event, stack, buffer->read_busy - esim_cycle + 1); return; } /* If link is busy, wait */ link = buffer->link; if (link->busy >= esim_cycle) { esim_schedule_event(event, stack, link->busy - esim_cycle + 1); return; } /* If buffer contain the message but doesn't have the shared link in control, wait*/ if (link->virtual_channel > 1) { struct net_buffer_t *temp_buffer; temp_buffer = net_link_arbitrator_vc(link, node); if (temp_buffer != buffer) { net_debug("msg " "a=\"arbitrator stall\" " "net=\"%s\" " "msg=%lld " "why=\"sched\"\n", net->name, msg->id); esim_schedule_event(event, stack, 1); return; } } /* If destination input buffer is busy, wait */ assert(buffer == link->src_buffer); input_buffer = link->dst_buffer; if (input_buffer->write_busy >= esim_cycle) { esim_schedule_event(event, stack, input_buffer->write_busy - esim_cycle + 1); return; } /* If destination input buffer is full, wait */ if (msg->size > input_buffer->size) fatal("%s: message does not fit in buffer.\n%s", net->name, net_err_large_message); if (input_buffer->count + msg->size > input_buffer->size) { net_buffer_wait(input_buffer, event, stack); return; } /* Calculate latency and occupy resources */ lat = (msg->size - 1) / link->bandwidth + 1; assert(lat > 0); buffer->read_busy = esim_cycle + lat - 1; link->busy = esim_cycle + lat - 1; input_buffer->write_busy = esim_cycle + lat - 1; /* Transfer message to next input buffer */ assert(msg->busy < esim_cycle); net_buffer_extract(buffer, msg); net_buffer_insert(input_buffer, msg); msg->node = input_buffer->node; msg->buffer = input_buffer; msg->busy = esim_cycle + lat - 1; /* Stats */ link->busy_cycles += lat; link->transferred_bytes += msg->size; link->transferred_msgs++; node->bytes_sent += msg->size; node->msgs_sent++; input_buffer->node->bytes_received += msg->size; input_buffer->node->msgs_received++; /* Schedule next event */ esim_schedule_event(EV_NET_INPUT_BUFFER, stack, lat); } else if (event == EV_NET_INPUT_BUFFER) { struct net_routing_table_entry_t *entry; struct net_buffer_t *output_buffer; int lat; /* Debug */ net_debug("msg " "a=\"ibuf\" " "net=\"%s\" " "msg=%lld " "node=\"%s\" " "buf=\"%s\"\n", net->name, msg->id, node->name, buffer->name); /* If message is not at buffer head, process later */ assert(list_count(buffer->msg_list)); if (list_get(buffer->msg_list, 0) != msg) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg=%lld " "why=\"not-head\"\n", net->name, msg->id); net_buffer_wait(buffer, event, stack); return; } /* If this is the destination node, finish */ if (node == msg->dst_node) { esim_schedule_event(EV_NET_RECEIVE, stack, 0); return; } /* If source input buffer is busy, wait */ if (buffer->read_busy >= esim_cycle) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg=%lld " "why=\"src-busy\"\n", net->name, msg->id); esim_schedule_event(event, stack, buffer->read_busy - esim_cycle + 1); return; } /* Get output buffer */ entry = net_routing_table_lookup(routing_table, node, dst_node); output_buffer = entry->output_buffer; if (!output_buffer) fatal("%s: no route from %s to %s.\n%s", net->name, node->name, dst_node->name, net_err_no_route); /* If destination output buffer is busy, wait */ if (output_buffer->write_busy >= esim_cycle) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg=%lld " "why=\"dst-busy\"\n", net->name, msg->id); esim_schedule_event(event, stack, output_buffer->write_busy - esim_cycle + 1); return; } /* If destination output buffer is full, wait */ if (msg->size > output_buffer->size) fatal("%s: message does not fit in buffer.\n%s", net->name, net_err_large_message); if (output_buffer->count + msg->size > output_buffer->size) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg=%lld " "why=\"dst-full\"\n", net->name, msg->id); net_buffer_wait(output_buffer, event, stack); return; } /* If scheduler says that it is not our turn, try later */ if (net_node_schedule(node, output_buffer) != buffer) { net_debug("msg " "a=\"stall\" " "net=\"%s\" " "msg=%lld " "why=\"sched\"\n", net->name, msg->id); esim_schedule_event(event, stack, 1); return; } /* Calculate latency and occupy resources */ assert(node->kind != net_node_end); assert(node->bandwidth > 0); lat = (msg->size - 1) / node->bandwidth + 1; assert(lat > 0); buffer->read_busy = esim_cycle + lat - 1; output_buffer->write_busy = esim_cycle + lat - 1; /* Transfer message to next output buffer */ assert(msg->busy < esim_cycle); net_buffer_extract(buffer, msg); net_buffer_insert(output_buffer, msg); msg->buffer = output_buffer; msg->busy = esim_cycle + lat - 1; /* Schedule next event */ esim_schedule_event(EV_NET_OUTPUT_BUFFER, stack, lat); } else if (event == EV_NET_RECEIVE) { /* Debug */ net_debug("msg " "a=\"receive\" " "net=\"%s\" " "msg=%lld " "node=\"%s\"\n", net->name, msg->id, dst_node->name); /* Stats */ net->transfers++; net->lat_acc += esim_cycle - msg->send_cycle; net->msg_size_acc += msg->size; /* If not return event was specified, free message here */ if (stack->ret_event == ESIM_EV_NONE) net_receive(net, node, msg); /* Finish */ net_stack_return(stack); } else { panic("%s: unknown event", __FUNCTION__); } }