001/* 002 * (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 */ 019package org.nuxeo.runtime.util; 020 021import java.text.DecimalFormat; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Objects; 025import java.util.concurrent.TimeUnit; 026 027/** 028 * Usage: 029 * 030 * <pre> 031 * <code> 032 * Watch w = new Watch() 033 * w.start(); 034 * ... 035 * w.start("interval-name") 036 * w.stop("interval-name") 037 * .. 038 * w.stop() 039 * </code> 040 * </pre> 041 * 042 * @author bogdan 043 * @since 9.2 044 */ 045public class Watch { 046 047 public final TimeInterval total; 048 049 public final Map<String, TimeInterval> intervals; 050 051 public Watch() { 052 this(new HashMap<>()); 053 } 054 055 public Watch(Map<String, TimeInterval> intervals) { 056 this.total = new TimeInterval("total"); 057 this.intervals = Objects.requireNonNull(intervals, "Given intervals can't be null"); 058 } 059 060 public Watch start() { 061 // reset if needed 062 total.t0 = 0; 063 total.t1 = 0; 064 intervals.clear(); 065 066 total.start(); 067 return this; 068 } 069 070 public Watch stop() { 071 total.stop(); 072 return this; 073 } 074 075 public Watch start(String interval) { 076 intervals.computeIfAbsent(interval, TimeInterval::new).start(); 077 return this; 078 } 079 080 public Watch stop(String interval) { 081 TimeInterval ti = intervals.get(interval); 082 if (ti != null) { 083 ti.stop(); 084 } 085 return this; 086 } 087 088 public long elapsed(TimeUnit unit) { 089 return total.elapsed(unit); 090 } 091 092 public long elapsed(String name, TimeUnit unit) { 093 TimeInterval ti = intervals.get(name); 094 if (ti != null) { 095 return ti.elapsed(unit); 096 } 097 return 0; 098 } 099 100 public TimeInterval getTotal() { 101 return total; 102 } 103 104 public TimeInterval[] getIntervals() { 105 return intervals.values().toArray(new TimeInterval[intervals.size()]); 106 } 107 108 public static class TimeInterval implements Comparable<TimeInterval> { 109 110 protected final String name; 111 112 protected long t0; 113 114 protected long t1; 115 116 public TimeInterval(String name) { 117 this.name = name; 118 } 119 120 public String getName() { 121 return name; 122 } 123 124 /** 125 * Elapsed time in nano seconds 126 */ 127 public long elapsed() { 128 return t1 - t0; 129 } 130 131 public long elapsed(TimeUnit unit) { 132 return unit.convert(t1 - t0, TimeUnit.NANOSECONDS); 133 } 134 135 protected void start() { 136 this.t0 = System.nanoTime(); 137 } 138 139 protected void stop() { 140 this.t1 = System.nanoTime(); 141 } 142 143 public boolean isStopped() { 144 return t1 != 0; 145 } 146 147 @Override 148 public int compareTo(TimeInterval o) { 149 long dt = (t1 - t0) - (o.t1 - o.t0); // this may be out of range for an int 150 return dt < 0 ? -1 : (dt > 0 ? 1 : 0); 151 } 152 153 public String formatSeconds() { 154 return new DecimalFormat("0.000").format(((double) this.t1 - this.t0) / 1000000000); 155 } 156 157 @Override 158 public String toString() { 159 return name + ": " + this.formatSeconds() + " sec."; 160 } 161 162 } 163 164}