1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: bench.c 8022 2007-06-05 22:23:38Z giles $ */
15 /* Simple hardware benchmarking suite (C and PostScript) */
16 #include "stdio_.h"
17 #include <stdlib.h>
18 
19 /* Patchup for GS externals */
20 FILE *gs_stdout;
21 FILE *gs_stderr;
22 FILE *gs_debug_out;
23 const char gp_scratch_file_name_prefix[] = "gs_";
24 static void
capture_stdio(void)25 capture_stdio(void)
26 {
27     gs_stdout = stdout;
28     gs_stderr = stderr;
29     gs_debug_out = stderr;
30 }
31 #include "gsio.h"
32 #undef gs_stdout
33 #undef gs_stderr
34 #undef stdout
35 #define stdout gs_stdout
36 #undef stderr
37 #define stderr gs_stderr
38 FILE *
gp_open_scratch_file(const char * prefix,char * fname,const char * mode)39 gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
40 {
41     return NULL;
42 }
43 void
gp_set_printer_binary(int prnfno,int binary)44 gp_set_printer_binary(int prnfno, int binary)
45 {
46 }
47 void
gs_to_exit(int n)48 gs_to_exit(int n)
49 {
50 }
51 #define eprintf_program_ident(f, pn, rn) (void)0
52 void
lprintf_file_and_line(FILE * f,const char * file,int line)53 lprintf_file_and_line(FILE * f, const char *file, int line)
54 {
55     fprintf(f, "%s(%d): ", file, line);
56 }
57 
58 /*
59  * Read the CPU time (in seconds since an implementation-defined epoch)
60  * into ptm[0], and fraction (in nanoseconds) into ptm[1].
61  */
62 #include "gp_unix.c"
63 #undef stdout
64 #define stdout gs_stdout
65 #undef stderr
66 #define stderr gs_stderr
67 
68 /* Loop unrolling macros */
69 #define do10(x) x;x;x;x;x; x;x;x;x;x
70 
71 /* Define the actual benchmarks. */
72 static int
iadd(int a,int n,char ** msg)73 iadd(int a, int n, char **msg)
74 {
75     int b = 0, i;
76 
77     for (i = n / 20; --i >= 0;) {
78 	do10((b += a, b += i));
79     }
80     *msg = "integer adds";
81     return b;
82 }
83 static int
imul(int a,int n,char ** msg)84 imul(int a, int n, char **msg)
85 {
86     int b = 1, i;
87 
88     for (i = n / 20; --i > 0;) {
89 	do10((b *= a, b *= i));
90     }
91     *msg = "integer multiplies";
92     return b;
93 }
94 static int
idiv(int a,int n,char ** msg)95 idiv(int a, int n, char **msg)
96 {
97     int b = 1, i;
98 
99     for (i = n / 20; --i > 0;) {
100 	b += 999999;
101 	do10((b /= a, b /= i));
102     }
103     *msg = "integer divides";
104     return b;
105 }
106 static int
fadd(float a,int n,char ** msg)107 fadd(float a, int n, char **msg)
108 {
109     float b = 0;
110     int i;
111 
112     for (i = n / 10; --i >= 0;) {
113 	do10((b += a));
114     }
115     *msg = "floating adds";
116     return b;
117 }
118 static int
fmul(float a,int n,char ** msg)119 fmul(float a, int n, char **msg)
120 {
121     float b = 1;
122     int i;
123 
124     for (i = n / 10; --i >= 0;) {
125 	do10((b *= a));
126     }
127     *msg = "floating multiplies";
128     return b;
129 }
130 static int
fdiv(float a,int n,char ** msg)131 fdiv(float a, int n, char **msg)
132 {
133     float b = 1;
134     int i;
135 
136     for (i = n / 10; --i >= 0;) {
137 	do10((b /= a));
138     }
139     *msg = "floating divides";
140     return b;
141 }
142 static int
fconv(int a,int n,char ** msg)143 fconv(int a, int n, char **msg)
144 {
145     int b[10];
146     float f[10];
147     int i;
148 
149     b[0] = a;
150     for (i = n / 20; --i >= 0;)
151 	f[0] = b[0], f[1] = b[1], f[2] = b[2], f[3] = b[3], f[4] = b[4],
152 	    f[5] = b[5], f[6] = b[6], f[7] = b[7], f[8] = b[8], f[9] = b[9],
153 	    b[0] = f[1], b[1] = f[2], b[2] = f[3], b[3] = f[4], b[4] = f[5],
154 	    b[5] = f[6], b[6] = f[7], b[7] = f[8], b[8] = f[9], b[9] = f[0];
155     *msg = "float/int conversions";
156     return b[0];
157 }
158 static int
mfast(int * m,int n,char ** msg)159 mfast(int *m, int n, char **msg)
160 {
161     int i;
162 
163     m[0] = n;
164     for (i = n / 20; --i >= 0;)
165 	m[9] = m[8], m[8] = m[7], m[7] = m[6], m[6] = m[5], m[5] = m[4],
166 	    m[4] = m[3], m[3] = m[2], m[2] = m[1], m[1] = m[0], m[0] = m[9];
167     *msg = "fast memory accesses";
168     return m[0];
169 }
170 static int
mslow(int * m,int n,char ** msg)171 mslow(int *m, int n, char **msg)
172 {
173     int *p;
174     int i, k = 0;
175 
176     m[0] = n;
177     for (i = n / 20; --i >= 0; k = (k + 397) & 0x3ffff)
178 	p = m + k,
179 	    p[0] = p[100], p[20] = p[120], p[40] = p[140],
180 	    p[60] = p[160], p[80] = p[180],
181 	    p[200] = p[300], p[220] = p[320], p[240] = p[340],
182 	    p[260] = p[360], p[280] = p[380];
183     *msg = "slow memory accesses";
184     return m[0];
185 }
186 
187 int
main(int argc,const char * argv[])188 main(int argc, const char *argv[])
189 {
190     int i;
191     int *mem = malloc(1100000);
192 
193     capture_stdio();
194     for (i = 0;; ++i) {
195 	long t0[2], t1[2];
196 	char *msg;
197 	int n;
198 
199 	gp_get_usertime(t0);
200 	switch (i) {
201 	    case 0:
202 		iadd(0, n = 10000000, &msg);
203 		break;
204 	    case 1:
205 		imul(1, n = 1000000, &msg);
206 		break;
207 	    case 2:
208 		idiv(1, n = 1000000, &msg);
209 		break;
210 	    case 3:
211 		fadd(3.14, n = 10000000, &msg);
212 		break;
213 	    case 4:
214 		fmul(1.0000001, n = 10000000, &msg);
215 		break;
216 	    case 5:
217 		fdiv(1.0000001, n = 1000000, &msg);
218 		break;
219 	    case 6:
220 		fconv(12345, n = 10000000, &msg);
221 		break;
222 	    case 7:
223 		mfast(mem, n = 10000000, &msg);
224 		break;
225 	    case 8:
226 		mslow(mem, n = 1000000, &msg);
227 		break;
228 	    default:
229 		free(mem);
230 		exit(0);
231 	}
232 	gp_get_usertime(t1);
233 	fprintf(stdout, "Time for %9d %s = %g ms\n", n, msg,
234 		(t1[0] - t0[0]) * 1000.0 + (t1[1] - t0[1]) / 1000000.0);
235 	fflush(stdout);
236     }
237 }
238 
239 /*
240    Output from SPARCstation 10, gcc -O bench.c gp_unix.c:
241 
242    Time for  10000000 integer adds = 113.502 ms
243    Time for   1000000 integer multiplies = 467.965 ms
244    Time for   1000000 integer divides = 594.328 ms
245    Time for  10000000 floating adds = 641.21 ms
246    Time for  10000000 floating multiplies = 643.357 ms
247    Time for   1000000 floating divides = 131.995 ms
248    Time for  10000000 float/int conversions = 602.061 ms
249    Time for  10000000 fast memory accesses = 201.048 ms
250    Time for   1000000 slow memory accesses = 552.606 ms
251 
252    Output from 486DX/25, wcl386 -oit bench.c gp_iwatc.c gp_msdos.c:
253 
254    Time for  10000000 integer adds = 490 ms
255    Time for   1000000 integer multiplies = 770 ms
256    Time for   1000000 integer divides = 1860 ms
257    Time for  10000000 floating adds = 4070 ms
258    Time for  10000000 floating multiplies = 4450 ms
259    Time for   1000000 floating divides = 2470 ms
260    Time for  10000000 float/int conversions = 25650 ms
261    Time for  10000000 fast memory accesses = 990 ms
262    Time for   1000000 slow memory accesses = 330 ms
263 
264  */
265 
266 /*
267    The rest of this file contains a similar benchmark in PostScript.
268 
269    %!
270    /timer               % <str> <N> <proc> timer
271    { bind 2 copy usertime mark 4 2 roll repeat cleartomark usertime exch sub
272    % Stack: str N proc dt
273    exch pop
274    (Time for ) print exch =only ( ) print exch =only (: ) print
275    =only ( ms
276    ) print flush
277    } def
278 
279    (x 20 integer adds) 5000 { 0
280    0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add
281    0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add 0 add
282    pop } timer
283 
284    (x 20 integer multiplies) 5000 { 1
285    3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul
286    3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul 3 mul
287    pop } timer
288 
289    (x 20 integer divides) 5000 { 1000000000
290    3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv
291    3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv 3 idiv
292    pop } timer
293 
294    (x 20 floating adds) 5000 { 0.0
295    1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add
296    1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add 1.0 add
297    pop } timer
298 
299    (x 20 floating multiplies) 5000 { 1.0
300    2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul
301    2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul 2.3 mul
302    pop } timer
303 
304    (x 20 floating divides) 5000 { 1.0
305    2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div
306    2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div 2.3 div
307    pop } timer
308 
309    (x 20 float/int conversions) 5000 { 12345.0
310    cvi cvr cvi cvr cvi cvr cvi cvr cvi cvr
311    cvi cvr cvi cvr cvi cvr cvi cvr cvi cvr
312    pop } timer
313 
314    /S 2048 string def
315    (x 10000(byte) fast memory accesses) 1000 {
316    //S 1024 1000 getinterval //S copy pop
317    //S 1024 1000 getinterval //S copy pop
318    //S 1024 1000 getinterval //S copy pop
319    //S 1024 1000 getinterval //S copy pop
320    //S 1024 1000 getinterval //S copy pop
321    } timer
322 
323    /A [ 500 { 2048 string } repeat ] def
324    (x 500 x 2000(byte) slower memory accesses) 10 {
325    0 1 499 {
326    //A exch get dup 1024 1000 getinterval exch copy pop
327    } for
328    } timer
329 
330    /Times-Roman findfont 36 scalefont setfont
331    currentcacheparams pop pop 0 1 index setcacheparams
332    /D [4 0 0 4 0 0] 1440 1440 <00 ff> makeimagedevice def
333    D setdevice
334    72 72 translate
335    gsave 15 rotate
336    0 0 moveto (A) show
337    (x 10 (A) show (cache)) 100 {
338    0 0 moveto
339    (A) show (A) show (A) show (A) show (A) show
340    (A) show (A) show (A) show (A) show (A) show
341    } timer grestore
342 
343    0 setcachelimit
344    gsave 10 rotate
345    (x 10 (A) show (no cache)) 10 {
346    0 0 moveto
347    (A) show (A) show (A) show (A) show (A) show
348    (A) show (A) show (A) show (A) show (A) show
349    } timer grestore
350 
351    quit
352 
353    Results for SUN Sparc 2 (rated at 25 MIPS according to manual)
354 
355    ./gs
356    Now in gs_init.ps
357    TextAlphaBits defined GraphicsAlphaBits defined
358    Aladdin Ghostscript 3.50 (1995-9-24)
359    (c) 1995 Aladdin Enterprises, Menlo Park, CA.  All rights reserved. This
360    software comes with NO WARRANTY: see the file PUBLIC for details. Leaving
361    gs_init.ps
362    GS>(ben1.c) run
363    Time for 5000 x 20 integer adds: 171 ms
364    Time for 5000 x 20 integer multiplies: 504 ms
365    Time for 5000 x 20 integer divides: 334 ms
366    Time for 5000 x 20 floating adds: 148 ms
367    Time for 5000 x 20 floating multiplies: 165 ms
368    Time for 5000 x 20 floating divides: 194 ms
369    Time for 5000 x 20 float/int conversions: 121 ms
370    Time for 1000 x 10000(byte) fast memory accesses: 112 ms
371    Time for 10 x 500 x 2000(byte) slower memory accesses: 236 ms
372    Loading NimbusRomanNo9L-Regular font from
373    [...]/n021003l.gsf... 1739080 414724 2564864 1251073 0
374    done. Time for 100 x 10 (A) show (cache): 144 ms
375    Time for 10 x 10 (A) show (no cache): 538 ms
376 
377    Output from SPARCstation 10, gs 3.60 compiled with gcc -g -O -DDEBUG:
378 
379    gsnd bench.c
380    Aladdin Ghostscript 3.60 (1995-10-23)
381    Copyright (C) 1995 Aladdin Enterprises, Menlo Park, CA.  All rights reserved.
382    This software comes with NO WARRANTY: see the file PUBLIC for details.
383    Time for 5000 x 20 integer adds: 192 ms
384    Time for 5000 x 20 integer multiplies: 561 ms
385    Time for 5000 x 20 integer divides: 396 ms
386    Time for 5000 x 20 floating adds: 202 ms
387    Time for 5000 x 20 floating multiplies: 247 ms
388    Time for 5000 x 20 floating divides: 243 ms
389    Time for 5000 x 20 float/int conversions: 157 ms
390    Time for 1000 x 10000(byte) fast memory accesses: 136 ms
391    Time for 10 x 500 x 2000(byte) slower memory accesses: 235 ms
392    Loading Temps-RomanSH font from /opt/home/peter/gs/fonts/soho/tersh___.pfb... 1759156 432729 2564864 1251025 0 done.
393    Time for 100 x 10 (A) show (cache): 161 ms
394    Time for 10 x 10 (A) show (no cache): 449 ms
395 
396    Output from 486DX/25, gs 2.6.1 compiled with wcc386 -oi[t]:
397 
398    gsndt bench.c
399    Initializing... done.
400    Ghostscript 2.6.1 (5/28/93)
401    Copyright (C) 1990-1993 Aladdin Enterprises, Menlo Park, CA.
402    All rights reserved.
403    Ghostscript comes with NO WARRANTY: see the file COPYING for details.
404    Time for 5000 x 20 integer adds: 550 ms
405    Time for 5000 x 20 integer multiplies: 940 ms
406    Time for 5000 x 20 integer divides: 880 ms
407    Time for 5000 x 20 floating adds: 550 ms
408    Time for 5000 x 20 floating multiplies: 660 ms
409    Time for 5000 x 20 floating divides: 930 ms
410    Time for 5000 x 20 float/int conversions: 830 ms
411    Time for 1000 x 10000(byte) fast memory accesses: 660 ms
412    Time for 10 x 500 x 2000(byte) slower memory accesses: 540 ms
413    Loading Temps-RomanSH font from c:\gs\fonts\softhorz\tersh___.pfb... 1298792 1207949 0 done.
414    Time for 100 x 10 (A) show (cache): 13520 ms
415    Time for 10 x 10 (A) show (no cache): 1310 ms
416 
417    Output from 486DX/25, gs 3.52 compiled with wcc386 -oi[t]:
418 
419    Aladdin Ghostscript 3.52 (1995-10-2)
420    Copyright (c) 1995 Aladdin Enterprises, Menlo Park, CA.  All rights reserved.
421    This software comes with NO WARRANTY: see the file PUBLIC for details.
422    Time for 5000 x 20 integer adds: 660 ms
423    Time for 5000 x 20 integer multiplies: 1100 ms
424    Time for 5000 x 20 integer divides: 940 ms
425    Time for 5000 x 20 floating adds: 710 ms
426    Time for 5000 x 20 floating multiplies: 830 ms
427    Time for 5000 x 20 floating divides: 1040 ms
428    Time for 5000 x 20 float/int conversions: 820 ms
429    Time for 1000 x 10000(byte) fast memory accesses: 660 ms
430    Time for 10 x 500 x 1000(byte) slower memory accesses: 600 ms
431    Loading Temps-RomanSH font from c:\gs\fonts\softhorz\tersh___.pfb... 1678548 375231 2564864 1250964 0 done.
432    Time for 100 x 10 (A) show (cache): 2520 ms
433    Time for 10 x 10 (A) show (no cache): 1600 ms
434 
435  */
436