private double generateSegment(double t, double end, double readRate, double writeRate, Filer actor) throws InterruptedException, IOException {
        // total event rate
        final double rate = readRate + writeRate;
        // what portion are reads?
        final double readP = readRate / rate;

        actor.segmentStart(t);
        t = Math.min(end, t + expSample(rate));
        while (t < end) {
            // only really sleep if there is a millisecond or more to sleep
            final double t1 = actor.currentTime();
            boolean slept = false;
            if (t - t1 > 20e-3) {
                actor.sleep(t - t1);
                slept = true;
            }
            if (actor.currentTime() > t + 0.1 && slept) {
                log.error("Whacky waits");
            }
            messageCount++;
            if (actor.currentTime() > t + 0.1 && messageCount % 100 == 0) {
                log.warn("Slippage {}", actor.currentTime() - t);
            }

            if (actor.currentTime() > t + 5) {
                actor.segmentEnd(t);
                throw new IOException("Generator fell more than 5 seconds behind ... aborting run");
            }

            double t0 = actor.currentTime();
            // select type of transaction
            if (rand.nextDouble() < readP) {
                actor.read(t, blockSize);
            } else {
                actor.write(t, blockSize);
            }
            totalLatency += (actor.currentTime() - t0);

            t = Math.min(end, t + expSample(rate));
        }
        if (t - actor.currentTime() > 20e-3) {
            actor.sleep(t - actor.currentTime());
        }
        actor.segmentEnd(t);
        return end;
    }