Beispiel #1
0
/*------------------------------------------------------------------------
 * int request_stop(session_t *session);
 *
 * Requests that the server stop transmitting data for the current
 * file transfer in the given session.  This is done by sending a
 * retransmission request with a type of REQUEST_STOP.  Returns 0 on
 * success and non-zero otherwise.  Success means that we successfully
 * requested, not that we successfully halted.
 *------------------------------------------------------------------------*/
func (s *Session) requestStop() error {
	var retransmission []tsunami.Retransmission = []tsunami.Retransmission{tsunami.Retransmission{0, 0, 0}}
	retransmission[0].RequestType = tsunami.REQUEST_STOP

	/* send out the request */
	_, err := s.connection.Write(tsunami.Retransmissions(retransmission).Bytes())
	if err != nil {
		return err
	}
	return nil
}
Beispiel #2
0
/*------------------------------------------------------------------------
 * int update_stats(session_t *session);
 *
 * This routine must be called every interval to update the statistics
 * for the progress of the ongoing file transfer.  Returns 0 on success
 * and non-zero on failure.  (There is not currently any way to fail.)
 *------------------------------------------------------------------------*/
func (s *Session) updateStats() {
	now_epoch := time.Now() /* the current Unix epoch                         */
	var delta int64         /* time delta since last statistics update (usec) */
	var delta_total int64   /* time delta since start of transmission (usec)  */
	var temp int64          /* temporary value for building the elapsed time  */

	var data_total float64       /* the total amount of data transferred (bytes)   */
	var data_this float64        /* the amount of data since last stat time        */
	var data_this_rexmit float64 /* the amount of data in received retransmissions */
	// var data_this_goodpt float64     /* the amount of data as non-lost packets         */
	var retransmits_fraction float64 /* how many retransmit requests there were vs received blocks */

	retransmission := make([]tsunami.Retransmission, 1)

	stats := &s.tr.stats

	/* find the total time elapsed */
	delta = tsunami.Get_usec_since(stats.thisTime)
	temp = tsunami.Get_usec_since(stats.startTime)
	milliseconds := (temp % 1000000) / 1000
	temp /= 1000000
	seconds := temp % 60
	temp /= 60
	minutes := temp % 60
	temp /= 60
	hours := temp

	d_seconds := delta / 1e6
	d_seconds_total := delta_total / 1e6

	/* find the amount of data transferred (bytes) */
	data_total = float64(s.param.blockSize) * float64(stats.totalBlocks)
	data_this = float64(s.param.blockSize) * float64(stats.totalBlocks-stats.thisBlocks)
	data_this_rexmit = float64(s.param.blockSize) * float64(stats.thisFlowRetransmitteds)
	// data_this_goodpt = float64(s.param.blockSize) * float64(stats.thisFlowOriginals)

	/* get the current UDP receive error count reported by the operating system */
	stats.thisUdpErrors = tsunami.Get_udp_in_errors()

	/* precalculate some fractions */
	retransmits_fraction = float64(stats.thisRetransmits) / (1.0 + float64(stats.thisRetransmits+stats.totalBlocks-stats.thisBlocks))
	ringfill_fraction := float64(s.tr.ringBuffer.countData) / MAX_BLOCKS_QUEUED
	total_retransmits_fraction := float64(stats.totalRetransmits) / float64(stats.totalRetransmits+stats.totalBlocks)

	/* update the rate statistics */
	// incoming transmit rate R = goodput R (Mbit/s) + retransmit R (Mbit/s)
	stats.thisTransmitRate = 8.0 * data_this / float64(d_seconds*u_mega)
	stats.thisRetransmitRate = 8.0 * data_this_rexmit / float64(d_seconds*u_mega)
	data_total_rate := 8.0 * data_total / float64(d_seconds_total*u_mega)

	fb := float64(s.param.history) / 100.0 // feedback
	ff := 1.0 - fb                         // feedforward

	// IIR filter rate R
	stats.transmitRate = fb*stats.transmitRate + ff*stats.thisRetransmitRate

	// IIR filtered composite error and loss, some sort of knee function
	stats.errorRate = fb*stats.errorRate + ff*500*100*(retransmits_fraction+ringfill_fraction)

	/* send the current error rate information to the server */
	retransmission[0].RequestType = tsunami.REQUEST_ERROR_RATE
	retransmission[0].ErrorRate = uint32(s.tr.stats.errorRate)
	_, err := s.connection.Write(tsunami.Retransmissions(retransmission).Bytes())
	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not send error rate information", err)
		return
	}

	/* build the stats string */
	statsFlags := s.statsFlags()
	//matlab
	// format := "%02d\t%02d\t%02d\t%03d\t%4u\t%6.2f\t%6.1f\t%5.1f\t%7u\t%6.1f\t%6.1f\t%5.1f\t%5d\t%5d\t%7u\t%8u\t%8Lu\t%s\n"
	format := "%02d:%02d:%02d.%03d %4u %6.2fM %6.1fMbps %5.1f%% %7u %6.1fG %6.1fMbps %5.1f%% %5d %5d %7u %8u %8u %s\n"
	/* print to the transcript if the user wants */
	statusLine := fmt.Sprintf(format, hours, minutes, seconds, milliseconds,
		stats.totalBlocks-stats.thisBlocks,
		stats.thisRetransmitRate,
		stats.thisTransmitRate,
		100.0*retransmits_fraction,
		s.tr.stats.totalBlocks,
		data_total/float64(u_giga),
		data_total_rate,
		100.0*total_retransmits_fraction,
		s.tr.retransmit.indexMax,
		s.tr.ringBuffer.countData,
		s.tr.blocksLeft,
		stats.thisRetransmits,
		uint64(stats.thisUdpErrors-stats.startUdpErrors),
		statsFlags)

	/* give the user a show if they want it */
	if s.param.verbose {
		/* screen mode */
		if s.param.outputMode == SCREEN_MODE {
			fmt.Printf("\033[2J\033[H")
			fmt.Printf("Current time:   %s\n", now_epoch.Format(time.RFC3339))
			fmt.Printf("Elapsed time:   %02d:%02d:%02d.%03d\n\n", hours, minutes, seconds, milliseconds)
			fmt.Printf("Last interval\n--------------------------------------------------\n")
			fmt.Printf("Blocks count:     %u\n", stats.totalBlocks-stats.thisBlocks)
			fmt.Printf("Data transferred: %0.2f GB\n", data_this/float64(u_giga))
			fmt.Printf("Transfer rate:    %0.2f Mbps\n", stats.thisTransmitRate)
			fmt.Printf("Retransmissions:  %u (%0.2f%%)\n\n", stats.thisRetransmits, 100.0*retransmits_fraction)
			fmt.Printf("Cumulative\n--------------------------------------------------\n")
			fmt.Printf("Blocks count:     %u\n", s.tr.stats.totalBlocks)
			fmt.Printf("Data transferred: %0.2f GB\n", data_total/float64(u_giga))
			fmt.Printf("Transfer rate:    %0.2f Mbps\n", data_total_rate)
			fmt.Printf("Retransmissions:  %u (%0.2f%%)\n", stats.totalRetransmits, 100.0*total_retransmits_fraction)
			fmt.Printf("Flags          :  %s\n\n", statsFlags)
			fmt.Printf("OS UDP rx errors: %u\n", uint64(stats.thisUdpErrors-stats.startUdpErrors))

			/* line mode */
		} else {
			// s.iteration++
			// if s.iteration%23 == 0 {
			// 	fmt.Printf("             last_interval                   transfer_total                   buffers      transfer_remaining  OS UDP\n")
			// 	fmt.Printf("time          blk    data       rate rexmit     blk    data       rate rexmit queue  ring     blk   rt_len      err \n")
			// }
			fmt.Printf("%s", statusLine)
		}
		os.Stdout.Sync()
	}

	s.XsriptDataLog(statusLine)

	/* reset the statistics for the next interval */
	stats.thisBlocks = stats.totalBlocks
	stats.thisRetransmits = 0
	stats.thisFlowOriginals = 0
	stats.thisFlowRetransmitteds = 0
	stats.thisTime = time.Now()
}
Beispiel #3
0
/*------------------------------------------------------------------------
 * int repeat_retransmit(session_t *session);
 *
 * Tries to repeat all of the outstanding retransmit requests for the
 * current transfer on the given session.  Returns 0 on success and
 * non-zero on error.  This also takes care of maintanence operations
 * on the transmission table, such as relocating the entries toward the
 * bottom of the array.
 *------------------------------------------------------------------------*/
func (s *Session) repeatRetransmit() error {
	var retransmission [MAX_RETRANSMISSION_BUFFER]tsunami.Retransmission

	s.tr.stats.thisRetransmits = 0
	var count uint32
	var entry uint32
	var block uint32
	transmit := &s.tr.retransmit
	// fmt.Fprintln(os.Stderr, "ttp_repeat_retransmit: index_max=", transmit.indexMax)

	/* discard received blocks from the list and prepare retransmit requests */
	for entry = 0; (entry < transmit.indexMax) && (count < MAX_RETRANSMISSION_BUFFER); entry++ {
		/* get the block number */
		block = transmit.table[entry]
		/* if we want the block */
		if block != 0 && s.gotBlock(block) == 0 {
			/* save it */
			transmit.table[count] = block
			/* insert retransmit request */
			retransmission[count].RequestType = tsunami.REQUEST_RETRANSMIT
			retransmission[count].Block = block
			count++
		}
	}

	/* if there are too many entries, restart transfer from earlier point */
	if count >= MAX_RETRANSMISSION_BUFFER {
		/* restart from first missing block */
		block = s.tr.blockCount
		if s.tr.blockCount > s.tr.gaplessToBlock+1 {
			block = s.tr.gaplessToBlock + 1
		}
		retransmission[0].RequestType = tsunami.REQUEST_RESTART
		retransmission[0].Block = block

		_, err := s.connection.Write(tsunami.Retransmissions(retransmission[:1]).Bytes())
		if err != nil {
			fmt.Fprintln(os.Stderr, "Could not send restart-at request")
			return err
		}

		/* remember the request so we can then ignore blocks that are still on the wire */
		s.tr.restartPending = true
		s.tr.restartLastIndex = transmit.table[transmit.indexMax-1]
		s.tr.restartWireClearIndex = s.tr.blockCount
		if s.tr.blockCount > s.tr.restartLastIndex+s.tr.onWireEstimate {
			s.tr.restartWireClearIndex = s.tr.restartLastIndex + s.tr.onWireEstimate
		}

		/* reset the retransmission table and head block */
		transmit.indexMax = 0
		s.tr.nextBlock = block
		s.tr.stats.thisRetransmits = MAX_RETRANSMISSION_BUFFER

		/* queue is small enough */
	} else {

		/* update to shrunken size */
		transmit.indexMax = count

		/* update the statistics */
		s.tr.stats.thisRetransmits = count
		s.tr.stats.totalRetransmits += count

		/* send out the requests */
		if count > 0 {
			_, err := s.connection.Write(tsunami.Retransmissions(retransmission[:count]).Bytes())
			if err != nil {
				fmt.Fprintln(os.Stderr, "Could not send retransmit requests")
				return err
			}
		}

	}

	fmt.Fprintln(os.Stderr, "ttp_repeat_retransmit: post-index_max=", transmit.indexMax)
	return nil
}