~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to hw/dmx/dmxstat.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86$ */
 
2
/*
 
3
 * Copyright 2002, 2003 Red Hat Inc., Durham, North Carolina.
 
4
 *
 
5
 * All Rights Reserved.
 
6
 *
 
7
 * Permission is hereby granted, free of charge, to any person obtaining
 
8
 * a copy of this software and associated documentation files (the
 
9
 * "Software"), to deal in the Software without restriction, including
 
10
 * without limitation on the rights to use, copy, modify, merge,
 
11
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
12
 * and to permit persons to whom the Software is furnished to do so,
 
13
 * subject to the following conditions:
 
14
 *
 
15
 * The above copyright notice and this permission notice (including the
 
16
 * next paragraph) shall be included in all copies or substantial
 
17
 * portions of the Software.
 
18
 *
 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
20
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
21
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
22
 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 
23
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
24
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
25
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
26
 * SOFTWARE.
 
27
 */
 
28
 
 
29
/*
 
30
 * Authors:
 
31
 *   Rickard E. (Rik) Faith <faith@redhat.com>
 
32
 *
 
33
 */
 
34
 
 
35
/** \file
 
36
 *
 
37
 * The DMX server code is written to call #dmxSync() whenever an XSync()
 
38
 * might be necessary.  However, since XSync() requires a two way
 
39
 * communication with the other X server, eliminating unnecessary
 
40
 * XSync() calls is a key performance optimization.  Support for this
 
41
 * optimization is provided in #dmxsync.c.  This file provides routines
 
42
 * that evaluate this optimization by counting the number of XSync()
 
43
 * calls and monitoring their latency.  This functionality can be turned
 
44
 * on using the -stat command-line parameter. */
 
45
 
 
46
#ifdef HAVE_DMX_CONFIG_H
 
47
#include <dmx-config.h>
 
48
#endif
 
49
 
 
50
#include "dmx.h"
 
51
#include "dmxstat.h"
 
52
#include "dmxlog.h"
 
53
#include <X11/Xos.h>                /* For sys/time.h */
 
54
 
 
55
/** Used to compute a running average of value. */
 
56
typedef struct _DMXStatAvg {
 
57
    int           pos;
 
58
    int           count;
 
59
    unsigned long value[DMX_STAT_LENGTH];
 
60
} DMXStatAvg;
 
61
 
 
62
/** Statistical information about XSync calls. */
 
63
struct _DMXStatInfo {
 
64
    unsigned long syncCount;
 
65
    unsigned long oldSyncCount;
 
66
 
 
67
    DMXStatAvg    usec;
 
68
    DMXStatAvg    pending;
 
69
 
 
70
    unsigned long bins[DMX_STAT_BINS];
 
71
};
 
72
 
 
73
/* Interval in mS between statistic message log entries. */
 
74
       int        dmxStatInterval;
 
75
static int        dmxStatDisplays;
 
76
static OsTimerPtr dmxStatTimer;
 
77
 
 
78
/** Return the number of microseconds as an unsigned long.
 
79
 * Unfortunately, this is only useful for intervals < about 4 sec.  */
 
80
static unsigned long usec(struct timeval *stop, struct timeval *start)
 
81
{
 
82
    return (stop->tv_sec - start->tv_sec) * 1000000
 
83
        + stop->tv_usec - start->tv_usec;
 
84
}
 
85
 
 
86
static unsigned long avg(DMXStatAvg *data, unsigned long *max)
 
87
{
 
88
    unsigned long sum;
 
89
    int           i;
 
90
 
 
91
    *max = 0;
 
92
    if (!data->count) return 0;
 
93
 
 
94
    for (i = 0, sum = 0; i < data->count; i++) {
 
95
        if (data->value[i] > *max) *max = data->value[i];
 
96
        sum += data->value[i];
 
97
    }
 
98
    return sum / data->count;
 
99
}
 
100
 
 
101
/** Turn on XSync statistic gathering and printing.  Print every \a
 
102
 * interval seconds, with lines for the first \a displays.  If \a
 
103
 * interval is NULL, 1 will be used.  If \a displays is NULL, 0 will be
 
104
 * used (meaning a line for every display will be printed).  Note that
 
105
 * this function takes string arguments because it will usually be
 
106
 * called from #ddxProcessArgument in #dmxinit.c. */
 
107
void dmxStatActivate(const char *interval, const char *displays)
 
108
{
 
109
    dmxStatInterval = (interval ? atoi(interval) : 1) * 1000;
 
110
    dmxStatDisplays = (displays ? atoi(displays) : 0);
 
111
 
 
112
    if (dmxStatInterval < 1000) dmxStatInterval = 1000;
 
113
    if (dmxStatDisplays < 0)    dmxStatDisplays = 0;
 
114
}
 
115
 
 
116
/** Allocate a \a DMXStatInfo structure. */
 
117
DMXStatInfo *dmxStatAlloc(void)
 
118
{
 
119
    DMXStatInfo *pt = malloc(sizeof(*pt));
 
120
    memset(pt, 0, sizeof(*pt));
 
121
    return pt;
 
122
}
 
123
 
 
124
/** Free the memory used by a \a DMXStatInfo structure. */
 
125
void dmxStatFree(DMXStatInfo *pt)
 
126
{
 
127
    if (pt) free(pt);
 
128
}
 
129
 
 
130
static void dmxStatValue(DMXStatAvg *data, unsigned long value)
 
131
{
 
132
    if (data->count != DMX_STAT_LENGTH) ++data->count;
 
133
    if (data->pos >= DMX_STAT_LENGTH-1) data->pos = 0;
 
134
    data->value[data->pos++] = value;
 
135
}
 
136
 
 
137
/** Note that a XSync() was just done on \a dmxScreen with the \a start
 
138
 * and \a stop times (from gettimeofday()) and the number of
 
139
 * pending-but-not-yet-processed XSync requests.  This routine is called
 
140
 * from #dmxDoSync in #dmxsync.c */
 
141
void dmxStatSync(DMXScreenInfo *dmxScreen,
 
142
                 struct timeval *stop, struct timeval *start,
 
143
                 unsigned long pending)
 
144
{
 
145
    DMXStatInfo   *s      = dmxScreen->stat;
 
146
    unsigned long elapsed = usec(stop, start);
 
147
    unsigned long thresh;
 
148
    int           i;
 
149
 
 
150
    ++s->syncCount;
 
151
    dmxStatValue(&s->usec, elapsed);
 
152
    dmxStatValue(&s->pending, pending);
 
153
    
 
154
    for (i = 0, thresh = DMX_STAT_BIN0; i < DMX_STAT_BINS-1; i++) {
 
155
        if (elapsed < thresh) {
 
156
            ++s->bins[i];
 
157
            break;
 
158
        }
 
159
        thresh *= DMX_STAT_BINMULT;
 
160
    }
 
161
    if (i == DMX_STAT_BINS-1) ++s->bins[i];
 
162
}
 
163
 
 
164
/* Actually do the work of printing out the human-readable message. */
 
165
static CARD32 dmxStatCallback(OsTimerPtr timer, CARD32 t, pointer arg)
 
166
{
 
167
    int         i, j;
 
168
    static int  header = 0;
 
169
    int         limit = dmxNumScreens;
 
170
 
 
171
    if (!dmxNumScreens) {
 
172
        header = 0;
 
173
        return DMX_STAT_INTERVAL;
 
174
    }
 
175
 
 
176
    if (!header++ || !(header % 10)) {
 
177
        dmxLog(dmxDebug,
 
178
               " S SyncCount  Sync/s avSync mxSync avPend mxPend | "
 
179
               "<10ms   <1s   >1s\n");
 
180
    }
 
181
 
 
182
    if (dmxStatDisplays && dmxStatDisplays < limit) limit = dmxStatDisplays;
 
183
    for (i = 0; i < limit; i++) {
 
184
        DMXScreenInfo *dmxScreen = &dmxScreens[i];
 
185
        DMXStatInfo   *s         = dmxScreen->stat;
 
186
        unsigned long aSync, mSync;
 
187
        unsigned long aPend, mPend;
 
188
        
 
189
        if (!s) continue;
 
190
 
 
191
        aSync = avg(&s->usec,    &mSync);
 
192
        aPend = avg(&s->pending, &mPend);
 
193
        dmxLog(dmxDebug, "%2d %9lu %7lu %6lu %6lu %6lu %6lu |",
 
194
               i,                                               /* S */
 
195
               s->syncCount,                                    /* SyncCount */
 
196
               (s->syncCount
 
197
                - s->oldSyncCount) * 1000 / dmxStatInterval,    /* Sync/s */
 
198
               aSync,                                           /* us/Sync */
 
199
               mSync,                                           /* max/Sync */
 
200
               aPend,                                           /* avgPend */
 
201
               mPend);                                          /* maxPend */
 
202
        for (j = 0; j < DMX_STAT_BINS; j++)
 
203
            dmxLogCont(dmxDebug, " %5lu", s->bins[j]);
 
204
        dmxLogCont(dmxDebug, "\n");
 
205
 
 
206
                                /* Reset/clear */
 
207
        s->oldSyncCount = s->syncCount;
 
208
        for (j = 0; j < DMX_STAT_BINS; j++) s->bins[j] = 0;
 
209
    }
 
210
    return DMX_STAT_INTERVAL;   /* Place on queue again */
 
211
}
 
212
 
 
213
/** Try to initialize the statistic gathering and printing routines.
 
214
 * Initialization only takes place if #dmxStatActivate has already been
 
215
 * called.  We don't need the same generation protection that we used in
 
216
 * dmxSyncInit because our timer is always on a queue -- hence, server
 
217
 * generation will always free it. */
 
218
void dmxStatInit(void)
 
219
{
 
220
    if (dmxStatInterval)
 
221
        dmxStatTimer = TimerSet(NULL, 0,
 
222
                                dmxStatInterval, dmxStatCallback, NULL);
 
223
}