View Javadoc
1   package org.djutils.profile;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertNull;
5   import static org.junit.Assert.assertTrue;
6   import static org.junit.Assert.fail;
7   
8   import org.junit.Test;
9   
10  /**
11   * Test the Profile class.
12   */
13  public class ProfileTest
14  {
15  
16      /**
17       * Test the Profile class using sine and cosine.
18       */
19      @Test
20      public void profileTestUsingTrigFunctions()
21      {
22          System.gc();
23          Profile.clear();
24          // preload
25          doSine(Math.toRadians(90));
26          doCosine(Math.toRadians(90));
27          Profile.setPrintInterval(0);
28          Profile.print();
29          Profile.reset();
30          for (int step = 0; step <= 90; step++)
31          {
32              // System.out.println("step " + step);
33              double angle = Math.toRadians(step);
34              doCosine(angle);
35              doSine(angle);
36          }
37          Profile.print();
38      }
39  
40      /**
41       * Perform a somewhat CPU time intensive function.
42       * @param angle double; the argument
43       */
44      public void doSine(final double angle)
45      {
46          Profile.start();
47          Math.sin(angle);
48          Profile.end();
49      }
50  
51      /**
52       * Perform a somewhat CPU time intensive function.
53       * @param angle double; the argument
54       */
55      public void doCosine(final double angle)
56      {
57          Profile.start();
58          Math.cos(angle);
59          Profile.end();
60      }
61  
62      /**
63       * Test the Profile class using busy waiting.
64       * @throws InterruptedException if that happens; this test has failed
65       */
66      @Test
67      public void profileTestUsingBusyWaiting() throws InterruptedException
68      {
69          System.gc();
70          Profile.setPrintInterval(0);
71          Profile.clear();
72          // warm up
73          delay(100000);
74          Profile.reset();
75          for (long sleepTime : new long[] {100000, 1000000, 10000000})
76          {
77              for (int calls : new int[] {1, 5, 10})
78              {
79                  Profile.clear();
80                  System.out.print("sleep time " + sleepTime + "; calls " + calls + ": iterations:");
81                  for (int call = 0; call < calls; call++)
82                  {
83                      System.out.print(" " + delay(sleepTime));
84                  }
85                  System.out.println();
86                  Profile.print();
87                  String stats = Profile.statistics("delay");
88                  // System.out.println(stats);
89                  stats = stats.substring(stats.indexOf("[") + 1);
90                  stats = stats.substring(0, stats.length() - 1);
91                  String[] pairs = stats.split(", ");
92                  for (String pair : pairs)
93                  {
94                      String[] parts = pair.split("=");
95                      // System.out.println("key=" + parts[0] + ", value=" + parts[1]);
96                      String value = parts[1].substring(0, parts[1].length() - 1);
97                      switch (parts[0])
98                      {
99                          case "name":
100                             assertEquals("value of name should be \"delay\"", "delay", parts[1]);
101                             break;
102                         case "start":
103                             assertEquals("value of start should be \"null\"", "null", parts[1]);
104                             break;
105                         case "total":
106                             assertTrue("value of total should be at least ... ",
107                                     calls * sleepTime <= Double.parseDouble(value) * 1000);
108                         case "totalSquared":
109                             assertTrue("value of totalSquared should be at least ... ",
110                                     calls * sleepTime * calls * sleepTime <= Math.pow(Double.parseDouble(value), 2) * 1000);
111                             break;
112                         case "minTime":
113                             assertTrue("value of minTime should be at least ... ",
114                                     calls * sleepTime <= Double.parseDouble(value) * 1000);
115                             break;
116                         case "maxTime":
117                             assertTrue("value of maxTime should be at least ... ",
118                                     calls * sleepTime <= Double.parseDouble(value) * 1000);
119                             break;
120                         case "invocations":
121                             assertEquals("value of invocations should be number of calls", calls, Long.parseLong(parts[1]));
122                             break;
123 
124                         default:
125                             fail("Unexpected key: " + parts[0]);
126                     }
127                 }
128             }
129         }
130     }
131 
132     /**
133      * Delay for specified number of nano seconds. <br>
134      * Derived from
135      * https://stackoverflow.com/questions/11498585/how-to-suspend-a-java-thread-for-a-small-period-of-time-like-100-nanoseconds
136      * @param nanoSeconds long; time to delay in nano seconds
137      * @return long; number of iterations in the busy waiting loop
138      * @throws InterruptedException If that happens; this test fails
139      */
140     public long delay(final long nanoSeconds) throws InterruptedException
141     {
142         Profile.start("delay");
143         long start = System.nanoTime();
144         long iteration = 0;
145         while (start + nanoSeconds >= System.nanoTime())
146         {
147             iteration++;
148         }
149         Profile.end("delay");
150         return iteration;
151     }
152 
153     /**
154      * Test handling of inappropriate calling sequences.
155      */
156     @Test
157     public void testFailureModes()
158     {
159         Profile.setPrintInterval(0);
160         Profile.clear();
161         try
162         {
163             Profile.end();
164             fail("end without start should have thrown an exception");
165         }
166         catch (IllegalStateException ise)
167         {
168             // Ignore expected exception
169         }
170 
171         startOnly();
172         try
173         {
174             startOnly();
175             fail("start while already started should have thrown an exception");
176         }
177         catch (IllegalStateException ise)
178         {
179             // Ignore expected exception
180         }
181 
182         Profile.start();
183         Profile.end();
184         try
185         {
186             Profile.end();
187             fail("end without start should have thrown an exception");
188         }
189         catch (IllegalStateException ise)
190         {
191             // Ignore expected exception
192         }
193 
194         assertNull("statistics for method that never called Profile.start should return null", Profile.statistics("Naaahhhh"));
195 
196         try
197         {
198             Profile.statistics(null);
199             fail("calling statistics with a null pointer for the name should have thrown a NullPointerException");
200         }
201         catch (NullPointerException npe)
202         {
203             // Ignore expected exception
204         }
205     }
206 
207     /**
208      * Calls start, but not end.
209      */
210     public void startOnly()
211     {
212         Profile.start();
213     }
214 
215 }