1/* drmstat.c -- DRM device status and testing program 2 * Created: Tue Jan 5 08:19:24 1999 by faith@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@valinux.com> 28 * 29 */ 30 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif 34 35#include <stdio.h> 36#include <stdlib.h> 37#include <unistd.h> 38#include <sys/types.h> 39#include <sys/time.h> 40#include <sys/mman.h> 41#include <getopt.h> 42#include <strings.h> 43#include <errno.h> 44#include <signal.h> 45#include <fcntl.h> 46#ifdef HAVE_ALLOCA_H 47# include <alloca.h> 48#endif 49#include "xf86drm.h" 50 51int sigio_fd; 52 53static double usec(struct timeval *end, struct timeval *start) 54{ 55 double e = end->tv_sec * 1000000 + end->tv_usec; 56 double s = start->tv_sec * 1000000 + start->tv_usec; 57 58 return e - s; 59} 60 61static void getversion(int fd) 62{ 63 drmVersionPtr version; 64 65 version = drmGetVersion(fd); 66 if (version) { 67 printf( "Name: %s\n", version->name ? version->name : "?" ); 68 printf( " Version: %d.%d.%d\n", 69 version->version_major, 70 version->version_minor, 71 version->version_patchlevel ); 72 printf( " Date: %s\n", version->date ? version->date : "?" ); 73 printf( " Desc: %s\n", version->desc ? version->desc : "?" ); 74 drmFreeVersion(version); 75 } else { 76 printf( "No driver available\n" ); 77 } 78} 79 80static void process_sigio(char *device) 81{ 82 int fd; 83 84 if ((fd = open(device, 0)) < 0) { 85 drmError(-errno, __func__); 86 exit(1); 87 } 88 89 sigio_fd = fd; 90 for (;;) sleep(60); 91} 92 93int main(int argc, char **argv) 94{ 95 int c; 96 int r = 0; 97 int fd = -1; 98 drm_handle_t handle; 99 void *address; 100 char *pt; 101 unsigned long count; 102 unsigned long offset; 103 unsigned long size; 104 drm_context_t context; 105 int loops; 106 char buf[1024]; 107 int i; 108 drmBufInfoPtr info; 109 drmBufMapPtr bufs; 110 drmLockPtr lock; 111 int secs; 112 113 while ((c = getopt(argc, argv, 114 "lc:vo:O:f:s:w:W:b:r:R:P:L:C:XS:B:F:")) != EOF) 115 switch (c) { 116 case 'F': 117 count = strtoul(optarg, NULL, 0); 118 if (!fork()) { 119 dup(fd); 120 sleep(count); 121 } 122 close(fd); 123 break; 124 case 'v': getversion(fd); break; 125 case 'X': 126 if ((r = drmCreateContext(fd, &context))) { 127 drmError(r, argv[0]); 128 return 1; 129 } 130 printf( "Got %d\n", context); 131 break; 132 case 'S': 133 process_sigio(optarg); 134 break; 135 case 'C': 136 if ((r = drmSwitchToContext(fd, strtoul(optarg, NULL, 0)))) { 137 drmError(r, argv[0]); 138 return 1; 139 } 140 break; 141 case 'c': 142 if ((r = drmSetBusid(fd,optarg))) { 143 drmError(r, argv[0]); 144 return 1; 145 } 146 break; 147 case 'o': 148 if ((fd = drmOpen(optarg, NULL)) < 0) { 149 drmError(fd, argv[0]); 150 return 1; 151 } 152 break; 153 case 'O': 154 if ((fd = drmOpen(NULL, optarg)) < 0) { 155 drmError(fd, argv[0]); 156 return 1; 157 } 158 break; 159 case 'B': /* Test buffer allocation */ 160 count = strtoul(optarg, &pt, 0); 161 size = strtoul(pt+1, &pt, 0); 162 secs = strtoul(pt+1, NULL, 0); 163 { 164 drmDMAReq dma; 165 int *indices, *sizes; 166 167 indices = alloca(sizeof(*indices) * count); 168 sizes = alloca(sizeof(*sizes) * count); 169 dma.context = context; 170 dma.send_count = 0; 171 dma.request_count = count; 172 dma.request_size = size; 173 dma.request_list = indices; 174 dma.request_sizes = sizes; 175 dma.flags = DRM_DMA_WAIT; 176 if ((r = drmDMA(fd, &dma))) { 177 drmError(r, argv[0]); 178 return 1; 179 } 180 for (i = 0; i < dma.granted_count; i++) { 181 printf("%5d: index = %d, size = %d\n", 182 i, dma.request_list[i], dma.request_sizes[i]); 183 } 184 sleep(secs); 185 drmFreeBufs(fd, dma.granted_count, indices); 186 } 187 break; 188 case 'b': 189 count = strtoul(optarg, &pt, 0); 190 size = strtoul(pt+1, NULL, 0); 191 if ((r = drmAddBufs(fd, count, size, 0, 65536)) < 0) { 192 drmError(r, argv[0]); 193 return 1; 194 } 195 if (!(info = drmGetBufInfo(fd))) { 196 drmError(0, argv[0]); 197 return 1; 198 } 199 for (i = 0; i < info->count; i++) { 200 printf("%5d buffers of size %6d (low = %d, high = %d)\n", 201 info->list[i].count, 202 info->list[i].size, 203 info->list[i].low_mark, 204 info->list[i].high_mark); 205 } 206 if ((r = drmMarkBufs(fd, 0.50, 0.80))) { 207 drmError(r, argv[0]); 208 return 1; 209 } 210 if (!(info = drmGetBufInfo(fd))) { 211 drmError(0, argv[0]); 212 return 1; 213 } 214 for (i = 0; i < info->count; i++) { 215 printf("%5d buffers of size %6d (low = %d, high = %d)\n", 216 info->list[i].count, 217 info->list[i].size, 218 info->list[i].low_mark, 219 info->list[i].high_mark); 220 } 221 printf("===== /proc/dri/0/mem =====\n"); 222 sprintf(buf, "cat /proc/dri/0/mem"); 223 system(buf); 224#if 1 225 if (!(bufs = drmMapBufs(fd))) { 226 drmError(0, argv[0]); 227 return 1; 228 } 229 printf("===============================\n"); 230 printf( "%d bufs\n", bufs->count); 231 for (i = 0; i < bufs->count; i++) { 232 printf( " %4d: %8d bytes at %p\n", 233 i, 234 bufs->list[i].total, 235 bufs->list[i].address); 236 } 237 printf("===== /proc/dri/0/vma =====\n"); 238 sprintf(buf, "cat /proc/dri/0/vma"); 239 system(buf); 240#endif 241 break; 242 case 'f': 243 offset = strtoul(optarg, &pt, 0); 244 size = strtoul(pt+1, NULL, 0); 245 handle = 0; 246 if ((r = drmAddMap(fd, offset, size, 247 DRM_FRAME_BUFFER, 0, &handle))) { 248 drmError(r, argv[0]); 249 return 1; 250 } 251 printf("0x%08lx:0x%04lx added\n", offset, size); 252 printf("===== /proc/dri/0/mem =====\n"); 253 sprintf(buf, "cat /proc/dri/0/mem"); 254 system(buf); 255 break; 256 case 'r': 257 case 'R': 258 offset = strtoul(optarg, &pt, 0); 259 size = strtoul(pt+1, NULL, 0); 260 handle = 0; 261 if ((r = drmAddMap(fd, offset, size, 262 DRM_REGISTERS, 263 c == 'R' ? DRM_READ_ONLY : 0, 264 &handle))) { 265 drmError(r, argv[0]); 266 return 1; 267 } 268 printf("0x%08lx:0x%04lx added\n", offset, size); 269 printf("===== /proc/dri/0/mem =====\n"); 270 sprintf(buf, "cat /proc/dri/0/mem"); 271 system(buf); 272 break; 273 case 's': 274 size = strtoul(optarg, &pt, 0); 275 handle = 0; 276 if ((r = drmAddMap(fd, 0, size, 277 DRM_SHM, DRM_CONTAINS_LOCK, 278 &handle))) { 279 drmError(r, argv[0]); 280 return 1; 281 } 282 printf("0x%04lx byte shm added at 0x%08lx\n", size, handle); 283 sprintf(buf, "cat /proc/dri/0/vm"); 284 system(buf); 285 break; 286 case 'P': 287 offset = strtoul(optarg, &pt, 0); 288 size = strtoul(pt+1, NULL, 0); 289 address = NULL; 290 if ((r = drmMap(fd, offset, size, &address))) { 291 drmError(r, argv[0]); 292 return 1; 293 } 294 printf("0x%08lx:0x%04lx mapped at %p for pid %d\n", 295 offset, size, address, getpid()); 296 printf("===== /proc/dri/0/vma =====\n"); 297 sprintf(buf, "cat /proc/dri/0/vma"); 298 system(buf); 299 mprotect((void *)offset, size, PROT_READ); 300 printf("===== /proc/dri/0/vma =====\n"); 301 sprintf(buf, "cat /proc/dri/0/vma"); 302 system(buf); 303 break; 304 case 'w': 305 case 'W': 306 offset = strtoul(optarg, &pt, 0); 307 size = strtoul(pt+1, NULL, 0); 308 address = NULL; 309 if ((r = drmMap(fd, offset, size, &address))) { 310 drmError(r, argv[0]); 311 return 1; 312 } 313 printf("0x%08lx:0x%04lx mapped at %p for pid %d\n", 314 offset, size, address, getpid()); 315 printf("===== /proc/%d/maps =====\n", getpid()); 316 sprintf(buf, "cat /proc/%d/maps", getpid()); 317 system(buf); 318 printf("===== /proc/dri/0/mem =====\n"); 319 sprintf(buf, "cat /proc/dri/0/mem"); 320 system(buf); 321 printf("===== /proc/dri/0/vma =====\n"); 322 sprintf(buf, "cat /proc/dri/0/vma"); 323 system(buf); 324 printf("===== READING =====\n"); 325 for (i = 0; i < 0x10; i++) 326 printf("%02x ", (unsigned int)((unsigned char *)address)[i]); 327 printf("\n"); 328 if (c == 'w') { 329 printf("===== WRITING =====\n"); 330 for (i = 0; i < size; i+=2) { 331 ((char *)address)[i] = i & 0xff; 332 ((char *)address)[i+1] = i & 0xff; 333 } 334 } 335 printf("===== READING =====\n"); 336 for (i = 0; i < 0x10; i++) 337 printf("%02x ", (unsigned int)((unsigned char *)address)[i]); 338 printf("\n"); 339 printf("===== /proc/dri/0/vma =====\n"); 340 sprintf(buf, "cat /proc/dri/0/vma"); 341 system(buf); 342 break; 343 case 'L': 344 context = strtoul(optarg, &pt, 0); 345 offset = strtoul(pt+1, &pt, 0); 346 size = strtoul(pt+1, &pt, 0); 347 loops = strtoul(pt+1, NULL, 0); 348 address = NULL; 349 if ((r = drmMap(fd, offset, size, &address))) { 350 drmError(r, argv[0]); 351 return 1; 352 } 353 lock = address; 354#if 1 355 { 356 int counter = 0; 357 struct timeval loop_start, loop_end; 358 struct timeval lock_start, lock_end; 359 double wt; 360#define HISTOSIZE 9 361 int histo[HISTOSIZE]; 362 int output = 0; 363 int fast = 0; 364 365 if (loops < 0) { 366 loops = -loops; 367 ++output; 368 } 369 370 for (i = 0; i < HISTOSIZE; i++) histo[i] = 0; 371 372 gettimeofday(&loop_start, NULL); 373 for (i = 0; i < loops; i++) { 374 gettimeofday(&lock_start, NULL); 375 DRM_LIGHT_LOCK_COUNT(fd,lock,context,fast); 376 gettimeofday(&lock_end, NULL); 377 DRM_UNLOCK(fd,lock,context); 378 ++counter; 379 wt = usec(&lock_end, &lock_start); 380 if (wt <= 2.5) ++histo[8]; 381 if (wt < 5.0) ++histo[0]; 382 else if (wt < 50.0) ++histo[1]; 383 else if (wt < 500.0) ++histo[2]; 384 else if (wt < 5000.0) ++histo[3]; 385 else if (wt < 50000.0) ++histo[4]; 386 else if (wt < 500000.0) ++histo[5]; 387 else if (wt < 5000000.0) ++histo[6]; 388 else ++histo[7]; 389 if (output) printf( "%.2f uSec, %d fast\n", wt, fast); 390 } 391 gettimeofday(&loop_end, NULL); 392 printf( "Average wait time = %.2f usec, %d fast\n", 393 usec(&loop_end, &loop_start) / counter, fast); 394 printf( "%9d <= 2.5 uS\n", histo[8]); 395 printf( "%9d < 5 uS\n", histo[0]); 396 printf( "%9d < 50 uS\n", histo[1]); 397 printf( "%9d < 500 uS\n", histo[2]); 398 printf( "%9d < 5000 uS\n", histo[3]); 399 printf( "%9d < 50000 uS\n", histo[4]); 400 printf( "%9d < 500000 uS\n", histo[5]); 401 printf( "%9d < 5000000 uS\n", histo[6]); 402 printf( "%9d >= 5000000 uS\n", histo[7]); 403 } 404#else 405 printf( "before lock: 0x%08x\n", lock->lock); 406 printf( "lock: 0x%08x\n", lock->lock); 407 sleep(5); 408 printf( "unlock: 0x%08x\n", lock->lock); 409#endif 410 break; 411 default: 412 fprintf( stderr, "Usage: drmstat [options]\n" ); 413 return 1; 414 } 415 416 return r; 417} 418 419int xf86ConfigDRI[10]; 420