1 /* drmstat.c -- DRM device status and testing program 2 * Created: Tue Jan 5 08:19:24 1999 by faith (at) precisioninsight.com 3 * 4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 * 27 * Authors: Rickard E. (Rik) Faith <faith (at) valinux.com> 28 * 29 */ 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <sys/mman.h> 37 #include <getopt.h> 38 #include <strings.h> 39 #include <errno.h> 40 #include <signal.h> 41 #include <fcntl.h> 42 #include "xf86drm.h" 43 44 int sigio_fd; 45 46 static double usec(struct timeval *end, struct timeval *start) 47 { 48 double e = end->tv_sec * 1000000 + end->tv_usec; 49 double s = start->tv_sec * 1000000 + start->tv_usec; 50 51 return e - s; 52 } 53 54 static void getversion(int fd) 55 { 56 drmVersionPtr version; 57 58 version = drmGetVersion(fd); 59 if (version) { 60 printf( "Name: %s\n", version->name ? version->name : "?" ); 61 printf( " Version: %d.%d.%d\n", 62 version->version_major, 63 version->version_minor, 64 version->version_patchlevel ); 65 printf( " Date: %s\n", version->date ? version->date : "?" ); 66 printf( " Desc: %s\n", version->desc ? version->desc : "?" ); 67 drmFreeVersion(version); 68 } else { 69 printf( "No driver available\n" ); 70 } 71 } 72 73 void handler(int fd, void *oldctx, void *newctx) 74 { 75 printf("Got fd %d\n", fd); 76 } 77 78 void process_sigio(char *device) 79 { 80 int fd; 81 82 if ((fd = open(device, 0)) < 0) { 83 drmError(-errno, __FUNCTION__); 84 exit(1); 85 } 86 87 sigio_fd = fd; 88 /* drmInstallSIGIOHandler(fd, handler); */ 89 for (;;) sleep(60); 90 } 91 92 int main(int argc, char **argv) 93 { 94 int c; 95 int r = 0; 96 int fd = -1; 97 drm_handle_t handle; 98 void *address; 99 char *pt; 100 unsigned long count; 101 unsigned long offset; 102 unsigned long size; 103 drm_context_t context; 104 int loops; 105 char buf[1024]; 106 int i; 107 drmBufInfoPtr info; 108 drmBufMapPtr bufs; 109 drmLockPtr lock; 110 int secs; 111 112 while ((c = getopt(argc, argv, 113 "lc:vo:O:f:s:w:W:b:r:R:P:L:C:XS:B:F:")) != EOF) 114 switch (c) { 115 case 'F': 116 count = strtoul(optarg, NULL, 0); 117 if (!fork()) { 118 dup(fd); 119 sleep(count); 120 } 121 close(fd); 122 break; 123 case 'v': getversion(fd); break; 124 case 'X': 125 if ((r = drmCreateContext(fd, &context))) { 126 drmError(r, argv[0]); 127 return 1; 128 } 129 printf( "Got %d\n", context); 130 break; 131 case 'S': 132 process_sigio(optarg); 133 break; 134 case 'C': 135 if ((r = drmSwitchToContext(fd, strtoul(optarg, NULL, 0)))) { 136 drmError(r, argv[0]); 137 return 1; 138 } 139 break; 140 case 'c': 141 if ((r = drmSetBusid(fd,optarg))) { 142 drmError(r, argv[0]); 143 return 1; 144 } 145 break; 146 case 'o': 147 if ((fd = drmOpen(optarg, NULL)) < 0) { 148 drmError(fd, argv[0]); 149 return 1; 150 } 151 break; 152 case 'O': 153 if ((fd = drmOpen(NULL, optarg)) < 0) { 154 drmError(fd, argv[0]); 155 return 1; 156 } 157 break; 158 case 'B': /* Test buffer allocation */ 159 count = strtoul(optarg, &pt, 0); 160 size = strtoul(pt+1, &pt, 0); 161 secs = strtoul(pt+1, NULL, 0); 162 { 163 drmDMAReq dma; 164 int *indices, *sizes; 165 166 indices = alloca(sizeof(*indices) * count); 167 sizes = alloca(sizeof(*sizes) * count); 168 dma.context = context; 169 dma.send_count = 0; 170 dma.request_count = count; 171 dma.request_size = size; 172 dma.request_list = indices; 173 dma.request_sizes = sizes; 174 dma.flags = DRM_DMA_WAIT; 175 if ((r = drmDMA(fd, &dma))) { 176 drmError(r, argv[0]); 177 return 1; 178 } 179 for (i = 0; i < dma.granted_count; i++) { 180 printf("%5d: index = %d, size = %d\n", 181 i, dma.request_list[i], dma.request_sizes[i]); 182 } 183 sleep(secs); 184 drmFreeBufs(fd, dma.granted_count, indices); 185 } 186 break; 187 case 'b': 188 count = strtoul(optarg, &pt, 0); 189 size = strtoul(pt+1, NULL, 0); 190 if ((r = drmAddBufs(fd, count, size, 0, 65536)) < 0) { 191 drmError(r, argv[0]); 192 return 1; 193 } 194 if (!(info = drmGetBufInfo(fd))) { 195 drmError(0, argv[0]); 196 return 1; 197 } 198 for (i = 0; i < info->count; i++) { 199 printf("%5d buffers of size %6d (low = %d, high = %d)\n", 200 info->list[i].count, 201 info->list[i].size, 202 info->list[i].low_mark, 203 info->list[i].high_mark); 204 } 205 if ((r = drmMarkBufs(fd, 0.50, 0.80))) { 206 drmError(r, argv[0]); 207 return 1; 208 } 209 if (!(info = drmGetBufInfo(fd))) { 210 drmError(0, argv[0]); 211 return 1; 212 } 213 for (i = 0; i < info->count; i++) { 214 printf("%5d buffers of size %6d (low = %d, high = %d)\n", 215 info->list[i].count, 216 info->list[i].size, 217 info->list[i].low_mark, 218 info->list[i].high_mark); 219 } 220 printf("===== /proc/dri/0/mem =====\n"); 221 sprintf(buf, "cat /proc/dri/0/mem"); 222 system(buf); 223 #if 1 224 if (!(bufs = drmMapBufs(fd))) { 225 drmError(0, argv[0]); 226 return 1; 227 } 228 printf("===============================\n"); 229 printf( "%d bufs\n", bufs->count); 230 for (i = 0; i < bufs->count; i++) { 231 printf( " %4d: %8d bytes at %p\n", 232 i, 233 bufs->list[i].total, 234 bufs->list[i].address); 235 } 236 printf("===== /proc/dri/0/vma =====\n"); 237 sprintf(buf, "cat /proc/dri/0/vma"); 238 system(buf); 239 #endif 240 break; 241 case 'f': 242 offset = strtoul(optarg, &pt, 0); 243 size = strtoul(pt+1, NULL, 0); 244 handle = 0; 245 if ((r = drmAddMap(fd, offset, size, 246 DRM_FRAME_BUFFER, 0, &handle))) { 247 drmError(r, argv[0]); 248 return 1; 249 } 250 printf("0x%08lx:0x%04lx added\n", offset, size); 251 printf("===== /proc/dri/0/mem =====\n"); 252 sprintf(buf, "cat /proc/dri/0/mem"); 253 system(buf); 254 break; 255 case 'r': 256 case 'R': 257 offset = strtoul(optarg, &pt, 0); 258 size = strtoul(pt+1, NULL, 0); 259 handle = 0; 260 if ((r = drmAddMap(fd, offset, size, 261 DRM_REGISTERS, 262 c == 'R' ? DRM_READ_ONLY : 0, 263 &handle))) { 264 drmError(r, argv[0]); 265 return 1; 266 } 267 printf("0x%08lx:0x%04lx added\n", offset, size); 268 printf("===== /proc/dri/0/mem =====\n"); 269 sprintf(buf, "cat /proc/dri/0/mem"); 270 system(buf); 271 break; 272 case 's': 273 size = strtoul(optarg, &pt, 0); 274 handle = 0; 275 if ((r = drmAddMap(fd, 0, size, 276 DRM_SHM, DRM_CONTAINS_LOCK, 277 &handle))) { 278 drmError(r, argv[0]); 279 return 1; 280 } 281 printf("0x%04lx byte shm added at 0x%08lx\n", size, handle); 282 sprintf(buf, "cat /proc/dri/0/vm"); 283 system(buf); 284 break; 285 case 'P': 286 offset = strtoul(optarg, &pt, 0); 287 size = strtoul(pt+1, NULL, 0); 288 address = NULL; 289 if ((r = drmMap(fd, offset, size, &address))) { 290 drmError(r, argv[0]); 291 return 1; 292 } 293 printf("0x%08lx:0x%04lx mapped at %p for pid %d\n", 294 offset, size, address, getpid()); 295 printf("===== /proc/dri/0/vma =====\n"); 296 sprintf(buf, "cat /proc/dri/0/vma"); 297 system(buf); 298 mprotect((void *)offset, size, PROT_READ); 299 printf("===== /proc/dri/0/vma =====\n"); 300 sprintf(buf, "cat /proc/dri/0/vma"); 301 system(buf); 302 break; 303 case 'w': 304 case 'W': 305 offset = strtoul(optarg, &pt, 0); 306 size = strtoul(pt+1, NULL, 0); 307 address = NULL; 308 if ((r = drmMap(fd, offset, size, &address))) { 309 drmError(r, argv[0]); 310 return 1; 311 } 312 printf("0x%08lx:0x%04lx mapped at %p for pid %d\n", 313 offset, size, address, getpid()); 314 printf("===== /proc/%d/maps =====\n", getpid()); 315 sprintf(buf, "cat /proc/%d/maps", getpid()); 316 system(buf); 317 printf("===== /proc/dri/0/mem =====\n"); 318 sprintf(buf, "cat /proc/dri/0/mem"); 319 system(buf); 320 printf("===== /proc/dri/0/vma =====\n"); 321 sprintf(buf, "cat /proc/dri/0/vma"); 322 system(buf); 323 printf("===== READING =====\n"); 324 for (i = 0; i < 0x10; i++) 325 printf("%02x ", (unsigned int)((unsigned char *)address)[i]); 326 printf("\n"); 327 if (c == 'w') { 328 printf("===== WRITING =====\n"); 329 for (i = 0; i < size; i+=2) { 330 ((char *)address)[i] = i & 0xff; 331 ((char *)address)[i+1] = i & 0xff; 332 } 333 } 334 printf("===== READING =====\n"); 335 for (i = 0; i < 0x10; i++) 336 printf("%02x ", (unsigned int)((unsigned char *)address)[i]); 337 printf("\n"); 338 printf("===== /proc/dri/0/vma =====\n"); 339 sprintf(buf, "cat /proc/dri/0/vma"); 340 system(buf); 341 break; 342 case 'L': 343 context = strtoul(optarg, &pt, 0); 344 offset = strtoul(pt+1, &pt, 0); 345 size = strtoul(pt+1, &pt, 0); 346 loops = strtoul(pt+1, NULL, 0); 347 address = NULL; 348 if ((r = drmMap(fd, offset, size, &address))) { 349 drmError(r, argv[0]); 350 return 1; 351 } 352 lock = address; 353 #if 1 354 { 355 int counter = 0; 356 struct timeval loop_start, loop_end; 357 struct timeval lock_start, lock_end; 358 double wt; 359 #define HISTOSIZE 9 360 int histo[HISTOSIZE]; 361 int output = 0; 362 int fast = 0; 363 364 if (loops < 0) { 365 loops = -loops; 366 ++output; 367 } 368 369 for (i = 0; i < HISTOSIZE; i++) histo[i] = 0; 370 371 gettimeofday(&loop_start, NULL); 372 for (i = 0; i < loops; i++) { 373 gettimeofday(&lock_start, NULL); 374 DRM_LIGHT_LOCK_COUNT(fd,lock,context,fast); 375 gettimeofday(&lock_end, NULL); 376 DRM_UNLOCK(fd,lock,context); 377 ++counter; 378 wt = usec(&lock_end, &lock_start); 379 if (wt <= 2.5) ++histo[8]; 380 if (wt < 5.0) ++histo[0]; 381 else if (wt < 50.0) ++histo[1]; 382 else if (wt < 500.0) ++histo[2]; 383 else if (wt < 5000.0) ++histo[3]; 384 else if (wt < 50000.0) ++histo[4]; 385 else if (wt < 500000.0) ++histo[5]; 386 else if (wt < 5000000.0) ++histo[6]; 387 else ++histo[7]; 388 if (output) printf( "%.2f uSec, %d fast\n", wt, fast); 389 } 390 gettimeofday(&loop_end, NULL); 391 printf( "Average wait time = %.2f usec, %d fast\n", 392 usec(&loop_end, &loop_start) / counter, fast); 393 printf( "%9d <= 2.5 uS\n", histo[8]); 394 printf( "%9d < 5 uS\n", histo[0]); 395 printf( "%9d < 50 uS\n", histo[1]); 396 printf( "%9d < 500 uS\n", histo[2]); 397 printf( "%9d < 5000 uS\n", histo[3]); 398 printf( "%9d < 50000 uS\n", histo[4]); 399 printf( "%9d < 500000 uS\n", histo[5]); 400 printf( "%9d < 5000000 uS\n", histo[6]); 401 printf( "%9d >= 5000000 uS\n", histo[7]); 402 } 403 #else 404 printf( "before lock: 0x%08x\n", lock->lock); 405 printf( "lock: 0x%08x\n", lock->lock); 406 sleep(5); 407 printf( "unlock: 0x%08x\n", lock->lock); 408 #endif 409 break; 410 default: 411 fprintf( stderr, "Usage: drmstat [options]\n" ); 412 return 1; 413 } 414 415 return r; 416 } 417 418 void 419 xf86VDrvMsgVerb(int scrnIndex, int type, int verb, const char *format, 420 va_list args) 421 { 422 vfprintf(stderr, format, args); 423 } 424 425 int xf86ConfigDRI[10]; 426