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