Initial commit
authorMikko Rasa <mikko.rasa@movial.fi>
Thu, 5 Mar 2009 14:22:35 +0000 (16:22 +0200)
committerMikko Rasa <mikko.rasa@movial.fi>
Thu, 5 Mar 2009 14:22:35 +0000 (16:22 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
benchcompare.py [new file with mode: 0755]
main.c [new file with mode: 0644]
synthetic.bench [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5f44355
--- /dev/null
@@ -0,0 +1 @@
+mx11mark
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..26dedff
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+mx11mark: main.c
+       $(CC) -o $@ $< $(shell pkg-config --cflags --libs xrender xft) -lm -ggdb -Wall -Wextra
diff --git a/benchcompare.py b/benchcompare.py
new file mode 100755 (executable)
index 0000000..fcc7604
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+# -*- encoding: utf-8 -*-
+
+import sys
+
+order=[]
+marks={}
+
+data=[]
+for fn in sys.argv[1:]:
+       data.append([l[:-1].split(',') for l in file(fn)])
+
+for i in range(len(data)):
+       for b in data[i]:
+               if len(b)==5:
+                       score=int(b[0])
+                       margin=int(b[1])
+                       label=b[4]
+               elif len(b)==1:
+                       score=int(b[0])
+                       margin=0
+                       label="Overall"
+               if label not in marks:
+                       marks[label]=[(0, 0)]*len(data)
+                       order.append(label)
+               marks[label][i]=(score, margin)
+
+print """<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<style type="text/css">
+table { border-collapse: collapse; }
+tr { border-bottom: 1px dotted gray; }
+td { padding-left: 1em; }
+.best { color: green; }
+.worst { color: maroon; }
+.increase { color: lime; }
+.decrease { color: red; }
+</style>
+</head>
+<body>
+<table>"""
+for m in order:
+       v=marks[m]
+       scores=[i[0] for i in v if i[0]>0]
+       if not scores:
+               continue
+       high=max(scores)
+       low=min(scores)
+       baseline=scores[0]
+       print "<tr><td>%s</td>"%m
+       for i in range(len(data)):
+               diff=v[i][0]*100.0/baseline-100
+               if diff:
+                       if diff<0:
+                               k="decrease"
+                       elif diff>0:
+                               k="increase"
+                       diff=" (<span class=\"color:%s\">%+.1f%%</span>)"%(k, diff)
+               else:
+                       diff=""
+
+               k=""
+               if v[i][0]==high:
+                       k="best"
+               elif v[i][0]==low:
+                       k="worst"
+
+               print "<td><span class=\"%s\">%s</span> (±%.1f%%)%s</td>"%(k, v[i][0], v[i][1]*100.0/v[i][0], diff)
+       print "</tr>"
+print """</table>
+</body>
+</html>"""
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..69eff72
--- /dev/null
+++ b/main.c
@@ -0,0 +1,417 @@
+#include <stdio.h>
+#include <math.h>
+#include <sys/time.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/Xft/Xft.h>
+
+typedef enum eMeasureType
+{
+       NORMAL,
+       SINGLE_BATCH,
+       STATISTICAL
+} MeasureType;
+
+typedef struct sResult
+{
+       unsigned ops_per_sec;
+       unsigned error_margin;
+} Result;
+
+Result measure(void (*func)(), unsigned batch, unsigned time, MeasureType type);
+void create_destroy_pixmap();
+void create_destroy_picture();
+void fill_rectangle();
+void composite_trapezoid();
+void draw_string8();
+
+Display *dpy;
+Window wnd;
+Pixmap pxm;
+int depth;
+XRenderPictFormat *pfmt;
+Picture pict;
+Picture srcpict;
+int op;
+unsigned width;
+unsigned height;
+XftFont *font;
+XftDraw *ftdraw;
+char *text;
+unsigned textlen;
+
+int main(int argc, char **argv)
+{
+       int screen;
+       Visual *visual;
+       Colormap cmap;
+       Window root;
+       Pixmap srcpxm;
+       XRenderPictFormat pft;
+       XRenderPictFormat *pfmt32;
+       XRenderPictureAttributes pattr;
+       char *test_name=NULL;
+       unsigned batch=3000;
+       unsigned time=1000;
+       MeasureType type=NORMAL;
+       FILE *in, *out;
+       float total=0;
+       float weight=1.0;
+       XRenderColor color;
+
+       dpy=XOpenDisplay(NULL);
+       screen=DefaultScreen(dpy);
+       depth=DefaultDepth(dpy, screen);
+       visual=DefaultVisual(dpy, screen);
+       cmap=DefaultColormap(dpy, screen);
+
+       root=DefaultRootWindow(dpy);
+       wnd=XCreateWindow(dpy, root, 0, 0, 640, 480, 0, depth, InputOutput, visual, 0, NULL);
+       XSelectInput(dpy, wnd, StructureNotifyMask);
+       XMapRaised(dpy, wnd);
+
+       while(1)
+       {
+               XEvent event;
+               XNextEvent(dpy, &event);
+               if(event.type==MapNotify)
+                       break;
+       }
+
+       pft.depth=depth;
+       pfmt=XRenderFindFormat(dpy, PictFormatDepth, &pft, 1);
+       pict=XRenderCreatePicture(dpy, wnd, pfmt, 0, NULL);
+
+       pfmt32=XRenderFindStandardFormat(dpy, PictStandardARGB32);
+       srcpxm=XCreatePixmap(dpy, wnd, 1, 1, 32);
+       pattr.repeat=RepeatNormal;
+       srcpict=XRenderCreatePicture(dpy, srcpxm, pfmt32, CPRepeat, &pattr);
+       
+       color.red=0xFFFF;
+       color.green=0xFFFF;
+       color.blue=0xFFFF;
+       XRenderFillRectangle(dpy, PictOpSrc, srcpict, &color, 0, 0, 1, 1);
+
+       if(argc>=2)
+               in=fopen(argv[1], "r");
+       else
+               in=fopen("bench.txt", "r");
+       out=fopen("result.csv", "w");
+
+       op=PictOpSrc;
+       while(1)
+       {
+               char line[1024];
+               char *delim;
+               int ret;
+               
+               ret=fscanf(in, " %[^\n]", line);
+               if(ret<1)
+                       break;
+
+               delim=strchr(line, '=');
+               if(delim)
+               {
+                       if(!strncmp(line, "time", delim-line))
+                               time=strtoul(delim+1, NULL, 10);
+                       else if(!strncmp(line, "batch", delim-line))
+                               batch=strtoul(delim+1, NULL, 10);
+                       else if(!strncmp(line, "type", delim-line))
+                       {
+                               if(!strcmp(delim+1, "normal"))
+                                       type=NORMAL;
+                               else if(!strcmp(delim+1, "single-batch"))
+                                       type=SINGLE_BATCH;
+                               else if(!strcmp(delim+1, "statistical"))
+                                       type=STATISTICAL;
+                       }
+                       else if(!strncmp(line, "size", delim-line))
+                               sscanf(delim+1, "%dx%d", &width, &height);
+                       else if(!strncmp(line, "font", delim-line))
+                       {
+                               if(font)
+                                       XftFontClose(dpy, font);
+                               font=XftFontOpenName(dpy, screen, delim+1);
+                       }
+                       else if(!strncmp(line, "text", delim-line))
+                       {
+                               if(text)
+                                       free(text);
+                               text=strdup(delim+1);
+                               textlen=strlen(text);
+                       }
+                       else if(!strncmp(line, "randomtext", delim-line))
+                       {
+                               if(text)
+                                       free(text);
+                               text=NULL;
+                               textlen=strtoul(delim+1, NULL, 0);
+                       }
+                       else if(!strncmp(line, "op", delim-line))
+                       {
+                               if(!strcmp(delim+1, "over"))
+                                       op=PictOpOver;
+                               else if(!strcmp(delim+1, "src"))
+                                       op=PictOpSrc;
+                               else if(!strcmp(delim+1, "add"))
+                                       op=PictOpAdd;
+                       }
+                       else if(!strncmp(line, "weight", delim-line))
+                               weight=strtod(delim+1, NULL);
+                       else
+                               fprintf(stderr, "Unknown assignment '%s'\n", line);
+                       continue;
+               }
+
+               delim=strchr(line, ':');
+               if(delim && delim[1]==0)
+               {
+                       if(test_name)
+                               free(test_name);
+                       test_name=(char *)malloc(delim-line+1);
+                       strncpy(test_name, line, delim-line);
+                       test_name[delim-line]=0;
+                       continue;
+               }
+
+               delim=strchr(line, ' ');
+               if(delim)
+               {
+                       if(!strncmp(line, "run", delim-line))
+                       {
+                               printf("%s:\n", test_name);
+                               Result res;
+                               unsigned size=0;
+                               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"))
+                               {
+                                       size=width*height;
+                                       res=measure(composite_trapezoid, batch, time, type);
+                               }
+                               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, "pixmap"))
+                                       res=measure(create_destroy_pixmap, batch, time, type);
+                               else if(!strcmp(delim+1, "picture"))
+                               {
+                                       pxm=XCreatePixmap(dpy, wnd, width, height, depth);
+                                       res=measure(create_destroy_picture, batch, time, type);
+                                       XFreePixmap(dpy, pxm);
+                               }
+                               if(res.ops_per_sec>0)
+                               {
+                                       float score=(res.ops_per_sec-res.error_margin)/weight;
+                                       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);
+                                       total+=1/score;
+                               }
+                       }
+               }
+       }
+       total=1/total;
+       printf("Total score: %.0f\n", total);
+       fprintf(out, "%.0f\n", total);
+       fclose(out);
+       fclose(in);
+
+       return 0;
+}
+
+unsigned filter_outliers(unsigned *data, unsigned count)
+{
+       unsigned i;
+       float average=0;
+       unsigned n_out=0;
+
+       for(i=0; i<count; ++i)
+               average+=data[i];
+       average/=count;
+
+       for(i=0; i<count; ++i)
+               if(fabs(data[i]-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;
+       printf("  Filtered %d outliers\n", n_out);
+
+       return n_out;
+}
+
+Result measure(void (*func)(), unsigned batch, unsigned time, MeasureType type)
+{
+       if(type==SINGLE_BATCH)
+       {
+               unsigned speed=measure(func, 100, 100, NORMAL).ops_per_sec;
+               return measure(func, speed*time/1000, 1, NORMAL);
+       }
+       else if(type==STATISTICAL)
+       {
+               unsigned speed;
+               unsigned i;
+               unsigned *data;
+               Result res;
+               unsigned nbatches;
+               unsigned ngood;
+               float average=0;
+               float stddev=0;
+
+               nbatches=batch;
+               speed=measure(func, 100, 100, NORMAL).ops_per_sec;
+               batch=(long long)speed*time/1000/nbatches;
+
+               data=(unsigned *)malloc(nbatches*sizeof(unsigned));
+               for(i=0; i<nbatches; ++i)
+                       data[i]=measure(func, batch, 1, NORMAL).ops_per_sec;
+
+               ngood=nbatches-filter_outliers(data, nbatches);
+
+               for(i=0; i<nbatches; ++i)
+                       if(data[i])
+                       {
+                               average+=data[i];
+                               stddev+=(float)data[i]*data[i];
+                       }
+               average/=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);
+               printf("  95%% confidence margin: %d (%.1lf%%)\n", res.error_margin, res.error_margin*100.0/res.ops_per_sec);
+               return res;
+       }
+       else
+       {
+               struct timeval start, end;
+               unsigned count=0;
+               unsigned delta=0;
+               Result res;
+
+               srand(0);
+
+               gettimeofday(&start, NULL);
+               while(delta<time)
+               {
+                       unsigned i;
+                       for(i=0; i<batch; ++i)
+                               func();
+                       XSync(dpy, True);
+                       count+=batch;
+                       gettimeofday(&end, NULL);
+                       delta=(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec)/1000;
+               }
+               res.ops_per_sec=count*1000/delta;
+               res.error_margin=0;
+               printf("  %d calls in %d ms = %d/sec\n", count, delta, res.ops_per_sec);
+               return res;
+       }
+}
+
+void create_destroy_pixmap()
+{
+       Pixmap p=XCreatePixmap(dpy, wnd, width, height, depth);
+       XFreePixmap(dpy, p);
+}
+
+void create_destroy_picture()
+{
+       Picture p=XRenderCreatePicture(dpy, pxm, pfmt, 0, NULL);
+       XRenderFreePicture(dpy, p);
+}
+
+void random_color(XRenderColor *color, int alpha)
+{
+       color->red=rand()%0x10000;
+       color->green=rand()%0x10000;
+       color->blue=rand()%0x10000;
+       if(alpha)
+       {
+               color->alpha=rand()%0x10000;
+               color->red=color->red*color->alpha/0xFFFF;
+               color->green=color->green*color->alpha/0xFFFF;
+               color->blue=color->blue*color->alpha/0xFFFF;
+       }
+}
+
+void fill_rectangle()
+{
+       int x, y;
+       XRenderColor color;
+       
+       x=rand()%(641-width);
+       y=rand()%(481-height);
+       random_color(&color, op==PictOpOver);
+       XRenderFillRectangle(dpy, op, pict, &color, x, y, width, height);
+}
+
+void composite_trapezoid()
+{
+       int x, y;
+       unsigned w;
+       XTrapezoid trap;
+
+       x=rand()%(641-width);
+       y=rand()%(481-height);
+       trap.top=y<<16;
+       trap.bottom=(y+height)<<16;
+       w=width/2;
+       if(w<1)
+               w=1;
+       trap.left.p1.x=(x+rand()%w)<<16;
+       trap.left.p1.y=trap.top;
+       trap.left.p2.x=(x+rand()%w)<<16;
+       trap.left.p2.y=trap.bottom;
+       trap.right.p1.x=(x+width-rand()%w)<<16;
+       trap.right.p1.y=trap.top;
+       trap.right.p2.x=(x+width-rand()%w)<<16;
+       trap.right.p2.y=trap.bottom;
+
+       XRenderCompositeTrapezoids(dpy, op, srcpict, pict, NULL, 0, 0, &trap, 1);
+       XFlush(dpy);
+}
+
+void draw_string8()
+{
+       unsigned char textbuf[128];
+       unsigned char *textptr;
+       unsigned i;
+       int screen;
+       Visual *visual;
+       Colormap cmap;
+       XRenderColor rcolor;
+       XftColor ftcolor;
+       XGlyphInfo extents;
+       int x, y;
+
+       if(text)
+               textptr=(unsigned char *)text;
+       else
+       {
+               textptr=textbuf;
+               for(i=0; i<textlen; ++i)
+                       textbuf[i]=33+rand()%94;
+       }
+
+       screen=DefaultScreen(dpy);
+       visual=DefaultVisual(dpy, screen);
+       cmap=DefaultColormap(dpy, screen);
+       random_color(&rcolor, 1);
+       XftColorAllocValue(dpy, visual, cmap, &rcolor, &ftcolor);
+
+       XftTextExtents8(dpy, font, textptr, textlen, &extents);
+       x=rand()%(641-extents.width);
+       y=rand()%(481-extents.height);
+       XftDrawString8(ftdraw, &ftcolor, font, x, y, textptr, textlen);
+}
diff --git a/synthetic.bench b/synthetic.bench
new file mode 100644 (file)
index 0000000..e4c8198
--- /dev/null
@@ -0,0 +1,99 @@
+time=5000
+type=statistical
+batch=10
+
+weight=1.0
+
+Pixmap 16x16:
+       size=16x16
+       run pixmap
+
+Pixmap 256x256:
+       size=256x256
+       run pixmap
+
+Pixmap 1024x1024:
+       size=1024x1024
+       run pixmap
+
+Picture 16x16:
+       size=16x16
+       run picture
+
+Picture 256x256:
+       size=256x256
+       run picture
+
+Picture 1024x1024:
+       size=1024x1024
+       run picture
+
+op=src
+
+Rect 8x8 Src:
+       size=8x8
+       run rect
+
+Rect 32x32 Src:
+       size=32x32
+       run rect
+
+Rect 128x128 Src:
+       size=128x128
+       run rect
+
+Rect 512x256 Src:
+       size=512x256
+       run rect
+
+op=over
+
+Rect 8x8 Over:
+       size=8x8
+       run rect
+
+Rect 32x32 Over:
+       size=32x32
+       run rect
+
+Rect 128x128 Over:
+       size=128x128
+       run rect
+
+Rect 512x256 Over:
+       size=512x256
+       run rect
+
+Rect 32x8 Over:
+       size=32x8
+       run rect
+
+Rect 128x8 Over:
+       size=128x8
+       run rect
+
+Rect 8x32 Over:
+       size=8x32
+       run rect
+
+Rect 8x128 Over:
+       size=8x128
+       run rect
+
+randomtext=20
+
+Text 8px:
+       font=Sans Serif:pixelsize=8
+       run text
+
+Text 12px:
+       font=Sans Serif:pixelsize=12
+       run text
+
+Text 16px:
+       font=Sans Serif:pixelsize=16
+       run text
+
+Text 24px:
+       font=Sans Serif:pixelsize=24
+       run text