Merge mga-1-0-0-branch into trunk.
[platform/upstream/libdrm.git] / tests / dristat.c
1 /* dristat.c -- 
2  * Created: Mon Jan 15 05:05:07 2001 by faith@acm.org
3  *
4  * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  * 
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  * 
26  * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
27  * 
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include "../../../xf86drm.h"
34 #include "../xf86drmRandom.c"
35 #include "../xf86drmHash.c"
36 #include "../xf86drm.c"
37
38 #define DRM_DIR_NAME "/dev/dri"
39 #define DRM_DEV_NAME "%s/card%d"
40
41 #define DRM_VERSION 0x00000001
42 #define DRM_MEMORY  0x00000002
43 #define DRM_CLIENTS 0x00000004
44 #define DRM_STATS   0x00000008
45
46 typedef struct drmStatsS {
47     unsigned long count;
48     struct {
49         unsigned long value;
50         const char    *long_format;
51         const char    *long_name;
52         const char    *rate_format;
53         const char    *rate_name;
54         int           isvalue;
55         const char    *mult_names;
56         int           mult;
57         int           verbose;
58     } data[15];
59 } drmStatsT;
60
61 static void getversion(int fd)
62 {
63     drmVersionPtr version;
64     
65     version = drmGetVersion(fd);
66     if (version) {
67         printf("  Version information:\n");
68         printf("    Name: %s\n", version->name ? version->name : "?");
69         printf("    Version: %d.%d.%d\n",
70                version->version_major,
71                version->version_minor,
72                version->version_patchlevel);
73         printf("    Date: %s\n", version->date ? version->date : "?");
74         printf("    Desc: %s\n", version->desc ? version->desc : "?");
75         drmFreeVersion(version);
76     } else {
77         printf("  No version information available\n");
78     }
79 }
80
81 typedef struct {
82     unsigned long       offset;  /* Requested physical address (0 for SAREA)*/
83     unsigned long       size;    /* Requested physical size (bytes)         */
84     drm_map_type_t      type;    /* Type of memory to map                   */
85     drm_map_flags_t flags;       /* Flags                                   */
86     void                *handle; /* User-space: "Handle" to pass to mmap    */
87     /* Kernel-space: kernel-virtual address    */
88     int         mtrr;    /* MTRR slot used                          */
89                                  /* Private data                            */
90 } drmVmRec, *drmVmPtr;
91
92 int drmGetMap(int fd, int idx, drmHandle *offset, drmSize *size,
93               drmMapType *type, drmMapFlags *flags, drmHandle *handle,
94               int *mtrr)
95 {
96     drm_map_t map;
97
98     map.offset = idx;
99     if (ioctl(fd, DRM_IOCTL_GET_MAP, &map)) return -errno;
100     *offset = map.offset;
101     *size   = map.size;
102     *type   = map.type;
103     *flags  = map.flags;
104     *handle = (unsigned long)map.handle;
105     *mtrr   = map.mtrr;
106     return 0;
107 }
108
109 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
110                  unsigned long *magic, unsigned long *iocs)
111 {
112     drm_client_t client;
113
114     client.idx = idx;
115     if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client)) return -errno;
116     *auth      = client.auth;
117     *pid       = client.pid;
118     *uid       = client.uid;
119     *magic     = client.magic;
120     *iocs      = client.iocs;
121     return 0;
122 }
123
124 int drmGetStats(int fd, drmStatsT *stats)
125 {
126     drm_stats_t s;
127     int         i;
128
129     if (ioctl(fd, DRM_IOCTL_GET_STATS, &s)) return -errno;
130
131     stats->count = 0;
132     memset(stats, 0, sizeof(*stats));
133     if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
134         return -1;
135
136 #define SET_VALUE                              \
137     stats->data[i].long_format = "%-20.20s";   \
138     stats->data[i].rate_format = "%8.8s";      \
139     stats->data[i].isvalue     = 1;            \
140     stats->data[i].verbose     = 0
141
142 #define SET_COUNT                              \
143     stats->data[i].long_format = "%-20.20s";     \
144     stats->data[i].rate_format = "%5.5s";      \
145     stats->data[i].isvalue     = 0;            \
146     stats->data[i].mult_names  = "kgm";        \
147     stats->data[i].mult        = 1000;         \
148     stats->data[i].verbose     = 0
149
150 #define SET_BYTE                             \
151     stats->data[i].long_format = "%-9.9s";   \
152     stats->data[i].rate_format = "%5.5s";    \
153     stats->data[i].isvalue     = 0;          \
154     stats->data[i].mult_names  = "KGM";      \
155     stats->data[i].mult        = 1024;       \
156     stats->data[i].verbose     = 0
157
158
159     stats->count = s.count;
160     for (i = 0; i < s.count; i++) {
161         stats->data[i].value = s.data[i].value;
162         switch (s.data[i].type) {
163         case _DRM_STAT_LOCK:
164             stats->data[i].long_name = "Lock";
165             stats->data[i].rate_name = "Lock";
166             SET_VALUE;
167             break;
168         case _DRM_STAT_OPENS:
169             stats->data[i].long_name = "Opens";
170             stats->data[i].rate_name = "O";
171             SET_COUNT;
172             stats->data[i].verbose   = 1;
173             break;
174         case _DRM_STAT_CLOSES:
175             stats->data[i].long_name = "Closes";
176             stats->data[i].rate_name = "Lock";
177             SET_COUNT;
178             stats->data[i].verbose   = 1;
179             break;
180         case _DRM_STAT_IOCTLS:
181             stats->data[i].long_name = "Ioctls";
182             stats->data[i].rate_name = "Ioc/s";
183             SET_COUNT;
184             break;
185         case _DRM_STAT_LOCKS:
186             stats->data[i].long_name = "Locks";
187             stats->data[i].rate_name = "Lck/s";
188             SET_COUNT;
189             break;
190         case _DRM_STAT_UNLOCKS:
191             stats->data[i].long_name = "Unlocks";
192             stats->data[i].rate_name = "Unl/s";
193             SET_COUNT;
194             break;
195         case _DRM_STAT_IRQ:
196             stats->data[i].long_name = "IRQs";
197             stats->data[i].rate_name = "IRQ/s";
198             SET_COUNT;
199             break;
200         case _DRM_STAT_PRIMARY:
201             stats->data[i].long_name = "Primary Bytes";
202             stats->data[i].rate_name = "PB/s";
203             SET_BYTE;
204             break;
205         case _DRM_STAT_SECONDARY:
206             stats->data[i].long_name = "Secondary Bytes";
207             stats->data[i].rate_name = "SB/s";
208             SET_BYTE;
209             break;
210         case _DRM_STAT_DMA:
211             stats->data[i].long_name = "DMA";
212             stats->data[i].rate_name = "DMA/s";
213             SET_COUNT;
214             break;
215         case _DRM_STAT_SPECIAL:
216             stats->data[i].long_name = "Special DMA";
217             stats->data[i].rate_name = "dma/s";
218             SET_COUNT;
219             break;
220         case _DRM_STAT_MISSED:
221             stats->data[i].long_name = "Miss";
222             stats->data[i].rate_name = "Ms/s";
223             SET_COUNT;
224             break;
225         case _DRM_STAT_VALUE:
226             stats->data[i].long_name = "Value";
227             stats->data[i].rate_name = "Value";
228             SET_VALUE;
229             break;
230         case _DRM_STAT_BYTE:
231             stats->data[i].long_name = "Bytes";
232             stats->data[i].rate_name = "B/s";
233             SET_BYTE;
234             break;
235         case _DRM_STAT_COUNT:
236         default:
237             stats->data[i].long_name = "Count";
238             stats->data[i].rate_name = "Cnt/s";
239             SET_COUNT;
240             break;
241         }
242     }
243     return 0;
244 }
245
246 static void getvm(int fd)
247 {
248     int             i;
249     const char      *typename;
250     char            flagname[33];
251     drmHandle       offset;
252     drmSize         size;
253     drmMapType      type;
254     drmMapFlags     flags;
255     drmHandle       handle;
256     int             mtrr;
257
258     printf("  VM map information:\n");
259     printf("    slot     offset       size type flags    address mtrr\n");
260
261     for (i = 0;
262          !drmGetMap(fd, i, &offset, &size, &type, &flags, &handle, &mtrr);
263          i++) {
264         
265         switch (type) {
266         case DRM_FRAME_BUFFER: typename = "FB";  break;
267         case DRM_REGISTERS:    typename = "REG"; break;
268         case DRM_SHM:          typename = "SHM"; break;
269         case DRM_AGP:          typename = "AGP"; break;
270         default:               typename = "???"; break;
271         }
272
273         flagname[0] = (flags & DRM_RESTRICTED)      ? 'R' : ' ';
274         flagname[1] = (flags & DRM_READ_ONLY)       ? 'r' : 'w';
275         flagname[2] = (flags & DRM_LOCKED)          ? 'l' : ' ';
276         flagname[3] = (flags & DRM_KERNEL)          ? 'k' : ' ';
277         flagname[4] = (flags & DRM_WRITE_COMBINING) ? 'W' : ' ';
278         flagname[5] = (flags & DRM_CONTAINS_LOCK)   ? 'L' : ' ';
279         flagname[6] = '\0';
280         
281         printf("    %4d 0x%08lx 0x%08lx %3.3s %6.6s 0x%08lx ",
282                i, offset, (unsigned long)size, typename, flagname, handle);
283         if (mtrr < 0) printf("none\n");
284         else          printf("%4d\n", mtrr);
285     }
286 }
287
288 static void getclients(int fd)
289 {
290     int           i;
291     int           auth;
292     int           pid;
293     int           uid;
294     unsigned long magic;
295     unsigned long iocs;
296     char          buf[64];
297     char          cmd[40];
298     int           procfd;
299     
300     printf("  DRI client information:\n");
301     printf("    a   pid    uid      magic     ioctls  prog\n");
302
303     for (i = 0; !drmGetClient(fd, i, &auth, &pid, &uid, &magic, &iocs); i++) {
304         sprintf(buf, "/proc/%d/cmdline", pid);
305         memset(cmd, sizeof(cmd), 0);
306         if ((procfd = open(buf, O_RDONLY, 0)) >= 0) {
307             read(procfd, cmd, sizeof(cmd)-1);
308             close(procfd);
309         }
310         if (*cmd)
311             printf("    %c %5d %5d %10lu %10lu   %s\n",
312                    auth ? 'y' : 'n', pid, uid, magic, iocs, cmd);
313         else
314             printf("    %c %5d %5d %10lu %10lu\n",
315                    auth ? 'y' : 'n', pid, uid, magic, iocs);
316     }
317 }
318
319 static void printhuman(unsigned long value, const char *name, int mult)
320 {
321     const char *p;
322     double     f;
323                                 /* Print width 5 number in width 6 space */
324     if (value < 100000) {
325         printf(" %5lu", value);
326         return;
327     }
328
329     p = name;
330     f = (double)value / (double)mult;
331     if (f < 10.0) {
332         printf(" %4.2f%c", f, *p);
333         return;
334     }
335
336     p++;
337     f = (double)value / (double)mult;
338     if (f < 10.0) {
339         printf(" %4.2f%c", f, *p);
340         return;
341     }
342     
343     p++;
344     f = (double)value / (double)mult;
345     if (f < 10.0) {
346         printf(" %4.2f%c", f, *p);
347         return;
348     }
349 }
350
351 static void getstats(int fd, int i)
352 {
353     drmStatsT prev, curr;
354     int       j;
355     double    rate;
356     
357     printf("  System statistics:\n");
358
359     if (drmGetStats(fd, &prev)) return;
360     if (!i) {
361         for (j = 0; j < prev.count; j++) {
362             printf("    ");
363             printf(prev.data[j].long_format, prev.data[j].long_name);
364             if (prev.data[j].isvalue) printf(" 0x%08lx\n", prev.data[j].value);
365             else                      printf(" %10lu\n", prev.data[j].value);
366         }
367         return;
368     }
369
370     printf("    ");
371     for (j = 0; j < prev.count; j++)
372         if (!prev.data[j].verbose) {
373             printf(" ");
374             printf(prev.data[j].rate_format, prev.data[j].rate_name);
375         }
376     printf("\n");
377     
378     for (;;) {
379         sleep(i);
380         if (drmGetStats(fd, &curr)) return;
381         printf("    ");
382         for (j = 0; j < curr.count; j++) {
383             if (curr.data[j].verbose) continue;
384             if (curr.data[j].isvalue) {
385                 printf(" %08lx", curr.data[j].value);
386             } else {
387                 rate = (curr.data[j].value - prev.data[j].value) / (double)i;
388                 printhuman(rate, curr.data[j].mult_names, curr.data[j].mult);
389             }
390         }
391         printf("\n");
392         memcpy(&prev, &curr, sizeof(prev));
393     }
394     
395 }
396
397 static int drmOpenMinor(int minor, uid_t user, gid_t group,
398                         mode_t dirmode, mode_t devmode, int force)
399 {
400     struct stat st;
401     char        buf[64];
402     long        dev    = makedev(DRM_MAJOR, minor);
403     int         setdir = 0;
404     int         setdev = 0;
405     int         fd;
406
407     if (stat(DRM_DIR_NAME, &st) || !S_ISDIR(st.st_mode)) {
408         remove(DRM_DIR_NAME);
409         mkdir(DRM_DIR_NAME, dirmode);
410         ++setdir;
411     }
412
413     if (force || setdir) {
414         chown(DRM_DIR_NAME, user, group);
415         chmod(DRM_DIR_NAME, dirmode);
416     }
417
418     sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
419     if (stat(buf, &st) || st.st_rdev != dev) {
420         remove(buf);
421         mknod(buf, S_IFCHR, dev);
422         ++setdev;
423     }
424
425     if (force || setdev) {
426         chown(buf, user, group);
427         chmod(buf, devmode);
428     }
429
430     if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
431     if (setdev) remove(buf);
432     return -errno;
433 }
434         
435 int main(int argc, char **argv)
436 {
437     int  c;
438     int  mask     = 0;
439     int  minor    = 0;
440     int  interval = 0;
441     int  fd;
442     char buf[64];
443     int  i;
444
445     while ((c = getopt(argc, argv, "avmcsM:i:")) != EOF)
446         switch (c) {
447         case 'a': mask = ~0;                          break;
448         case 'v': mask |= DRM_VERSION;                break;
449         case 'm': mask |= DRM_MEMORY;                 break;
450         case 'c': mask |= DRM_CLIENTS;                break;
451         case 's': mask |= DRM_STATS;                  break;
452         case 'i': interval = strtol(optarg, NULL, 0); break;
453         case 'M': minor = strtol(optarg, NULL, 0);    break;
454         default:
455             fprintf( stderr, "Usage: dristat [options]\n" );
456             return 1;
457         }
458
459     for (i = 0; i < 16; i++) if (!minor || i == minor) {
460         sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i);
461         fd = drmOpenMinor(i, 0, 0, 0700, 0600, 0);
462         if (fd >= 0) {
463             printf("%s\n", buf);
464             if (mask & DRM_VERSION) getversion(fd);
465             if (mask & DRM_MEMORY)  getvm(fd);
466             if (mask & DRM_CLIENTS) getclients(fd);
467             if (mask & DRM_STATS)   getstats(fd, interval);
468             close(fd);
469         }
470     }
471
472     return 0; 
473 }