{
unsigned ops_per_sec;
unsigned error_margin;
+ unsigned long long pixels_per_sec;
} Result;
void update_crc32(unsigned *crc32, const char *data, unsigned size);
-Result measure(void (*func)(), unsigned batch, unsigned time, MeasureType type);
-void sync();
-void nop();
-void create_destroy_pixmap();
-void create_destroy_picture();
+Result measure(unsigned (*func)(), unsigned batch, unsigned time, MeasureType type);
+unsigned doSync();
+unsigned nop();
+unsigned create_destroy_pixmap();
+unsigned create_destroy_picture();
void random_color(XRenderColor *color, int alpha);
-void fill_rectangle();
-void composite_trapezoid();
-void draw_string8();
-void copy_area();
-void composite_copy_area();
+unsigned fill_rectangle();
+unsigned composite_trapezoid();
+unsigned draw_string8();
+unsigned copy_area();
+unsigned composite_copy_area();
Display *dpy;
Window wnd;
GC gc;
int depth;
XRenderPictFormat *pfmt;
+XRenderPictFormat *pfmtWin;
+XRenderPictFormat *pfmt16;
+XRenderPictFormat *pfmt24;
+XRenderPictFormat *pfmt32;
Picture pict;
Picture srcpict;
int op;
unsigned textlen;
int copymode;
int verbosity;
+static unsigned metrics[256] = {0};
int main(int argc, char **argv)
{
break;
}
- pft.depth=depth;
- pfmt=XRenderFindFormat(dpy, PictFormatDepth, &pft, 1);
- pict=XRenderCreatePicture(dpy, wnd, pfmt, 0, NULL);
+ pfmt24=XRenderFindStandardFormat(dpy, PictStandardRGB24);
+ pfmt32=XRenderFindStandardFormat(dpy, PictStandardARGB32);
+
+ pft.depth=16;
+ pft.direct.redMask = 0x1F;
+ pft.direct.greenMask = 0x3F;
+ pft.direct.blueMask = 0x1F;
+ pfmt16=XRenderFindFormat(dpy, PictFormatDepth | PictFormatRedMask | PictFormatGreenMask | PictFormatBlueMask, &pft, 1);
+
+ if(!pfmt16)
+ {
+ fprintf(stderr, "Warning: 16-bit pixel format not found.\n");
+ pfmt16 = pfmt24;
+ }
+
+ pfmtWin=XRenderFindVisualFormat(dpy, visual);
+ pict=XRenderCreatePicture(dpy, wnd, pfmtWin, 0, NULL);
+
+ pfmt = pfmtWin;
+
+ if(verbosity)
+ {
+ printf("PictFormat: id %X, type %X, depth %d, RGB%d%d%d A%d\n",
+ (unsigned int) pfmtWin->id, pfmtWin->type, pfmtWin->depth,
+ pfmtWin->direct.red, pfmtWin->direct.green, pfmtWin->direct.blue, pfmtWin->direct.alpha);
+ printf(" R=%08X G=%08X B=%08X A=%08X\n",
+ pfmtWin->direct.redMask, pfmtWin->direct.greenMask, pfmtWin->direct.blueMask, pfmtWin->direct.alphaMask);
+
+ }
op=PictOpSrc;
while(1)
sscanf(delim+1, "%dx%d", &width, &height);
else if(!strncmp(line, "font", delim-line))
{
+ unsigned char c;
+
if(font)
XftFontClose(dpy, font);
font=XftFontOpenName(dpy, screen, delim+1);
+
+ for(c=32; c < 127; c++)
+ {
+ XGlyphInfo extents;
+ unsigned char textptr[2] = {0,0};
+ textptr[0] = c;
+ XftTextExtents8(dpy, font, textptr, 1, &extents);
+ metrics[c] = extents.width * extents.height;
+ }
}
else if(!strncmp(line, "text", delim-line))
{
else
fprintf(stderr, "Unknown copy mode '%s'\n", delim+1);
}
+ else if(!strncmp(line, "depth", delim-line))
+ {
+ if(!strcmp(delim+1, "window"))
+ pfmt = pfmtWin;
+ else if(!strcmp(delim+1, "16"))
+ pfmt = pfmt16;
+ else if(!strcmp(delim+1, "24"))
+ pfmt = pfmt24;
+ else if(!strcmp(delim+1, "32"))
+ pfmt = pfmt32;
+ else
+ fprintf(stderr, "Unknown pixmap depth '%s'\n", delim+1);
+ }
else
fprintf(stderr, "Unknown assignment '%s'\n", line);
continue;
if(!strncmp(line, "run", delim-line))
{
Result res;
- unsigned size=0;
update_crc32(&crc32, line, strlen(line));
printf("%s:\n", test_name);
if(!strcmp(delim+1, "rect") || !strcmp(delim+1, "rectangle"))
{
- size=width*height;
res=measure(fill_rectangle, batch, time, type);
}
else if(!strcmp(delim+1, "trapezoid"))
{
XRenderColor color;
random_color(&color, 0);
- size=width*height;
srcpict=XRenderCreateSolidFill(dpy, &color);
res=measure(composite_trapezoid, batch, time, type);
XRenderFreePicture(dpy, srcpict);
}
else if(!strcmp(delim+1, "text"))
{
- size=textlen;
ftdraw=XftDrawCreate(dpy, wnd, visual, cmap);
res=measure(draw_string8, batch, time, type);
XftDrawDestroy(ftdraw);
}
else if(!strcmp(delim+1, "copy"))
{
- size=width*height;
- pxm=XCreatePixmap(dpy, wnd, 640, 480, depth);
+ pxm=XCreatePixmap(dpy, wnd, 640, 480, pfmtWin->depth);
gc=XCreateGC(dpy, wnd, 0, NULL);
XCopyArea(dpy, wnd, pxm, gc, 0, 0, 640, 480, 0, 0);
res=measure(copy_area, batch, time, type);
}
else if(!strcmp(delim+1, "composite"))
{
- size=width*height;
- pxm=XCreatePixmap(dpy, wnd, 640, 480, depth);
- gc=XCreateGC(dpy, wnd, 0, NULL);
- XCopyArea(dpy, wnd, pxm, gc, 0, 0, 640, 480, 0, 0);
- XFreeGC(dpy, gc);
- srcpict=XRenderCreatePicture(dpy, pxm, pfmt, 0, NULL);
+ XRenderPictureAttributes attrib;
+ attrib.component_alpha = !!(pfmt->direct.alphaMask);
+ pxm=XCreatePixmap(dpy, wnd, 640, 480, pfmt->depth);
+ srcpict=XRenderCreatePicture(dpy, pxm, pfmt, CPComponentAlpha, &attrib);
+ XRenderComposite(dpy, PictOpSrc, pict, None, srcpict, 0,0,0,0,0,0,640,480);
res=measure(composite_copy_area, batch, time, type);
XFreePixmap(dpy, pxm);
}
res=measure(create_destroy_pixmap, batch, time, type);
else if(!strcmp(delim+1, "picture"))
{
- pxm=XCreatePixmap(dpy, wnd, width, height, depth);
+ pxm=XCreatePixmap(dpy, wnd, width, height, pfmt->depth);
res=measure(create_destroy_picture, batch, time, type);
XFreePixmap(dpy, pxm);
}
else if(!strcmp(delim+1, "sync"))
- res=measure(sync, batch, time, type);
+ res=measure(doSync, batch, time, type);
else if(!strcmp(delim+1, "nop"))
res=measure(nop, batch, time, type);
if(res.ops_per_sec>0)
{
float score=(res.ops_per_sec-res.error_margin)/weight;
if(out)
- fprintf(out, "%d,%d,%.0f,%lld,%s\n", res.ops_per_sec, res.error_margin, score, (long long)res.ops_per_sec*size, test_name);
+ fprintf(out, "%d,%d,%.0f,%lld,%s\n", res.ops_per_sec, res.error_margin, score, res.pixels_per_sec, test_name);
total+=1/score;
}
}
}
}
-unsigned filter_outliers(unsigned *data, unsigned count)
+unsigned filter_outliers(Result *data, unsigned count)
{
unsigned i;
float average=0;
unsigned n_out=0;
for(i=0; i<count; ++i)
- average+=data[i];
- average/=count;
+ average += data[i].ops_per_sec;
+ average /= count;
for(i=0; i<count; ++i)
- if(fabs(data[i]-average)/average>0.05)
+ if(fabs(data[i].ops_per_sec - average) / average > 0.05)
++n_out;
if(n_out==0 || n_out>count/10)
return 0;
for(i=0; i<count; ++i)
- if(fabs(data[i]-average)/average>0.05)
- data[i]=0;
+ if(fabs(data[i].ops_per_sec - average) / average > 0.05)
+ data[i].ops_per_sec = 0;
printf(" Filtered %d outliers\n", n_out);
return n_out;
}
-Result measure(void (*func)(), unsigned batch, unsigned time, MeasureType type)
+Result measure(unsigned (*func)(), unsigned batch, unsigned time, MeasureType type)
{
if(type==SINGLE_BATCH)
{
{
unsigned speed;
unsigned i;
- unsigned *data;
+ Result *data;
Result res;
unsigned nbatches;
unsigned ngood;
float average=0;
float stddev=0;
+ float average_pixels=0;
nbatches=batch;
i=time/nbatches;
speed=measure(func, 100, (i<1000 ? i<100 ? 100 : i : 1000), NORMAL).ops_per_sec;
batch=(long long)speed*time/1000/nbatches;
- data=(unsigned *)malloc(nbatches*sizeof(unsigned));
+ data = (Result*) malloc(nbatches*sizeof(Result));
for(i=0; i<nbatches; ++i)
- data[i]=measure(func, batch, 1, NORMAL).ops_per_sec;
+ data[i]=measure(func, batch, 1, NORMAL);
- ngood=nbatches-filter_outliers(data, nbatches);
+ ngood = nbatches - filter_outliers(data, nbatches);
for(i=0; i<nbatches; ++i)
- if(data[i])
+ if(data[i].ops_per_sec)
{
- average+=data[i];
- stddev+=(float)data[i]*data[i];
+ float n = data[i].ops_per_sec;
+ average += n;
+ stddev += n*n;
+ average_pixels += data[i].pixels_per_sec;
}
- average/=ngood;
- stddev=sqrt(stddev/ngood-average*average);
+ average /= ngood;
+ average_pixels /= ngood;
+ stddev = sqrt(stddev/ngood - average*average);
res.ops_per_sec=(unsigned)(average+0.5);
res.error_margin=(unsigned)(stddev*2+0.5);
- printf(" Average: %.0lf/sec Std.dev.: %.0lf\n", average, stddev);
+ res.pixels_per_sec=(unsigned long long)(average_pixels+0.5);
+ printf(" Average: %.0lf/sec (%.2lf Mpix/s) Std.dev.: %.0lf\n", average, average_pixels/1000000, stddev);
printf(" 95%% confidence margin: %d (%.1lf%%)\n", res.error_margin, res.error_margin*100.0/res.ops_per_sec);
return res;
}
unsigned count=0;
unsigned delta=0;
Result res;
+ unsigned long long pixels = 0;
srand(0);
while(delta<time)
{
unsigned i;
- for(i=0; i<batch; ++i)
- func();
+ for(i=0; i<batch; ++i) {
+ pixels += func();
+ // XFlush(dpy);
+ }
XSync(dpy, True);
count+=batch;
gettimeofday(&end, NULL);
}
res.ops_per_sec=count*1000/delta;
res.error_margin=0;
+ res.pixels_per_sec=pixels*1000/delta;
if(verbosity>=1)
printf(" %d calls in %d ms = %d/sec\n", count, delta, res.ops_per_sec);
return res;
}
}
-void sync()
+unsigned doSync()
{
XSync(dpy, True);
+
+ return 0;
}
-void nop()
+unsigned nop()
{
XMapWindow(dpy, wnd);
+
+ return 0;
}
-void create_destroy_pixmap()
+unsigned create_destroy_pixmap()
{
- Pixmap p=XCreatePixmap(dpy, wnd, width, height, depth);
+ Pixmap p=XCreatePixmap(dpy, wnd, width, height, pfmt->depth);
XFreePixmap(dpy, p);
+
+ return 0;
}
-void create_destroy_picture()
+unsigned create_destroy_picture()
{
Picture p=XRenderCreatePicture(dpy, pxm, pfmt, 0, NULL);
XRenderFreePicture(dpy, p);
+
+ return 0;
}
void random_color(XRenderColor *color, int alpha)
}
}
-void fill_rectangle()
+unsigned fill_rectangle()
{
int x, y;
XRenderColor color;
y=rand()%(481-height);
random_color(&color, op==PictOpOver);
XRenderFillRectangle(dpy, op, pict, &color, x, y, width, height);
+
+ return width*height;
}
-void composite_trapezoid()
+unsigned composite_trapezoid()
{
int x, y;
unsigned w;
XRenderCompositeTrapezoids(dpy, op, srcpict, pict, NULL, 0, 0, &trap, 1);
XFlush(dpy);
+
+ return (((trap.right.p1.x - trap.left.p1.x) + (trap.right.p2.x - trap.left.p2.x)) >> 17) * height;
}
-void draw_string8()
+unsigned draw_string8()
{
unsigned char textbuf[128];
unsigned char *textptr;
XftColor ftcolor;
XGlyphInfo extents;
int x, y;
+ unsigned pixels = 0;
if(text)
textptr=(unsigned char *)text;
else
{
textptr=textbuf;
- for(i=0; i<textlen; ++i)
- textbuf[i]=33+rand()%94;
+ for(i=0; i<textlen; ++i) {
+ unsigned char c = 33+rand()%94;
+ textbuf[i] = c;
+ pixels += metrics[c];
+ }
}
screen=DefaultScreen(dpy);
XftColorAllocValue(dpy, visual, cmap, &rcolor, &ftcolor);
XftTextExtents8(dpy, font, textptr, textlen, &extents);
- x=rand()%(641-extents.width);
- y=rand()%(481-extents.height);
+ x = (rand()%(641-extents.width)) + extents.x;
+ y = (rand()%(481-extents.height)) + extents.y;
XftDrawString8(ftdraw, &ftcolor, font, x, y, textptr, textlen);
+
+ return pixels;
}
-void copy_area()
+unsigned copy_area()
{
int x1, y1;
int x2, y2;
case 2: XCopyArea(dpy, wnd, wnd, gc, x1, y1, width, height, x2, y2); break;
case 3: XCopyArea(dpy, wnd, pxm, gc, x1, y1, width, height, x2, y2); break;
}
+
+ return width*height;
}
-void composite_copy_area()
+unsigned composite_copy_area()
{
int x1, y1;
int x2, y2;
case 2: XRenderComposite(dpy, op, pict, None, pict, x1, y1, 0, 0, x2, y2, width, height); break;
case 3: XRenderComposite(dpy, op, pict, None, srcpict, x1, y1, 0, 0, x2, y2, width, height); break;
}
+
+ return width*height;
}