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 @SuppressWarnings("PMD.UseConcurrentHashMap") 026 private final Map<String, Long> m_epochs = new HashMap<>(); // microseconds 027 028 /** Tracer constructor. */ 029 public Tracer() { 030 resetTimer(); 031 } 032 033 /** Clears all epochs. */ 034 public void clearEpochs() { 035 m_epochs.clear(); 036 resetTimer(); 037 } 038 039 /** Restarts the epoch timer. */ 040 public void resetTimer() { 041 m_startTime = RobotController.getFPGATime(); 042 } 043 044 /** 045 * Adds time since last epoch to the list printed by printEpochs(). 046 * 047 * <p>Epochs are a way to partition the time elapsed so that when overruns occur, one can 048 * determine which parts of an operation consumed the most time. 049 * 050 * <p>This should be called immediately after execution has finished, with a call to this method 051 * or {@link #resetTimer()} before execution. 052 * 053 * @param epochName The name to associate with the epoch. 054 */ 055 public void addEpoch(String epochName) { 056 long currentTime = RobotController.getFPGATime(); 057 m_epochs.put(epochName, currentTime - m_startTime); 058 m_startTime = currentTime; 059 } 060 061 /** Prints list of epochs added so far and their times to the DriverStation. */ 062 public void printEpochs() { 063 printEpochs(out -> DriverStation.reportWarning(out, false)); 064 } 065 066 /** 067 * Prints list of epochs added so far and their times to the entered String consumer. 068 * 069 * <p>This overload can be useful for logging to a file, etc. 070 * 071 * @param output the stream that the output is sent to 072 */ 073 public void printEpochs(Consumer<String> output) { 074 long now = RobotController.getFPGATime(); 075 if (now - m_lastEpochsPrintTime > kMinPrintPeriod) { 076 StringBuilder sb = new StringBuilder(); 077 m_lastEpochsPrintTime = now; 078 m_epochs.forEach( 079 (key, value) -> { 080 sb.append(String.format("\t%s: %.6fs\n", key, value / 1.0e6)); 081 }); 082 if (sb.length() > 0) { 083 output.accept(sb.toString()); 084 } 085 } 086 } 087}