1 | /* |
---|
2 | * ---------------------------------------------------------------------- |
---|
3 | * P2P: performance test program for worker nodes |
---|
4 | * |
---|
5 | * This little program gets executed from time to time by each worker |
---|
6 | * to measure the performance and available resources of this node. |
---|
7 | * It performs a non-trivial calculation involving memory access and |
---|
8 | * floating point operations, and returns a single number representing |
---|
9 | * the wall time (in microseconds) for this calculation. That wall |
---|
10 | * time rolls up the power of the node and its current availability, |
---|
11 | * giving a reasonable estimate of how long a similar calculation |
---|
12 | * would take. We call this unit of work a "wonk" (WOrker Node |
---|
13 | * Kapability). |
---|
14 | * ---------------------------------------------------------------------- |
---|
15 | * Michael McLennan (mmclennan@purdue.edu) |
---|
16 | * ====================================================================== |
---|
17 | * Copyright (c) 2004-2012 HUBzero Foundation, LLC |
---|
18 | * |
---|
19 | * See the file "license.terms" for information on usage and |
---|
20 | * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
21 | * ====================================================================== |
---|
22 | */ |
---|
23 | #include <stdio.h> |
---|
24 | #include <math.h> |
---|
25 | #include <stdlib.h> |
---|
26 | #include <string.h> |
---|
27 | #include <sys/time.h> |
---|
28 | |
---|
29 | #define LARGE_CHUNK_SIZE 10000000 |
---|
30 | #define SMALL_CHUNK_SIZE 1000 |
---|
31 | |
---|
32 | double ran3(); |
---|
33 | |
---|
34 | int |
---|
35 | main(argc,argv) |
---|
36 | int argc; char **argv; /* ignored */ |
---|
37 | { |
---|
38 | int i, j; |
---|
39 | double d, *dvals; |
---|
40 | long tval; |
---|
41 | struct timeval tstart, tend; |
---|
42 | |
---|
43 | /* query the starting wall time for this calculation */ |
---|
44 | if (gettimeofday(&tstart, (struct timezone*)NULL) < 0) { |
---|
45 | exit(1); |
---|
46 | } |
---|
47 | |
---|
48 | /* |
---|
49 | * Allocate a large chunk of memory and zero it out. |
---|
50 | * This tests available memory and speed of allocation |
---|
51 | * to some extent. |
---|
52 | */ |
---|
53 | dvals = malloc((size_t)(LARGE_CHUNK_SIZE*sizeof(double))); |
---|
54 | if (dvals == NULL) { |
---|
55 | printf("out of memory\n"); |
---|
56 | exit(1); |
---|
57 | } |
---|
58 | memset(dvals, 0, (size_t)(LARGE_CHUNK_SIZE*sizeof(double))); |
---|
59 | |
---|
60 | /* |
---|
61 | * Scan through the chunk of memory and fill with random |
---|
62 | * numbers. This hits lots of memory pages and causes lots |
---|
63 | * of integer arithmetic operations. |
---|
64 | */ |
---|
65 | ran3(-1234); |
---|
66 | for (j=0; j < SMALL_CHUNK_SIZE; j++) { |
---|
67 | for (i=0; i < LARGE_CHUNK_SIZE; i += SMALL_CHUNK_SIZE) { |
---|
68 | dvals[i+j] = ran3(0); |
---|
69 | } |
---|
70 | } |
---|
71 | |
---|
72 | /* |
---|
73 | * Scan back through again and multiply random numbers together. |
---|
74 | * This hits logs of memory pages again and causes lots of |
---|
75 | * floating point operations. Use division, since it's more |
---|
76 | * expensive than multiplication. |
---|
77 | */ |
---|
78 | d = 1.0; |
---|
79 | for (j=0; j < SMALL_CHUNK_SIZE; j++) { |
---|
80 | for (i=0; i < LARGE_CHUNK_SIZE; i += SMALL_CHUNK_SIZE) { |
---|
81 | d /= dvals[i+j]; |
---|
82 | } |
---|
83 | } |
---|
84 | |
---|
85 | /* query the ending wall time and report the overall time */ |
---|
86 | if (gettimeofday(&tend, (struct timezone*)NULL) < 0) { |
---|
87 | exit(1); |
---|
88 | } |
---|
89 | |
---|
90 | tval = (tend.tv_sec - tstart.tv_sec)*1000000 |
---|
91 | + tend.tv_usec - tstart.tv_usec; |
---|
92 | |
---|
93 | printf("rappture-wonks/v1 %ld\n", tval); |
---|
94 | exit(0); |
---|
95 | } |
---|
96 | |
---|
97 | /* |
---|
98 | * ---------------------------------------------------------------------- |
---|
99 | * FUNCTION: ran3(seed) |
---|
100 | * |
---|
101 | * This function generates a random number in the range 0.0-1.0. |
---|
102 | * Set seed to any negative number to reset the sequence with that |
---|
103 | * seed value. |
---|
104 | * |
---|
105 | * This routine is taken from "Numerical Recipes in C" by by William |
---|
106 | * H. Press, Brian P. Flannery, Saul A. Teukolsky, William T. |
---|
107 | * Vetterling, Chapter 7, p. 283. |
---|
108 | * ---------------------------------------------------------------------- |
---|
109 | */ |
---|
110 | #define MBIG 1000000000 |
---|
111 | #define MSEED 161803398 |
---|
112 | #define MZ 0 |
---|
113 | #define FAC (1.0/MBIG) |
---|
114 | |
---|
115 | double |
---|
116 | ran3(seed) |
---|
117 | long seed; /* pass in negative value to restart */ |
---|
118 | { |
---|
119 | static int inext, inextp; |
---|
120 | static long ma[56]; |
---|
121 | static int iff=0; |
---|
122 | long mj, mk; |
---|
123 | int i, ii, k; |
---|
124 | |
---|
125 | if (seed < 0 || iff == 0) { |
---|
126 | iff = 1; |
---|
127 | mj = MSEED - (seed < 0 ? -seed : seed); |
---|
128 | mj %= MBIG; |
---|
129 | ma[55] = mj; |
---|
130 | mk = 1; |
---|
131 | for (i=1; i < 54; i++) { |
---|
132 | ii = (21*i) % 55; |
---|
133 | ma[ii] = mk; |
---|
134 | mk = mj - mk; |
---|
135 | if (mk < MZ) mk += MBIG; |
---|
136 | mj = ma[ii]; |
---|
137 | } |
---|
138 | for (k=1; k <= 4; k++) { |
---|
139 | for (i=1; i <= 55; i++) { |
---|
140 | ma[i] -= ma[1+(i+30) % 55]; |
---|
141 | if (ma[i] < MZ) ma[i] += MBIG; |
---|
142 | } |
---|
143 | } |
---|
144 | inext = 0; |
---|
145 | inextp = 31; |
---|
146 | } |
---|
147 | if (++inext == 56) inext=1; |
---|
148 | if (++inextp == 56) inextp=1; |
---|
149 | mj = ma[inext] - ma[inextp]; |
---|
150 | if (mj < MZ) mj += MBIG; |
---|
151 | ma[inext] = mj; |
---|
152 | return mj*FAC; |
---|
153 | } |
---|