package water; import jsr166y.CountedCompleter; import jsr166y.ForkJoinPool; import jsr166y.ForkJoinTask; import jsr166y.RecursiveAction; import water.H2O.H2OCountedCompleter; import water.api.DocGen; import water.fvec.Vec; import water.util.Log; import water.util.Utils; import java.util.Arrays; import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; public class UDPDropTest extends Func { static final int API_WEAVER=1; // This file has auto-gen'd doc & json fields static public DocGen.FieldDoc[] DOC_FIELDS; // Initialized from Auto-Gen code. @API(help = "Message sizes", filter = Default.class, json=true) public int[] msg_sizes = new int[]{1,32,64,128,256,512,1024,AutoBuffer.MTU-100}; //INPUT @API(help = "Nodes", json=true) public String[] nodes; //OUTPUT @API(help = "Drop rates between each (ordered) pair of nodes for different message sizes", json = true) public UDPDropMatrix [] dropRates; private static class UDPPing extends DTask<UDPPing>{ boolean _done; int _retries = -1; final long _t1; long _t2; byte [] _payload; public UDPPing(){_t1 = -1;} public UDPPing(int sz){ assert sz <= AutoBuffer.MTU:"msg size does not fit into UDP"; _payload = MemoryManager.malloc1(sz); Random rnd = new Random(); for(int i = 0; i < _payload.length; ++i) _payload[i] = (byte)rnd.nextInt(); _t1 = System.currentTimeMillis(); } @Override public void compute2() { tryComplete();} @Override public synchronized UDPPing read(AutoBuffer ab){ if(_done)return this; _done = true; _t2 = System.currentTimeMillis(); _retries = ab.get4(); byte [] bs = ab.getA1(); _payload = bs; return this; } @Override public synchronized AutoBuffer write(AutoBuffer ab){ if(!_done) ++_retries; ab.put4(_retries); // count the number of retries as number of serialization calls ab.putA1(_payload); return ab; } @Override public void copyOver(Freezable f){ UDPPing u = (UDPPing)f; _retries = u._retries; _payload = u._payload; } } private static class TCPTester extends DTask<TCPTester> { public final int _srcId; public final int _tgtId; public final int _N; private final int[] _msgSzs; private transient RPC<UDPPing>[][] _pings; double[] _dropRates; int[] _droppedPackets; public TCPTester(H2ONode src, H2ONode tgt, int[] msgSzs, int ntests) { _srcId = src.index(); _tgtId = tgt.index(); _msgSzs = msgSzs; _N = ntests; } private transient boolean _done; private final void doTest() { _droppedPackets = new int[_N]; Arrays.fill(_droppedPackets, -1); _pings = new RPC[_msgSzs.length][_N]; // addToPendingCount(_msgSzs.length*_N - 1); for (int i = 0; i < _msgSzs.length; ++i) for (int j = 0; j < _N; ++j) // instead of synchronization, just wait for predetermined amount of time _pings[i][j] = new RPC(H2O.CLOUD._memary[_tgtId], new UDPPing(_msgSzs[i]))/*.addCompleter(this)*/.call(); try { Thread.sleep(5000); } catch (InterruptedException e) { } // if not done yet, finish no matter what (racy but we don't care here - only a debug tool, does not have to be precise) // setPendingCount(0); } @Override public synchronized void onCompletion(CountedCompleter caller) { if (!_done) { // only one completion _done = true; _dropRates = MemoryManager.malloc8d(_msgSzs.length); // compute the drop rates for (int i = 0; i < _msgSzs.length; ++i) { double sum = 0; for (int j = 0; j < _N; ++j) { RPC<UDPPing> rpc = _pings[i][j]; sum += (rpc._dt._retries == -1 ? Double.POSITIVE_INFINITY : rpc._dt._retries); } _dropRates[i] = 1 - _N / (_N + sum); } } } @Override public void compute2() { } } private static class UDPDropTester extends DTask<UDPDropTester> { public final int _srcId; public final int _tgtId; public final int _N; private final int [] _msgSzs; private transient RPC<UDPPing> [][] _pings; double [] _dropRates; int [] _droppedPackets; public UDPDropTester(H2ONode src, H2ONode tgt, int [] msgSzs, int ntests){ _srcId = src.index(); _tgtId = tgt.index(); _msgSzs = msgSzs; _N = ntests; } private transient boolean _done; private final void doTest(){ _droppedPackets = new int[_N]; Arrays.fill(_droppedPackets,-1); _pings = new RPC[_msgSzs.length][_N]; // addToPendingCount(_msgSzs.length*_N - 1); for(int i = 0; i < _msgSzs.length; ++i) for(int j = 0; j < _N; ++j) // instead of synchronization, just wait for predetermined amount of time _pings[i][j] = new RPC(H2O.CLOUD._memary[_tgtId],new UDPPing(_msgSzs[i]))/*.addCompleter(this)*/.call(); try { Thread.sleep(5000); } catch (InterruptedException e) {} // if not done yet, finish no matter what (racy but we don't care here - only a debug tool, does not have to be precise) // setPendingCount(0); } @Override public synchronized void onCompletion(CountedCompleter caller){ if(!_done){ // only one completion _done = true; _dropRates = MemoryManager.malloc8d(_msgSzs.length); // compute the drop rates for(int i = 0; i < _msgSzs.length; ++i) { double sum = 0; for (int j = 0; j < _N; ++j) { RPC<UDPPing> rpc = _pings[i][j]; sum += (rpc._dt._retries == -1 ? Double.POSITIVE_INFINITY : rpc._dt._retries); } _dropRates[i] = 1 - _N/(_N+sum); } } } @Override public void compute2() { if(_srcId == H2O.SELF.index()) { doTest(); tryComplete(); } else { _done = true; final UDPDropTester t = (UDPDropTester) clone(); new RPC(H2O.CLOUD._memary[_srcId], t).addCompleter(new H2OCountedCompleter(this) { @Override public void compute2() { } @Override public void onCompletion(CountedCompleter cc) { copyOver(t); } }).call(); } } } private static class UDPDropMatrix extends Iced { static final int API_WEAVER=1; // This file has auto-gen'd doc & json fields static public DocGen.FieldDoc[] DOC_FIELDS; // Initialized from Auto-Gen code. @API(help="message size") public final int messageSz; @API(help="meassured drop rates") public final double [][] dropRates; public UDPDropMatrix(int msgSz, double [][] dropRates){ messageSz = msgSz; this.dropRates = dropRates; } @Override public String toString(){ return " drop rates at " + messageSz + " bytes\n" + Utils.pprint(dropRates); } } @Override protected void execImpl() { logStart(); Log.debug("NetworkTester testing udp drops"); final UDPDropTester [] dropTests = new UDPDropTester[H2O.CLOUD.size()*H2O.CLOUD.size()-H2O.CLOUD.size()]; H2O.submitTask(new H2OCountedCompleter() { @Override public void compute2() { int k = 0; for(int i = 0; i < H2O.CLOUD.size(); ++i) for(int j = 0; j < H2O.CLOUD.size(); ++j){ if(i == j) continue; dropTests[k++] = new UDPDropTester(H2O.CLOUD._memary[i],H2O.CLOUD._memary[j],msg_sizes,10); } ForkJoinTask.invokeAll(dropTests); tryComplete(); } }).join(); dropRates = new UDPDropMatrix[msg_sizes.length]; for(int m = 0; m < msg_sizes.length; ++m){ double [][] ds = new double[H2O.CLOUD.size()][H2O.CLOUD.size()]; int k = 0; for(int i = 0; i < H2O.CLOUD.size(); ++i) for(int j = 0; j < H2O.CLOUD.size(); ++j){ if(i == j) continue; ds[i][j] = dropTests[k++]._dropRates[m]; } dropRates[m] = new UDPDropMatrix(msg_sizes[m],ds); } Log.debug("Network test udp drop rates: "); for(UDPDropMatrix m:dropRates) Log.debug(m.toString()); // now do the tcp bandwith test // print out } @Override public boolean toHTML(StringBuilder sb) { try { DocGen.HTML.section(sb, "UDP Drop rates"); for(int i = 0; i < msg_sizes.length; ++i){ sb.append("<h4>" + "Message size = " + msg_sizes[i] + " bytes</h4>"); sb.append("<div>"); UDPDropMatrix d = dropRates[i]; sb.append("<table class='table table-bordered table-condensed'>\n"); sb.append("<tr>"); sb.append("<th></th>"); for(int j = 0 ; j < H2O.CLOUD.size(); ++j) sb.append("<th>" + j + "</th>"); sb.append("</tr>\n"); for(int j = 0 ; j < H2O.CLOUD.size(); ++j){ sb.append("<tr><td>" + j + "</td>"); for(int k = 0; k < d.dropRates[j].length; ++k){ sb.append("<td>" + (int)(100*d.dropRates[j][k]) + "%</td>"); } sb.append("</tr>\n"); } sb.append("</table>"); sb.append("</div>"); } } catch(Throwable t){ t.printStackTrace(); } return true; } }