ttmtest.c revision f3708b4c04b35b03c28b2297c23eb424206747cd
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28/*
29 * Authors: Thomas Hellstr�m <thomas-at-tungstengraphics-dot-com>
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <X11/Xlib.h>
37#include <X11/Xutil.h>
38#include <stdint.h>
39#include <drm/drm.h>
40#include "xf86dri.h"
41#include "xf86drm.h"
42#include "stdio.h"
43#include "sys/types.h"
44#include <unistd.h>
45#include <string.h>
46#include <errno.h>
47#include <stdlib.h>
48#include "sys/mman.h"
49
50typedef struct
51{
52    enum
53    {
54	haveNothing,
55	haveDisplay,
56	haveConnection,
57	haveDriverName,
58	haveDeviceInfo,
59	haveDRM,
60	haveContext
61    }
62    state;
63
64    Display *display;
65    int screen;
66    drm_handle_t sAreaOffset;
67    char *curBusID;
68    char *driverName;
69    int drmFD;
70    XVisualInfo visualInfo;
71    XID id;
72    drm_context_t hwContext;
73    void *driPriv;
74    int driPrivSize;
75    int fbSize;
76    int fbOrigin;
77    int fbStride;
78    drm_handle_t fbHandle;
79    int ddxDriverMajor;
80    int ddxDriverMinor;
81    int ddxDriverPatch;
82} TinyDRIContext;
83
84#ifndef __x86_64__
85static unsigned
86fastrdtsc(void)
87{
88    unsigned eax;
89    __asm__ volatile ("\t"
90	"pushl  %%ebx\n\t"
91	"cpuid\n\t" ".byte 0x0f, 0x31\n\t" "popl %%ebx\n":"=a" (eax)
92	:"0"(0)
93	:"ecx", "edx", "cc");
94
95    return eax;
96}
97#else
98static unsigned
99fastrdtsc(void)
100{
101    unsigned eax;
102    __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax)
103	:"0"(0)
104	:"ecx", "edx", "ebx", "cc");
105
106    return eax;
107}
108#endif
109
110void
111bmError(int val, const char *file, const char *function, int line)
112{
113    fprintf(stderr, "Fatal video memory manager error \"%s\".\n"
114	"Check kernel logs or set the LIBGL_DEBUG\n"
115	"environment variable to \"verbose\" for more info.\n"
116	"Detected in file %s, line %d, function %s.\n",
117	strerror(-val), file, line, function);
118    abort();
119}
120
121#define BM_CKFATAL(val)					       \
122  do{							       \
123    int tstVal = (val);					       \
124    if (tstVal) 					       \
125      bmError(tstVal, __FILE__, __FUNCTION__, __LINE__);       \
126  } while(0);
127
128static unsigned
129time_diff(unsigned t, unsigned t2)
130{
131    return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1));
132}
133
134static int
135releaseContext(TinyDRIContext * ctx)
136{
137    switch (ctx->state) {
138    case haveContext:
139	uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id);
140    case haveDRM:
141	drmClose(ctx->drmFD);
142    case haveDeviceInfo:
143	XFree(ctx->driPriv);
144    case haveDriverName:
145	XFree(ctx->driverName);
146    case haveConnection:
147	XFree(ctx->curBusID);
148	uniDRICloseConnection(ctx->display, ctx->screen);
149    case haveDisplay:
150	XCloseDisplay(ctx->display);
151    default:
152	break;
153    }
154    return -1;
155}
156
157static void
158readBuf(void *buf, unsigned long size)
159{
160    volatile unsigned *buf32 = (unsigned *)buf;
161    unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32);
162
163    while (buf32 < end) {
164	(void)*buf32++;
165    }
166}
167
168static int
169benchmarkBuffer(TinyDRIContext * ctx, unsigned long size,
170    unsigned long *ticks)
171{
172    unsigned long curTime, oldTime;
173    int ret;
174    drmBO buf;
175    void *virtual;
176
177    /*
178     * Test system memory objects.
179     */
180    oldTime = fastrdtsc();
181    BM_CKFATAL(drmBOCreate(ctx->drmFD, size, 0, NULL,
182			   DRM_BO_FLAG_READ |
183			   DRM_BO_FLAG_WRITE |
184			   DRM_BO_FLAG_MEM_LOCAL, 0, &buf));
185    curTime = fastrdtsc();
186    *ticks++ = time_diff(oldTime, curTime);
187
188    oldTime = fastrdtsc();
189    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
190	    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
191    curTime = fastrdtsc();
192    *ticks++ = time_diff(oldTime, curTime);
193
194    oldTime = fastrdtsc();
195    memset(virtual, 0xF0, buf.size);
196    curTime = fastrdtsc();
197    *ticks++ = time_diff(oldTime, curTime);
198
199    oldTime = fastrdtsc();
200    memset(virtual, 0x0F, buf.size);
201    curTime = fastrdtsc();
202    *ticks++ = time_diff(oldTime, curTime);
203
204    oldTime = fastrdtsc();
205    readBuf(virtual, buf.size);
206    curTime = fastrdtsc();
207    *ticks++ = time_diff(oldTime, curTime);
208
209    oldTime = fastrdtsc();
210    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
211    curTime = fastrdtsc();
212    *ticks++ = time_diff(oldTime, curTime);
213
214    /*
215     * Test TT bound buffer objects.
216     */
217
218    oldTime = fastrdtsc();
219    BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
220			     DRM_BO_FLAG_MEM_TT,
221			     DRM_BO_MASK_MEM,
222			      0,0,0));
223    curTime = fastrdtsc();
224    *ticks++ = time_diff(oldTime, curTime);
225
226    oldTime = fastrdtsc();
227    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
228	    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
229    curTime = fastrdtsc();
230    *ticks++ = time_diff(oldTime, curTime);
231
232    oldTime = fastrdtsc();
233    memset(virtual, 0xF0, buf.size);
234    curTime = fastrdtsc();
235    *ticks++ = time_diff(oldTime, curTime);
236
237    oldTime = fastrdtsc();
238    memset(virtual, 0x0F, buf.size);
239    curTime = fastrdtsc();
240    *ticks++ = time_diff(oldTime, curTime);
241
242    oldTime = fastrdtsc();
243    readBuf(virtual, buf.size);
244    curTime = fastrdtsc();
245    *ticks++ = time_diff(oldTime, curTime);
246
247    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
248
249    oldTime = fastrdtsc();
250    BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
251			     DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM, 0, 0,0));
252    curTime = fastrdtsc();
253    *ticks++ = time_diff(oldTime, curTime);
254
255    /*
256     * Test cached buffers objects.
257     */
258
259    oldTime = fastrdtsc();
260    ret = drmBOSetStatus(ctx->drmFD, &buf,
261			 DRM_BO_FLAG_MEM_TT |
262			 DRM_BO_FLAG_CACHED |
263			 DRM_BO_FLAG_FORCE_CACHING,
264			 DRM_BO_MASK_MEMTYPE |
265			 DRM_BO_FLAG_FORCE_CACHING,
266			 0, 0, 0);
267    curTime = fastrdtsc();
268
269    if (ret) {
270	printf("Couldn't bind cached. Probably no support\n");
271	BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
272	return 1;
273    }
274    *ticks++ = time_diff(oldTime, curTime);
275
276    oldTime = fastrdtsc();
277    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
278	    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
279
280    curTime = fastrdtsc();
281    *ticks++ = time_diff(oldTime, curTime);
282
283    oldTime = fastrdtsc();
284    memset(virtual, 0xF0, buf.size);
285    curTime = fastrdtsc();
286    *ticks++ = time_diff(oldTime, curTime);
287
288    oldTime = fastrdtsc();
289    memset(virtual, 0x0F, buf.size);
290    curTime = fastrdtsc();
291    *ticks++ = time_diff(oldTime, curTime);
292
293    oldTime = fastrdtsc();
294    readBuf(virtual, buf.size);
295    curTime = fastrdtsc();
296    *ticks++ = time_diff(oldTime, curTime);
297
298    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
299    BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
300
301    return 0;
302}
303
304static void
305testAGP(TinyDRIContext * ctx)
306{
307    unsigned long ticks[128], *pTicks;
308    unsigned long size = 8 * 1024;
309    int ret;
310
311    ret = benchmarkBuffer(ctx, size, ticks);
312    if (ret < 0) {
313	fprintf(stderr, "Buffer error %s\n", strerror(-ret));
314	return;
315    }
316    pTicks = ticks;
317
318    printf("Buffer size %d bytes\n", size);
319    printf("System memory timings ********************************\n");
320    printf("Creation took            %12lu ticks\n", *pTicks++);
321    printf("Mapping took             %12lu ticks\n", *pTicks++);
322    printf("Writing took             %12lu ticks\n", *pTicks++);
323    printf("Writing Again took       %12lu ticks\n", *pTicks++);
324    printf("Reading took             %12lu ticks\n", *pTicks++);
325    printf("Unmapping took           %12lu ticks\n", *pTicks++);
326
327    printf("\nTT Memory timings ************************************\n");
328    printf("Moving to TT took        %12lu ticks\n", *pTicks++);
329    printf("Mapping in TT took       %12lu ticks\n", *pTicks++);
330    printf("Writing to TT took       %12lu ticks\n", *pTicks++);
331    printf("Writing again to TT took %12lu ticks\n", *pTicks++);
332    printf("Reading from TT took     %12lu ticks\n", *pTicks++);
333    printf("Moving to system took    %12lu ticks\n", *pTicks++);
334
335    if (ret == 1)
336	return;
337
338    printf("\nCached TT Memory timings *****************************\n");
339    printf("Moving to CTT took       %12lu ticks\n", *pTicks++);
340    printf("Mapping in CTT took      %12lu ticks\n", *pTicks++);
341    printf("Writing to CTT took      %12lu ticks\n", *pTicks++);
342    printf("Re-writing to CTT took   %12lu ticks\n", *pTicks++);
343    printf("Reading from CTT took    %12lu ticks\n", *pTicks++);
344    printf("\n\n");
345}
346
347int
348main()
349{
350    int ret, screen, isCapable;
351    char *displayName = ":0";
352    TinyDRIContext ctx;
353    unsigned magic;
354
355    ctx.screen = 0;
356    ctx.state = haveNothing;
357    ctx.display = XOpenDisplay(displayName);
358    if (!ctx.display) {
359	fprintf(stderr, "Could not open display\n");
360	return releaseContext(&ctx);
361    }
362    ctx.state = haveDisplay;
363
364    ret =
365	uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen,
366	&isCapable);
367    if (!ret || !isCapable) {
368	fprintf(stderr, "No DRI on this display:sceen\n");
369	return releaseContext(&ctx);
370    }
371
372    if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset,
373	    &ctx.curBusID)) {
374	fprintf(stderr, "Could not open DRI connection.\n");
375	return releaseContext(&ctx);
376    }
377    ctx.state = haveConnection;
378
379    if (!uniDRIGetClientDriverName(ctx.display, ctx.screen,
380	    &ctx.ddxDriverMajor, &ctx.ddxDriverMinor,
381	    &ctx.ddxDriverPatch, &ctx.driverName)) {
382	fprintf(stderr, "Could not get DRI driver name.\n");
383	return releaseContext(&ctx);
384    }
385    ctx.state = haveDriverName;
386
387    if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen,
388	    &ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize,
389	    &ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) {
390	fprintf(stderr, "Could not get DRI device info.\n");
391	return releaseContext(&ctx);
392    }
393    ctx.state = haveDriverName;
394
395    if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) {
396	perror("DRM Device could not be opened");
397	return releaseContext(&ctx);
398    }
399    ctx.state = haveDRM;
400
401    drmGetMagic(ctx.drmFD, &magic);
402    if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) {
403	fprintf(stderr, "Could not get X server to authenticate us.\n");
404	return releaseContext(&ctx);
405    }
406
407    ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor,
408	&ctx.visualInfo);
409    if (!ret) {
410	ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor,
411	    &ctx.visualInfo);
412	if (!ret) {
413	    fprintf(stderr, "Could not find a matching visual.\n");
414	    return releaseContext(&ctx);
415	}
416    }
417
418    if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual,
419	    &ctx.id, &ctx.hwContext)) {
420	fprintf(stderr, "Could not create DRI context.\n");
421	return releaseContext(&ctx);
422    }
423    ctx.state = haveContext;
424
425    testAGP(&ctx);
426
427    releaseContext(&ctx);
428    printf("Terminating normally\n");
429    return 0;
430}
431