x11perf.c revision 264fa531
1/* $Xorg: x11perf.c,v 1.4 2000/08/17 19:54:10 cpqbld Exp $ */ 2/* $XdotOrg: app/x11perf/x11perf.c,v 1.4 2006/02/14 02:48:22 anholt Exp $ */ 3/**************************************************************************** 4Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 5 6 All Rights Reserved 7 8Permission to use, copy, modify, and distribute this software and its 9documentation for any purpose and without fee is hereby granted, 10provided that the above copyright notice appear in all copies and that 11both that copyright notice and this permission notice appear in 12supporting documentation, and that the name of Digital not be 13used in advertising or publicity pertaining to distribution of the 14software without specific, written prior permission. 15 16DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 17ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 18DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 19ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 20WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 22SOFTWARE. 23 24****************************************************************************/ 25/* $XFree86: xc/programs/x11perf/x11perf.c,v 3.6 2001/11/03 21:59:20 dawes Exp $ */ 26 27#include <stdio.h> 28#include <ctype.h> 29#include <signal.h> 30 31#ifndef VMS 32#include <X11/Xatom.h> 33#include <X11/Xos.h> 34#else 35#include <decw$include/Xatom.h> 36#endif 37#include "x11perf.h" 38#include <X11/Xmu/SysUtil.h> 39 40#include <time.h> 41#define Time_t time_t 42#include <stdlib.h> 43 44/* Only for working on ``fake'' servers, for hardware that doesn't exist */ 45static Bool drawToFakeServer = False; 46static Pixmap tileToQuery = None; 47static char *displayName; 48int abortTest; 49 50typedef struct _RopNames { char *name; int rop; } RopNameRec, *RopNamePtr; 51 52RopNameRec ropNames[] = { 53 { "clear", GXclear }, /* 0 */ 54 { "and", GXand }, /* src AND dst */ 55 { "andReverse", GXandReverse }, /* src AND NOT dst */ 56 { "copy", GXcopy }, /* src */ 57 { "andInverted", GXandInverted }, /* NOT src AND dst */ 58 { "noop", GXnoop }, /* dst */ 59 { "xor", GXxor }, /* src XOR dst */ 60 { "or", GXor }, /* src OR dst */ 61 { "nor", GXnor }, /* NOT src AND NOT dst */ 62 { "equiv", GXequiv }, /* NOT src XOR dst */ 63 { "invert", GXinvert }, /* NOT dst */ 64 { "orReverse", GXorReverse }, /* src OR NOT dst */ 65 { "copyInverted", GXcopyInverted }, /* NOT src */ 66 { "orInverted", GXorInverted }, /* NOT src OR dst */ 67 { "nand", GXnand }, /* NOT src OR NOT dst */ 68 { "set", GXset } /* 1 */ 69}; 70 71char *(visualClassNames)[] = { 72 "StaticGray", 73 "GrayScale", 74 "StaticColor", 75 "PseudoColor", 76 "TrueColor", 77 "DirectColor" 78}; 79 80static Bool labels = False; 81static int repeat = 5; 82static int seconds = 5; 83 84static Window status; /* Status window and GC */ 85static GC tgc; 86static int HSx, HSy; 87 88static double syncTime = 0.0; 89 90static int saveargc; 91static char **saveargv; 92 93static int numRops = 1; 94static int rops[16] = { GXcopy }; 95static int numPlanemasks = 1; 96static unsigned long planemasks[256] = { (unsigned long)~0 }; 97 98static char *foreground = NULL; 99static char *background = NULL; 100static char *ddbackground = NULL; 101static int clips = 0; 102 103static int numSubWindows = 7; 104static unsigned long subWindows[] = {4, 16, 25, 50, 75, 100, 200, 0}; 105 106static int fixedReps = 0; 107 108static Bool *doit; 109 110static XRectangle ws[] = { /* Clip rectangles */ 111 {195, 195, 120, 120}, 112 { 45, 145, 120, 120}, 113 {345, 245, 120, 120}, 114 { 45, 275, 120, 120}, 115 {345, 115, 120, 120}, 116 {195, 325, 120, 120} 117 118}; 119#define MAXCLIP (sizeof(ws) / sizeof(ws[0])) 120static Window clipWindows[MAXCLIP]; 121static Colormap cmap; 122static int depth = -1; /* -1 means use default depth */ 123static int vclass = -1; /* -1 means use CopyFromParent */ 124 125/* ScreenSaver state */ 126static XParmRec xparms; 127static int ssTimeout, ssInterval, ssPreferBlanking, ssAllowExposures; 128 129/* Static functions */ 130static int GetWords(int argi, int argc, char **argv, char **wordsp, int *nump); 131static int GetNumbers(int argi, int argc, char **argv, unsigned long *intsp, 132 int *nump); 133static int GetRops(int argi, int argc, char **argv, int *ropsp, int *nump); 134 135/************************************************ 136* time related stuff * 137************************************************/ 138 139#ifdef VMS 140 141typedef struct _vms_time { 142 unsigned long low; 143 unsigned long high; 144}vms_time; 145 146struct timeval { 147 long tv_sec; /* seconds since Jan. 1, 1970 */ 148 long tv_usec; /* and microseconds */ 149}; 150 151struct timezone { 152 int tz_minuteswest; /* of Greenwich */ 153 int tz_dsttime; /* type of dst correction to apply */ 154}; 155 156 157static int firsttime = True; 158static vms_time basetime; 159 160int gettimeofday(tp) 161 struct timeval *tp; 162{ 163 vms_time current_time, resultant; 164 unsigned long mumble, foo; 165 int status; 166 167 if (firsttime) { 168 sys$gettim(&basetime); 169 firsttime = False; 170 } 171 sys$gettim(¤t_time); 172 resultant.high = current_time.high - basetime.high; 173 resultant.low = current_time.low - basetime.low; 174 if (current_time.low < basetime.low) { 175 resultant.high -= 1; 176 } 177 status = lib$ediv( &(10000000), &resultant, &tp->tv_sec, &tp->tv_usec); 178 tp->tv_usec /= 10; 179 return 0; 180} 181 182#endif 183 184static struct timeval start; 185 186static void 187PrintTime(void) 188{ 189 Time_t t; 190 191 t = time((Time_t *)NULL); 192 printf("%s\n", ctime(&t)); 193} 194 195static void 196InitTimes(void) 197{ 198 X_GETTIMEOFDAY(&start); 199} 200 201static double 202ElapsedTime(double correction) 203{ 204 struct timeval stop; 205 206 X_GETTIMEOFDAY(&stop); 207 if (stop.tv_usec < start.tv_usec) { 208 stop.tv_usec += 1000000; 209 stop.tv_sec -= 1; 210 } 211 return (double)(stop.tv_usec - start.tv_usec) + 212 (1000000.0 * (double)(stop.tv_sec - start.tv_sec)) - correction; 213} 214 215static double 216RoundTo3Digits(double d) 217{ 218 /* It's kind of silly to print out things like ``193658.4/sec'' so just 219 junk all but 3 most significant digits. */ 220 221 double exponent, sign; 222 223 exponent = 1.0; 224 /* the code below won't work if d should happen to be non-positive. */ 225 if (d < 0.0) { 226 d = -d; 227 sign = -1.0; 228 } else 229 sign = 1.0; 230 if (d >= 1000.0) { 231 do { 232 exponent *= 10.0; 233 } while (d/exponent >= 1000.0); 234 d = (double)((int) (d/exponent + 0.5)); 235 d *= exponent; 236 } else { 237 if (d != 0.0) { 238 while (d*exponent < 100.0) { 239 exponent *= 10.0; 240 } 241 } 242 d = (double)((int) (d*exponent + 0.5)); 243 d /= exponent; 244 } 245 return d * sign; 246} 247 248 249static void 250ReportTimes(double usecs, int n, char *str, int average) 251{ 252 double msecsperobj, objspersec; 253 254 if(usecs != 0.0) 255 { 256 msecsperobj = usecs / (1000.0 * (double)n); 257 objspersec = (double) n * 1000000.0 / usecs; 258 259 /* Round obj/sec to 3 significant digits. Leave msec untouched, to 260 allow averaging results from several repetitions. */ 261 objspersec = RoundTo3Digits(objspersec); 262 263 if (average) { 264 printf("%7d trep @ %8.4f msec (%8.1f/sec): %s\n", 265 n, msecsperobj, objspersec, str); 266 } else { 267 printf("%7d reps @ %8.4f msec (%8.1f/sec): %s\n", 268 n, msecsperobj, objspersec, str); 269 } 270 } else { 271 printf("%6d %sreps @ 0.0 msec (unmeasurably fast): %s\n", 272 n, average ? "t" : "", str); 273 } 274 275} 276 277 278 279/************************************************ 280* Generic X stuff * 281************************************************/ 282 283static char *program_name; 284static void usage(void); 285 286/* 287 * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obselete) 288 * If found, remove it from command line. Don't go past a lone -. 289 */ 290static char * 291Get_Display_Name(int *pargc, /* MODIFIED */ 292 char **argv) /* MODIFIED */ 293{ 294 int argc = *pargc; 295 char **pargv = argv+1; 296 char *displayname = NULL; 297 int i; 298 299 for (i = 1; i != argc; i++) { 300 char *arg = argv[i]; 301 302 if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) { 303 if (++i >= argc) usage (); 304 305 displayname = argv[i]; 306 *pargc -= 2; 307 continue; 308 } 309 if (!strcmp(arg,"-")) { 310 while (i<argc) *pargv++ = argv[i++]; 311 break; 312 } 313 *pargv++ = arg; 314 } 315 316 *pargv = NULL; 317 return (displayname); 318} 319 320 321/* 322 * GetVersion (argc, argv) Look for -v1.2, -v1.3, or -v1.4. 323 * If found remove it from command line. Don't go past a lone -. 324 */ 325 326static Version 327GetVersion(int *pargc, /* MODIFIED */ 328 char **argv) /* MODIFIED */ 329{ 330 int argc = *pargc; 331 char **pargv = argv+1; 332 Version version = VERSION1_5; 333 int i; 334 Bool found = False; 335 336 for (i = 1; i != argc; i++) { 337 char *arg = argv[i]; 338 339 if (!strcmp (arg, "-v1.2")) { 340 version = VERSION1_2; 341 *pargc -= 1; 342 if (found) { 343 fprintf(stderr, "Warning: multiple version specifications\n"); 344 } 345 found = True; 346 continue; 347 } 348 if (!strcmp (arg, "-v1.3")) { 349 version = VERSION1_3; 350 *pargc -= 1; 351 if (found) { 352 fprintf(stderr, "Warning: multiple version specifications\n"); 353 } 354 found = True; 355 continue; 356 } 357 if (!strcmp (arg, "-v1.4")) { 358 version = VERSION1_4; 359 *pargc -= 1; 360 if (found) { 361 fprintf(stderr, "Warning: multiple version specifications\n"); 362 } 363 found = True; 364 continue; 365 } 366 if (!strcmp(arg,"-")) { 367 while (i<argc) *pargv++ = argv[i++]; 368 break; 369 } 370 *pargv++ = arg; 371 } 372 373 *pargv = NULL; 374 return (version); 375} 376 377 378 379/* 380 * Open_Display: Routine to open a display with correct error handling. 381 */ 382static Display * 383Open_Display(char *display_name) 384{ 385 Display *d; 386 387 d = XOpenDisplay(display_name); 388 if (d == NULL) { 389 fprintf (stderr, "%s: unable to open display '%s'\n", 390 program_name, XDisplayName (display_name)); 391 exit(1); 392 } 393 394 return(d); 395} 396 397 398/* defined by autoconf AC_TYPE_SIGNAL, need to define for Imake */ 399#ifndef RETSIGTYPE 400# ifdef SIGNALRETURNSINT 401# define RETSIGTYPE int 402# else 403# define RETSIGTYPE void 404# endif 405#endif 406 407static RETSIGTYPE 408Cleanup(int sig) 409{ 410 abortTest = sig; 411} 412 413void 414AbortTest(void) 415{ 416 fflush(stdout); 417 418 XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking, 419 ssAllowExposures); 420 XFlush(xparms.d); 421 exit (abortTest); 422} 423 424/************************************************ 425* Performance stuff * 426************************************************/ 427 428 429static void 430usage(void) 431{ 432 char **cpp; 433 int i = 0; 434 static char *help_message[] = { 435"where options include:", 436" -display <host:display> the X server to contact", 437" -sync do the tests in synchronous mode", 438" -pack pack rectangles right next to each other", 439" -repeat <n> do tests <n> times (default = 5)", 440" -time <s> do tests for <s> seconds each (default = 5)", 441/* 442" -draw draw after each test -- pmax only", 443*/ 444" -all do all tests", 445" -range <test1>[,<test2>] like all, but do <test1> to <test2>", 446" -labels generate test labels for use by fillblnk", 447" -fg the foreground color to use", 448" -bg the background color to use", 449" -clips <default> default number of clip windows per test", 450" -ddbg the background color to use for DoubleDash", 451" -rop <rop0 rop1 ...> use the given rops to draw (default = GXcopy)", 452" -pm <pm0 pm1 ...> use the given planemasks to draw (default = ~0)", 453" -depth <depth> use a visual with <depth> planes per pixel", 454" -vclass <class> the visual class to use (default = root)", 455" -reps <n> fix the rep count (default = auto scale)", 456" -subs <s0 s1 ...> a list of the number of sub-windows to use", 457" -v1.2 perform only v1.2 tests using old semantics", 458" -v1.3 perform only v1.3 tests using old semantics", 459" -su request save unders on windows", 460" -bs <backing_store_hint> WhenMapped or Always (default = NotUseful)", 461NULL}; 462 463 fflush(stdout); 464 fprintf(stderr, "usage: %s [-options ...]\n", program_name); 465 for (cpp = help_message; *cpp; cpp++) { 466 fprintf(stderr, "%s\n", *cpp); 467 } 468 while (test[i].option != NULL) { 469 if (test[i].versions & xparms.version ) { 470 fprintf(stderr, " %-24s %s\n", 471 test[i].option, 472 test[i].label14 ? test[i].label14 : test[i].label); 473 } 474 i++; 475 } 476 fprintf(stderr, "\n"); 477 478 /* Print out original command line as the above usage message is so long */ 479 for (i = 0; i != saveargc; i++) { 480 fprintf(stderr, "%s ", saveargv[i]); 481 } 482 fprintf(stderr, "\n\n"); 483 exit (1); 484} 485 486void 487NullProc(XParms xp, Parms p) 488{ 489} 490 491int 492NullInitProc(XParms xp, Parms p, int reps) 493{ 494 return reps; 495} 496 497static void 498HardwareSync(XParms xp) 499{ 500 /* 501 * Some graphics hardware allows the server to claim it is done, 502 * while in reality the hardware is busily working away. So fetch 503 * a pixel from the drawable that was drawn to, which should be 504 * enough to make the server wait for the graphics hardware. 505 */ 506 XImage *image; 507 508 image = XGetImage(xp->d, xp->p ? xp->p : xp->w, HSx, HSy, 509 1, 1, ~0, ZPixmap); 510 if (image) XDestroyImage(image); 511} 512 513static void 514DoHardwareSync(XParms xp, Parms p, int reps) 515{ 516 int i; 517 518 for (i = 0; i != reps; i++) { 519 HardwareSync(xp); 520 CheckAbort (); 521 } 522} 523 524static Test syncTest = { 525 "syncTime", "Internal test for finding how long HardwareSync takes", NULL, 526 NullInitProc, DoHardwareSync, NullProc, NullProc, 527 V1_2FEATURE, NONROP, 0, 528 {1} 529}; 530 531 532static Window 533CreatePerfWindow(XParms xp, int x, int y, int width, int height) 534{ 535 XSetWindowAttributes xswa; 536 Window w; 537/* 538 Screen *s; 539 int su; 540 541 s = DefaultScreenOfDisplay(xp->d); 542 su = XDoesBackingStore(s); 543 printf("Backing store of screen returns %d\n", su); 544 su = XDoesSaveUnders(s); 545 printf("Save unders of screen returns %d\n", su); 546 su = XPlanesOfScreen(s); 547 printf("Planes of screen returns %d\n", su); 548*/ 549 xswa.background_pixel = xp->background; 550 xswa.border_pixel = xp->foreground; 551 xswa.colormap = cmap; 552 xswa.override_redirect = True; 553 xswa.backing_store = xp->backing_store; 554 xswa.save_under = xp->save_under; 555 w = XCreateWindow(xp->d, DefaultRootWindow(xp->d), x, y, width, height, 1, 556 xp->vinfo.depth, CopyFromParent, xp->vinfo.visual, 557 CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect 558 | CWBackingStore | CWSaveUnder, &xswa); 559 XMapWindow (xp->d, w); 560 return w; 561} 562 563 564static void 565CreateClipWindows(XParms xp, int clips) 566{ 567 int j; 568 XWindowAttributes xwa; 569 570 (void) XGetWindowAttributes(xp->d, xp->w, &xwa); 571 if (clips > MAXCLIP) clips = MAXCLIP; 572 for (j = 0; j != clips; j++) { 573 clipWindows[j] = CreatePerfWindow(xp, 574 xwa.x + ws[j].x, xwa.y + ws[j].y, ws[j].width, ws[j].height); 575 } 576} /* CreateClipWindows */ 577 578 579static void 580DestroyClipWindows(XParms xp, int clips) 581{ 582 int j; 583 584 if (clips > MAXCLIP) clips = MAXCLIP; 585 for (j = 0; j != clips; j++) { 586 XDestroyWindow(xp->d, clipWindows[j]); 587 } 588} /* DestroyClipWindows */ 589 590 591static double 592DoTest(XParms xp, Test *test, int reps) 593{ 594 double time; 595 unsigned int ret_width, ret_height; 596 597 /* Tell screen-saver to restart counting again. See comments below for the 598 XSetScreenSaver call. */ 599 XForceScreenSaver(xp->d, ScreenSaverReset); 600 HardwareSync (xp); 601 InitTimes (); 602 (*test->proc) (xp, &test->parms, reps); 603 HardwareSync(xp); 604 605 time = ElapsedTime(syncTime); 606 CheckAbort (); 607 if (drawToFakeServer) 608 XQueryBestSize(xp->d, TileShape, tileToQuery, 609 32, 32, &ret_width, &ret_height); 610 (*test->passCleanup) (xp, &test->parms); 611 return time; 612} 613 614 615static int 616CalibrateTest(XParms xp, Test *test, int seconds, double *usecperobj) 617{ 618#define goal 2500000.0 /* Try to get up to 2.5 seconds */ 619#define enough 2000000.0 /* But settle for 2.0 seconds */ 620#define tick 10000.0 /* Assume clock not faster than .01 seconds */ 621 622 double usecs; 623 int reps, didreps; /* Reps desired, reps performed */ 624 int exponent; 625 626 /* Attempt to get an idea how long each rep lasts by getting enough 627 reps to last more tan enough. Then scale that up to the number of 628 seconds desired. 629 630 If init call to test ever fails, return False and test will be skipped. 631 */ 632 633 if (fixedReps != 0) { 634 return fixedReps; 635 } 636 reps = 1; 637 for (;;) { 638 XDestroySubwindows(xp->d, xp->w); 639 XClearWindow(xp->d, xp->w); 640 didreps = (*test->init) (xp, &test->parms, reps); 641 CheckAbort (); 642 if (didreps == 0) { 643 return 0; 644 } 645 if ( test->clips < clips ) 646 test->clips = clips ; 647 /* Create clip windows if requested */ 648 CreateClipWindows(xp, test->clips); 649 HardwareSync(xp); 650 InitTimes(); 651 (*test->proc) (xp, &test->parms, reps); 652 HardwareSync(xp); 653 usecs = ElapsedTime(syncTime); 654 (*test->passCleanup) (xp, &test->parms); 655 (*test->cleanup) (xp, &test->parms); 656 DestroyClipWindows(xp, test->clips); 657 CheckAbort (); 658 659 if (didreps != reps) { 660 /* The test can't do the number of reps as we asked for. 661 Give up */ 662 *usecperobj = 663 usecs / (double)(didreps * test->parms.objects); 664 return didreps; 665 } 666 /* Did we go long enough? */ 667 if (usecs >= enough) break; 668 669 /* Don't let too short a clock make new reps wildly high */ 670 if (usecs <= tick)reps = reps*10; 671 else{ 672 /* Try to get up to goal seconds. */ 673 reps = (int) (goal * (double)reps / usecs) + 1; 674 } 675 } 676 677 *usecperobj = usecs / (double) (reps * test->parms.objects); 678 reps = (int) ((double)seconds * 1000000.0 * (double)reps / usecs) + 1; 679 680 /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking 681 numbers of repetitions. */ 682 reps--; 683 exponent = 1; 684 while (reps > 9) { 685 reps /= 10; 686 exponent *= 10; 687 } 688 reps = (reps + 1) * exponent; 689 return reps; 690} /* CalibrateTest */ 691 692static void 693CreatePerfGCs(XParms xp, int func, unsigned long pm) 694{ 695 XGCValues gcvfg, gcvbg, gcvddbg,gcvddfg; 696 unsigned long fg, bg, ddbg; 697 698 fg = xp->foreground; 699 bg = xp->background; 700 ddbg = xp->ddbackground; 701 gcvfg.graphics_exposures = False; 702 gcvbg.graphics_exposures = False; 703 gcvddfg.graphics_exposures = False; 704 gcvddbg.graphics_exposures = False; 705 gcvfg.plane_mask = pm; 706 gcvbg.plane_mask = pm; 707 gcvddfg.plane_mask = pm; 708 gcvddbg.plane_mask = pm; 709 gcvfg.function = func; 710 gcvbg.function = func; 711 gcvddfg.function = func; 712 gcvddbg.function = func; 713 714 if (func == GXxor) { 715 /* Make test look good visually if possible */ 716 gcvbg.foreground = gcvfg.foreground = bg ^ fg; 717 gcvbg.background = gcvfg.background = bg; 718 /* Double Dash GCs (This doesn't make a huge amount of sense) */ 719 gcvddbg.foreground = gcvddfg.foreground = bg ^ fg; 720 gcvddbg.background = gcvddfg.foreground = bg ^ ddbg; 721 } else { 722 gcvfg.foreground = fg; 723 gcvfg.background = bg; 724 gcvbg.foreground = bg; 725 gcvbg.background = fg; 726 gcvddfg.foreground = fg; 727 gcvddfg.background = ddbg; 728 gcvddbg.foreground = ddbg; 729 gcvddbg.background = fg; 730 } 731 xp->fggc = XCreateGC(xp->d, xp->w, 732 GCForeground | GCBackground | GCGraphicsExposures 733 | GCFunction | GCPlaneMask, &gcvfg); 734 xp->bggc = XCreateGC(xp->d, xp->w, 735 GCForeground | GCBackground | GCGraphicsExposures 736 | GCFunction | GCPlaneMask, &gcvbg); 737 xp->ddfggc = XCreateGC(xp->d, xp->w, 738 GCForeground | GCBackground | GCGraphicsExposures 739 | GCFunction | GCPlaneMask, &gcvddfg); 740 xp->ddbggc = XCreateGC(xp->d, xp->w, 741 GCForeground | GCBackground | GCGraphicsExposures 742 | GCFunction | GCPlaneMask, &gcvddbg); 743} 744 745 746static void 747DestroyPerfGCs(XParms xp) 748{ 749 XFreeGC(xp->d, xp->fggc); 750 XFreeGC(xp->d, xp->bggc); 751 XFreeGC(xp->d, xp->ddfggc); 752 XFreeGC(xp->d, xp->ddbggc); 753} 754 755static unsigned long 756AllocateColor(Display *display, char *name, unsigned long pixel) 757{ 758 XColor color; 759 760 if (name != NULL) { 761 /* Try to parse color name */ 762 if (XParseColor(display, cmap, name, &color)) { 763 if (XAllocColor(display, cmap, &color)) { 764 pixel = color.pixel; 765 } else { 766 (void) fprintf(stderr, 767 "Can't allocate colormap entry for color %s\n", name); 768 } 769 } else { 770 if(*name >= '0' && *name <= '9') 771 pixel = atoi(name); 772 else 773 (void) fprintf(stderr, "Can't parse color name %s\n", name); 774 } 775 } 776 return pixel; 777} /* AllocateColor */ 778 779 780static void 781DisplayStatus(Display *d, char *message, char *test, int try) 782{ 783 char s[500]; 784 785 XClearWindow(d, status); 786 sprintf(s, "%d %s %s", try, message, test); 787 /* We should really look at the height, descent of the font, etc. but 788 who cares. This works. */ 789 XDrawString(d, status, tgc, 10, 13, s, strlen(s)); 790} 791 792 793static void 794ProcessTest(XParms xp, Test *test, int func, unsigned long pm, char *label) 795{ 796 double time, totalTime; 797 int reps; 798 int j; 799 800 xp->planemask = pm; 801 CreatePerfGCs(xp, func, pm); 802 DisplayStatus(xp->d, "Calibrating", label, 0); 803 reps = CalibrateTest(xp, test, seconds, &time); 804 if (reps != 0) { 805 srand(1); /* allow reproducible results */ 806 XDestroySubwindows(xp->d, xp->w); 807 XClearWindow(xp->d, xp->w); 808 reps = (*test->init) (xp, &test->parms, reps); 809 if (abortTest) 810 AbortTest (); 811 /* 812 * if using fixedReps then will not have done CalibrateTest so must 813 * check result of init for 0 here 814 */ 815 if(reps == 0){ 816 DestroyPerfGCs(xp); 817 return; 818 } 819 /* Create clip windows if requested */ 820 CreateClipWindows(xp, test->clips); 821 822 totalTime = 0.0; 823 for (j = 0; j != repeat; j++) { 824 DisplayStatus(xp->d, "Testing", label, j+1); 825 time = DoTest(xp, test, reps); 826 if (abortTest) 827 AbortTest (); 828 totalTime += time; 829 ReportTimes (time, reps * test->parms.objects, 830 label, False); 831 } 832 if (repeat > 1) { 833 ReportTimes(totalTime, 834 repeat * reps * test->parms.objects, 835 label, True); 836 } 837 (*test->cleanup) (xp, &test->parms); 838 DestroyClipWindows(xp, test->clips); 839 } else { 840 /* Test failed to initialize properly */ 841 } 842 printf ("\n"); 843 fflush(stdout); 844 DestroyPerfGCs(xp); 845} /* ProcessTest */ 846 847#define Strstr strstr 848 849#define LABELP(i) (test[i].label14 && (xparms.version >= VERSION1_4) \ 850 ? test[i].label14 : test[i].label) 851 852int 853main(int argc, char *argv[]) 854{ 855 int i, j, n, skip; 856 int numTests; /* Even though the linker knows, we don't. */ 857 char hostname[100]; 858 Bool foundOne = False; 859 Bool synchronous = False; 860 XGCValues tgcv; 861 int screen; 862 int rop, pm; 863 int window_y, window_x; 864 XVisualInfo *vinfolist, vinfotempl; 865 unsigned long vmask; 866 867 /* Save away argv, argc, for usage to print out */ 868 saveargc = argc; 869 saveargv = (char **) malloc(argc * sizeof(char *)); 870 for (i = 0; i != argc; i++) { 871 saveargv[i] = argv[i]; 872 } 873 874 xparms.pack = False; 875 xparms.save_under = False; 876 xparms.backing_store = NotUseful; 877 878 /* Count number of tests */ 879 ForEachTest(numTests); 880 doit = (Bool *)calloc(numTests, sizeof(Bool)); 881 882 /* Parse arguments */ 883 program_name = argv[0]; 884 displayName = Get_Display_Name (&argc, argv); 885 xparms.version = GetVersion(&argc, argv); 886 for (i = 1; i != argc; i++) { 887 if (strcmp (argv[i], "-all") == 0) { 888 ForEachTest (j) 889 doit[j] = test[j].versions & xparms.version; 890 foundOne = True; 891 } else if (strcmp (argv[i], "-labels") == 0) { 892 labels = True; 893 } else if (strcmp(argv[i], "-range") == 0) { 894 char *cp1; 895 char *cp2; 896 897 if (argc <= ++i) 898 usage(); 899 cp1 = argv[i]; 900 if (*cp1 == '-') 901 cp1++; 902 for (cp2 = cp1; *cp2 != '\0' && *cp2 != ','; cp2++) {}; 903 if (*cp2 == ',') { 904 *cp2++ = '\0'; 905 if (*cp2 == '-') 906 cp2++; 907 } else { 908 cp2 = "-"; 909 } 910 ForEachTest (j) { 911 if (strcmp (cp1, (test[j].option) + 1) == 0 && 912 (test[j].versions & xparms.version)) { 913 int k = j; 914 do { 915 doit[k] = test[j].versions & xparms.version; 916 } while (!(strcmp(cp2, (test[k].option + 1)) == 0 && 917 (test[k].versions & xparms.version)) && 918 test[++k].option != NULL); 919 if (*cp2 != '-' && test[k].option == NULL) 920 usage(); 921 break; 922 } 923 } 924 if (test[j].option == NULL) 925 usage(); 926 foundOne = True; 927 } else if (strcmp (argv[i], "-sync") == 0) { 928 synchronous = True; 929 } else if (strcmp(argv[i], "-pack") == 0) { 930 xparms.pack = True; 931 } else if (strcmp (argv[i], "-draw") == 0) { 932 drawToFakeServer = True; 933 } else if (strcmp (argv[i], "-repeat") == 0) { 934 i++; 935 if (argc <= i) 936 usage (); 937 repeat = atoi (argv[i]); 938 if (repeat <= 0) 939 usage (); 940 } else if (strcmp (argv[i], "-time") == 0) { 941 i++; 942 if (argc <= i) 943 usage (); 944 seconds = atoi (argv[i]); 945 if (seconds <= 0) 946 usage (); 947 } else if (strcmp(argv[i], "-fg") == 0) { 948 i++; 949 if (argc <= i) 950 usage (); 951 foreground = argv[i]; 952 } else if (strcmp(argv[i], "-bg") == 0) { 953 i++; 954 if (argc <= i) 955 usage (); 956 background = argv[i]; 957 if(ddbackground == NULL) 958 ddbackground = argv[i]; 959 } else if (strcmp(argv[i], "-clips") == 0 ) { 960 i++; 961 if (argc <= i) 962 usage (); 963 clips = atoi( argv[i] ); 964 } else if (strcmp(argv[i], "-ddbg") == 0) { 965 if (argc <= i) 966 usage (); 967 i++; 968 ddbackground = argv[i]; 969 } else if (strcmp(argv[i], "-rop") == 0) { 970 skip = GetRops (i+1, argc, argv, rops, &numRops); 971 i += skip; 972 } else if (strcmp(argv[i], "-pm") == 0) { 973 skip = GetNumbers (i+1, argc, argv, planemasks, &numPlanemasks); 974 i += skip; 975 } else if (strcmp(argv[i], "-xor") == 0) { 976 numRops = 1; 977 rops[0] = GXxor; 978 } else if (strcmp (argv[i], "-both") == 0) { 979 numRops = 2; 980 rops[0] = GXcopy; 981 rops[1] = GXxor; 982 } else if (strcmp(argv[i], "-reps") == 0) { 983 i++; 984 if (argc <= i) 985 usage (); 986 fixedReps = atoi (argv[i]); 987 if (fixedReps <= 0) 988 usage (); 989 } else if (strcmp(argv[i], "-depth") == 0) { 990 i++; 991 if (argc <= i) 992 usage (); 993 depth = atoi(argv[i]); 994 if (depth <= 0) 995 usage (); 996 } else if (strcmp(argv[i], "-vclass") == 0) { 997 i++; 998 if (argc <= i) 999 usage (); 1000 for (j = StaticGray; j <= DirectColor; j++) { 1001 if (strcmp(argv[i], visualClassNames[j]) == 0) { 1002 vclass = j; 1003 break; 1004 } 1005 } 1006 if (vclass < 0) 1007 usage (); 1008 } else if (strcmp(argv[i], "-subs") == 0) { 1009 skip = GetNumbers (i+1, argc, argv, subWindows, &numSubWindows); 1010 i += skip; 1011 } else if (strcmp(argv[i], "-v1.2") == 0) { 1012 xparms.version = VERSION1_2; 1013 } else if (strcmp(argv[i], "-v1.3") == 0) { 1014 xparms.version = VERSION1_3; 1015 } else if (strcmp(argv[i], "-su") == 0) { 1016 xparms.save_under = True; 1017 } else if (strcmp(argv[i], "-bs") == 0) { 1018 i++; 1019 if (argc <= i) 1020 usage (); 1021 if (strcmp(argv[i], "WhenMapped") == 0) { 1022 xparms.backing_store = WhenMapped; 1023 } else if (strcmp(argv[i], "Always") == 0) { 1024 xparms.backing_store = Always; 1025 } else usage (); 1026 } else { 1027 int len,found; 1028 ForEachTest (j) { 1029 if (strcmp (argv[i], test[j].option) == 0 && 1030 (test[j].versions & xparms.version)) { 1031 doit[j] = True; 1032 goto LegalOption; 1033 } 1034 } 1035 found = False; 1036 len = strlen(argv[i]); 1037 if(len>=3) 1038 ForEachTest (j) { 1039 if (Strstr (test[j].option, argv[i]+1) != 0) { 1040 fprintf(stderr," -> %s %s\n", test[j].option, LABELP(j)); 1041 doit[j] = found = True; 1042 } 1043 } 1044 if(!found) 1045 ForEachTest (j) { 1046 if (Strstr (LABELP(j), argv[i]+1) != 0) { 1047 fprintf(stderr," -> %s %s\n", test[j].option, LABELP(j)); 1048 doit[j] = found = True; 1049 } 1050 } 1051 if(!found) 1052 usage (); 1053 LegalOption: 1054 foundOne = True; 1055 } 1056 } 1057 1058 if (labels) { 1059 /* Just print out list of tests for use with .sh programs that 1060 assemble data from different x11perf runs into a nice format */ 1061 ForEachTest (i) { 1062 int child; 1063 if (doit[i]) { 1064 switch (test[i].testType) { 1065 case NONROP: 1066 printf ("%s\n", LABELP(i)); 1067 break; 1068 1069 case ROP: 1070 /* Run it through all specified rops and planemasks */ 1071 for (rop = 0; rop < numRops; rop++) { 1072 for (pm = 0; pm < numPlanemasks; pm++) { 1073 if (planemasks[pm] == ~0) { 1074 if (rops[rop] == GXcopy) { 1075 printf ("%s\n", LABELP(i)); 1076 } else { 1077 printf ("(%s) %s\n", 1078 ropNames[rops[rop]].name, 1079 LABELP(i)); 1080 } 1081 } else { 1082 printf ("(%s 0x%lx) %s\n", 1083 ropNames[rops[rop]].name, 1084 planemasks[pm], 1085 LABELP(i)); 1086 } 1087 } /* for pm */ 1088 } /* for rop */ 1089 break; 1090 1091 case PLANEMASK: 1092 /* Run it through all specified planemasks */ 1093 for (pm = 0; pm < numPlanemasks; pm++) { 1094 if (planemasks[pm] == ~0) { 1095 printf ("%s\n", LABELP(i)); 1096 } else { 1097 printf ("(0x%lx) %s\n", 1098 planemasks[pm], 1099 LABELP(i)); 1100 } 1101 } /* for pm */ 1102 break; 1103 1104 case WINDOW: 1105 for (child = 0; child != numSubWindows; child++) { 1106 printf ("%s (%ld kids)\n", 1107 LABELP(i), subWindows[child]); 1108 } 1109 break; 1110 } /* switch */ 1111 } 1112 } 1113 exit(0); 1114 } 1115 1116 if (!foundOne) 1117 usage (); 1118 xparms.d = Open_Display (displayName); 1119 screen = DefaultScreen(xparms.d); 1120 1121 /* get visual info of default visual */ 1122 vmask = VisualIDMask | VisualScreenMask; 1123 vinfotempl.visualid = XVisualIDFromVisual(XDefaultVisual(xparms.d, screen)); 1124 vinfotempl.screen = screen; 1125 vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n); 1126 if (!vinfolist || n != 1) { 1127 fprintf (stderr, "%s: can't get visual info of default visual\n", 1128 program_name); 1129 exit(1); 1130 } 1131 1132 if (depth == -1 && vclass == -1) { 1133 /* use the default visual and colormap */ 1134 xparms.vinfo = *vinfolist; 1135 cmap = XDefaultColormap(xparms.d, screen); 1136 } else { 1137 /* find the specified visual */ 1138 int errorDepth = vinfolist[0].depth; 1139 int errorClass = vinfolist[0].class; 1140 1141 vmask = VisualScreenMask; 1142 vinfotempl.screen = screen; 1143 if (depth >= 0) { 1144 vinfotempl.depth = depth; 1145 vmask |= VisualDepthMask; 1146 errorDepth = depth; 1147 } 1148 if (vclass >= 0) { 1149 vinfotempl.class = vclass; 1150 vmask |= VisualClassMask; 1151 errorClass = vclass; 1152 } 1153 vinfolist = XGetVisualInfo(xparms.d, vmask, &vinfotempl, &n); 1154 if (!vinfolist) { 1155 fprintf (stderr, 1156 "%s: can't find a visual of depth %d and class %s\n", 1157 program_name, errorDepth, visualClassNames[errorClass]); 1158 exit(1); 1159 } 1160 xparms.vinfo = *vinfolist; /* use the first one in list */ 1161 if (xparms.vinfo.visualid == 1162 XVisualIDFromVisual(XDefaultVisual(xparms.d, screen))) { 1163 /* matched visual is same as default visual */ 1164 cmap = XDefaultColormap(xparms.d, screen); 1165 } else { 1166 cmap = XCreateColormap(xparms.d, DefaultRootWindow(xparms.d), 1167 xparms.vinfo.visual, AllocNone); 1168 /* since this is not default cmap, must force color allocation */ 1169 if (!foreground) foreground = "Black"; 1170 if (!background) background = "White"; 1171 XInstallColormap(xparms.d, cmap); 1172 } 1173 } 1174 xparms.cmap = cmap; 1175 1176 printf("x11perf - X11 performance program, version %s\n", 1177 xparms.version & VERSION1_5 ? "1.5" : 1178 xparms.version & VERSION1_4 ? "1.4" : 1179 xparms.version & VERSION1_3 ? "1.3" : 1180 "1.2" 1181 ); 1182 XmuGetHostname(hostname, 100); 1183 printf ("%s server version %d on %s\nfrom %s\n", 1184 ServerVendor (xparms.d), VendorRelease (xparms.d), 1185 DisplayString (xparms.d), hostname); 1186 PrintTime (); 1187 1188 /* Force screen out of screen-saver mode, grab current data, and set 1189 time to blank to 8 hours. We should just be able to turn the screen- 1190 saver off, but this causes problems on some servers. We also reset 1191 the screen-saver timer each test, as 8 hours is about the maximum time 1192 we can use, and that isn't long enough for some X terminals using a 1193 serial protocol to finish all the tests. As long as the tests run to 1194 completion, the old screen-saver values are restored. */ 1195 XForceScreenSaver(xparms.d, ScreenSaverReset); 1196 XGetScreenSaver(xparms.d, &ssTimeout, &ssInterval, &ssPreferBlanking, 1197 &ssAllowExposures); 1198 (void) signal(SIGINT, Cleanup); /* ^C */ 1199#ifdef SIGQUIT 1200 (void) signal(SIGQUIT, Cleanup); 1201#endif 1202 (void) signal(SIGTERM, Cleanup); 1203#ifdef SIGHUP 1204 (void) signal(SIGHUP, Cleanup); 1205#endif 1206 XSetScreenSaver(xparms.d, 8 * 3600, ssInterval, ssPreferBlanking, 1207 ssAllowExposures); 1208 1209 if (drawToFakeServer) { 1210 tileToQuery = 1211 XCreatePixmap(xparms.d, DefaultRootWindow (xparms.d), 32, 32, 1); 1212 } 1213 1214 1215 xparms.foreground = 1216 AllocateColor(xparms.d, foreground, BlackPixel(xparms.d, screen)); 1217 xparms.background = 1218 AllocateColor(xparms.d, background, WhitePixel(xparms.d, screen)); 1219 xparms.ddbackground = 1220 AllocateColor(xparms.d, ddbackground, WhitePixel(xparms.d, screen)); 1221 window_x = 2; 1222 if (DisplayWidth(xparms.d, screen) < WIDTH + window_x + 1) 1223 window_x = -1; 1224 window_y = 2; 1225 if (DisplayHeight(xparms.d, screen) < HEIGHT + window_y + 1) 1226 window_y = -1; 1227 xparms.w = CreatePerfWindow(&xparms, window_x, window_y, WIDTH, HEIGHT); 1228 HSx = WIDTH-1; 1229 if (window_x + 1 + WIDTH > DisplayWidth(xparms.d, screen)) 1230 HSx = DisplayWidth(xparms.d, screen) - (1 + window_x + 1); 1231 HSy = HEIGHT-1; 1232 if (window_y + 1 + HEIGHT > DisplayHeight(xparms.d, screen)) 1233 HSy = DisplayHeight(xparms.d, screen) - (1 + window_y + 1); 1234 status = CreatePerfWindow(&xparms, window_x, HEIGHT+5, WIDTH, 20); 1235 tgcv.foreground = 1236 AllocateColor(xparms.d, "black", BlackPixel(xparms.d, screen)); 1237 tgcv.background = 1238 AllocateColor(xparms.d, "white", WhitePixel(xparms.d, screen)); 1239 tgc = XCreateGC(xparms.d, status, GCForeground | GCBackground, &tgcv); 1240 1241 xparms.p = (Pixmap)0; 1242 1243 if (synchronous) 1244 XSynchronize (xparms.d, True); 1245 1246 /* Get mouse pointer out of the way of the performance window. On 1247 software cursor machines it will slow graphics performance. On 1248 all current MIT-derived servers it will slow window 1249 creation/configuration performance. */ 1250 XWarpPointer(xparms.d, None, status, 0, 0, 0, 0, WIDTH+32, 20+32); 1251 1252 /* Figure out how long to call HardwareSync, so we can adjust for that 1253 in our total elapsed time */ 1254 (void) CalibrateTest(&xparms, &syncTest, 1, &syncTime); 1255 printf("Sync time adjustment is %6.4f msecs.\n\n", syncTime/1000); 1256 1257 ForEachTest (i) { 1258 int child; 1259 char label[200]; 1260 1261 if (doit[i] && (test[i].versions & xparms.version)) { 1262 switch (test[i].testType) { 1263 case NONROP: 1264 /* Simplest...just run it once */ 1265 strcpy (label, LABELP(i)); 1266 ProcessTest(&xparms, &test[i], GXcopy, ~0L, label); 1267 break; 1268 1269 case ROP: 1270 /* Run it through all specified rops and planemasks */ 1271 for (rop = 0; rop < numRops; rop++) { 1272 for (pm = 0; pm < numPlanemasks; pm++) { 1273 if (planemasks[pm] == ~0) { 1274 if (rops[rop] == GXcopy) { 1275 sprintf (label, "%s", LABELP(i)); 1276 } else { 1277 sprintf (label, "(%s) %s", 1278 ropNames[rops[rop]].name, 1279 LABELP(i)); 1280 } 1281 } else { 1282 sprintf (label, "(%s 0x%lx) %s", 1283 ropNames[rops[rop]].name, 1284 planemasks[pm], 1285 LABELP(i)); 1286 } 1287 ProcessTest(&xparms, &test[i], rops[rop], 1288 planemasks[pm], label); 1289 } /* for pm */ 1290 } /* for rop */ 1291 break; 1292 1293 case PLANEMASK: 1294 /* Run it through all specified planemasks */ 1295 for (pm = 0; pm < numPlanemasks; pm++) { 1296 if (planemasks[pm] == ~0) { 1297 sprintf (label, "%s", LABELP(i)); 1298 } else { 1299 sprintf (label, "(0x%lx) %s", 1300 planemasks[pm], 1301 LABELP(i)); 1302 } 1303 ProcessTest(&xparms, &test[i], GXcopy, 1304 planemasks[pm], label); 1305 } /* for pm */ 1306 break; 1307 1308 case WINDOW: 1309 /* Loop through number of children array */ 1310 for (child = 0; child != numSubWindows; child++) { 1311 test[i].parms.objects = subWindows[child]; 1312 sprintf(label, "%s (%d kids)", 1313 LABELP(i), test[i].parms.objects); 1314 ProcessTest(&xparms, &test[i], GXcopy, ~0L, label); 1315 } 1316 break; 1317 } /* switch */ 1318 } /* if doit */ 1319 } /* ForEachTest */ 1320 1321 XFreeGC(xparms.d, tgc); 1322 XDestroyWindow(xparms.d, xparms.w); 1323 XFree(vinfolist); 1324 if (drawToFakeServer) 1325 XFreePixmap(xparms.d, tileToQuery); 1326 /* Restore ScreenSaver to original state. */ 1327 XSetScreenSaver(xparms.d, ssTimeout, ssInterval, ssPreferBlanking, 1328 ssAllowExposures); 1329 XCloseDisplay(xparms.d); 1330 free(saveargv); 1331 free(doit); 1332 exit(0); 1333} 1334 1335static int 1336GetWords (int argi, int argc, char **argv, char **wordsp, int *nump) 1337{ 1338 int count; 1339 1340 if (argc <= argi) 1341 usage(); 1342 count = 0; 1343 while (argv[argi] && *(argv[argi]) != '-') { 1344 *wordsp++ = argv[argi]; 1345 ++argi; 1346 count++; 1347 } 1348 *nump = count; 1349 return count; 1350} 1351 1352static long 1353atox (char *s) 1354{ 1355 long v, c = 0; 1356 1357 v = 0; 1358 while (*s) { 1359 if ('0' <= *s && *s <= '9') 1360 c = *s - '0'; 1361 else if ('a' <= *s && *s <= 'f') 1362 c = *s - 'a' + 10; 1363 else if ('A' <= *s && *s <= 'F') 1364 c = *s - 'A' + 10; 1365 v = v * 16 + c; 1366 s++; 1367 } 1368 return v; 1369} 1370 1371static int 1372GetNumbers (int argi, int argc, char **argv, unsigned long *intsp, int *nump) 1373{ 1374 char *words[256]; 1375 int count; 1376 int i; 1377 int flip; 1378 1379 count = GetWords (argi, argc, argv, words, nump); 1380 for (i = 0; i < count; i++) { 1381 flip = 0; 1382 if (!strncmp (words[i], "~", 1)) { 1383 words[i]++; 1384 flip = ~0; 1385 } 1386 if (!strncmp (words[i], "0x", 2)) 1387 intsp[i] = atox(words[i] + 2) ^ flip; 1388 else 1389 intsp[i] = atoi (words[i]) ^ flip; 1390 } 1391 return count; 1392} 1393 1394static int 1395GetRops (int argi, int argc, char **argv, int *ropsp, int *nump) 1396{ 1397 char *words[256]; 1398 int count; 1399 int i; 1400 int rop; 1401 1402 count = GetWords (argi, argc, argv, words, nump); 1403 for (i = 0; i < count; i++) { 1404 if (!strncmp (words[i], "GX", 2)) 1405 words[i] += 2; 1406 if (!strcmp (words[i], "all")) { 1407 for (i = 0; i < 16; i++) 1408 ropsp[i] = ropNames[i].rop; 1409 *nump = 16; 1410 break; 1411 } 1412 for (rop = 0; rop < 16; rop++) { 1413 if (!strcmp (words[i], ropNames[rop].name)) { 1414 ropsp[i] = ropNames[rop].rop; 1415 break; 1416 } 1417 } 1418 if (rop == 16) { 1419 usage (); 1420 fprintf (stderr, "unknown rop name %s\n", words[i]); 1421 } 1422 } 1423 return count; 1424} 1425