o CSS 490C (Winter 2015): Special Topics — Tactical Software Engineering

Assignment 5: Loadgen

To test the capacity of the time server, you need a program to generate requests. One could cobble something together using a script that makes multiple calls to curl but that is, at best, imprecise. Furthermore, since the overhead of creating a new process for each request is so high, this approach would be limited in its effectiveness.

Write a Go program loadgen that takes the following flags:

Rate

The rate parameter determines the average number of requests (per second) to issue. The requests will be issued concurrently and will last for up to timeout-ms milliseconds. At any given moment there will be some number of active requests depending on the server's responsiveness.

For this proof-of-concept, we don't have to care about the number of inflight requests. Assume the system has enough resouces to handle it.

Bursts

To issue requests at the given rate one could issue a request and then wait for a period of 1 / rate, but realistic traffic is more random, arriving in clusters or bursts.

To simulate bursts at the given request rate, use time.Tick() to create a ticker with a period of burst / rate. You will also need to convert the period to microseconds (multiply by 1,000,000, so the period calculation will be time.Duration(burst * 1000000 / rate) * time.Microsecond)

On each tick, spawn off burst goroutines, with each routine making one get request.

Statistics

Keep a tally of the toatal number of requests issued and counts of status codes returned by century (100s, 200s, 300s, 400s, 500s). Also keep count of the number of timeout errors.

Counters

The basic operations of a counter are to reset the value, increment the value, and emit a map of all counter/value pairs. The map, of course, should be a copy.

An easy way to implement a counter is by using a map[string] int. The counter "variable" is a string, not a Go variable.

Counters do need to be thread-safe. If you use a map internally, the dump operation must return a copy of the map.

Design an appropriate package interface and implement the package.

Implement unit tests for your counter package using the testing package. Hint: your test should be concurrent.

Main Program

Implement the load generation function as an infinite loop.

The main program should call the load function (or whatever you want to call it) in a goroutine and then sleep for runtime seconds before collecting the statistics and terminating the program.

Output

Run loadgen targeting your timeserver. If you run the system with parameters like this:

./bin/authserver --log=etc/auth-log.xml &
./bin/timeserver --log=etc/log-01.xml --port=8081 --max-inflight=80 --avg-response-ms=500   --response-deviation-ms=300 &
./bin/loadgen --url='http://localhost:8081/time' --runtime=10 --rate=200 --burst=20 --timeout-ms=1000

Your output should look something like this:

Total : 2000
100s:   0
200s:   1341
300s:   0
400s:   0
500s:   524
Errors: 66

Hand-In

In addition to the usual hand-in requirements (source code and build script or Makefile), include text file(s) containing 3 sample runs of the the load generator running against timeserver. Experiment with different combinations of timeserver and loadgen parameters.