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