2 * Java implementation of the <tt>em3d</tt> Olden benchmark. This Olden
3 * benchmark models the propagation of electromagnetic waves through
4 * objects in 3 dimensions. It is a simple computation on an irregular
5 * bipartite graph containing nodes representing electric and magnetic
9 * D. Culler, A. Dusseau, S. Goldstein, A. Krishnamurthy, S. Lumetta, T. von
10 * Eicken and K. Yelick. "Parallel Programming in Split-C". Supercomputing
11 * 1993, pages 262-273.
14 * Java code converted to D by leonardo maffi, V.1.0, Oct 25 2009.
16 * Removed output unless an option is passed by Leandro Lucarella, 2010-08-04.
17 * Downloaded from http://www.fantascienza.net/leonardo/js/
18 * http://www.fantascienza.net/leonardo/js/dolden_em3d.zip
23 import tango.stdc.stdio: printf, sprintf;
24 import tango.stdc.stdlib: exit;
25 import tango.stdc.time: CLOCKS_PER_SEC, clock;
27 import Integer = tango.text.convert.Integer;
28 alias Integer.parse toInt;
30 import std.c.stdio: printf, sprintf;
31 import std.c.stdlib: exit;
32 import std.c.time: CLOCKS_PER_SEC, clock;
34 version (D_Version2) {
36 alias to!(int, char[]) toInt;
38 import std.conv: toInt;
44 return clock() / cast(double)CLOCKS_PER_SEC;
49 Basic uniform random generator: Minimal Standard in Park and
50 Miller (1988): "Random Number Generators: Good Ones Are Hard to
51 Find", Comm. of the ACM, 31, 1192-1201.
52 Parameters: m = 2^31-1, a=48271.
54 Adapted from Pascal code by Jesper Lund:
55 http://www.gnu-pascal.de/crystal/gpc/en/mail1390.html
58 const int m = int.max;
68 public double nextDouble() {
70 seed = a * (seed - k * q) - r * k;
73 return cast(double)seed / m;
76 public int nextInt(int max) {
78 int k = cast(int)(n * this.nextDouble());
79 return (k == n) ? k - 1 : k;
85 * This class implements nodes (both E- and H-nodes) of the EM graph. Sets
86 * up random neighbors and propagates field values among neighbors.
91 * The value of the node.
95 * The next node in the list.
99 * Array of nodes to which we send our value.
103 * Array of nodes from which we receive values.
107 * Coefficients on the fromNodes edges
111 * The number of fromNodes edges
115 * Used to create the fromEdges - keeps track of the number of edges that have
121 * A random number generator.
123 private static Random rand;
126 * Initialize the random number generator
128 public static void initSeed(long seed)
130 rand = new Random(seed);
134 * Constructor for a node with given `degree'. The value of the
135 * node is initialized to a random value.
139 value = rand.nextDouble();
140 // create empty array for holding toNodes
141 toNodes = new Node[degree];
151 * Create the linked list of E or H nodes. We create a table which is used
152 * later to create links among the nodes.
153 * @param size the no. of nodes to create
154 * @param degree the out degree of each node
155 * @return a table containing all the nodes.
157 static Node[] fillTable(int size, int degree)
159 Node[] table = new Node[size];
161 Node prevNode = new Node(degree);
163 for (int i = 1; i < size; i++) {
164 Node curNode = new Node(degree);
166 prevNode.next = curNode;
173 * Create unique `degree' neighbors from the nodes given in nodeTable.
174 * We do this by selecting a random node from the give nodeTable to
175 * be neighbor. If this neighbor has been previously selected, then
176 * a different random neighbor is chosen.
177 * @param nodeTable the list of nodes to choose from.
179 void makeUniqueNeighbors(Node[] nodeTable)
181 for (int filled = 0; filled < toNodes.length; filled++) {
186 // generate a random number in the correct range
187 int index = rand.nextInt(nodeTable.length - 1);
189 // find a node with the random index in the given table
190 otherNode = nodeTable[index];
192 for (k = 0; k < filled; k++) {
193 if (otherNode == toNodes[k]) break; // fixed a bug of the original Java code
195 } while (k < filled);
197 // other node is definitely unique among "filled" toNodes
198 toNodes[filled] = otherNode;
200 // update fromCount for the other node
201 otherNode.fromCount++;
206 * Allocate the right number of FromNodes for this node. This
207 * step can only happen once we know the right number of from nodes
208 * to allocate. Can be done after unique neighbors are created and known.
210 * It also initializes random coefficients on the edges.
214 fromNodes = new Node[fromCount]; // nodes fill be filled in later
215 coeffs = new double[fromCount];
219 * Fill in the fromNode field in "other" nodes which are pointed to
222 void updateFromNodes()
224 for (int i = 0; i < toNodes.length; i++) {
225 Node otherNode = toNodes[i];
226 int count = otherNode.fromLength++;
227 otherNode.fromNodes[count] = this;
228 otherNode.coeffs[count] = rand.nextDouble();
233 * Get the new value of the current node based on its neighboring
234 * from_nodes and coefficients.
236 void computeNewValue()
238 for (int i = 0; i < fromCount; i++) {
239 value -= coeffs[i] * fromNodes[i].value;
243 int opApply(int delegate(ref Node) dg) {
245 for (Node current = this; current !is null; current = current.next) {
246 result = dg(current);
253 public char* toCString()
255 static char[256] repr;
256 sprintf(repr.ptr, "value %.17f, from_count %d", value, fromCount);
263 * A class that represents the irregular bipartite graph used in
264 * EM3D. The graph contains two linked structures that represent the
265 * E nodes and the N nodes in the application.
270 * Nodes that represent the electrical field.
274 * Nodes that representhe the magnetic field.
279 * Construct the bipartite graph.
280 * @param e the nodes representing the electric fields
281 * @param h the nodes representing the magnetic fields
290 * Create the bi graph that contains the linked list of
292 * @param numNodes the number of nodes to create
293 * @param numDegree the out-degree of each node
294 * @param verbose should we print out runtime messages
295 * @return the bi graph that we've created.
297 static BiGraph create(int numNodes, int numDegree, bool verbose)
301 // making nodes (we create a table)
302 if (verbose) printf("making nodes (tables in orig. version)\n");
303 Node[] hTable = Node.fillTable(numNodes, numDegree);
304 Node[] eTable = Node.fillTable(numNodes, numDegree);
307 if (verbose) printf("updating from and coeffs\n");
308 foreach (n; hTable[0])
309 n.makeUniqueNeighbors(eTable);
310 foreach (n; eTable[0])
311 n.makeUniqueNeighbors(hTable);
313 // Create the fromNodes and coeff field
314 if (verbose) printf("filling from fields\n");
315 foreach (n; hTable[0])
317 foreach (n; eTable[0])
320 // Update the fromNodes
321 foreach (n; hTable[0])
323 foreach (n; eTable[0])
326 BiGraph g = new BiGraph(eTable[0], hTable[0]);
331 * Update the field values of e-nodes based on the values of
332 * neighboring h-nodes and vice-versa.
342 * Print out the values of the e and h nodes.
344 public void print() {
346 printf("E: %s\n", n.toCString());
348 printf("H: %s\n", n.toCString());
356 * The number of nodes (E and H)
358 private static int numNodes = 0;
360 * The out-degree of each node.
362 private static int numDegree = 0;
364 * The number of compute iterations
366 private static int numIter = 1;
368 * Should we print the results and other runtime messages
370 private static bool printResult = false;
372 * Print information messages?
374 private static bool printMsgs = false;
377 * The main roitine that creates the irregular, linked data structure
378 * that represents the electric and magnetic fields and propagates the
379 * waves through the graph.
380 * @param args the command line arguments
382 public static final void main(char[] args[])
387 printf("Initializing em3d random graph...\n");
388 auto start0 = myclock();
389 BiGraph graph = BiGraph.create(numNodes, numDegree, printResult);
390 auto end0 = myclock();
392 // compute a single iteration of electro-magnetic propagation
394 printf("Propagating field values for %d iteration(s)...\n", numIter);
395 auto start1 = myclock();
396 for (int i = 0; i < numIter; i++) {
399 auto end1 = myclock();
401 // print current field values
406 printf("EM3D build time %.2f\n", end0 - start0);
407 printf("EM3D compute time %.2f\n", end1 - start1);
408 printf("EM3D total time %.2f\n", end1 - start0);
415 * Parse the command line options.
416 * @param args the command line options.
418 private static final void parseCmdLine(char[] args[])
423 while (i < args.length && args[i][0] == '-') {
426 // check for options that require arguments
428 if (i < args.length) {
429 numNodes = toInt(args[i++]);
430 } else throw new Exception("-n requires the number of nodes");
431 } else if (arg == "-d") {
432 if (i < args.length) {
433 numDegree = toInt(args[i++]);
434 } else throw new Exception("-d requires the out degree");
435 } else if (arg == "-i") {
436 if (i < args.length) {
437 numIter = toInt(args[i++]);
438 } else throw new Exception("-i requires the number of iterations");
439 } else if (arg == "-p") {
441 } else if (arg == "-m") {
443 } else if (arg == "-h") {
447 if (numNodes == 0 || numDegree == 0) usage();
451 * The usage routine which describes the program options.
453 private static final void usage() {
454 printf("usage: em3d -n <nodes> -d <degree> [-p] [-m] [-h]\n");
455 printf(" -n the number of nodes\n");
456 printf(" -d the out-degree of each node\n");
457 printf(" -i the number of iterations\n");
458 printf(" -p (print detailed results)\n");
459 printf(" -m (print informative messages)\n");
460 printf(" -h (this message)\n");
466 void main(char[][] args) {