View Javadoc

1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.test.benchmark;
17  
18  
19  import net.sourceforge.domian.repository.HashSetRepository;
20  import net.sourceforge.domian.repository.InMemoryRepository;
21  import net.sourceforge.domian.repository.Repository;
22  import net.sourceforge.domian.util.concurrent.task.Task;
23  
24  import static net.sourceforge.domian.specification.SpecificationFactory.instancesOfType;
25  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.DB4O;
26  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.HASHSET;
27  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.HIGH_SCALE_LIB_HASH_SET;
28  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.INMEMORY;
29  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.INMEMORY_DB4O;
30  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.INMEMORY_XSTREAM;
31  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.NOT_IMPLEMENTED;
32  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.NULL;
33  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_DB4O;
34  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_HASHSET;
35  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_HIGH_SCALE_LIB_HASH_SET;
36  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_INMEMORY;
37  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_INMEMORY_DB4O;
38  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_INMEMORY_XSTREAM;
39  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.PARTITIONED_XSTREAM;
40  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.UNSUPPORTED;
41  import static net.sourceforge.domian.test.benchmark.AbstractQueenPuzzle.RepositoryType.XSTREAM;
42  
43  
44  /**
45   * An amusing little computing task involving (possible) vast numbers of repository inserts, updates, and search.
46   * <p/>
47   * In detail, it consists of:
48   * <ol>
49   * <li/>Generating random chess piece constellations consisting of 8 pieces, disguised as entity objects; adding them to a repository
50   * <li/>A batch processing task, iterating through all constellations, doing a little check, with a conditional update
51   * <li/>If the repository supports asynchronous persistence, all entities are persisted
52   * <li/>A search task for all constellations solving the queen puzzle
53   * <li/>A completion control search task for all constellations not processed (should be none)
54   * </ol>
55   * <p/>
56   * The batch processing task tries to solve the infamous "Queen Puzzle" which seeks to find all possible chess queen piece constellations
57   * where none of the queens are threatened by one of the other queens.
58   * A standard 8 x 8 chess board and 8 queen pieces are hard-coded.
59   * Possible sequences of queens are staggering 64^8 = 281.474.976.710.656 (over 280 trillions!)
60   * <p/>
61   * The JVM flag -Xms should not be set when using this class. it seems to screw up the garbage collectioning...
62   * <p/>
63   * Usage example:<br/>
64   * <pre>
65   * java net.sourceforge.domian.test.benchmark.QueenPuzzleTestRunner seq [repo type] [#executions] [#constellations]                   [#log interval]
66   * java net.sourceforge.domian.test.benchmark.QueenPuzzleTestRunner con [repo type] [#executions] [#constellations] [#worker threads] [#log interval]</pre>
67   * <code>seq</code> means <i>sequential</i> execution (one thread only), and <code>con</code> means <i>concurrent</i> execution by a given number of <i>worker threads</i>.<br/>
68   * The available <code>repo type</code>s are:
69   * <ul>
70   * <li/><code>hashset               -> {@link HashSetRepository}</code>
71   * <li/><code>part-hashset          -> Partitioned {@link HashSetRepository}</code>
72   * <li/><code>inmemory              -> {@link InMemoryRepository}</code>
73   * <li/><code>part-inmemory         -> Partitioned {@link InMemoryRepository}</code>
74   * <li/><code>xstream               -> {@link net.sourceforge.domian.repository.XStreamXmlFilePerEntityRepository}</code>
75   * <li/><code>part-xstream          -> Partitioned {@link net.sourceforge.domian.repository.XStreamXmlFilePerEntityRepository}</code>
76   * <li/><code>inmemory-xstream      -> {@link net.sourceforge.domian.repository.InMemoryAndXStreamXmlFileRepository}</code>
77   * <li/><code>part-inmemory-xstream -> Partitioned {@link net.sourceforge.domian.repository.InMemoryAndXStreamXmlFileRepository}</code>
78   * </ul>
79   * <code>#executions</code> is the number of iterating executions, always sequential.<br/>
80   * <code>#constellations</code> is the number of queen puzzle constellations, and thus the total number of entities the repository is to handle.<br/>
81   * <code>#log interval</code> is the number of generated/processed queen puzzle constellations between every emitted log message.<br/>
82   * <p/>
83   * Usage example:
84   * <pre>
85   * java -cp ... net.sourceforge.domian.test.benchmark.QueenPuzzleTestRunner con inmemory 1 100000 4 10000</pre>
86   * Process 100000 queen puzzle constellations, using 4 threads.
87   * Use the <code>InMemoryRepository</code>.
88   * Run the benchmark only once, and show status messages every for 10000 constellations.
89   *
90   * @author Eirik Torske
91   */
92  public class QueenPuzzleTestRunner {
93  
94      private static String executionStyle;
95  
96      public static void main(final String[] args) {
97          if (args.length != 5 && args.length != 6) {
98              System.out.println("Usage: QueenPuzzleTestRunner [\"seq\"] [repo type] [#executions] [#constellations]                   [#log interval] (all mandatory arguments)");
99              System.out.println("Usage: QueenPuzzleTestRunner [\"con\"] [repo type] [#executions] [#constellations] [#worker threads] [#log interval] (all mandatory arguments)");
100             return;
101         }
102         executionStyle = args[0];
103         final SequentialQueenPuzzle.RepositoryType repositoryType;
104         if (args[1].startsWith("unsupported")) {
105             repositoryType = UNSUPPORTED;
106 
107         } else if (args[1].startsWith("not-implemented")) {
108             repositoryType = NOT_IMPLEMENTED;
109 
110         } else if (args[1].startsWith("null")) {
111             repositoryType = NULL;
112 
113         } else if (args[1].startsWith("hashset")) {
114             repositoryType = HASHSET;
115 
116         } else if (args[1].startsWith("part-hashset")) {
117             repositoryType = PARTITIONED_HASHSET;
118 
119         } else if (args[1].startsWith("inmemory")) {
120             repositoryType = INMEMORY;
121 
122         } else if (args[1].startsWith("part-inmemory")) {
123             repositoryType = PARTITIONED_INMEMORY;
124 
125         } else if (args[1].startsWith("highscale")) {
126             repositoryType = HIGH_SCALE_LIB_HASH_SET;
127 
128         } else if (args[1].startsWith("part-highscale")) {
129             repositoryType = PARTITIONED_HIGH_SCALE_LIB_HASH_SET;
130 
131         } else if (args[1].startsWith("xstream")) {
132             repositoryType = XSTREAM;
133 
134         } else if (args[1].startsWith("part-xstream")) {
135             repositoryType = PARTITIONED_XSTREAM;
136 
137         } else if (args[1].startsWith("inmemory-xstream")) {
138             repositoryType = INMEMORY_XSTREAM;
139 
140         } else if (args[1].startsWith("part-inmemory-xstream")) {
141             repositoryType = PARTITIONED_INMEMORY_XSTREAM;
142 
143         } else if (args[1].startsWith("db4o")) {
144             repositoryType = DB4O;
145 
146         } else if (args[1].startsWith("part-db4o")) {
147             repositoryType = PARTITIONED_DB4O;
148 
149         } else if (args[1].startsWith("inmemory-db4o")) {
150             repositoryType = INMEMORY_DB4O;
151 
152         } else if (args[1].startsWith("part-inmemory-db4o")) {
153             repositoryType = PARTITIONED_INMEMORY_DB4O;
154 
155         } else {
156             throw new IllegalArgumentException("Unknown repository type '" + args[1] + "'");
157         }
158 
159         final long numberOfExecutions = Long.parseLong(args[2]);
160 
161         long numberOfConstellations = -1;
162         int numberOfWorkerThreads = -1;
163         long logInterval = -1;
164 
165         if (executionStyle.equalsIgnoreCase("seq")) {
166             numberOfConstellations = Long.parseLong(args[3]);
167             logInterval = Integer.parseInt(args[4]);
168 
169         } else if (executionStyle.equalsIgnoreCase("con")) {
170             numberOfConstellations = Long.parseLong(args[3]);
171             numberOfWorkerThreads = Integer.parseInt(args[4]);
172             logInterval = Long.parseLong(args[5]);
173         } else {
174             throw new IllegalArgumentException("First argument must be sequential [SEQ] or concurrent [CON]");
175         }
176         final Repository<AbstractQueenPuzzle> executionRepo = new HashSetRepository<AbstractQueenPuzzle>();
177 
178         if (executionStyle.equalsIgnoreCase("seq")) {
179             for (int i = 1; i <= numberOfExecutions; ++i) {
180                 System.out.println();
181                 System.out.println();
182                 System.out.println("---------------------------------------- Execution #" + i + " ----------------------------------------");
183                 QueenPuzzleConstellation.resetConstellationNumber();
184                 SequentialQueenPuzzle execution = new SequentialQueenPuzzle(repositoryType, numberOfConstellations, logInterval);
185                 executionRepo.put(execution);
186             }
187             //printReport(executionRepo);
188 
189         } else { // Concurrent
190             for (int i = 1; i <= numberOfExecutions; ++i) {
191                 System.out.println();
192                 System.out.println();
193                 System.out.println("---------------------------------------- Execution #" + i + " ----------------------------------------");
194                 Task.resetThreadNumber();
195                 QueenPuzzleConstellation.resetConstellationNumber();
196                 ConcurrentQueenPuzzle execution = new ConcurrentQueenPuzzle(repositoryType, numberOfConstellations, numberOfWorkerThreads, logInterval);
197                 executionRepo.put(execution);
198             }
199             printReport(executionRepo);
200         }
201     }
202 
203     private static void printReport(final Repository<AbstractQueenPuzzle> repo) {
204         System.out.println();
205         System.out.println();
206         System.out.println("****************************************");
207         System.out.println("   Queen Puzzle execution completed");
208         System.out.println("****************************************");
209         System.out.println("Execution style                        : " + getExecutionStyle());
210         System.out.println("Number of executions                   : " + getNumberOfExecutions(repo));
211         System.out.println("Repository type                        : " + getRepositoryType(repo));
212         System.out.println("Number of constellations per execution : " + getNumberOfConstellationsPerExecution(repo));
213         System.out.println("Number of worker threads per execution : " + getNumberOfWorkerThreadsPerExecution(repo));
214         //System.out.println("Average execution time                 : " + getAverageExecutionTimeInMilliSeconds(repo) + " ms");
215     }
216 
217     private static String getExecutionStyle() {
218         if (executionStyle.equalsIgnoreCase("con")) {
219             return "Multithreaded";
220         } else {
221             return "Sequential";
222         }
223     }
224 
225     private static long getNumberOfExecutions(final Repository<AbstractQueenPuzzle> repo) {
226         return repo.countAll(instancesOfType(AbstractQueenPuzzle.class));
227     }
228 
229     private static String getRepositoryType(final Repository<AbstractQueenPuzzle> repo) {
230         return repo.iterateAll(instancesOfType(AbstractQueenPuzzle.class)).next().repositoryType.toString();
231     }
232 
233     private static long getNumberOfConstellationsPerExecution(final Repository<AbstractQueenPuzzle> repo) {
234         return repo.iterateAll(instancesOfType(AbstractQueenPuzzle.class)).next().numberOfConstellations;
235     }
236 
237     private static int getNumberOfWorkerThreadsPerExecution(Repository<AbstractQueenPuzzle> repo) {
238         return repo.iterateAll(instancesOfType(AbstractQueenPuzzle.class)).next().numberOfWorkers;
239     }
240 
241     // TODO: check this...?
242     /*
243     private static String getAverageExecutionTimeInMilliSeconds(final Repository repo) {
244         final Collection<? extends AbstractQueenPuzzle> executions = repo.findAll(instancesOfType(AbstractQueenPuzzle.class));
245         final long numberOfExecutions = executions.size();
246 
247         long totalExecutionTime = 0;
248         for (AbstractQueenPuzzle execution : executions) {
249             totalExecutionTime += execution.endTime - execution.startTime;
250         }
251         return prettyPrintLargeNumber(new BigDecimal(totalExecutionTime)
252                 .divide(new BigDecimal(numberOfExecutions), 3, RoundingMode.HALF_UP)
253                 .divide(new BigDecimal(1000000))
254                 .longValue());
255     }*/
256 }