Skip to content

Commit d016e03

Browse files
committed
Added some more metrics. Added multiple thresholds to metrics.
1 parent 512795b commit d016e03

File tree

5 files changed

+106
-114
lines changed

5 files changed

+106
-114
lines changed

src/main/java/bwapi/BWClient.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,24 +94,12 @@ public void startGame(BWClientConfiguration configuration) {
9494
}
9595
while (liveGameData.isInGame()) {
9696
boolean timeFrame = liveGameData.getFrameCount() > 0 || ! configuration.unlimitedFrameZero;
97-
performanceMetrics.frameDuration5.timeIf(timeFrame, () ->
98-
performanceMetrics.frameDuration10.timeIf(timeFrame, () ->
99-
performanceMetrics.frameDuration15.timeIf(timeFrame, () ->
100-
performanceMetrics.frameDuration20.timeIf(timeFrame, () ->
101-
performanceMetrics.frameDuration25.timeIf(timeFrame, () ->
102-
performanceMetrics.frameDuration30.timeIf(timeFrame, () ->
103-
performanceMetrics.frameDuration35.timeIf(timeFrame, () ->
104-
performanceMetrics.frameDuration40.timeIf(timeFrame, () ->
105-
performanceMetrics.frameDuration45.timeIf(timeFrame, () ->
106-
performanceMetrics.frameDuration50.timeIf(timeFrame, () ->
107-
performanceMetrics.frameDuration55.timeIf(timeFrame, () ->
10897
performanceMetrics.totalFrameDuration.timeIf(
10998
timeFrame,
11099
() -> {
111100
botWrapper.onFrame();
112101
performanceMetrics.flushSideEffects.time(() -> getGame().sideEffects.flushTo(liveGameData));
113-
})
114-
)))))))))));
102+
});
115103
performanceMetrics.bwapiResponse.time(client::update);
116104
if (!client.isConnected()) {
117105
System.out.println("Reconnecting...");

src/main/java/bwapi/BotWrapper.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,11 @@ void onFrame() {
108108
int frame = liveClientData.gameData().getFrameCount();
109109
configuration.log("Main: Enqueuing frame #" + frame);
110110
frameBuffer.enqueueFrame();
111+
111112
configuration.log("Main: Enqueued frame #" + frame);
113+
if (frame > 0) {
114+
performanceMetrics.clientIdle.startTiming();
115+
}
112116
frameBuffer.lockSize.lock();
113117
try {
114118
while (!frameBuffer.empty()) {
@@ -140,19 +144,21 @@ void onFrame() {
140144
}
141145
configuration.log("Main: Waiting " + remainingNanos / 1000000 + "ms for bot on frame #" + frame);
142146
frameBuffer.conditionSize.awaitNanos(remainingNanos);
147+
long excessNanos = Math.max(0, (System.nanoTime() - endNanos) / 1000000);
148+
performanceMetrics.excessSleep.record(excessNanos);
143149
}
144150
}
145151
} catch(InterruptedException ignored) {
146152
} finally {
147153
frameBuffer.lockSize.unlock();
154+
performanceMetrics.clientIdle.stopTiming();
148155
configuration.log("Main: onFrame asynchronous end");
149156
}
150157
} else {
151158
configuration.log("Main: onFrame synchronous start");
152159
handleEvents();
153160
configuration.log("Main: onFrame synchronous end");
154161
}
155-
156162
}
157163

158164
/**
@@ -235,7 +241,7 @@ private void handleEvents() {
235241
}
236242

237243
if (configuration.async) {
238-
performanceMetrics.framesBehind.record(frameBuffer.framesBuffered() - 1);
244+
performanceMetrics.framesBehind.record(Math.max(1, frameBuffer.framesBuffered()) - 1);
239245
}
240246

241247
performanceMetrics.botResponse.timeIf(

src/main/java/bwapi/PerformanceMetric.java

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,56 @@
11
package bwapi;
22

33
import java.text.DecimalFormat;
4+
import java.util.ArrayList;
45

56
/**
67
* Aggregates labeled time series data.
78
*/
89
public class PerformanceMetric {
9-
private final String name;
10-
private final long maxAllowed;
10+
class RunningTotal {
11+
int samples = 0;
12+
double mean = 0d;
13+
double min = Long.MAX_VALUE;
14+
double max = Long.MIN_VALUE;
15+
void record(double value) {
16+
min = Math.min(min, value);
17+
max = Math.max(max, value);
18+
mean = (mean * samples + value) / (samples + 1d);
19+
++samples;
20+
}
21+
}
22+
class Threshold {
23+
double threshold;
24+
RunningTotal runningTotal = new RunningTotal();
25+
Threshold(double value) {
26+
threshold = value;
27+
}
28+
void record(double value) {
29+
if (value >= threshold) {
30+
runningTotal.record(value);
31+
}
32+
}
33+
public String toString() {
34+
if (runningTotal.samples <= 0) {
35+
return "";
36+
}
37+
DecimalFormat formatter = new DecimalFormat("###,###.#");
38+
return "\n>= " + formatter.format(threshold) + ": " + runningTotal.samples + " samples averaging " + formatter.format(runningTotal.mean) + ").";
39+
}
40+
}
1141

12-
public double minValue = Long.MAX_VALUE;
13-
public double maxValue = Long.MIN_VALUE;
14-
public double lastValue = 0;
15-
public double avgValue = 0;
16-
public double avgValueExceeding = 0;
17-
public int samples = 0;
18-
public int samplesExceeding = 0;
42+
private final String name;
1943
public int interrupted = 0;
20-
2144
private long timeStarted = 0;
2245

23-
PerformanceMetric(String name, long maxAllowed) {
46+
RunningTotal runningTotal = new RunningTotal();
47+
private ArrayList<Threshold> thresholds = new ArrayList<>();
48+
49+
PerformanceMetric(String name, double... thresholds) {
2450
this.name = name;
25-
this.maxAllowed = maxAllowed;
51+
for (double threshold : thresholds) {
52+
this.thresholds.add(new Threshold(threshold));
53+
}
2654
}
2755

2856
/**
@@ -77,47 +105,37 @@ void stopTiming() {
77105
* Manually records a specific value.
78106
*/
79107
void record(double value) {
80-
lastValue = value;
81-
minValue = Math.min(minValue, value);
82-
maxValue = Math.max(maxValue, value);
83-
avgValue = (avgValue * samples + value) / (samples + 1d);
84-
++samples;
85-
if (value > maxAllowed) {
86-
avgValueExceeding = (avgValueExceeding * samplesExceeding + value) / (samplesExceeding + 1d);
87-
++samplesExceeding;
88-
}
108+
runningTotal.record(value);
109+
thresholds.forEach(threshold -> threshold.record(value));
89110
}
90111

91112
/**
92113
* @return A pretty-printed description of the recorded values.
93114
*/
94115
@Override
95116
public String toString() {
117+
if (runningTotal.samples <= 0) {
118+
return name + ": No samples.";
119+
}
96120
DecimalFormat formatter = new DecimalFormat("###,###.#");
97-
return name
121+
String output = name
98122
+ ": "
99-
+ (samples > 0
100-
? formatter.format(samples)
101-
+ " samples averaging "
102-
+ formatter.format(avgValue)
103-
+ " ["
104-
+ formatter.format(minValue)
105-
+ " - "
106-
+ formatter.format(maxValue)
107-
+ "] over "
108-
+ samples
109-
+ " samples"
110-
+ (samplesExceeding > 0
111-
? ". "
112-
+ samplesExceeding
113-
+ " values over "
114-
+ maxAllowed
115-
+ " averaging "
116-
+ formatter.format(avgValueExceeding)
117-
: "")
118-
: "No samples")
119-
+ (interrupted > 0
120-
? ". Interrupted " + interrupted + " times"
121-
: "");
123+
+ formatter.format(runningTotal.samples)
124+
+ " samples averaging "
125+
+ formatter.format(runningTotal.mean)
126+
+ " ["
127+
+ formatter.format(runningTotal.min)
128+
+ " - "
129+
+ formatter.format(runningTotal.max)
130+
+ "] over "
131+
+ runningTotal.samples
132+
+ " samples. ";
133+
for (Threshold threshold : thresholds) {
134+
output += threshold.toString();
135+
}
136+
if (interrupted > 0) {
137+
output += "\n\tInterrupted " + interrupted + " times";
138+
}
139+
return output;
122140
}
123141
}

src/main/java/bwapi/PerformanceMetrics.java

Lines changed: 33 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,95 +10,84 @@ public class PerformanceMetrics {
1010
* Likely to be at least a little bit of an undercount,
1111
* given that the tournament module is timing a superset of JBWAPI's execution time.
1212
*/
13-
public PerformanceMetric totalFrameDuration;
13+
PerformanceMetric totalFrameDuration;
1414

1515
/**
1616
* Time spent copying game data from system pipe shared memory to a frame buffer.
1717
* Applicable only in asynchronous mode.
1818
*/
19-
public PerformanceMetric copyingToBuffer;
19+
PerformanceMetric copyingToBuffer;
2020

2121
/**
2222
* Time spent intentionally blocking on bot operation due to a full frame buffer.
2323
* Applicable only in asynchronous mode.
2424
*/
25-
public PerformanceMetric intentionallyBlocking;
25+
PerformanceMetric intentionallyBlocking;
2626

2727
/**
2828
* Number of frames backed up in the frame buffer, after enqueuing each frame (and not including the newest frame).
2929
* Applicable only in asynchronous mode.
3030
*/
31-
public PerformanceMetric frameBufferSize;
31+
PerformanceMetric frameBufferSize;
3232

3333
/**
3434
* Number of frames behind real-time the bot is at the time it handles events.
3535
* Applicable only in asynchronous mode.
3636
*/
37-
public PerformanceMetric framesBehind;
37+
PerformanceMetric framesBehind;
3838

3939
/**
4040
* Time spent applying bot commands to the live frame.
4141
*/
42-
public PerformanceMetric flushSideEffects;
42+
PerformanceMetric flushSideEffects;
4343

4444
/**
4545
* Time spent waiting for bot event handlers to complete for a single frame.
4646
*/
47-
public PerformanceMetric botResponse;
47+
PerformanceMetric botResponse;
4848

4949
/**
5050
* Time spent waiting for a response from BWAPI; is likely reflective of the performance of any opponent bots.
5151
*/
52-
public PerformanceMetric bwapiResponse;
52+
PerformanceMetric bwapiResponse;
5353

5454
/**
5555
* Time bot spends idle.
5656
* Applicable only in asynchronous mode.
5757
*/
58-
public PerformanceMetric botIdle;
59-
60-
public PerformanceMetric frameDuration5;
61-
public PerformanceMetric frameDuration10;
62-
public PerformanceMetric frameDuration15;
63-
public PerformanceMetric frameDuration20;
64-
public PerformanceMetric frameDuration25;
65-
public PerformanceMetric frameDuration30;
66-
public PerformanceMetric frameDuration35;
67-
public PerformanceMetric frameDuration40;
68-
public PerformanceMetric frameDuration45;
69-
public PerformanceMetric frameDuration50;
70-
public PerformanceMetric frameDuration55;
58+
PerformanceMetric botIdle;
59+
60+
/**
61+
* Time the main thread spends idle, waiting for the bot to finish processing frames.
62+
* Applicable only in asynchronous mode.
63+
*/
64+
PerformanceMetric clientIdle;
65+
66+
/**
67+
* Time the main thread spends oversleeping its timeout target, potentially causing overtime frames.
68+
* Applicable only in asynchronous mode.
69+
*/
70+
PerformanceMetric excessSleep;
7171

7272
private BWClientConfiguration configuration;
7373

74-
public PerformanceMetrics(BWClientConfiguration configuration) {
74+
PerformanceMetrics(BWClientConfiguration configuration) {
7575
this.configuration = configuration;
7676
reset();
7777
}
7878

7979
void reset() {
80-
final int sideEffectsBufferMs = 1;
81-
final int realTimeFrameMs = 42;
82-
totalFrameDuration = new PerformanceMetric("JBWAPI frame duration", configuration.maxFrameDurationMs + 5);
83-
copyingToBuffer = new PerformanceMetric("Time copying to buffer", configuration.maxFrameDurationMs + 5);
80+
totalFrameDuration = new PerformanceMetric("JBWAPI frame duration", 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);
81+
copyingToBuffer = new PerformanceMetric("Time copying to buffer", 5, 10, 15, 20, 25, 30);
8482
intentionallyBlocking = new PerformanceMetric("Blocking with full buffer", 0);
85-
frameBufferSize = new PerformanceMetric("Frames buffered", 0);
86-
framesBehind = new PerformanceMetric("Frames behind real-time", 0);
87-
flushSideEffects = new PerformanceMetric("Flushing side effects", sideEffectsBufferMs );
88-
botResponse = new PerformanceMetric("Bot event handlers", configuration.maxFrameDurationMs);
89-
bwapiResponse = new PerformanceMetric("Responses from BWAPI", realTimeFrameMs);
83+
frameBufferSize = new PerformanceMetric("Frames buffered", 0, 1);
84+
framesBehind = new PerformanceMetric("Frames behind real-time", 0, 1);
85+
flushSideEffects = new PerformanceMetric("Flushing side effects", 1, 3, 5);
86+
botResponse = new PerformanceMetric("Bot event handlers", 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);
87+
bwapiResponse = new PerformanceMetric("Responses from BWAPI", 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);
9088
botIdle = new PerformanceMetric("Bot idle", Long.MAX_VALUE);
91-
frameDuration5 = new PerformanceMetric("JBWAPI frame @ 5ms", 5);
92-
frameDuration10 = new PerformanceMetric("JBWAPI frame @ 10ms", 10);
93-
frameDuration15 = new PerformanceMetric("JBWAPI frame @ 15ms", 15);
94-
frameDuration20 = new PerformanceMetric("JBWAPI frame @ 20ms", 20);
95-
frameDuration25 = new PerformanceMetric("JBWAPI frame @ 25ms", 25);
96-
frameDuration30 = new PerformanceMetric("JBWAPI frame @ 30ms", 30);
97-
frameDuration35 = new PerformanceMetric("JBWAPI frame @ 35ms", 35);
98-
frameDuration40 = new PerformanceMetric("JBWAPI frame @ 40ms", 40);
99-
frameDuration45 = new PerformanceMetric("JBWAPI frame @ 45ms", 45);
100-
frameDuration50 = new PerformanceMetric("JBWAPI frame @ 50ms", 50);
101-
frameDuration55 = new PerformanceMetric("JBWAPI frame @ 55ms", 55);
89+
clientIdle = new PerformanceMetric("Client idling", configuration.maxFrameDurationMs);
90+
excessSleep = new PerformanceMetric("Excess sleep", 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);
10291
}
10392

10493
@Override
@@ -113,16 +102,7 @@ public String toString() {
113102
+ "\n" + botResponse.toString()
114103
+ "\n" + bwapiResponse.toString()
115104
+ "\n" + botIdle.toString()
116-
+ "\n" + frameDuration5.toString()
117-
+ "\n" + frameDuration10.toString()
118-
+ "\n" + frameDuration15.toString()
119-
+ "\n" + frameDuration20.toString()
120-
+ "\n" + frameDuration25.toString()
121-
+ "\n" + frameDuration30.toString()
122-
+ "\n" + frameDuration35.toString()
123-
+ "\n" + frameDuration40.toString()
124-
+ "\n" + frameDuration45.toString()
125-
+ "\n" + frameDuration50.toString()
126-
+ "\n" + frameDuration55.toString();
105+
+ "\n" + clientIdle.toString()
106+
+ "\n" + excessSleep.toString();
127107
}
128108
}

src/main/java/bwapi/Unit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public int getID() {
115115
* <p>
116116
* In the event that this function returns false, there are two cases to consider:
117117
* 1. You own the unit. This means the unit is dead.
118-
* 2. Another player owns the unit. This could either mean that you don't have access
118+
* 2. Another player owns the unit. This could either runningTotal that you don't have access
119119
* to the unit or that the unit has died. You can specifically identify dead units
120120
* by polling onUnitDestroy.
121121
* @see #isVisible

0 commit comments

Comments
 (0)