MATSIM
IterationStopWatch.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * IterationStopWatch.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.analysis;
22 
23 import org.jfree.chart.axis.CategoryLabelPositions;
25 import org.matsim.core.utils.io.IOUtils;
26 import org.matsim.core.utils.misc.Time;
27 
28 import java.io.BufferedWriter;
29 import java.io.IOException;
30 import java.text.DateFormat;
31 import java.text.SimpleDateFormat;
32 import java.util.*;
33 import java.util.Map.Entry;
34 
43 public final class IterationStopWatch {
47  public static final String OPERATION_ITERATION = "iteration";
48 
49  /*
50  * Time spent in operations which are not measured in detail.
51  */
52  public static final String OPERATION_OTHER = "other";
53 
55  private Integer iteration = null;
56 
58  private final Map<Integer, Map<String, Long>> iterations;
59 
61  private final List<String> identifiers;
62 
64  private final List<String> operations;
65 
67  private Map<String, Long> currentIterationValues;
68 
70  private int nextIdentifierPosition = 0;
71 
73  private int nextOperationPosition = 0;
74 
76  private final DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
77 
79  private Stack<String> currentMeasuredOperations;
80  private Map<String, List<String>> currentIterationChildren;
81  private final Map<Integer, Map<String, List<String>>> children;
82 
84  public IterationStopWatch() {
85  this.iterations = new LinkedHashMap<>();
86  this.identifiers = new LinkedList<>();
87  this.operations = new LinkedList<>();
88  this.currentIterationValues = null;
89  this.children = new LinkedHashMap<>();
90  }
91 
95  public void reset() {
96  this.nextIdentifierPosition = 0;
97  this.nextOperationPosition = 0;
98  this.iteration = null;
99  this.currentIterationValues = null;
100  this.iterations.clear();
101  this.identifiers.clear();
102  this.operations.clear();
103  this.currentMeasuredOperations.clear();
104  this.currentIterationChildren.clear();
105  this.children.clear();
106  }
107 
113  public void beginIteration(final int iteration) {
114  this.iteration = iteration;
115  if (this.iterations.get(this.iteration) == null) {
116  this.currentIterationValues = new HashMap<>();
117  this.iterations.put(this.iteration, this.currentIterationValues);
118  this.nextIdentifierPosition = 0;
119  this.nextOperationPosition = 0;
120  this.currentMeasuredOperations = new Stack<>();
121  this.currentIterationChildren = new HashMap<>();
122  this.children.put(this.iteration, this.currentIterationChildren);
123  }
124  this.beginOperation(OPERATION_ITERATION);
125  }
126 
132  public void beginOperation(final String identifier) {
133 
134  if (identifier.equals(OPERATION_OTHER)) {
135  throw new RuntimeException("Identifier " + OPERATION_OTHER + " is reserved! Please use another one. Aborting!");
136  }
137 
138  String ident = "BEGIN " + identifier;
139  ensureIdentifier(ident);
140  this.currentIterationValues.put(ident, System.currentTimeMillis());
141 
142  this.currentIterationChildren.put(identifier, new ArrayList<>());
143 
144  // check whether this operation has a parent operation
145  if (!this.currentMeasuredOperations.isEmpty()) {
146  String parent = this.currentMeasuredOperations.peek();
147  this.currentIterationChildren.get(parent).add(identifier);
148  }
149 
150  // add ident to stack
151  this.currentMeasuredOperations.push(identifier);
152  }
153 
160  public void endOperation(final String identifier) {
161  String ident = "END " + identifier;
162  ensureIdentifier(ident);
163  ensureOperation(identifier);
164  this.currentIterationValues.put(ident, System.currentTimeMillis());
165 
166 
167  this.currentMeasuredOperations.pop();
168  }
169 
170  public void endIteration() {
171  this.endOperation(OPERATION_ITERATION);
172  }
173 
179  public void timestamp(final String identifier) {
180  ensureIdentifier(identifier);
181  this.currentIterationValues.put(identifier, System.currentTimeMillis());
182  }
183 
190  public void writeSeparatedFile(final String filename, final String delimiter) {
191  try (BufferedWriter writer = IOUtils.getBufferedWriter(filename)) {
192 
193  // print header
194  writer.write("iteration");
195  for (String identifier : this.identifiers) {
196  writer.write(delimiter);
197  writer.write(identifier);
198  }
199  writer.write(delimiter);
200  for (String identifier : this.operations) {
201  writer.write(delimiter);
202  writer.write(identifier);
203  }
204  writer.write('\n');
205 
206  // print data
207  for (Map.Entry<Integer, Map<String, Long>> entry : this.iterations.entrySet()) {
208  Integer iteration = entry.getKey();
209  Map<String, Long> data = entry.getValue();
210  // iteration
211  writer.write(iteration.toString());
212  // identifiers
213  for (String identifier : this.identifiers) {
214  Long time = data.get(identifier);
215  writer.write(delimiter);
216  writer.write(formatMilliTime(time));
217  }
218  // blank separator
219  writer.write(delimiter);
220  // durations of operations
221  for (String identifier: this.operations) {
222  Long startTime = data.get("BEGIN " + identifier);
223  Long endTime = data.get("END " + identifier);
224  writer.write(delimiter);
225  if (startTime != null && endTime != null) {
226  double diff = (endTime - startTime) / 1000.0;
227  writer.write(Time.writeTime(diff));
228  }
229  }
230 
231  // finish
232  writer.write("\n");
233  }
234  writer.flush();
235  } catch (IOException e) {
236  throw new RuntimeException(e);
237  }
238  }
239 
245  public void writeGraphFile(String filename) {
246 
247  int iterations = this.iterations.entrySet().size();
248  Map<String, double[]> arrayMap = new HashMap<>();
249  for (String identifier : this.operations) arrayMap.put(identifier, new double[iterations]);
250 
251  int iter = 0;
252  for(Entry<Integer, Map<String, Long>> entry : this.iterations.entrySet()) {
253  Map<String, Long> data = entry.getValue();
254 
255  // children map of current iteration
256  Map<String, List<String>> childrenMap = this.children.get(entry.getKey());
257 
258  // durations of operations
259  for (String identifier : this.operations) {
260  Long startTime = data.get("BEGIN " + identifier);
261  Long endTime = data.get("END " + identifier);
262  if (startTime != null && endTime != null) {
263  double diff = (endTime - startTime);
264 
265  /*
266  * If the operation has children, subtract their durations since they are
267  * also included in the plot. Otherwise, their duration would be counted twice.
268  */
269  for (String child : childrenMap.get(identifier)) {
270  Long childStartTime = data.get("BEGIN " + child);
271  Long childEndTime = data.get("END " + child);
272  diff -= (childEndTime - childStartTime);
273  }
274 
275  arrayMap.get(identifier)[iter] = diff / 1000.0;
276  } else arrayMap.get(identifier)[iter] = 0.0;
277  }
278  iter++;
279  }
280 
281  String title = "Computation time distribution per iteration";
282  String xAxisLabel = "iteration";
283  String yAxisLabel = "seconds";
284 
285  String[] categories = new String[this.iterations.size()];
286  int index = 0;
287  for (int iteration : this.iterations.keySet()) {
288  categories[index] = String.valueOf(iteration);
289  index++;
290  }
291 
292  StackedBarChart chart = new StackedBarChart(title, xAxisLabel, yAxisLabel, categories);
293  chart.addMatsimLogo();
294 
295  /*
296  * Rotate x-axis labels by 90° which should allow more of them to be plotted before overlapping.
297  * However, a more general solution that also is able to skip labels would be nice.
298  * cdobler nov'13
299  */
300  chart.getChart().getCategoryPlot().getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
301 
302  double[] iterationData = null;
303  for (String operation : this.operations) {
304  double[] data = arrayMap.get(operation);
305  if (operation.equals(OPERATION_ITERATION)) {
306  iterationData = data;
307  } else {
308  chart.addSeries(operation, data);
309  }
310  }
311  if (iterationData != null) {
312  double[] otherData = new double[iterations];
313  System.arraycopy(iterationData, 0, otherData, 0, iterations);
314  chart.addSeries(OPERATION_OTHER, otherData);
315  }
316 
317  chart.saveAsPng(filename + ".png", 1024, 768);
318  }
319 
325  private void ensureIdentifier(final String identifier) {
326  int pos = this.identifiers.indexOf(identifier);
327  if (pos == -1) {
328  this.identifiers.add(this.nextIdentifierPosition, identifier);
329  this.nextIdentifierPosition++;
330  } else {
331  this.nextIdentifierPosition = pos + 1;
332  }
333  }
334 
338  private void ensureOperation(final String identifier) {
339  int pos = this.operations.indexOf(identifier);
340  if (pos == -1) {
341  this.operations.add(this.nextOperationPosition, identifier);
342  this.nextOperationPosition++;
343  } else {
344  this.nextOperationPosition = pos + 1;
345  }
346  }
347 
355  private String formatMilliTime(final Long millis) {
356  if (millis == null) {
357  return "";
358  }
359  return this.formatter.format(new Date(millis));
360  }
361 
362 }
final Map< Integer, Map< String, List< String > > > children
void writeSeparatedFile(final String filename, final String delimiter)
void ensureIdentifier(final String identifier)
void endOperation(final String identifier)
void timestamp(final String identifier)
static BufferedWriter getBufferedWriter(URL url, Charset charset, boolean append)
Definition: IOUtils.java:390
void addSeries(final String title, final double[] values)
final Map< Integer, Map< String, Long > > iterations
void ensureOperation(final String identifier)
Map< String, List< String > > currentIterationChildren
static final String writeTime(final double seconds, final String timeformat)
Definition: Time.java:80
void saveAsPng(final String filename, final int width, final int height)
Definition: ChartUtil.java:65
void beginOperation(final String identifier)