View Javadoc
1   /*
2    * Oceanus: Java Utilities
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.oceanus.profile;
18  
19  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  /**
27   * Profile data.
28   */
29  public class OceanusProfile {
30      /**
31       * number of decimals for elapsed.
32       */
33      private static final int NUM_DECIMALS = 6;
34  
35      /**
36       * Step name.
37       */
38      private final String theName;
39  
40      /**
41       * Status.
42       */
43      private OceanusProfileStatus theStatus;
44  
45      /**
46       * Start time.
47       */
48      private final long theStart;
49  
50      /**
51       * Elapsed (in milliseconds).
52       */
53      private OceanusDecimal theElapsed;
54  
55      /**
56       * Hidden Elapsed (in milliseconds).
57       */
58      private OceanusDecimal theHidden;
59  
60      /**
61       * Current subTask.
62       */
63      private OceanusProfile theCurrentTask;
64  
65      /**
66       * List of subTasks.
67       */
68      private List<OceanusProfile> theSubTasks;
69  
70      /**
71       * Constructor.
72       *
73       * @param pName the name of the step
74       */
75      public OceanusProfile(final String pName) {
76          /* Record the name and start the timer */
77          theName = pName;
78          theStart = System.nanoTime();
79          theStatus = OceanusProfileStatus.RUNNING;
80      }
81  
82      /**
83       * Obtain the name of the profile.
84       *
85       * @return the name
86       */
87      public String getName() {
88          return theName;
89      }
90  
91      /**
92       * Obtain the status of the profile.
93       *
94       * @return the status
95       */
96      public OceanusProfileStatus getStatus() {
97          return theStatus.isRunning()
98                  ? theStatus
99                  : null;
100     }
101 
102     /**
103      * Obtain the elapsed time of the profile.
104      *
105      * @return the elapsedTime
106      */
107     public OceanusDecimal getElapsed() {
108         return theStatus.isRunning()
109                 ? null
110                 : theElapsed;
111     }
112 
113     /**
114      * Obtain the hidden time of the profile.
115      *
116      * @return the hiddenTime
117      */
118     public OceanusDecimal getHidden() {
119         return theHidden;
120     }
121 
122     /**
123      * Obtain the subtask iterator.
124      *
125      * @return the iterator
126      */
127     public Iterator<OceanusProfile> subTaskIterator() {
128         return theSubTasks == null ? Collections.emptyIterator() : theSubTasks.iterator();
129     }
130 
131     /**
132      * Start a new subTask.
133      *
134      * @param pName the name of the subTask
135      * @return the new task
136      */
137     public OceanusProfile startTask(final String pName) {
138         /* If we are currently running */
139         if (theStatus.isRunning()) {
140             /* Prepare for the task */
141             prepareForTask();
142 
143             /* Loop through the subTasks */
144             for (OceanusProfile myProfile : theSubTasks) {
145                 /* Check for duplicate name */
146                 if (pName.equals(myProfile.getName())) {
147                     throw new IllegalArgumentException("Duplicate Task - " + pName);
148                 }
149             }
150 
151             /* Create the new task */
152             final OceanusProfile myTask = new OceanusProfile(pName);
153             theSubTasks.add(myTask);
154             theCurrentTask = myTask;
155         }
156 
157         /* Return the current task */
158         return theCurrentTask;
159     }
160 
161     /**
162      * Prepare for the task.
163      */
164     private void prepareForTask() {
165         /* End any subTask */
166         endSubTask();
167 
168         /* If we do not currently have a subTask list */
169         if (theSubTasks == null) {
170             /* Create the list */
171             theSubTasks = new ArrayList<>();
172         }
173     }
174 
175     /**
176      * End any subTask.
177      */
178     private void endSubTask() {
179         /* If we have a subTask */
180         if (theCurrentTask != null) {
181             /* End the current task */
182             theCurrentTask.end();
183             theCurrentTask = null;
184         }
185     }
186 
187     /**
188      * End the task.
189      */
190     public void end() {
191         /* If we are currently running */
192         if (theStatus.isRunning()) {
193             /* End any subTasks */
194             endSubTask();
195 
196             /* Stop the task and calculate the elapsed time */
197             final long myEnd = System.nanoTime();
198             theElapsed = new OceanusDecimal(myEnd - theStart, NUM_DECIMALS);
199             theHidden = theSubTasks == null
200                     ? null
201                     : calculateHidden();
202 
203             /* Mark time as stopped */
204             theStatus = OceanusProfileStatus.STOPPED;
205         }
206     }
207 
208     /**
209      * Calculate the hidden time.
210      *
211      * @return the hidden time
212      */
213     private OceanusDecimal calculateHidden() {
214         /* Initialise hidden value */
215         final OceanusDecimal myHidden = new OceanusDecimal(theElapsed);
216 
217         /* Loop through the subTasks */
218         for (OceanusProfile myProfile : theSubTasks) {
219             /* Subtract child time */
220             myHidden.subtractValue(myProfile.theElapsed);
221         }
222 
223         /* Return calculated value */
224         return myHidden;
225     }
226 
227     /**
228      * is the task running?
229      *
230      * @return true/false.
231      */
232     public boolean isRunning() {
233         /* return status */
234         return theStatus.isRunning();
235     }
236 
237     /**
238      * Obtain the currently active task.
239      *
240      * @return the task
241      */
242     public OceanusProfile getActiveTask() {
243         /* If we are not currently running */
244         if (!isRunning()) {
245             return null;
246         }
247 
248         /* Return self is no active and running subTask else ask subTask */
249         return theCurrentTask == null
250                 || !theCurrentTask.isRunning()
251                 ? this
252                 : theCurrentTask.getActiveTask();
253     }
254 
255     /**
256      * Status of timer.
257      */
258     public enum OceanusProfileStatus {
259         /**
260          * Running.
261          */
262         RUNNING,
263 
264         /**
265          * Stopped.
266          */
267         STOPPED;
268 
269         /**
270          * is the timer running?
271          *
272          * @return true/false
273          */
274         private boolean isRunning() {
275             return this == RUNNING;
276         }
277     }
278 }
279