ttmtest.c revision 2bc925430b522eda596499561eba6fb61278ae8c
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 <drm/drm.h>
39#include "xf86dri.h"
40#include "xf86drm.h"
41#include "stdio.h"
42#include "sys/types.h"
43#include <unistd.h>
44#include <string.h>
45#include <errno.h>
46#include <stdlib.h>
47#include "sys/mman.h"
48
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"
103	"cpuid\n\t" ".byte 0x0f, 0x31\n\t" :"=a" (eax)
104	:"0"(0)
105		      :"ecx", "edx", "ebx", "cc");
106
107    return eax;
108}
109#endif
110
111
112void
113bmError(int val, const char *file, const char *function, int line)
114{
115    fprintf(stderr,"Fatal video memory manager error \"%s\".\n"
116	    "Check kernel logs or set the LIBGL_DEBUG\n"
117	    "environment variable to \"verbose\" for more info.\n"
118	    "Detected in file %s, line %d, function %s.\n",
119	    strerror(-val), file, line, function);
120    abort();
121}
122
123#define BM_CKFATAL(val)					       \
124  do{							       \
125    int tstVal = (val);					       \
126    if (tstVal) 					       \
127      bmError(tstVal, __FILE__, __FUNCTION__, __LINE__);       \
128  } while(0);
129
130
131
132static unsigned
133time_diff(unsigned t, unsigned t2)
134{
135    return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1));
136}
137
138static int
139releaseContext(TinyDRIContext * ctx)
140{
141    switch (ctx->state) {
142    case haveContext:
143	uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id);
144    case haveDRM:
145	drmClose(ctx->drmFD);
146    case haveDeviceInfo:
147	XFree(ctx->driPriv);
148    case haveDriverName:
149	XFree(ctx->driverName);
150    case haveConnection:
151	XFree(ctx->curBusID);
152	uniDRICloseConnection(ctx->display, ctx->screen);
153    case haveDisplay:
154	XCloseDisplay(ctx->display);
155    default:
156	break;
157    }
158    return -1;
159}
160
161static void readBuf(void *buf, unsigned long size)
162{
163    volatile unsigned *buf32 = (unsigned *)buf;
164    unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32);
165
166    while(buf32 < end) {
167	(void) *buf32++;
168    }
169}
170
171
172static int benchmarkBuffer(TinyDRIContext *ctx, unsigned long size,
173			   unsigned long *ticks)
174{
175    unsigned long curTime, oldTime;
176    int ret;
177    drmBO buf;
178    void *virtual;
179
180    /*
181     * Test system memory objects.
182     */
183
184
185    oldTime = fastrdtsc();
186    BM_CKFATAL(drmBOCreate(ctx->drmFD, 0, size, 0, NULL,
187			   drm_bo_type_dc,
188			   DRM_BO_FLAG_READ |
189			   DRM_BO_FLAG_WRITE |
190			   DRM_BO_FLAG_MEM_LOCAL |
191			   DRM_BO_FLAG_NO_EVICT, 0, &buf));
192    curTime = fastrdtsc();
193    *ticks++ = time_diff(oldTime, curTime);
194
195    oldTime = fastrdtsc();
196    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
197			DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0,
198			&virtual));
199    curTime = fastrdtsc();
200    *ticks++ = time_diff(oldTime, curTime);
201
202    oldTime = fastrdtsc();
203    memset(virtual, 0xF0, buf.size);
204    curTime = fastrdtsc();
205    *ticks++ = time_diff(oldTime, curTime);
206
207    oldTime = fastrdtsc();
208    memset(virtual, 0x0F, buf.size);
209    curTime = fastrdtsc();
210    *ticks++ = time_diff(oldTime, curTime);
211
212    oldTime = fastrdtsc();
213    readBuf(virtual, buf.size);
214    curTime = fastrdtsc();
215    *ticks++ = time_diff(oldTime, curTime);
216
217    oldTime = fastrdtsc();
218    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
219    curTime = fastrdtsc();
220    *ticks++ = time_diff(oldTime, curTime);
221
222
223    /*
224     * Test TT bound buffer objects.
225     */
226
227
228    BM_CKFATAL(drmGetLock(ctx->drmFD, ctx->hwContext, 0));
229    oldTime = fastrdtsc();
230    BM_CKFATAL(drmBOValidate(ctx->drmFD, &buf,
231			     DRM_BO_FLAG_MEM_TT, DRM_BO_MASK_MEM,
232			     DRM_BO_HINT_DONT_FENCE));
233    curTime = fastrdtsc();
234    BM_CKFATAL(drmUnlock(ctx->drmFD, ctx->hwContext));
235    *ticks++ = time_diff(oldTime, curTime);
236
237    oldTime = fastrdtsc();
238    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
239			DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0,
240			&virtual));
241    curTime = fastrdtsc();
242    *ticks++ = time_diff(oldTime, curTime);
243
244    oldTime = fastrdtsc();
245    memset(virtual, 0xF0, buf.size);
246    curTime = fastrdtsc();
247    *ticks++ = time_diff(oldTime, curTime);
248
249    oldTime = fastrdtsc();
250    memset(virtual, 0x0F, buf.size);
251    curTime = fastrdtsc();
252    *ticks++ = time_diff(oldTime, curTime);
253
254    oldTime = fastrdtsc();
255    readBuf(virtual, buf.size);
256    curTime = fastrdtsc();
257    *ticks++ = time_diff(oldTime, curTime);
258
259    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
260
261    BM_CKFATAL(drmGetLock(ctx->drmFD, ctx->hwContext, 0));
262    oldTime = fastrdtsc();
263    BM_CKFATAL(drmBOValidate(ctx->drmFD, &buf,
264			     DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM,
265			     DRM_BO_HINT_DONT_FENCE));
266    curTime = fastrdtsc();
267    *ticks++ = time_diff(oldTime, curTime);
268
269    /*
270     * Test cached buffers objects.
271     */
272
273    oldTime = fastrdtsc();
274    ret = drmBOValidate(ctx->drmFD, &buf,
275			DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_BIND_CACHED,
276			DRM_BO_MASK_MEM | DRM_BO_FLAG_BIND_CACHED,
277			DRM_BO_HINT_DONT_FENCE);
278    curTime = fastrdtsc();
279    drmUnlock(ctx->drmFD, ctx->hwContext);
280
281    if (ret) {
282	printf("Couldn't bind cached. Probably no support\n");
283	BM_CKFATAL(drmBODestroy(ctx->drmFD, &buf));
284	return 1;
285    }
286    *ticks++ = time_diff(oldTime, curTime);
287
288    oldTime = fastrdtsc();
289    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
290			DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0,
291			&virtual));
292
293
294    curTime = fastrdtsc();
295    *ticks++ = time_diff(oldTime, curTime);
296
297    oldTime = fastrdtsc();
298    memset(virtual, 0xF0, buf.size);
299    curTime = fastrdtsc();
300    *ticks++ = time_diff(oldTime, curTime);
301
302    oldTime = fastrdtsc();
303    memset(virtual, 0x0F, buf.size);
304    curTime = fastrdtsc();
305    *ticks++ = time_diff(oldTime, curTime);
306
307    oldTime = fastrdtsc();
308    readBuf(virtual, buf.size);
309    curTime = fastrdtsc();
310    *ticks++ = time_diff(oldTime, curTime);
311
312    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
313    BM_CKFATAL(drmBODestroy(ctx->drmFD, &buf));
314
315    return 0;
316}
317
318
319static void
320testAGP(TinyDRIContext * ctx)
321{
322    unsigned long ticks[128], *pTicks;
323    unsigned long size = 4096*1024;
324    int ret;
325
326    ret = benchmarkBuffer(ctx, size, ticks);
327    if (ret < 0) {
328	fprintf(stderr, "Buffer error %s\n", strerror(-ret));
329	return;
330    }
331    pTicks = ticks;
332
333    printf("Buffer size %d bytes\n", size);
334    printf("System memory timings ********************************\n");
335    printf("Creation took            %12lu ticks\n", *pTicks++);
336    printf("Mapping took             %12lu ticks\n", *pTicks++);
337    printf("Writing took             %12lu ticks\n", *pTicks++);
338    printf("Writing Again took       %12lu ticks\n", *pTicks++);
339    printf("Reading took             %12lu ticks\n", *pTicks++);
340    printf("Unmapping took           %12lu ticks\n", *pTicks++);
341
342    printf("\nTT Memory timings ************************************\n");
343    printf("Moving to TT took        %12lu ticks\n", *pTicks++);
344    printf("Mapping in TT took       %12lu ticks\n", *pTicks++);
345    printf("Writing to TT took       %12lu ticks\n", *pTicks++);
346    printf("Writing again to TT took %12lu ticks\n", *pTicks++);
347    printf("Reading from TT took     %12lu ticks\n", *pTicks++);
348    printf("Moving to system took    %12lu ticks\n", *pTicks++);
349
350    if (ret == 1)
351	return;
352
353    printf("\nCached TT Memory timings *****************************\n");
354    printf("Moving to CTT took       %12lu ticks\n", *pTicks++);
355    printf("Mapping in CTT took      %12lu ticks\n", *pTicks++);
356    printf("Writing to CTT took      %12lu ticks\n", *pTicks++);
357    printf("Re-writing to CTT took   %12lu ticks\n", *pTicks++);
358    printf("Reading from CTT took    %12lu ticks\n", *pTicks++);
359    printf("\n\n");
360}
361
362int
363main()
364{
365    int ret, screen, isCapable;
366    char *displayName = ":0";
367    TinyDRIContext ctx;
368    unsigned magic;
369
370    ctx.screen = 0;
371    ctx.state = haveNothing;
372    ctx.display = XOpenDisplay(displayName);
373    if (!ctx.display) {
374	fprintf(stderr, "Could not open display\n");
375	return releaseContext(&ctx);
376    }
377    ctx.state = haveDisplay;
378
379    ret =
380	uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen,
381	&isCapable);
382    if (!ret || !isCapable) {
383	fprintf(stderr, "No DRI on this display:sceen\n");
384	return releaseContext(&ctx);
385    }
386
387    if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset,
388	    &ctx.curBusID)) {
389	fprintf(stderr, "Could not open DRI connection.\n");
390	return releaseContext(&ctx);
391    }
392    ctx.state = haveConnection;
393
394    if (!uniDRIGetClientDriverName(ctx.display, ctx.screen,
395	    &ctx.ddxDriverMajor, &ctx.ddxDriverMinor,
396	    &ctx.ddxDriverPatch, &ctx.driverName)) {
397	fprintf(stderr, "Could not get DRI driver name.\n");
398	return releaseContext(&ctx);
399    }
400    ctx.state = haveDriverName;
401
402    if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen,
403	    &ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize,
404	    &ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) {
405	fprintf(stderr, "Could not get DRI device info.\n");
406	return releaseContext(&ctx);
407    }
408    ctx.state = haveDriverName;
409
410    if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) {
411	perror("DRM Device could not be opened");
412	return releaseContext(&ctx);
413    }
414    ctx.state = haveDRM;
415
416    drmGetMagic(ctx.drmFD, &magic);
417    if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) {
418	fprintf(stderr, "Could not get X server to authenticate us.\n");
419	return releaseContext(&ctx);
420    }
421
422    ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor,
423	&ctx.visualInfo);
424    if (!ret) {
425	ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor,
426	    &ctx.visualInfo);
427	if (!ret) {
428	    fprintf(stderr, "Could not find a matching visual.\n");
429	    return releaseContext(&ctx);
430	}
431    }
432
433    if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual,
434	    &ctx.id, &ctx.hwContext)) {
435	fprintf(stderr, "Could not create DRI context.\n");
436	return releaseContext(&ctx);
437    }
438    ctx.state = haveContext;
439
440    testAGP(&ctx);
441
442    releaseContext(&ctx);
443    printf("Terminating normally\n");
444    return 0;
445}
446