1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 module capnproto.benchmark.TestCase; 23 24 import std.conv : to; 25 import std.stdio; 26 27 import java.io.IOException; 28 import java.nio.ByteBuffer; 29 30 import capnproto.ArrayInputStream; 31 import capnproto.ArrayOutputStream; 32 import capnproto.BufferedInputStreamWrapper; 33 import capnproto.BufferedOutputStreamWrapper; 34 import capnproto.FileDescriptor; 35 import capnproto.MessageBuilder; 36 import capnproto.MessageReader; 37 38 import capnproto.benchmark.Common; 39 import capnproto.benchmark.Compression; 40 41 abstract class TestCase(Request, Response, Expectation) 42 { 43 public: //Variables. 44 enum SCRATCH_SIZE = 128 * 1024; 45 46 public: //Methods. 47 abstract Expectation setupRequest(Request.Builder request); 48 abstract void handleRequest(Request.Reader request, Response.Builder response); 49 abstract bool checkResponse(Response.Reader response, Expectation expected); 50 51 void passByObject(Compression compression, long iters) 52 { 53 foreach(ii; 0..iters) 54 { 55 auto requestMessage = new MessageBuilder(); 56 auto responseMessage = new MessageBuilder(); 57 auto request = requestMessage.initRoot!Request; 58 auto expected = this.setupRequest(request); 59 auto response = responseMessage.initRoot!Response; 60 this.handleRequest(request.asReader(), response); 61 if(!this.checkResponse(response.asReader(), expected)) 62 writeln("Mismatch!"); 63 } 64 } 65 66 void passByBytes(Compression compression, long iters) 67 { 68 auto requestBytes = ByteBuffer(new ubyte[](SCRATCH_SIZE * 8)); 69 auto responseBytes = ByteBuffer(new ubyte[](SCRATCH_SIZE * 8)); 70 71 foreach(ii; 0..iters) 72 { 73 auto requestMessage = new MessageBuilder(); 74 auto responseMessage = new MessageBuilder(); 75 auto request = requestMessage.initRoot!Request; 76 auto expected = this.setupRequest(request); 77 auto response = responseMessage.initRoot!Response; 78 79 { 80 auto writer = new ArrayOutputStream(requestBytes); 81 compression.writeBuffered(writer, requestMessage); 82 } 83 84 { 85 auto messageReader = compression.newBufferedReader(new ArrayInputStream(requestBytes)); 86 this.handleRequest(messageReader.getRoot!Request, response); 87 } 88 89 { 90 auto writer = new ArrayOutputStream(responseBytes); 91 compression.writeBuffered(writer, responseMessage); 92 } 93 94 { 95 auto messageReader = compression.newBufferedReader(new ArrayInputStream(responseBytes)); 96 if(!this.checkResponse(messageReader.getRoot!Response, expected)) 97 throw new Error("Incorrect response!"); 98 } 99 } 100 } 101 102 void syncServer(Compression compression, long iters) 103 { 104 auto outBuffered = new BufferedOutputStreamWrapper(new FileDescriptor(stdout)); 105 auto inBuffered = new BufferedInputStreamWrapper(new FileDescriptor(stdin)); 106 107 foreach(ii; 0..iters) 108 { 109 auto responseMessage = new MessageBuilder(); 110 { 111 auto response = responseMessage.initRoot!Response; 112 auto messageReader = compression.newBufferedReader(inBuffered); 113 auto request = messageReader.getRoot!Request; 114 this.handleRequest(request, response); 115 } 116 compression.writeBuffered(outBuffered, responseMessage); 117 } 118 } 119 120 void syncClient(Compression compression, long iters) 121 { 122 auto outBuffered = new BufferedOutputStreamWrapper(new FileDescriptor(stdout)); 123 auto inBuffered = new BufferedInputStreamWrapper(new FileDescriptor(stdin)); 124 125 foreach(ii; 0..iters) 126 { 127 auto requestMessage = new MessageBuilder(); 128 auto request = requestMessage.initRoot!Request; 129 auto expected = this.setupRequest(request); 130 131 compression.writeBuffered(outBuffered, requestMessage); 132 auto messageReader = compression.newBufferedReader(inBuffered); 133 auto response = messageReader.getRoot!Response; 134 if(!this.checkResponse(response, expected)) 135 throw new Error("Incorrect response!"); 136 } 137 } 138 139 void execute(string[] args) 140 { 141 if(args.length != 5) 142 { 143 writeln("USAGE: TestCase MODE REUSE COMPRESSION ITERATION_COUNT"); 144 return; 145 } 146 147 auto mode = args[1]; 148 auto reuse = args[2]; 149 Compression compression; 150 if(args[3] == "packed") 151 compression = cast(Compression)Compression.packed; 152 else if(args[3] == "none") 153 compression = cast(Compression)Compression.uncompressed; 154 else 155 throw new Error("Unrecognized compression: " ~ args[2]); 156 157 long iters = to!long(args[4]); 158 159 if(mode == "object") 160 passByObject(compression, iters); 161 else if(mode == "bytes") 162 passByBytes(compression, iters); 163 else if(mode == "client") 164 syncClient(compression, iters); 165 else if(mode == "server") 166 syncServer(compression, iters); 167 else 168 writefln("Unrecognized mode: %s", mode); 169 } 170 }