예제 #1
0
void *thread_body(void *arg) {
  
  int ret;
  int nperiods;
  struct sched_param param;
  timing_point_t *timings;
  pid_t tid;
  struct sched_attr attr;
  unsigned int flags = 0;
  struct timespec t, t_next;
  timing_point_t tmp_timing;
  timing_point_t *curr_timing;
  unsigned long t_start_usec;
  int i = 0;

  thread_data_t *data = (thread_data_t*) arg;

  /* set thread affinity */
  if (data->cpuset != NULL) {
    log_notice("[%d] setting cpu affinity to CPU(s) %s",
      data->ind, data->cpuset_str);
    ret = pthread_setaffinity_np(pthread_self(),
      sizeof(cpu_set_t), data->cpuset);
    if (ret < 0) {
      errno = ret;
      perror("pthread_setaffinity_np");
      exit(EXIT_FAILURE);
    }
  }

  /* set scheduling policy and print pretty info on stdout */
  log_notice("[%d] Using %s policy:", data->ind, data->sched_policy_descr);
  switch (data->sched_policy) {
    case rr:
    case fifo:
      fprintf(data->log_handler, "# Policy : %s\n",
        (data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO"));
      param.sched_priority = data->sched_prio;
      ret = pthread_setschedparam(pthread_self(),
        data->sched_policy, &param);
      if (ret != 0) {
        errno = ret; 
        perror("pthread_setschedparam"); 
        exit(EXIT_FAILURE);
      }

      log_notice("[%d] starting thread with period: %" PRIu64 
        ", exec: %" PRIu64 ",""deadline: %" PRIu64 ", priority: %d",
        data->ind,
        timespec_to_usec(&data->period), 
        timespec_to_usec(&data->min_et),
        timespec_to_usec(&data->deadline),
        data->sched_prio
      );
      break;
    case other:
      fprintf(data->log_handler, "# Policy : SCHED_OTHER\n");
      log_notice("[%d] starting thread with period: %" PRIu64 
           ", exec: %" PRIu64 ",""deadline: %" PRIu64 "", data->ind,
        timespec_to_usec(&data->period), 
        timespec_to_usec(&data->min_et),
        timespec_to_usec(&data->deadline)
      );
      data->lock_pages = 0; /* forced off for SCHED_OTHER */
      break;
    case deadline:
      fprintf(data->log_handler, "# Policy : SCHED_DEADLINE\n");
      tid = gettid();
      attr.size = sizeof(attr);
      attr.sched_flags = data->sched_flags;
      if (data->sched_flags && SCHED_FLAG_SOFT_RSV)
        fprintf(data->log_handler, "# Type : SOFT_RSV\n");
      else
        fprintf(data->log_handler, "# Type : HARD_RSV\n");
      attr.sched_policy = SCHED_DEADLINE;
      attr.sched_priority = 0;
      attr.sched_runtime = timespec_to_nsec(&data->max_et) +
        (timespec_to_nsec(&data->max_et) /100) * BUDGET_OVERP;
      attr.sched_deadline = timespec_to_nsec(&data->period);
      attr.sched_period = timespec_to_nsec(&data->period);  
      break;
    default:
      log_error("Unknown scheduling policy %d",
        data->sched_policy);
      exit(EXIT_FAILURE);
  }

  if (data->lock_pages == 1) {
    log_notice("[%d] Locking pages in memory", data->ind);
    ret = mlockall(MCL_CURRENT | MCL_FUTURE);
    if (ret < 0) {
      errno = ret;
      perror("mlockall");
      exit(EXIT_FAILURE);
    }
  }

  /* if we know the duration we can calculate how many periods we will
   * do at most, and the log to memory, instead of logging to file.
   */
  timings = NULL;
  if (data->duration > 0) {
    nperiods = (int) ceil( (data->duration * 10e6) / 
              (double) timespec_to_usec(&data->period));
    timings = malloc ( nperiods * sizeof(timing_point_t));
  }

  fprintf(data->log_handler, "#idx\tperiod\tmin_et\tmax_et\trel_st\tstart"
           "\t\tend\t\tdeadline\tdur.\tslack\tresp_t"
           "\tBudget\tUsed Budget\n");

  if (data->ind == 0) {
    clock_gettime(CLOCK_MONOTONIC, &t_zero);
#ifdef TRACE_SETS_ZERO_TIME
    if (opts.ftrace)
      log_ftrace(ft_data.marker_fd,
           "[%d] sets zero time",
           data->ind);
#endif
  }

  pthread_barrier_wait(&threads_barrier);

  /*
   * Set the task to SCHED_DEADLINE as far as possible touching its
   * budget as little as possible for the first iteration.
   */
  if (data->sched_policy == SCHED_DEADLINE) {
    ret = sched_setattr(tid, &attr, flags);
    if (ret != 0) {
      log_critical("[%d] sched_setattr "
        "returned %d", data->ind, ret);
      errno = ret;
      perror("sched_setattr");
      exit(EXIT_FAILURE);
    }
  }

  t = t_zero;
  t_next = msec_to_timespec(1000LL);
  t_next = timespec_add(&t, &t_next);
  clock_nanosleep(CLOCK_MONOTONIC, 
    TIMER_ABSTIME, 
    &t_next,
    NULL);

  data->deadline = timespec_add(&t_next, &data->deadline);

  while (continue_running) {
    int pn;
    struct timespec t_start, t_end, t_diff, t_slack, t_resp;

    /* Thread numeration reported starts with 1 */
#ifdef TRACE_BEGINS_LOOP
    if (opts.ftrace)
      log_ftrace(ft_data.marker_fd, "[%d] begins job %d", data->ind+1, i);
#endif
    clock_gettime(CLOCK_MONOTONIC, &t_start);
    if (data->nphases == 0) {
      compute(data->ind, &data->min_et, NULL, 0);
    } else {
      for (pn = 0; pn < data->nphases; pn++) {
        log_notice("[%d] phase %d start", data->ind+1, pn);
        exec_phase(data, pn);
        log_notice("[%d] phase %d end", data->ind+1, pn);
      }
    }
    clock_gettime(CLOCK_MONOTONIC, &t_end);
    
    t_diff = timespec_sub(&t_end, &t_start);
    t_slack = timespec_sub(&data->deadline, &t_end);
    t_resp = timespec_sub(&t_end, &t_next);
    t_start_usec = timespec_to_usec(&t_start); 

    if (i < nperiods) {
      if (timings)
        curr_timing = &timings[i];
      else
        curr_timing = &tmp_timing;

      curr_timing->ind = data->ind;
      curr_timing->period = timespec_to_usec(&data->period);
      curr_timing->min_et = timespec_to_usec(&data->min_et);
      curr_timing->max_et = timespec_to_usec(&data->max_et);
      curr_timing->rel_start_time = 
        t_start_usec - timespec_to_usec(&data->main_app_start);
      curr_timing->abs_start_time = t_start_usec;
      curr_timing->end_time = timespec_to_usec(&t_end);
      curr_timing->deadline = timespec_to_usec(&data->deadline);
      curr_timing->duration = timespec_to_usec(&t_diff);
      curr_timing->slack =  timespec_to_lusec(&t_slack);
      curr_timing->resp_time =  timespec_to_usec(&t_resp);
    }
    if (!timings)
      log_timing(data->log_handler, curr_timing);

    t_next = timespec_add(&t_next, &data->period);
    data->deadline = timespec_add(&data->deadline, &data->period);
#ifdef TRACE_END_LOOP
    if (opts.ftrace)
      log_ftrace(ft_data.marker_fd, "[%d] end loop %d", data->ind, i);
#endif
    if (curr_timing->slack < 0)
      log_notice("[%d] DEADLINE MISS !!!", data->ind+1);
    i++;
  }

  free(timings);
}
예제 #2
0
void* trans_main(void* arg){

    gd_thread_data_t *tdata = (gd_thread_data_t *) arg;
    int id = tdata->ind;

    thread_common(pthread_self(), tdata);
    unsigned long abs_period_start = timespec_to_usec(&tdata->main_start);


    gd_timing_meta_t *timings;
    long duration_usec = (tdata->duration * 1e6);
    int nperiods = (int) ceil( duration_usec /
            (double) timespec_to_usec(&tdata->period));
    timings = (gd_timing_meta_t*) malloc ( nperiods * sizeof(gd_timing_meta_t));
    gd_timing_meta_t* timing;


    struct timespec t_next, t_deadline, trans_start, trans_end, t_temp, t_now;

    t_next = tdata->main_start;
    int period = 0;
    int bs_id  = ((int)(id/num_ants));
    int subframe_id;

    while(running && (period < nperiods)){


        subframe_id = period%(num_cores_bs);

        // get current deadline and next period
        t_deadline = timespec_add(&t_next, &tdata->deadline);
        t_next = timespec_add(&t_next, &tdata->period);

        clock_gettime(CLOCK_MONOTONIC, &trans_start);
        /******* Main transport ******/
        if (debug_trans==1) {
            int j, k;
            for(j=0; j <60000; j++){k=k+1;}
        } else {
            gd_trans_read(tdata->conn_desc);
        }
        /******* Main transport ******/


        pthread_mutex_lock(&subframe_mutex[bs_id*num_cores_bs + subframe_id]);
        // subframe_avail[bs_id*num_cores_bs + subframe_id] = (subframe_avail[bs_id*num_cores_bs + subframe_id]+1)%(num_ants);
        subframe_avail[bs_id*num_cores_bs + subframe_id] ++;
		// printf("subframe_avail:%d %d\n",bs_id*num_cores_bs + subframe_id,subframe_avail[bs_id*num_cores_bs + subframe_id]);


        // hanging fix -- if trans misses a proc, reset the subframe available counter
        if (subframe_avail[bs_id*num_cores_bs + subframe_id] == (num_ants+1)) {
               subframe_avail[bs_id*num_cores_bs + subframe_id] = 1;
        }

        pthread_cond_signal(&subframe_cond[bs_id*num_cores_bs + subframe_id]);
        pthread_mutex_unlock(&subframe_mutex[bs_id*num_cores_bs + subframe_id]);


        clock_gettime(CLOCK_MONOTONIC, &trans_end);
        /*****************************/

        timing = &timings[period];
        timing->ind = id;
        timing->period = period;
        timing->abs_period_time = timespec_to_usec(&t_next);
        timing->rel_period_time = timing->abs_period_time - abs_period_start;

        timing->abs_start_time = timespec_to_usec(&trans_start);
        timing->rel_start_time = timing->abs_start_time - abs_period_start;
        timing->abs_end_time = timespec_to_usec(&trans_end);
        timing->rel_end_time = timing->abs_end_time - abs_period_start;
        timing->abs_deadline = timespec_to_usec(&t_deadline);
        timing->rel_deadline = timing->abs_deadline - abs_period_start;
        timing->actual_duration = timing->rel_end_time - timing->rel_start_time;
        timing->miss = (timing->rel_deadline - timing->rel_end_time >= 0) ? 0 : 1;

        if (timing->actual_duration > 1000){
            // log_critical("Transport overload. Thread[%d] Duration= %lu us. Reduce samples or increase threads",
                // tdata->ind, timing->actual_duration);
        }

        clock_gettime(CLOCK_MONOTONIC, &t_now);

        // check if deadline was missed
        if (timespec_lower(&t_now, &t_next)){
            // sleep for remaining time
            clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
        }else{
            printf("Transport %d is too slow\n", id);
        }

        period ++;

    }
    clock_gettime(CLOCK_MONOTONIC, &t_temp);
    log_notice("Trans thread [%d] ran for %f s", id, ((float) (timespec_to_usec(&t_temp)-abs_period_start))/1e6);


    fprintf(tdata->log_handler, "#idx\t\tabs_period\t\tabs_deadline\t\tabs_start\t\tabs_end"
                   "\t\trel_period\t\trel_start\t\trel_end\t\tduration\t\tmiss\n");


    int i;
    for (i=0; i < nperiods; i++){
        log_timing(tdata->log_handler, &timings[i]);
    }
    fclose(tdata->log_handler);
    log_notice("Exit trans thread %d", id);

    running = 0;
    for (i=0;i<proc_nthreads;i++) {
            pthread_mutex_lock(&subframe_mutex[i]);
            subframe_avail[i]=-1;
            pthread_cond_signal(&subframe_cond[i]);
            pthread_mutex_unlock(&subframe_mutex[i]);
    }

    pthread_exit(NULL);
}
예제 #3
0
/*
 * Transmit a packet (called by the kernel)
 */
int virt_tx(struct sk_buff *skb, struct net_device *dev)
{
    int rtn = 0;
    struct virt_priv *priv = netdev_priv(dev);
    struct device_node *slave = NULL;
    int payload_len;

    struct packet *pkt = NULL;

#ifndef VIRT_USE_RTABLE
    struct net_device *out_dev = NULL;
#endif

    //VIRT_DBG("in virt_tx...\n");
    if( use_timing() )
        log_timing(TIMING_TX_START);

    // if no slaves default off => drop packet
    if(get_slave_list_head() == NULL)
        goto drop;

    /* For flow byte counts, we are interested in network layer and above. */
    payload_len = skb->len;

    dev->trans_start = jiffies; /* save the timestamp */

    if( use_timing() )
        log_timing(TIMING_TX_SETUP);

    //malloc packet struct and flow struct
    pkt = kmalloc(sizeof(struct packet), GFP_ATOMIC);
    if(!pkt)
        goto drop;
    memset(pkt, 0, sizeof(struct packet));

    pkt->key = kmalloc(sizeof(struct flow_tuple), GFP_ATOMIC);
    if(!pkt->key)
        goto drop_and_free;
    memset(pkt->key, 0, sizeof(struct flow_tuple));

    pkt->hdr_ptrs = kmalloc(sizeof(struct hdr_ptrs), GFP_ATOMIC);
    if(!pkt->hdr_ptrs)
        goto drop_and_free;
    memset(pkt->hdr_ptrs, 0, sizeof(struct hdr_ptrs));

    pkt->master = dev;
    pkt->skb = skb;

    if( use_timing() )
        log_timing(TIMING_TX_PARSE);

    rtn = virt_parse_egress_pkt(pkt);

    if( ntohs(pkt->key->net_proto) == ETH_P_ARP )
        goto drop_and_free;

    if( use_timing() )
        log_timing(TIMING_TX_LOOKUP);

    // lookup flow route info
    if(virt_egress_lookup_flow(priv, pkt) < 0)
        goto drop_and_free;

    /* Update policy hit statistics. */
    if(pkt->policy) {
        struct policy_stats *stats = &pkt->policy->stats;
        stats->tx_packets++;
        stats->tx_bytes += skb->len;
    }

    // route the packet
    if( use_timing() )
        log_timing(TIMING_TX_MANGLE);

    switch(POLICY_ACTION(pkt->policy->action)) {
        case POLICY_ACT_PASS:
            slave = select_local_interface(priv, pkt->ftable_entry, NULL, get_slave_list_head());
            if(!slave)
                goto drop_and_free;

            VIRT_DBG("egress PASS this packet\n");

            /* TODO: It would be nice if PASSed packets would still go through
             * netfilter, especially the post-routing hook, so that we could
             * make use of netfilter's NAT function.  However, the netfilter
             * hooks rely on routing information being filled in, so we would
             * have to play along with the routing code.
             *
             * if(nf_hook(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, 
             *      slave->dev, dev_queue_xmit) == NF_ACCEPT)
             *      dev_queue_xmit(skb);
             */
            break;
        case POLICY_ACT_LISP:
        case POLICY_ACT_NAT:
            slave = select_local_interface(priv, pkt->ftable_entry, NULL, get_slave_list_head());
            if(!slave)
                goto drop_and_free;

            VIRT_DBG("egress NAT this packet\n");
            virt_nat_egress_pkt(pkt, slave);
            break;
        case POLICY_ACT_ENCAP:
            {
                struct remote_node *rnode = pkt->ftable_entry->rnode;
                
                if(!rnode) {
                    rnode = select_remote_node(priv, pkt);
                    if(!rnode) {
                        VIRT_DBG("routing packet failed\n");
                        goto drop_and_free;
                    }

                    pkt->ftable_entry->rnode = rnode;
                }

                virt_queue_tx(priv, pkt, rnode);
                return NETDEV_TX_OK;
            }
        case POLICY_ACT_DROP:
            VIRT_DBG("egress DROP this packet\n");
            goto drop_and_free;
        default:
            // unknown route policy
            VIRT_DBG("egress ERROR: unknown policy action (%x)\n", pkt->policy->action);
    }

    // update flow statistics
    pkt->flow_stats->tx_packets++;
    pkt->flow_stats->tx_bytes += payload_len;
    pkt->flow_stats->last_tx_dev = slave->dev->ifindex;
    // update device statistics
    priv->stats.tx_packets++;
    priv->stats.tx_bytes += skb->len;
    // update link statistics
    slave->stats.tx_packets++;
    slave->stats.tx_bytes += skb->len;

    VIRT_DBG("transmitting the packet...\n\n");
    if( use_timing() )
        log_timing(TIMING_TX_END);

#ifdef VIRT_USE_RTABLE
    uint32_t gw_ip = 0x020FA8C0;
    struct rtable *rt = skb_rtable(skb);
    struct iphdr *ip = ip_hdr(skb);

    VIRT_DBG("routing %x->%x (%s)\n", ntohl(ip->saddr), ntohl(ip->daddr),
            slave->dev->name);
    struct flowi fl = {
//        .oif = pkt->slave->dev->iflink,
        .oif = slave->dev->ifindex,
        .nl_u = {
            .ip4_u = {
                .daddr = ip->daddr,
                .saddr = ip->saddr,
                .tos = 0,
            },
        },
        .proto = IPPROTO_IP,
    };