001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj; 006 007import java.util.HashMap; 008import java.util.Map; 009import java.util.function.Consumer; 010 011/** 012 * A class for keeping track of how much time it takes for different parts of code to execute. This 013 * is done with epochs, that are added by calls to {@link #addEpoch(String)}, and can be printed 014 * with a call to {@link #printEpochs()}. 015 * 016 * <p>Epochs are a way to partition the time elapsed so that when overruns occur, one can determine 017 * which parts of an operation consumed the most time. 018 */ 019public class Tracer { 020 private static final long kMinPrintPeriod = 1000000; // microseconds 021 022 private long m_lastEpochsPrintTime; // microseconds 023 private long m_startTime; // microseconds 024 025 private final Map<String, Long> m_epochs = new HashMap<>(); // microseconds 026 027 /** Tracer constructor. */ 028 public Tracer() { 029 resetTimer(); 030 } 031 032 /** Clears all epochs. */ 033 public void clearEpochs() { 034 m_epochs.clear(); 035 resetTimer(); 036 } 037 038 /** Restarts the epoch timer. */ 039 public final void resetTimer() { 040 m_startTime = RobotController.getFPGATime(); 041 } 042 043 /** 044 * Adds time since last epoch to the list printed by printEpochs(). 045 * 046 * <p>Epochs are a way to partition the time elapsed so that when overruns occur, one can 047 * determine which parts of an operation consumed the most time. 048 * 049 * <p>This should be called immediately after execution has finished, with a call to this method 050 * or {@link #resetTimer()} before execution. 051 * 052 * @param epochName The name to associate with the epoch. 053 */ 054 public void addEpoch(String epochName) { 055 long currentTime = RobotController.getFPGATime(); 056 m_epochs.put(epochName, currentTime - m_startTime); 057 m_startTime = currentTime; 058 } 059 060 /** Prints list of epochs added so far and their times to the DriverStation. */ 061 public void printEpochs() { 062 printEpochs(out -> DriverStation.reportWarning(out, false)); 063 } 064 065 /** 066 * Prints list of epochs added so far and their times to the entered String consumer. 067 * 068 * <p>This overload can be useful for logging to a file, etc. 069 * 070 * @param output the stream that the output is sent to 071 */ 072 public void printEpochs(Consumer<String> output) { 073 long now = RobotController.getFPGATime(); 074 if (now - m_lastEpochsPrintTime > kMinPrintPeriod) { 075 StringBuilder sb = new StringBuilder(); 076 m_lastEpochsPrintTime = now; 077 m_epochs.forEach( 078 (key, value) -> sb.append(String.format("\t%s: %.6fs\n", key, value / 1.0e6))); 079 if (sb.length() > 0) { 080 output.accept(sb.toString()); 081 } 082 } 083 } 084}