1 package com.atlassian.scheduler.core.tests;
2
3 import org.joda.time.DateTime;
4 import org.joda.time.DateTimeZone;
5 import org.junit.Test;
6
7 import java.io.PrintWriter;
8 import java.io.StringWriter;
9 import java.lang.ref.WeakReference;
10 import java.util.Date;
11
12 import static java.lang.System.nanoTime;
13 import static org.junit.Assert.fail;
14
15
16
17
18
19
20 public abstract class CronExpressionTimingTest extends AbstractCronExpressionTest {
21 private static final Object TEST_LOCK = new Object();
22 private static final DateTime DTZ1 = dtz(2014, 4, 6, 1, 57, 0, "Australia/Sydney");
23 private static final DateTime DTZ2 = dtz(2014, 4, 5, 23, 30, 0, "Australia/Lord_Howe");
24 private static final DateTime DTZ3 = dtz(1970, 2, 1, 0, 0, 0, "Australia/Sydney");
25
26 private static final int PARSE_ITERS = 100000;
27 private static final int EVAL_ITERS = 1000;
28 private static final int EVAL_REPS = 100;
29
30 private final StringWriter sw = new StringWriter();
31 private final PrintWriter pw = new PrintWriter(sw);
32
33 protected CronExpressionTimingTest(CronFactory cronFactory) {
34 super(cronFactory);
35 }
36
37 @Test
38 public void test() {
39
40
41
42 synchronized (TEST_LOCK) {
43 runTimingTest();
44 }
45 }
46
47 protected void runTimingTest() {
48 pw.println(getClass().getSimpleName() + ':');
49 runParseTest("simple", "0 * * ? * *");
50 runParseTest("names", "0 * * ? JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC MON,TUE,WED,THU,FRI,SAT,SUN");
51 runParseTest("complex", "* 7-12,57-2 */3 20-3/7 JUN-OCT/3,DEC-APR/2 ? 1970-2099/4");
52 runEvalTest("Sydney hours", "0 30 * * * ?", DTZ1);
53 runEvalTest("Lord Howe hours", "0 30 * * * ?", DTZ2);
54 runEvalTest("Sydney daily", "0 23 2 * * ?", DTZ1);
55 runEvalTest("Sydney twice monthly", "0 30 4 1,15 * ?", DTZ1);
56 runEvalTest("Sydney evil", "1 */17 */23 31 2,4,6,9,11,12 ? */4", DTZ3);
57 pw.flush();
58 System.err.println(sw.toString());
59 sw.getBuffer().setLength(0);
60 }
61
62 protected void runParseTest(final String desc, final String cronExpression) {
63 runParseTest(desc, cronExpression, PARSE_ITERS);
64 }
65
66 protected void runParseTest(final String desc, final String cronExpression, final int iters) {
67 cleanMem();
68 final long startTime = nanoTime();
69 for (int i = 0; i < iters; ++i) {
70 cronFactory.parseAndDiscard(cronExpression);
71 }
72 final long time = nanoTime() - startTime;
73 report("runParse", desc, iters, time);
74 }
75
76 protected void runEvalTest(final String desc, final String cronExpression, final DateTime startingAt) {
77 runEvalTest(desc, cronExpression, EVAL_ITERS, startingAt, EVAL_REPS);
78 }
79
80 protected void runEvalTest(final String desc, final String cronExpression, final int iters,
81 final DateTime startingAt, final int reps) {
82 final Date startingDate = startingAt.toDate();
83 final CronFactory.CronExpressionAdapter cron = cronFactory.parse(cronExpression, startingAt.getZone());
84
85 cleanMem();
86 final long startTime = nanoTime();
87 for (int i = 0; i < iters; ++i) {
88 Date date = startingDate;
89 for (int rep = 0; rep < reps; ++rep) {
90 date = cron.nextRunTime(date);
91 }
92 }
93 final long time = nanoTime() - startTime;
94 report("runEvalTest", desc, iters, time);
95 }
96
97 private void report(final String what, final String desc, final int iters, final long time) {
98 pw.println("\t" + what + ": " + desc + "; iters=" + iters +
99 "; time=" + time + "ns; iters/sec=" + (long) (((double) iters / (double) time) * 1000000000L));
100 }
101
102 private static DateTime dtz(final int year, final int month, final int day,
103 final int hour, final int minute, final int second,
104 final String timeZoneId) {
105 return new DateTime(year, month, day, hour, minute, second, DateTimeZone.forID(timeZoneId));
106 }
107
108 private static void cleanMem() {
109 final WeakReference<Object> ref = new WeakReference<Object>(new Object());
110 for (int i = 0; i < 100; ++i) {
111 System.gc();
112 if (ref.get() == null) {
113 return;
114 }
115 try {
116 Thread.sleep(100L);
117 } catch (InterruptedException ie) {
118 throw new AssertionError(ie);
119 }
120 }
121 fail("Ummm, what's wrong with the garbage collector?!");
122 }
123 }