838 lines
28 KiB
Plaintext
838 lines
28 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: MonNet.cs
|
|
//
|
|
// Note: Tool to transfer monitoring log entries over network
|
|
//
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using Microsoft.Singularity;
|
|
|
|
using Microsoft.Singularity.Channels;
|
|
using Microsoft.Singularity.Naming;
|
|
|
|
using System.Net.IP;
|
|
using NetStack.Contracts;
|
|
using NetStack.Channels.Public;
|
|
|
|
using Microsoft.Singularity.Applications.Network;
|
|
using Microsoft.Singularity.Diagnostics.Contracts;
|
|
|
|
using Microsoft.Singularity.V1.Types;
|
|
|
|
/* For contract type handle dumping: */
|
|
using Microsoft.Singularity.Io;
|
|
using Microsoft.Singularity.Io.Net;
|
|
using Microsoft.Singularity.Directory;
|
|
using Microsoft.Singularity.FileSystem;
|
|
|
|
using Thread = System.Threading.Thread;
|
|
|
|
|
|
using Microsoft.Singularity.Channels;
|
|
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 {
|
|
[ConsoleCategory(DefaultAction=true)]
|
|
internal class Parameters {
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[BoolParameter( "help", Default=false, HelpMessage="Display Extended help message.")]
|
|
internal bool doHelp;
|
|
|
|
[StringArrayParameter( "args", HelpMessage="arg bucket")]
|
|
internal string[] args;
|
|
|
|
reflective internal Parameters();
|
|
|
|
internal int AppMain() {
|
|
return Monnet.AppMain(this);
|
|
}
|
|
}
|
|
|
|
public class Monnet
|
|
{
|
|
public class Proc
|
|
{
|
|
public static ProcessContract.Imp:ReadyState BindToProcessDiagnostics()
|
|
{
|
|
ProcessContract.Exp! exp;
|
|
ProcessContract.Imp! imp;
|
|
ProcessContract.NewChannel(out imp, out exp);
|
|
|
|
// get NS endpoint
|
|
DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint();
|
|
try
|
|
{
|
|
ErrorCode errorOut;
|
|
bool ok = SdsUtils.Bind(ProcessContract.ModuleName, ns, exp, out errorOut);
|
|
if (!ok) {
|
|
delete imp;
|
|
Console.WriteLine("Bind of {0} failed. reason: {1}\n", MemoryContract.ModuleName,SdsUtils.ErrorCodeToString(errorOut) );
|
|
if (errorOut == ErrorCode.ChannelClosed)
|
|
{
|
|
throw new Exception("Encountered a ChannelClosed to NameServer");
|
|
}
|
|
return null;
|
|
}
|
|
else {
|
|
imp.RecvReady();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
delete ns;
|
|
}
|
|
return imp;
|
|
}
|
|
|
|
public static int []! GetProcessIDs(ProcessContract.Imp:ReadyState! imp)
|
|
{
|
|
int [] ids = null;
|
|
int[]! in ExHeap xids;
|
|
imp.SendGetProcessIDs();
|
|
imp.RecvProcessIDs(out xids);
|
|
// REVIEW: The kernel process is being returned twice so we're
|
|
// skipping one of the entries if the process ID matches.
|
|
int startIndex = 0;
|
|
if (xids[0] == xids[1])
|
|
startIndex++;
|
|
ids = new int[xids.Length - startIndex];
|
|
for (int i = startIndex; i < xids.Length; i++)
|
|
{
|
|
ids[i - startIndex] = xids[i];
|
|
}
|
|
delete xids;
|
|
return ids;
|
|
}
|
|
|
|
public static int [] GetProcessThreadIDs(ProcessContract.Imp:ReadyState! imp, int procID)
|
|
{
|
|
imp.SendGetProcessThreadIDs(procID);
|
|
int [] retVal = null;
|
|
|
|
switch receive
|
|
{
|
|
case imp.NotFound() :
|
|
break;
|
|
|
|
case imp.ProcessThreadIDs(int[]! in ExHeap tids) :
|
|
retVal = new int[tids.Length];
|
|
for (int i=0; i<tids.Length; i++) {
|
|
retVal[i] = tids[i];
|
|
}
|
|
delete tids;
|
|
break;
|
|
|
|
case imp.ChannelClosed() :
|
|
throw new Exception("GetProcessThreadIDs: imp channel closed");
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
public static string []! GetProcessNames(ProcessContract.Imp:ReadyState! imp, int []! ids)
|
|
{
|
|
string [] names = new string[ids.Length];
|
|
for (int i = 0; i < ids.Length; i++)
|
|
{
|
|
imp.SendGetProcessName(ids[i]);
|
|
|
|
switch receive
|
|
{
|
|
case imp.NotFound() :
|
|
break;
|
|
|
|
case imp.ProcessName(char[]! in ExHeap procName) :
|
|
names[i] = Bitter.ToString(procName);
|
|
delete procName;
|
|
break;
|
|
|
|
case imp.ChannelClosed() :
|
|
throw new Exception("GetProcessNames: imp channel closed");
|
|
}
|
|
}
|
|
return names;
|
|
}
|
|
} // public class Proc
|
|
|
|
public enum SysInfoEvent : ushort
|
|
{
|
|
CpuSpeed = 1,
|
|
ContractName = 2,
|
|
PidInfo = 3,
|
|
ThreadInfo = 4,
|
|
}
|
|
private static Monitoring.LogEntry newSysInfoEvent(SysInfoEvent type)
|
|
{
|
|
Monitoring.LogEntry ev = new Monitoring.LogEntry();
|
|
|
|
ev.provider = Monitoring.Provider.SysInfo;
|
|
ev.type = (ushort)type;
|
|
ev.version = 0;
|
|
return ev;
|
|
}
|
|
private static void postSysInfoEvent(ref Monitoring.LogEntry ev,
|
|
string msg)
|
|
{
|
|
if (msg != null) {
|
|
textlen = System.Text.Encoding.ASCII.GetBytes(msg, 0, msg.Length,
|
|
text, 0);
|
|
unsafe {
|
|
ev.text = (byte *)textlen;
|
|
}
|
|
}
|
|
|
|
int ret = Marshall(ref ev);
|
|
if (ret != 0) {
|
|
Console.WriteLine("Error marshalling sysinfo event... continuing anyway");
|
|
}
|
|
}
|
|
|
|
|
|
// Add system info (CPU speeds, memory, disks, process
|
|
// & thread run-downs) to event buffer
|
|
private static void dumpSysInfo()
|
|
{
|
|
Monitoring.LogEntry ev = newSysInfoEvent(SysInfoEvent.CpuSpeed);
|
|
|
|
// TODO: foreach CPU...
|
|
ev.cpu = 0;
|
|
ulong hz = (ulong)Processor.CyclesPerSecond;
|
|
ev.arg0 = (uint)hz;
|
|
ev.arg1 = (uint)(hz >> 32);
|
|
postSysInfoEvent(ref ev, null);
|
|
|
|
dumpContractTypeHandles();
|
|
dumpPidEntries();
|
|
|
|
// TODO: disk ID -> name rundowns
|
|
}
|
|
|
|
private static void dumpPidEntries()
|
|
{
|
|
Monitoring.LogEntry ev = newSysInfoEvent(SysInfoEvent.PidInfo);
|
|
Monitoring.LogEntry ev2 = newSysInfoEvent(SysInfoEvent.ThreadInfo);
|
|
|
|
ProcessContract.Imp:ReadyState pDiag = Proc.BindToProcessDiagnostics();
|
|
|
|
if (pDiag == null) {
|
|
}
|
|
else {
|
|
int [] procIds = Proc.GetProcessIDs(pDiag);
|
|
string [] names = Proc.GetProcessNames(pDiag,procIds);
|
|
|
|
for (int i=0; i<procIds.Length; i++) {
|
|
ev.arg0 = (uint)procIds[i];
|
|
postSysInfoEvent(ref ev,names[i]);
|
|
|
|
int [] threads = Proc.GetProcessThreadIDs(pDiag, procIds[i]);
|
|
if (threads != null) {
|
|
for (int j=0; j< threads.Length; j++) {
|
|
ev2.arg0 = (uint) threads[j];
|
|
ev2.arg1 = (uint) procIds[i];
|
|
postSysInfoEvent(ref ev2, null);
|
|
}
|
|
}
|
|
}
|
|
delete pDiag;
|
|
}
|
|
}
|
|
|
|
// list of interesting contracts we dump SystemType handles for
|
|
private static System.Type []! contractTypes = new System.Type [] {
|
|
/* NetStack.Contracts.dll */
|
|
typeof(DNSContract.Exp),
|
|
typeof(DNSContract.Imp),
|
|
typeof(IPContract.Exp),
|
|
typeof(IPContract.Imp),
|
|
typeof(RoutingContract.Exp),
|
|
typeof(RoutingContract.Imp),
|
|
typeof(TcpConnectionContract.Exp),
|
|
typeof(TcpConnectionContract.Imp),
|
|
typeof(TcpContract.Exp),
|
|
typeof(TcpContract.Imp),
|
|
typeof(UdpConnectionContract.Exp),
|
|
typeof(UdpConnectionContract.Imp),
|
|
typeof(UdpContract.Exp),
|
|
typeof(UdpContract.Imp),
|
|
|
|
/* Io.Contracts.dll */
|
|
typeof(ConsoleDeviceContract.Exp),
|
|
typeof(ConsoleDeviceContract.Imp),
|
|
typeof(DeviceContract.Exp),
|
|
typeof(DeviceContract.Imp),
|
|
typeof(DiskDeviceContract.Exp),
|
|
typeof(DiskDeviceContract.Imp),
|
|
typeof(KeyboardDeviceContract.Exp),
|
|
typeof(KeyboardDeviceContract.Imp),
|
|
typeof(PnpContract.Exp),
|
|
typeof(PnpContract.Imp),
|
|
typeof(SoundDeviceContract.Exp),
|
|
typeof(SoundDeviceContract.Imp),
|
|
typeof(VideoDeviceContract.Exp),
|
|
typeof(VideoDeviceContract.Imp),
|
|
typeof(VolumeManagerContract.Exp),
|
|
typeof(VolumeManagerContract.Imp),
|
|
typeof(NicDeviceContract.Exp),
|
|
typeof(NicDeviceContract.Imp),
|
|
typeof(NicDeviceEventContract.Exp),
|
|
typeof(NicDeviceEventContract.Imp),
|
|
|
|
/* Directory.Contracts.dll */
|
|
typeof(DirectoryServiceContract.Exp),
|
|
typeof(DirectoryServiceContract.Imp),
|
|
typeof(FileContract.Exp),
|
|
typeof(FileContract.Imp),
|
|
typeof(NotifyContract.Exp),
|
|
typeof(NotifyContract.Imp),
|
|
typeof(ServiceContract.Exp),
|
|
typeof(ServiceContract.Imp),
|
|
typeof(ServiceProviderContract.Exp),
|
|
typeof(ServiceProviderContract.Imp),
|
|
typeof(Microsoft.Singularity.Extending.ExtensionContract.Exp),
|
|
typeof(Microsoft.Singularity.Extending.ExtensionContract.Imp),
|
|
|
|
/* Security.Contracts.dll */
|
|
typeof(Microsoft.Singularity.Security.SecurityDiagnosticsContract.Exp),
|
|
typeof(Microsoft.Singularity.Security.SecurityDiagnosticsContract.Imp),
|
|
|
|
/* FileSystem.Contracts.dll */
|
|
typeof(ThreadPoolControlContract.Exp),
|
|
typeof(ThreadPoolControlContract.Imp),
|
|
|
|
/* Diagnostics.Contracts.dll */
|
|
typeof(Microsoft.Singularity.Diagnostics.Contracts.ChannelContract.Exp),
|
|
typeof(Microsoft.Singularity.Diagnostics.Contracts.ChannelContract.Imp),
|
|
typeof(Microsoft.Singularity.Diagnostics.Contracts.MemoryContract.Exp),
|
|
typeof(Microsoft.Singularity.Diagnostics.Contracts.MemoryContract.Imp),
|
|
typeof(Microsoft.Singularity.Diagnostics.Contracts.ProcessContract.Exp),
|
|
typeof(Microsoft.Singularity.Diagnostics.Contracts.ProcessContract.Imp),
|
|
};
|
|
|
|
private static void dumpContractTypeHandles()
|
|
{
|
|
Monitoring.LogEntry ev =newSysInfoEvent(SysInfoEvent.ContractName);
|
|
|
|
for (int i=0; i<contractTypes.Length; i++)
|
|
{
|
|
System.Type! ty = (System.Type!) contractTypes[i];
|
|
SystemType st = ty.GetSystemType();
|
|
string! fullname = (string!)ty.FullName;
|
|
ev.arg0 = (uint)st.TypeId;
|
|
|
|
// trim the enclosing type off the fullname
|
|
int idx = fullname.LastIndexOf('+');
|
|
string smallname;
|
|
if (idx >= 0)
|
|
smallname = fullname.Substring(idx+1);
|
|
else
|
|
smallname = fullname;
|
|
|
|
postSysInfoEvent(ref ev, smallname);
|
|
}
|
|
}
|
|
|
|
|
|
public static byte[]! buf; // event buffer
|
|
public static int bufoffset; // current position in event buffer
|
|
public static byte[] text; // buffer for event string
|
|
public static int textlen; // length of event string
|
|
|
|
public static TcpConnectionContract.Imp:Connected!
|
|
OpenConnection(IPv4 address, ushort port)
|
|
{
|
|
TcpConnectionContract.Imp tcpConn = Utils.GetNewTcpEndPoint();
|
|
if (tcpConn == null) {
|
|
Console.WriteLine("Could not initialize TCP endpoint.");
|
|
throw new ArgumentException("Could not initialize TCP endpoint.");
|
|
}
|
|
|
|
Console.Write("Connecting...");
|
|
|
|
// Try to connect to the remote host
|
|
tcpConn.SendConnect((uint)address, port);
|
|
|
|
switch receive
|
|
{
|
|
case tcpConn.CouldNotConnect(TcpError error) :
|
|
Console.WriteLine("Failed to connect: TcpError = " + System.Net.Sockets.TcpException.GetMessageForTcpError(error));
|
|
delete tcpConn;
|
|
throw new ArgumentException("Failed to connect.");
|
|
break;
|
|
|
|
case tcpConn.OK() :
|
|
// success;
|
|
break;
|
|
|
|
case tcpConn.ChannelClosed() :
|
|
// how rude
|
|
Console.WriteLine("Netstack channel closed unexpectedly");
|
|
delete tcpConn;
|
|
throw new ArgumentException("Netstack channel closed unexpectedly");
|
|
break;
|
|
}
|
|
|
|
Console.WriteLine("Connected");
|
|
return tcpConn;
|
|
}
|
|
|
|
public static TcpConnectionContract.Imp:Connected
|
|
SetupNetwork(string sIp, string sPort)
|
|
{
|
|
IPv4 host;
|
|
try
|
|
{
|
|
host = IPv4.Parse(sIp);
|
|
}
|
|
catch (FormatException e)
|
|
{
|
|
Console.WriteLine("{0}: {1}", e, sIp);
|
|
return null;
|
|
}
|
|
|
|
ushort port;
|
|
try
|
|
{
|
|
port = UInt16.Parse(sPort);
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
Console.WriteLine("Malformed port number: {0}", sPort);
|
|
return null;
|
|
}
|
|
catch (OverflowException)
|
|
{
|
|
Console.WriteLine("Port number out of range: {0}", sPort);
|
|
return null;
|
|
}
|
|
|
|
TcpConnectionContract.Imp! conn = OpenConnection(host, port);
|
|
|
|
return conn;
|
|
}
|
|
|
|
|
|
// we segment our large buffer into COMMSZ chunks for punting through
|
|
// to the network stack
|
|
private static int COMMSZ = 64*1024; // 64KB
|
|
|
|
public static int SendLogBuffer(TcpConnectionContract.Imp! conn)
|
|
{
|
|
int sendidx = 0;
|
|
int sendlen;
|
|
byte[]! in ExHeap data;
|
|
|
|
// copy data to exheap in chunks and send
|
|
Console.Write("Sending");
|
|
while (sendidx < bufoffset)
|
|
{
|
|
sendlen = Math.Min(COMMSZ, bufoffset - sendidx);
|
|
data = Bitter.FromByteArray(buf, sendidx, sendlen);
|
|
|
|
conn.SendWrite(data);
|
|
switch receive
|
|
{
|
|
case conn.OK() :
|
|
Console.Write(".");
|
|
break;
|
|
|
|
case conn.CantSend() :
|
|
Console.WriteLine(": Connection closed unexpectedly (CantSend)");
|
|
return -1;
|
|
break;
|
|
|
|
case conn.ConnectionClosed():
|
|
Console.WriteLine(": Connection closed unexpectedly (ConnectionClosed)");
|
|
return -1;
|
|
break;
|
|
}
|
|
|
|
sendidx += sendlen;
|
|
}
|
|
|
|
Console.WriteLine("OK");
|
|
return 0;
|
|
}
|
|
|
|
public static int marshalled; // count of events marshalled
|
|
|
|
public static int Marshall(ref Monitoring.LogEntry e)
|
|
{
|
|
int tl = (textlen > 0)? textlen : 0;
|
|
if (sizeof(Monitoring.LogEntry) + bufoffset + tl > buf.Length) {
|
|
Console.WriteLine("Marshall: buffer full");
|
|
return -1;
|
|
}
|
|
|
|
unsafe {
|
|
fixed (byte *bp = &buf[bufoffset]) {
|
|
/* Use a simple cast */
|
|
Monitoring.LogEntry *lep = (Monitoring.LogEntry *)bp;
|
|
*lep = e;
|
|
}
|
|
}
|
|
bufoffset += sizeof(Monitoring.LogEntry);
|
|
|
|
if (textlen > 0) {
|
|
Array.Copy(text, 0, buf, bufoffset, textlen);
|
|
bufoffset += textlen;
|
|
}
|
|
textlen = 0;
|
|
|
|
marshalled++;
|
|
return 0;
|
|
}
|
|
|
|
// Fill event buffer until either duration has passed or
|
|
// we have maxevents
|
|
public static int FillEventBuffer(ulong duration, ulong maxevents,
|
|
ulong evstart)
|
|
{
|
|
int ret = -1;
|
|
ulong counter = evstart;
|
|
ulong old_counter = 0;
|
|
ulong count_lost = 0;
|
|
ulong sum_lost = 0;
|
|
|
|
ulong hz = (ulong)Processor.CyclesPerSecond;
|
|
ulong now = Processor.CycleCount;
|
|
ulong end = now + duration * hz;
|
|
|
|
ulong evcount = 0;
|
|
|
|
Monitoring.LogEntry e = new Monitoring.LogEntry();
|
|
|
|
Console.WriteLine("MonNet: collecting with duration={0}secs, maxevents={1}",
|
|
duration, maxevents);
|
|
|
|
bool done = false;
|
|
while (!done)
|
|
{
|
|
// Get an event
|
|
while (true)
|
|
{
|
|
ret = -1;
|
|
now = Processor.CycleCount;
|
|
if (now > end || evcount >= maxevents)
|
|
{
|
|
done = true;
|
|
|
|
if (now > end)
|
|
Console.WriteLine("Timed out ({0}ms late)", (now-end)*1000/hz);
|
|
if (evcount >= maxevents)
|
|
Console.WriteLine("Got enough events");
|
|
break;
|
|
}
|
|
|
|
unsafe {
|
|
ret = Monitoring.GetEntry(ref counter, out e);
|
|
}
|
|
if (old_counter != counter)
|
|
{
|
|
count_lost++;
|
|
sum_lost += counter - old_counter;
|
|
//Console.Write("X{0}", counter - old_counter);
|
|
}
|
|
old_counter = counter;
|
|
|
|
if (ret == 0) {// Got an event
|
|
evcount++;
|
|
break;
|
|
} else { // No event to get, sleep and try again
|
|
// are we just using defaults?
|
|
if (duration == ((ulong)DEF_DUR) &&
|
|
maxevents == ((ulong)DEF_MAXEV))
|
|
{
|
|
done = true;
|
|
Console.WriteLine("No more events");
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Thread.Sleep(100);
|
|
}
|
|
}
|
|
}
|
|
counter++;
|
|
|
|
if (ret == 0)
|
|
{
|
|
if (e.cycleCount == 0)
|
|
{
|
|
// Console.Write('^');
|
|
evcount--;
|
|
continue; // got illegal entry, so try next
|
|
}
|
|
|
|
// Try to get text buffer for event
|
|
if (e.text != null)
|
|
{
|
|
int size;
|
|
unsafe {
|
|
assume text != null;
|
|
fixed (byte * b = text) {
|
|
size = Monitoring.FillTextEntry(e.text, e.cycleCount,
|
|
b, text.Length);
|
|
}
|
|
}
|
|
|
|
if (size != 0) // fixup size in event structure
|
|
{
|
|
if (size < 0) // error: dropped text string
|
|
Console.WriteLine("size={0}", size);
|
|
|
|
unsafe {
|
|
e.text = (byte *)size;
|
|
}
|
|
textlen = size;
|
|
}
|
|
}
|
|
|
|
// put event in buffer
|
|
ret = Marshall(ref e);
|
|
if (ret != 0) {
|
|
Console.WriteLine("BUFFER FULL: exiting EARLY!");
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Console.WriteLine("Got {0} events", evcount);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* We can't actually "clear" the kernel log; what this does
|
|
* is find the counter number for the log's current end,
|
|
* so we can pass it into FillEventBuffer() later. */
|
|
private static ulong clearLog()
|
|
{
|
|
int ret;
|
|
ulong counter = 0;
|
|
Monitoring.LogEntry e = new Monitoring.LogEntry();
|
|
int i = 0;
|
|
|
|
while (true)
|
|
{
|
|
unsafe {
|
|
ret = Monitoring.GetEntry(ref counter, out e);
|
|
}
|
|
if (ret == 0) {
|
|
counter++; // got an event; try next one
|
|
} else {
|
|
break; // failed to get an event, we're done
|
|
}
|
|
|
|
/* sanity check */
|
|
if (i++ > 5000000)
|
|
{
|
|
Console.WriteLine("error: clearLog() looped 5000000 times; bailing");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return counter;
|
|
}
|
|
|
|
|
|
|
|
/************************************************/
|
|
/* Command line gubbins */
|
|
|
|
|
|
private static int doTransfer(string sIp, string sPort)
|
|
{
|
|
int ret;
|
|
|
|
// Setup the networking stuff.
|
|
// austind: due to a race in the netstack, must open the connection
|
|
// and start sending data on it promptly, otherwise you'll get
|
|
// a RST and an exception.
|
|
TcpConnectionContract.Imp conn = SetupNetwork(sIp, sPort);
|
|
if (conn == null)
|
|
return -1;
|
|
|
|
// Transmit the buffer
|
|
ret = SendLogBuffer(conn);
|
|
|
|
// Tidy up
|
|
conn.SendClose();
|
|
delete conn;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
private static int doSlurp(long runTime, long maxevents,
|
|
ulong evstart)
|
|
{
|
|
// Allocate the buffers
|
|
buf = new Byte[16<<20]; // should be big enough
|
|
bufoffset = 0;
|
|
text = new byte[256];
|
|
textlen = 0;
|
|
|
|
marshalled = 0; // num events copied to buf
|
|
|
|
// Put preamble into buffer
|
|
dumpSysInfo();
|
|
|
|
return FillEventBuffer((ulong)runTime, (ulong)maxevents, evstart);
|
|
}
|
|
|
|
|
|
public static bool ParseNumber(string/*!*/ arg,
|
|
string/*!*/ name,
|
|
out long value)
|
|
{
|
|
// arg should look like "[-][A-z]:[0-9]*"
|
|
if (arg.Length >= 4)
|
|
{
|
|
try
|
|
{
|
|
value = Int64.Parse(arg.Substring(3));
|
|
return true;
|
|
}
|
|
catch (FormatException)
|
|
{Console.WriteLine("format ex"); }
|
|
catch (OverflowException)
|
|
{Console.WriteLine("overflow ex");}
|
|
}
|
|
Console.WriteLine("Could not parse {0}, {1}", name,arg.Substring(3));
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
internal static int usage()
|
|
{
|
|
Console.WriteLine("Usage: monnet /d /c /w:WARMUP /e /r:RUNTIME /n:MAXEVENTS /s /t:IP:PORT");
|
|
Console.WriteLine(" /d disable logging");
|
|
Console.WriteLine(" /c \"clear\" log: ie note current end");
|
|
Console.WriteLine(" /w:WARMUP pause for WARMUP seconds");
|
|
Console.WriteLine(" /e enable logging");
|
|
Console.WriteLine(" /r:RUNTIME set event slurp limit to RUNTIME seconds");
|
|
Console.WriteLine(" /n:MAXEVENTS set event slurp limit to MAXEVENTS");
|
|
Console.WriteLine(" (without /r or /n options: slurp until log empty or marshal buffer full)");
|
|
Console.WriteLine(" /s slurp events according to limits");
|
|
Console.WriteLine(" /t:IP:PORT transfer via TCP to IPADDR:PORT");
|
|
Console.WriteLine("All options can occur in any order, zero or more times");
|
|
Console.WriteLine("They are executed in order. Example:");
|
|
Console.WriteLine("monnet /d /c /w:300 /e /r:300 /s /d /t:10.99.99.1:5000");
|
|
return -1;
|
|
}
|
|
|
|
private static long DEF_DUR = 999999999; // seconds ie forever
|
|
private static long DEF_MAXEV = 999999999;
|
|
|
|
internal static int AppMain(Parameters! config)
|
|
{
|
|
int ret = 0;
|
|
long runTime = DEF_DUR, maxevents = DEF_MAXEV;
|
|
ulong evstart = 0;
|
|
string[] args = config.args;
|
|
|
|
if (config.doHelp) return usage();
|
|
|
|
if (args == null)
|
|
{
|
|
return usage();
|
|
}
|
|
|
|
bool needHelp = (args.Length == 0);
|
|
|
|
int i;
|
|
for (i = 0; !needHelp && i < args.Length; i++)
|
|
{
|
|
string arg = args[i];
|
|
|
|
if (arg == null || arg.Length < 2 || (arg[0] != '-' && arg[0] != '/') )
|
|
{
|
|
Console.WriteLine("Invalid argument: {0}", arg);
|
|
return usage();
|
|
}
|
|
|
|
long temp;
|
|
switch (arg[1])
|
|
{
|
|
case 'd':
|
|
case 'e':
|
|
bool active = (arg[1] == 'e');
|
|
Console.WriteLine(active?"Enabling logging":"Disabling logging");
|
|
Monitoring.setActive(active);
|
|
break;
|
|
|
|
case '?':
|
|
case 'h':
|
|
needHelp = true;
|
|
break;
|
|
|
|
case 'c':
|
|
Console.WriteLine("Clearing log");
|
|
evstart = clearLog();
|
|
break;
|
|
|
|
case 'w':
|
|
ParseNumber(arg, "Warmup time", out temp);
|
|
Console.WriteLine("Pausing {0}secs for warmup", temp);
|
|
Thread.Sleep(((int)temp) * 1000);
|
|
break;
|
|
|
|
case 'r':
|
|
ParseNumber(arg, "Run time", out runTime);
|
|
break;
|
|
|
|
case 'n':
|
|
ParseNumber(arg, "Maxevents", out maxevents);
|
|
break;
|
|
|
|
case 's':
|
|
doSlurp(runTime, maxevents, evstart);
|
|
break;
|
|
|
|
case 't':
|
|
int colon = arg.IndexOf(':', 3);
|
|
if (colon < 0)
|
|
{
|
|
Console.WriteLine("argument error: missing colon in '{0}': expecting IPADDR:PORT", arg);
|
|
return usage();
|
|
}
|
|
string ipaddr = arg.Substring(3, colon-3);
|
|
string port = arg.Substring(colon+1);
|
|
ret = doTransfer(ipaddr, port);
|
|
if (ret != 0)
|
|
return ret;
|
|
break;
|
|
|
|
default:
|
|
Console.WriteLine("Unknown option {0}", arg);
|
|
needHelp = true;
|
|
break;
|
|
}
|
|
} // for args
|
|
|
|
if (needHelp)
|
|
{
|
|
return usage();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
}
|