/** * Stop the trace. This may only be done once and must be done from the same thread that started * it. * * @param silenceThreshold Traces for time less than silence_threshold ms will be left out of the * trace report. A value of -1 indicates that the current ThreadTrace silence_threshold should * be used. * @return The time that this trace actually ran */ long stop(int silenceThreshold) { Preconditions.checkState(Thread.currentThread() == startThread); ThreadTrace trace = getThreadTrace(); // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } stopTimeMs = clock.currentTimeMillis(); if (extraTracingValues != null) { // We use extraTracingValues.length rather than // extraTracingStatistics.size() because a new statistic may // have been added for (int i = 0; i < extraTracingValues.length; i++) { long value = extraTracingStatistics.get(i).stop(startThread); extraTracingValues[i] = value - extraTracingValues[i]; } } // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } trace.endEvent(this, silenceThreshold); return stopTimeMs - startTimeMs; }
/** * Create and start a tracer. Both type and comment may be null. See class comment for usage. * * @param type The type for totaling * @param comment Comment about this tracer */ Tracer(@Nullable String type, @Nullable String comment) { this.type = type; this.comment = nullToEmpty(comment); startTimeMs = clock.currentTimeMillis(); startThread = Thread.currentThread(); if (!extraTracingStatistics.isEmpty()) { int size = extraTracingStatistics.size(); extraTracingValues = new long[size]; int i = 0; for (TracingStatistic tracingStatistic : extraTracingStatistics) { extraTracingValues[i] = tracingStatistic.start(startThread); i++; } } ThreadTrace trace = getThreadTrace(); // Do nothing if the current thread trace wasn't initialized. if (!trace.isInitialized()) { return; } // Check if we are creating too many Tracers. if (trace.events.size() >= MAX_TRACE_SIZE) { logger.log( Level.WARNING, "Giant thread trace. Too many Tracers created. " + "Clearing to avoid memory leak.", new Throwable(trace.toString())); trace.truncateEvents(); } // Check if we forgot to close the Tracers. if (trace.outstandingEvents.size() >= MAX_TRACE_SIZE) { logger.log( Level.WARNING, "Too many outstanding Tracers. Tracer.stop() is missing " + "or Tracer.stop() is not wrapped in a " + "try/finally block. " + "Clearing to avoid memory leak.", new Throwable(trace.toString())); trace.truncateOutstandingEvents(); } trace.startEvent(this); }
// Nullness checker does not understand that prettyPrint => indent != null @SuppressWarnings("nullness") @Override public String toString() { int numDigits = getMaxDigits(); StringBuilder sb = new StringBuilder(); long etime = -1; LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null; for (Event e : events) { if (prettyPrint && !e.isStart && !indent.isEmpty()) { indent.pop(); } sb.append(" "); if (prettyPrint) { sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits)); } else { sb.append(e.toString(etime, "", 4)); } etime = e.eventTime(); sb.append('\n'); if (prettyPrint && e.isStart) { indent.push("| "); } } if (!outstandingEvents.isEmpty()) { long now = clock.currentTimeMillis(); sb.append(" Unstopped timers:\n"); for (Tracer t : outstandingEvents) { sb.append(" ") .append(t) .append(" (") .append(now - t.startTimeMs) .append(" ms, started at ") .append(formatTime(t.startTimeMs)) .append(")\n"); } } for (Map.Entry<String, Stat> statEntry : stats.entrySet()) { Stat stat = statEntry.getValue(); if (stat.count > 1) { sb.append(" TOTAL ") .append(statEntry.getKey()) .append(" ") .append(stat.count) .append(" (") .append(stat.clockTime) .append(" ms"); if (stat.extraInfo != null) { for (int i = 0; i < stat.extraInfo.length; i++) { sb.append("; "); sb.append(stat.extraInfo[i]) .append(' ') .append(extraTracingStatistics.get(i).getUnits()); } } sb.append(")\n"); } } return sb.toString(); }