Computer Laboratory

Bluepsec Examples

Server Farm

Introduction

This is generic package replicates any Server as many times as you like. For example, we could take the DividerServer example and replicate it twice as illustrated below. This will route the requests to in an alternating (round-robin) manner the two internal DividerServer. Since the DividerServer is iterative and takes several cycles, the ServerFarm version with two DividerServers will have twice the bandwidth.

ServerFarm Illustration

Example of ServerFarm instantiating two DividerServers

So if the original DividerServer was instantiated vis:

DividerServerT#(`width) divServ <- mkDividerServer;

then the new version with two DividerServers is simply:

DividerServerT#(`width) fasterDivServ <- mkServerFarm2(mkDividerServer);

This, for me, is an excellent example of how Bluespec allows you to do rapid design exploration.

Notes

  • The Server to be replicated is passed in as a higher-order type called mkServer. A vector of mkServers is created using replicateM (monadic replicate).
  • The incoming request is enqueued into a BypassFIFO. Exactly one of put_requests rules (generated using a for-loop) will be enabled and can forward the request to corresponding server.
  • There are some helper functions (e.g. mkServerFarm2) which preserve the Server interface type externally and internally invoke mkServerFarmFull with a ServerFarmFullIfc interface and provides 2 as a parameter of the number of replications required. There doesn't appear to be a mechanism to provide the number of replications without modifying the interface.

The code

/*****************************************************************************
 ServerFarm
 ==========
 Simon Moore, Oct 2009

 Generic module which multiplexes N servers to one server interface.
 Useful if the base server is quite slow and you want several copies of it.
 *****************************************************************************/

package ServerFarm;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import GetPut::*;
import ClientServer::*;
import Connectable::*;
import Vector::*;


interface ServerFarmFullIfc#(numeric type num_servers, type requestT, type responseT);
   interface Server#(requestT,responseT) server;
endinterface

typedef UInt#(TAdd#(TLog#(num_servers),1)) ServerNumT#(numeric type num_servers);


module mkServerFarmFull#(module#(Server#(requestT,responseT)) mkServer)
   (ServerFarmFullIfc#(num_servers,requestT,responseT))
   provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
   
   let inum_servers = valueof(num_servers);

   Vector#(num_servers, Server#(requestT,responseT)) servers <- replicateM(mkServer);
   Reg#(ServerNumT#(num_servers)) write_server <- mkReg(0);
   Reg#(ServerNumT#(num_servers)) read_server  <- mkReg(0);
   FIFOF#(requestT)  request_fifo  <- mkBypassFIFOF;
   FIFOF#(responseT) response_fifo <- mkBypassFIFOF;

   function ServerNumT#(num_servers) next_server(ServerNumT#(num_servers) n, ServerNumT#(num_servers) max);
      let next = n+1;
      return (next>=max) ? 0 : next;
   endfunction
   
   for(Integer j=0; j<inum_servers; j=j+1)
      begin			   
	 rule put_requests (write_server==fromInteger(j)); // && request_fifo.notEmpty);
	    let r = request_fifo.first;
	    request_fifo.deq;
	    servers[j].request.put(r);
	    write_server <= next_server(fromInteger(j),fromInteger(inum_servers));
	 endrule
	 rule gather_results (read_server==fromInteger(j)); // && response_fifo.notFull);
	    let result <- servers[j].response.get;
	    response_fifo.enq(result);
	    read_server <= next_server(fromInteger(j),fromInteger(inum_servers));
	 endrule
      end		

   interface Server server;
      interface Put request = toPut(request_fifo);
      interface Get response = toGet(response_fifo);
   endinterface
   
endmodule



module mkServerFarm2#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(2,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule


module mkServerFarm3#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(2,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule


module mkServerFarm4#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(4,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule

   
module mkServerFarm5#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(5,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule

   
module mkServerFarm6#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(6,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule

   
module mkServerFarm7#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(7,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule

   
module mkServerFarm8#(module#(Server#(requestT,responseT)) mkServer)
    (Server#(requestT,responseT))
    provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
  ServerFarmFullIfc#(8,requestT,responseT) sf <- mkServerFarmFull(mkServer);
  interface Put request = sf.server.request;
  interface Get response = sf.server.response;		
endmodule


endpackage

Link to the ServerFarm.bsv source