1/*
2**
3*/
4
5#include <X11/Intrinsic.h>
6#include <X11/StringDefs.h>
7#include <X11/Xaw/AsciiText.h>
8#include <X11/Xos.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <math.h>
12#include "xgc.h"
13#ifdef SVR4
14#define SYSV
15#endif
16#if !defined(SYSV) && !defined(QNX4)
17#include <sys/resource.h>
18#endif
19
20#ifndef PI
21#define PI 3.14159265
22#endif
23
24#ifdef SYSV
25#define random lrand48
26#endif
27
28
29/* timer(flag)
30** -----------
31** When called with StartTimer, starts the stopwatch and returns nothing.
32** When called with EndTimer, stops the stopwatch and returns the time
33** in microseconds since it started.
34**
35** Uses rusage() so we can subtract the time used by the system and user
36** from our timer, and just concentrate on the time used in the X calls.
37*/
38
39static long
40timer(int flag)
41{
42#if !defined(SYSV)
43  static struct timeval starttime;  /* starting time for gettimeofday() */
44  struct timeval endtime;           /* ending time for gettimeofday() */
45#if !defined(__UNIXOS2__) && !defined(QNX4)
46  static struct rusage startusage;  /* starting time for getrusage() */
47  struct rusage endusage;           /* ending time for getrusage() */
48#endif
49  struct timezone tz;               /* to make gettimeofday() happy */
50
51  long elapsedtime;                 /* how long since we started the timer */
52
53  switch (flag) {
54    case StartTimer:                       /* store initial values */
55      gettimeofday(&starttime,&tz);
56#if !defined(__UNIXOS2__) && !defined(QNX4)
57      getrusage(RUSAGE_SELF,&startusage);
58#endif
59      return((long) NULL);
60    case EndTimer:
61      gettimeofday(&endtime,&tz);          /* store final values */
62#if !defined(__UNIXOS2__) && !defined(QNX4)
63      getrusage(RUSAGE_SELF,&endusage);
64#endif
65
66  /* all the following line does is use the formula
67     elapsed time = ending time - starting time, but there are three
68     different timers and two different units of time, ack... */
69
70#if !defined(__UNIXOS2__) && !defined(QNX4)
71      elapsedtime = (long) ((long)
72	((endtime.tv_sec - endusage.ru_utime.tv_sec - endusage.ru_stime.tv_sec
73	 - starttime.tv_sec + startusage.ru_utime.tv_sec
74	 + startusage.ru_stime.tv_sec)) * 1000000) + (long)
75      ((endtime.tv_usec - endusage.ru_utime.tv_usec - endusage.ru_stime.tv_usec
76	 - starttime.tv_usec + startusage.ru_utime.tv_usec
77	 + startusage.ru_stime.tv_usec));
78#else
79      elapsedtime = (long)( ((long)endtime.tv_sec-(long)starttime.tv_sec)*1000000
80			   +((long)endtime.tv_usec-(long)starttime.tv_usec));
81#endif
82      return(elapsedtime);
83
84    default:
85      fprintf(stderr,"Invalid flag in timer()\n");
86      return((long) NULL);
87    }
88#else
89  static time_t starttime;
90
91  switch (flag) {
92    case StartTimer:
93      time(&starttime);
94      return((long) NULL);
95    case EndTimer:
96      return( (time(NULL) - starttime) * 1000000);
97    default:
98      fprintf(stderr,"Invalid flag in timer()\n");
99      return((long) NULL);
100    }
101#endif
102}
103
104
105void
106copyarea_test(void)
107{
108  int num_copies = 200;
109  int i;
110  long totaltime;
111  char buf[80];
112
113  num_copies *= X.percent;
114
115  XSetFillStyle(X.dpy,X.miscgc,FillTiled);
116  XFillRectangle(X.dpy,X.win,X.miscgc,0,0,400,400);
117
118  XSync(X.dpy,0);
119  timer(StartTimer);
120  for (i=0;i<num_copies;++i)
121    XCopyArea(X.dpy,X.win,X.win,X.gc,i,200-i,
122	      200,200,200-i,i);
123  XSync(X.dpy,0);
124  totaltime = timer(EndTimer);
125
126  snprintf(buf,sizeof buf,"%.2f seconds.",(double)totaltime/1000000.);
127  show_result(buf);
128}
129
130void
131copyplane_test(void)
132{
133  int num_copies = 200;
134  int i;
135  long totaltime;
136  char buf[80];
137
138  if(!X.gcv.plane_mask || (X.gcv.plane_mask & (X.gcv.plane_mask - 1))) {
139    show_result("exactly one bit in plane mask must be set for this test");
140    return;
141  }
142
143
144  num_copies *= X.percent;
145
146  XSetPlaneMask(X.dpy, X.gc, ~0L);
147  XSetFillStyle(X.dpy,X.miscgc,FillTiled);
148  XFillRectangle(X.dpy,X.win,X.miscgc,0,0,400,400);
149
150  XSync(X.dpy,0);
151  timer(StartTimer);
152  for (i=0;i<num_copies;++i)
153    XCopyPlane(X.dpy,X.win,X.win,X.gc,i,200-i,
154	      200,200,200-i,i,X.gcv.plane_mask);
155  XSync(X.dpy,0);
156  totaltime = timer(EndTimer);
157  XSetPlaneMask(X.dpy, X.gc, X.gcv.plane_mask);
158
159  snprintf(buf,sizeof buf,"%.2f seconds.",(double)totaltime/1000000.);
160  show_result(buf);
161}
162
163void
164circle_line_test(int num_vertices, int radius)
165{
166  double theta, delta;
167  int length, centerx, centery, i;
168  int relative_angle;
169  long totaltime;
170  char buf[80];
171  XPoint *coord;
172
173  relative_angle = num_vertices*5/12+1;
174  delta = (double) relative_angle / (double) num_vertices * 2 * PI;
175  centerx = centery = 200;
176
177  coord = (XPoint *) malloc (sizeof(XPoint)*(num_vertices+1));
178
179  length = (int) (2 * radius * (float) atan(delta/2.));
180
181  for (i=0;i<=num_vertices;++i) {
182    theta = (double) i * delta;
183    coord[i].x = centerx + (int) (radius * cos(theta));
184    coord[i].y = centery + (int) (radius * sin(theta));
185  }
186
187  XSync(X.dpy,0);
188  timer(StartTimer);
189  XDrawLines(X.dpy,X.win,X.gc,coord,num_vertices+1,CoordModeOrigin);
190  XSync(X.dpy,0);
191  totaltime = timer(EndTimer);
192
193  snprintf(buf,sizeof buf,"%d lines of length %d in %.3f seconds.",num_vertices,
194	  length,(double)totaltime/1000000.);
195  show_result(buf);
196
197  free(coord);
198}
199
200
201
202void
203polyline_test(void)
204{
205  circle_line_test((int)(601*X.percent),190);
206}
207
208void
209polysegment_test(void)
210{
211  XSegment *segments;
212  int num_segments = 600;
213  long totaltime;
214  char buf[80];
215  int i;
216
217  num_segments *= X.percent;
218
219  segments = (XSegment *) malloc(sizeof(XSegment) * num_segments);
220
221  segments[0].x1 = random()%400; segments[0].y1 = random()%400;
222  segments[0].x2 = random()%400; segments[0].y2 = random()%400;
223
224  for(i=1;i<num_segments;++i) {
225    segments[i].x1 = (segments[i-1].x1-segments[i-1].y2+400+i)%400;
226    segments[i].y1 = (segments[i-1].y1+segments[i-1].x2+i)%400;
227    segments[i].x2 = (segments[i-1].x1-segments[i-1].y1+400+i)%400;
228    segments[i].y2 = (segments[i-1].x2+segments[i-1].y2+i)%400;
229  }
230
231  XSync(X.dpy,0);
232  start_timer();
233  XDrawSegments(X.dpy,X.win,X.gc,segments,num_segments);
234  XSync(X.dpy,0);
235  totaltime = end_timer();
236
237  snprintf(buf,sizeof buf,"%d segments in %.3f seconds.",num_segments,
238	  (double)totaltime/1000000.);
239  show_result(buf);
240
241  free(segments);
242}
243
244void
245polypoint_test(void)
246{
247  XPoint *points;
248  int num_points = 100000;
249  long totaltime;
250  char buf[80];
251  int i;
252
253  num_points *= X.percent;
254
255  points = (XPoint *) malloc(sizeof(XPoint) * num_points);
256
257  points[0].x = random()%400; points[0].y = random()%400;
258  points[1].x = random()%400; points[1].y = random()%400;
259
260  for (i=2;i<num_points;++i) {
261    points[i].x = (points[i-1].x+points[i-2].y+i*3/200)%400;
262    points[i].y = (points[i-1].y+points[i-2].x+i*5/200)%400;
263  }
264
265  XSync(X.dpy,0);
266  start_timer();
267  XDrawPoints(X.dpy,X.win,X.gc,points,num_points,CoordModeOrigin);
268  XSync(X.dpy,0);
269  totaltime = end_timer();
270
271  snprintf(buf,sizeof buf,"%d points in %.3f seconds.",num_points,
272	  (double)totaltime/1000000.);
273  show_result(buf);
274
275  free(points);
276}
277
278void
279genericrectangle_test(Boolean fill)
280{
281  XRectangle *rects;
282  int num_rects = 200;
283  int perimeter = 0, area = 0;
284  int i;
285  long totaltime;
286  char buf[80];
287
288  num_rects *= X.percent;
289
290  rects = (XRectangle *) malloc(sizeof(XRectangle) * num_rects);
291
292  for (i=0;i<num_rects;++i) {
293    rects[i].x = rects[i].y = 200 - i;
294    rects[i].width = rects[i].height = 2 * i;
295    perimeter += rects[i].width * 2 + rects[i].height * 2;
296    area += rects[i].width * rects[i].height;
297  }
298
299  XSync(X.dpy,0);
300  start_timer();
301  if (fill) XFillRectangles(X.dpy,X.win,X.gc,rects,num_rects);
302  else XDrawRectangles(X.dpy,X.win,X.gc,rects,num_rects);
303  XSync(X.dpy,0);
304  totaltime = end_timer();
305
306  if (fill)
307    snprintf(buf,sizeof buf,"%d pixels in %.2f seconds.",area,(double)totaltime/1000000.);
308  else
309    snprintf(buf,sizeof buf,"Total line length %d in %.3f seconds.",perimeter,
310	    (double)totaltime/1000000.);
311  show_result(buf);
312
313  free(rects);
314}
315
316void
317polyrectangle_test(void)
318{
319  genericrectangle_test(FALSE);
320}
321
322void
323polyfillrectangle_test(void)
324{
325  genericrectangle_test(TRUE);
326}
327
328/*****************************/
329
330void
331fillpolygon_test(void)
332{
333  int i;
334  int points_per_side = 40;
335  int spacing;
336  XPoint *points;
337  XPoint polypoints[3];
338
339  points = (XPoint *) malloc (sizeof(XPoint) * points_per_side * 4);
340  spacing = 400 / points_per_side;
341
342  for (i = 0; i < points_per_side; ++i) {
343    points[i].x = i * spacing;
344    points[i].y = 0;
345
346    points[i + points_per_side].x = 400;
347    points[i + points_per_side].y = i * spacing;
348
349    points[i + 2 * points_per_side].x = 400 - i * spacing;
350    points[i + 2 * points_per_side].y = 400;
351
352    points[i + 3 * points_per_side].x = 0;
353    points[i + 3 * points_per_side].y = 400 - i * spacing;
354  }
355
356  for (i = 0; i < 2 * points_per_side; i += 2) {
357    polypoints[0].x = points[i].x;
358    polypoints[0].y = points[i].y;
359
360    polypoints[1].x = points[i + 2 * points_per_side].x;
361    polypoints[1].y = points[i + 2 * points_per_side].y;
362
363    polypoints[2].x = points[i + 2 * points_per_side + 1].x;
364    polypoints[2].y = points[i + 2 * points_per_side + 1].y;
365
366    XFillPolygon (X.dpy, X.win, X.gc, polypoints, 3, Convex, CoordModeOrigin);
367  }
368  free(points);
369}
370
371/*****************************/
372
373void
374genericarc_test(Boolean fill)
375{
376  XArc *arcs;
377  int num_arcs = 180;
378  int i;
379  long totaltime;
380  char buf[80];
381
382  num_arcs *= X.percent;
383
384  arcs = (XArc *) malloc(sizeof(XArc) * num_arcs);
385
386  for (i=0;i<num_arcs;++i) {
387    arcs[i].x = i;
388    arcs[i].y = i;
389    arcs[i].width = i;
390    arcs[i].height = i;
391    arcs[i].angle1 = i * 128;
392    arcs[i].angle2 = i * 128;
393  }
394
395  XSync(X.dpy,0);
396  start_timer();
397  if (fill) XFillArcs(X.dpy,X.win,X.gc,arcs,num_arcs);
398  else XDrawArcs(X.dpy,X.win,X.gc,arcs,num_arcs);
399  XSync(X.dpy,0);
400  totaltime = end_timer();
401
402  snprintf(buf,sizeof buf,"An uncounted number of pixels in %.3f seconds.",
403	  (double)totaltime/1000000.);
404  show_result(buf);
405
406  free(arcs);
407}
408
409void
410polyarc_test(void)
411{
412  genericarc_test(FALSE);
413}
414
415void
416polyfillarc_test(void)
417{
418  genericarc_test(TRUE);
419}
420
421static const char string8[] = "pack my box with five dozen liquor jugs";
422
423void
424polytext8_test(void)
425{
426  int num_strings = 200;
427  int i;
428  long totaltime;
429  char buf[80];
430
431  num_strings *= X.percent;
432
433  XSync(X.dpy,0);
434  start_timer();
435  for (i=0;i<num_strings;++i) {
436    XDrawString(X.dpy,X.win,X.gc,(i%2 ? i : num_strings - i),i,
437		string8,sizeof(string8)-1);
438  }
439  XSync(X.dpy,0);
440  totaltime = end_timer();
441
442  snprintf(buf,sizeof buf,"%d strings in %.2f seconds.",num_strings,
443	  (double) totaltime/1000000.);
444  show_result(buf);
445}
446
447void
448imagetext8_test(void)
449{
450  int num_strings = 200;
451  int i;
452  long totaltime;
453  char buf[80];
454
455  num_strings *= X.percent;
456
457  XSync(X.dpy,0);
458  start_timer();
459  for (i=0;i<num_strings;++i) {
460    XDrawImageString(X.dpy,X.win,X.gc,(i%2 ? i : num_strings - i),i,
461		     string8,sizeof(string8)-1);
462  }
463  XSync(X.dpy,0);
464  totaltime = end_timer();
465
466  snprintf(buf,sizeof buf,"%d strings in %.2f seconds.",num_strings,
467	  (double) totaltime/1000000.);
468  show_result(buf);
469}
470
471static char unicode_font[] =
472  "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1";
473
474static const XChar2b string16[] = {
475  { 0x00, 0x20 }, { 0x00, 0x20 }, { 0x22, 0x2E }, { 0x00, 0x20 },
476  { 0x00, 0x45 }, { 0x22, 0xC5 }, { 0x00, 0x64 }, { 0x00, 0x61 },
477  { 0x00, 0x20 }, { 0x00, 0x3D }, { 0x00, 0x20 }, { 0x00, 0x51 },
478  { 0x00, 0x2C }, { 0x00, 0x20 }, { 0x00, 0x20 }, { 0x00, 0x6E },
479  { 0x00, 0x20 }, { 0x21, 0x92 }, { 0x00, 0x20 }, { 0x22, 0x1E },
480  { 0x00, 0x2C }, { 0x00, 0x20 }, { 0x22, 0x11 }, { 0x00, 0x20 },
481  { 0x00, 0x66 }, { 0x00, 0x28 }, { 0x00, 0x69 }, { 0x00, 0x29 },
482  { 0x00, 0x20 }, { 0x00, 0x3D }, { 0x00, 0x20 }, { 0x22, 0x0F },
483  { 0x00, 0x20 }, { 0x00, 0x67 }, { 0x00, 0x28 }, { 0x00, 0x69 },
484  { 0x00, 0x29 }, { 0x00, 0x2C }, { 0x00, 0x20 }, { 0x22, 0x00 },
485  { 0x00, 0x78 }, { 0x22, 0x08 }, { 0x21, 0x1D }, { 0x00, 0x3A },
486  { 0x00, 0x20 }, { 0x23, 0x08 }, { 0x00, 0x78 }, { 0x23, 0x09 },
487  { 0x00, 0x20 }, { 0x00, 0x3D }, { 0x00, 0x20 }, { 0x22, 0x12 },
488  { 0x23, 0x0A }, { 0x22, 0x12 }, { 0x00, 0x78 }, { 0x23, 0x0B },
489  { 0x00, 0x2C }, { 0x00, 0x20 }, { 0x03, 0xB1 }, { 0x00, 0x20 },
490  { 0x22, 0x27 }, { 0x00, 0x20 }, { 0x00, 0xAC }, { 0x03, 0xB2 },
491  { 0x00, 0x20 }, { 0x00, 0x3D }, { 0x00, 0x20 }, { 0x00, 0xAC },
492  { 0x00, 0x28 }, { 0x00, 0xAC }, { 0x03, 0xB1 }, { 0x00, 0x20 },
493  { 0x22, 0x28 }, { 0x00, 0x20 }, { 0x03, 0xB2 }, { 0x00, 0x29 },
494  { 0x00, 0x2C }
495};
496
497void
498polytext16_test(void)
499{
500  int num_strings = 50;
501  int i;
502  long totaltime;
503  char buf[80];
504
505  num_strings *= X.percent;
506
507  GC_change_font(unicode_font,FALSE);
508
509  XSync(X.dpy,0);
510  start_timer();
511  for (i=0;i<num_strings;++i) {
512    XDrawString16(X.dpy,X.win,X.gc,(i%2 ? i : num_strings - i),10*i,
513		  string16,sizeof(string16)/sizeof(XChar2b));
514  }
515  XSync(X.dpy,0);
516  totaltime = end_timer();
517
518  GC_change_font(X.fontname,FALSE);
519
520  snprintf(buf,sizeof buf,"%d strings in %.2f seconds.",num_strings,
521	  (double) totaltime/1000000.);
522  show_result(buf);
523}
524
525void
526imagetext16_test(void)
527{
528  int num_strings = 50;
529  int i;
530  long totaltime;
531  char buf[80];
532
533  num_strings *= X.percent;
534
535  GC_change_font(unicode_font,FALSE);
536
537  XSync(X.dpy,0);
538  start_timer();
539  for (i=0;i<num_strings;++i) {
540    XDrawImageString16(X.dpy,X.win,X.gc,(i%2 ? i : num_strings - i),10*i,
541		       string16,sizeof(string16)/sizeof(XChar2b));
542  }
543  XSync(X.dpy,0);
544  totaltime = end_timer();
545
546  GC_change_font(X.fontname,FALSE);
547
548  snprintf(buf,sizeof buf,"%d strings in %.2f seconds.",num_strings,
549	  (double) totaltime/1000000.);
550  show_result(buf);
551}
552
553void
554putimage_test(void)
555{
556  int num_copies = 200;
557  int i;
558  long totaltime;
559  char buf[80];
560
561  num_copies *= X.percent;
562
563  XSetFillStyle(X.dpy,X.miscgc,FillTiled);
564  XFillRectangle(X.dpy,X.win,X.miscgc,0,0,400,400);
565
566  X.image = XGetImage(X.dpy,X.win,0,0,200,200,~0,XYPixmap);
567
568  XSync(X.dpy,0);
569  timer(StartTimer);
570  for (i=0;i<num_copies;++i)
571    XPutImage(X.dpy,X.win,X.gc,X.image,0,0,i,i,200,200);
572  XSync(X.dpy,0);
573  totaltime = timer(EndTimer);
574
575  snprintf(buf,sizeof buf,"%.2f seconds.",(double)totaltime/1000000.);
576  show_result(buf);
577}
578
579
580/*****************************/
581/*****************************/
582
583void
584run_test(void)
585{
586  XClearWindow(X.dpy,X.win);
587
588  print_if_recording("run\n");
589
590  switch (X.test) {
591    case CopyArea:      copyarea_test();           break;
592    case CopyPlane:     copyplane_test();          break;
593    case PolyPoint:     polypoint_test();          break;
594    case PolyLine:      polyline_test();           break;
595    case PolySegment:   polysegment_test();        break;
596    case PolyRectangle: polyrectangle_test();      break;
597    case PolyArc:       polyarc_test();            break;
598    case FillPolygon:   fillpolygon_test();        break;
599    case PolyFillRect:  polyfillrectangle_test();  break;
600    case PolyFillArc:   polyfillarc_test();        break;
601    case PolyText8:     polytext8_test();          break;
602    case ImageText8:    imagetext8_test();         break;
603    case PolyText16:    polytext16_test();         break;
604    case ImageText16:   imagetext16_test();        break;
605    case PutImage:      putimage_test();           break;
606    default: fprintf(stderr,"That test doesn't exist yet.\n");
607    }
608}
609
610/*****************************/
611
612/* set_text(w,string)
613** ------------------
614** Sets the text in a read-only text widget to the specified string.
615*/
616
617void
618set_text(Widget w, char *string)
619{
620  static Arg args[2];
621
622  XtSetArg(args[0], XtNstring, string);
623  XtSetArg(args[1], XtNlength, strlen(string));
624  XtSetValues(w, args, (Cardinal) 2 );
625}
626
627void
628show_result(char *string)
629{
630  char buf[80];
631
632  set_text(result,string);
633
634  strcpy(buf,"# ");
635  strncat(buf,string,sizeof(buf) - 3);
636  buf[sizeof(buf) - 3] = '\0';
637  strcat(buf,"\n");
638  print_if_recording(buf);
639}
640