singrdk/base/Applications/Network/UdpBlast/UdpBlast.cs

262 lines
9.1 KiB
C#

////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note: Simple Singularity test program.
//
using System;
using System.Diagnostics;
using System.Net.IP;
using System.Threading;
using Microsoft.Singularity;
using Microsoft.SingSharp;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using NetStack.Contracts;
using NetStack.Channels.Public;
using Microsoft.Contracts;
using Microsoft.SingSharp.Reflection;
using Microsoft.Singularity.Applications;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Configuration;
[assembly: Transform(typeof(ApplicationResourceTransform))]
namespace Microsoft.Singularity.Applications.Network
{
[ConsoleCategory(HelpMessage="Send UDP data to and ipAddress and port",
DefaultAction=true)]
internal class Parameters {
[InputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
[OutputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
[Endpoint]
public readonly TRef<UdpContract.Imp:Start> udpRef;
[LongParameter("p", Mandatory=false, HelpMessage="Packet size (bytes)", Default = 1500)]
internal long packetBytes;
[LongParameter("r", Mandatory=false, HelpMessage="Transmission rate in bits per second", Default = 64000)]
internal long bitsPerSecond;
[LongParameter("t", Mandatory=false, HelpMessage="Seconds to send packets for", Default = 30)]
internal long seconds;
[BoolParameter("v", Mandatory=false, HelpMessage="Verbose output", Default = true)]
internal bool verbose;
[StringParameter("Address", Mandatory=true, Position=0, HelpMessage="Destination IP Address")]
internal string address;
[LongParameter("port", Mandatory=true, Position=1, HelpMessage="Destination UDP port")]
internal long port;
reflective internal Parameters();
internal int AppMain() {
return UdpBlast.AppMain(this);
}
}
public class UdpBlast
{
private const uint FixedHeaderBytes = 42; // Ether + IP + UDP
private static bool verbose;
public static void VerboseWriteLine(string format,
params Object [] args)
{
string msg = String.Format(format, args);
DebugStub.WriteLine(msg);
if (verbose) {
Console.WriteLine(format, args);
}
}
private static void
SendPackets(
UdpConnectionContract.Imp:ReadyState! udpConn,
long bitsPerSecond,
uint bytesPerPacket,
long durationSeconds
)
{
DateTime startTime = DateTime.Now;
DateTime endTime = (startTime +
TimeSpan.FromSeconds(durationSeconds));
DateTime secondStart = startTime;
DateTime secondEnd = startTime + TimeSpan.FromSeconds(1);
DateTime now = startTime;
uint second = 0;
long bitsThisSecond = 0;
long totalBits = 0;
int totalPackets = 0;
VerboseWriteLine("UdpBlast: {0} bytesPerPacket, Limiting transfer to {1} bitsPerSecond, for {2} seconds",
bytesPerPacket, bitsPerSecond, durationSeconds);
while (now < endTime) {
int pps = 0;
while (now < secondEnd && bitsThisSecond < bitsPerSecond) {
// XXX: Just bursting packets out for
// now rather than pacing them,
// interested mainly in saturation case.
byte[] in ExHeap pkt;
uint pktSize;
if ((long)bytesPerPacket * 8 < bitsPerSecond - bitsThisSecond) {
pktSize = bytesPerPacket;
}
else {
// Send a final runt packet for this cycle to keep us under
// the agreed total bits per second rate.
pktSize = (uint)((bitsPerSecond - bitsThisSecond) / 8);
if (pktSize <= FixedHeaderBytes) {
pktSize = FixedHeaderBytes + 1;
}
}
pkt = new [ExHeap] byte [pktSize - FixedHeaderBytes];
udpConn.SendWrite(pkt);
udpConn.RecvOK();
bitsThisSecond += pktSize * 8;
now = DateTime.Now;
pps++;
totalPackets++;
}
while (now < secondEnd) {
Thread.Sleep(0);
now = DateTime.Now;
}
TimeSpan tau = secondEnd - secondStart;
long bytesPerSecond = (bitsThisSecond / tau.TotalSeconds) / 8;
VerboseWriteLine(
"Round {0} duration(secs) {1:f2} rate (pps) {2} rate (bps) {3:e3}, bytes/sec {4:e3}",
second, tau.TotalSeconds,
pps,
bitsThisSecond / tau.TotalSeconds,
bytesPerSecond);
second++;
totalBits += bitsThisSecond;
bitsThisSecond = 0;
secondStart = now;
secondEnd = now + TimeSpan.FromSeconds(1);
}
Console.WriteLine(
"Average rate: packets/sec {0}, bits/sec {1:e3}, bytes/sec {2:e3}",
totalPackets / (now - startTime).TotalSeconds,
totalBits / (now - startTime).TotalSeconds,
(totalBits / (now - startTime).TotalSeconds) / 8
);
}
public static int
Blast(
[Claims] UdpConnectionContract.Imp:ReadyState! udpConn,
IPv4 address,
ushort port,
long bitsPerSecond,
long bytesPerPacket,
long durationSeconds
)
{
Console.WriteLine("UdpBlast({0}, {1})", address, port);
try {
udpConn.SendConnectWithAnyLocalEndPoint((uint)address, port);
switch receive {
case udpConn.OK() :
// success;
Console.WriteLine("Connected");
break;
case udpConn.InvalidEndPoint(ip, rejectedPort) :
throw new Exception("udpConn address and port rejected");
case udpConn.ChannelClosed() :
throw new Exception("udpConn channel closed");
}
SendPackets(udpConn,
bitsPerSecond,
(uint)bytesPerPacket,
durationSeconds);
Console.WriteLine("Closing connection");
udpConn.SendClose();
}
catch (Exception e) {
Console.WriteLine("Unexpected exception: {0}", e);
}
finally {
delete udpConn;
}
return 0;
}
internal static int AppMain(Parameters! config)
{
IPv4 host;
try {
host = IPv4.Parse(config.address);
}
catch (FormatException e) {
Console.WriteLine("{0}: {1}", e, config.address);
return -1;
}
if (config.port > 65536 || config.port < 0) {
Console.WriteLine("Port number out of range: {0}", config.port);
return -1;
}
ushort port = (ushort) config.port;
if ((uint)config.packetBytes < FixedHeaderBytes) {
Console.WriteLine("Packet size needs to be larger than fixed header size ({0} bytes)", FixedHeaderBytes);
return -1;
}
UdpBlast.verbose = config.verbose;
UdpContract.Imp udpConn = ((!)config.udpRef).Acquire();
if (udpConn == null) {
Console.WriteLine("Could not initialize TCP endpoint.");
return 1;
}
udpConn.RecvReady();
UdpConnectionContract.Imp! connImp;
UdpConnectionContract.Exp! connExp;
UdpConnectionContract.NewChannel(out connImp, out connExp);
udpConn.SendCreateUdpSession(connExp);
connImp.RecvReady();
delete udpConn;
return Blast(connImp,
host, port,
config.bitsPerSecond,
config.packetBytes,
config.seconds
);
}
} // end class UdpBlast
}