/* $Xorg: lbxutil.c,v 1.4 2000/08/17 19:53:55 cpqbld Exp $ */ /* * Copyright 1994 Network Computing Devices, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name Network Computing Devices, Inc. not be * used in advertising or publicity pertaining to distribution of this * software without specific, written prior permission. * * THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC., * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA, * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* $XFree86$ */ /* * utility routines for LBX requests */ #include #include "misc.h" #include "assert.h" #include "lbxproxy.h" #include "util.h" #include "tags.h" #include "resource.h" #include "wire.h" #include "swap.h" #include "colormap.h" #include "lbxext.h" Bool compStats = FALSE; /* report stream compression statistics */ #ifdef DEBUG extern int lbxDebug; #endif extern int lbxMaxMotionEvents; ReplyStuffPtr NewReply(ClientPtr client, int major, int minor, ReplyFunc reply_func) { ReplyStuffPtr new, *end; new = (ReplyStuffPtr) xalloc(sizeof(ReplyStuffRec)); if (!new) return new; new->sequenceNumber = LBXSequenceNumber(client); new->major = major; new->minor = minor; new->reply_func = reply_func; new->next = NULL; end = &LBXReplyList(client); while (*end) end = &(*end)->next; *end = new; return new; } void RemoveReply(ClientPtr client, ReplyStuffPtr rp) { ReplyStuffPtr cur, *prev; prev = &LBXReplyList(client); while ((cur = *prev) != rp) prev = &cur->next; *prev = cur->next; if (cur->major == client->server->lbxReq) { if (CacheTrimNeeded(client->server, client->server->global_cache) && !AnyTagBearingReplies(client->server, client->server->global_cache)) CacheTrim(client->server, client->server->global_cache); if (CacheTrimNeeded(client->server, client->server->prop_cache) && !AnyTagBearingReplies(client->server, client->server->prop_cache)) CacheTrim(client->server, client->server->prop_cache); } xfree(cur); } ReplyStuffPtr GetMatchingReply(ClientPtr client, int seqno, Bool flush_older) { ReplyStuffPtr t, old; seqno &= 0xffff; for (t = LBXReplyList(client); t; t = t->next) { if ((t->sequenceNumber & 0xffff) == seqno) break; } #ifdef SEQ_DEBUG if (t) fprintf(stderr, "matched reply for seq 0x%x\n", seqno); else fprintf(stderr, "no reply for seq 0x%x\n", seqno); #endif if (t && flush_older) { while ((old = LBXReplyList(client)) != t) { fprintf(stderr, "unclaimed reply: maj %d min %d seq 0x%x curseq 0x%x\n", old->major, old->minor, old->sequenceNumber, seqno); LBXReplyList(client) = old->next; xfree(old); } } return t; } Bool AnyReplies(ClientPtr client) { return (LBXReplyList(client) != NULL); } Bool AnyTagBearingReplies(XServerPtr server, Cache cache) { int i; int lbxreq; ReplyStuffPtr t; Bool found = FALSE; /* assume this is called while a reply is being processed, so need two */ for (i = 1; i < currentMaxClients; i++) { if (!clients[i]) continue; lbxreq = clients[i]->server->lbxReq; for (t = LBXReplyList(clients[i]); t; t = t->next) { if (t->major == lbxreq) { switch (t->minor) { case X_LbxGetModifierMapping: case X_LbxGetKeyboardMapping: case X_LbxQueryFont: if (cache == server->global_cache) { if (found) return TRUE; found = TRUE; } break; case X_LbxGetProperty: if (cache == server->prop_cache) { if (found) return TRUE; found = TRUE; } break; } } } } return FALSE; } /* * this is used for stashing short-circuited replies for later. * it currently assumes that all of them will be 32 bytes for the reply * plus some amount of extra data */ Bool SaveReplyData(ClientPtr client, xReply *rep, int len, pointer data) { ReplyDataPtr new, *end; new = (ReplyDataPtr) xalloc(sizeof(ReplyDataRec)); if (!new) return FALSE; if (len) { new->data = (pointer) xalloc(len); if (!new->data) { xfree(new); return FALSE; } else { memcpy((char *) new->data, (char *) data, len); } } new->reply = *rep; new->dlen = len; new->delay_seq_no = LBXSequenceNumber(client); new->next = NULL; end = &LBXReplyData(client); while (*end) end = &(*end)->next; *end = new; #ifdef SEQ_DEBUG fprintf(stderr, "saving reply seq 0x%x\n", LBXSequenceNumber(client)); #endif return TRUE; } Bool FlushDelayedReplies(ClientPtr client) { ReplyDataPtr *prev, cur; #ifdef SEQ_DEBUG fprintf(stderr, "flushing replies seq 0x%x:", LBXLastResponse(client)); #endif for (prev = &LBXReplyData(client); (cur = *prev); ) { #ifdef SEQ_DEBUG fprintf(stderr, " 0x%x", cur->delay_seq_no); #endif if ((cur->delay_seq_no & 0xffff) == LBXLastResponse(client) + 1) { WriteToClient(client, sizeof(xReply), (char *) &cur->reply); if (cur->dlen) WriteToClient(client, cur->dlen, (char *) cur->data); LBXLastResponse(client) = cur->delay_seq_no; *prev = cur->next; xfree(cur); } else prev = &cur->next; } #ifdef SEQ_DEBUG fprintf(stderr, "\n"); #endif return TRUE; } void BumpSequence(ClientPtr client) { DBG(DBG_CLIENT, (stderr, "bumping client %d sequence by %d to %d\n", client->index, LBXSequenceLost(client), LBXSequenceNumber(client))); ModifySequence(client, LBXSequenceLost(client)); LBXSequenceLost(client) = 0; } void ForceSequenceUpdate(ClientPtr client) { if (LBXSequenceLost(client)) { BumpSequence(client); } } void LbxFreeTag(XServerPtr server, XID tag, int tagtype) { Cache tag_cache; switch (tagtype) { case LbxTagTypeProperty: tag_cache = server->prop_cache; break; case LbxTagTypeFont: case LbxTagTypeModmap: case LbxTagTypeKeymap: case LbxTagTypeConnInfo: tag_cache = server->global_cache; break; default: fprintf(stderr, "unknown type in InvalidateTag request: tag 0x%lx type %d\n", (long)tag, tagtype); return; } TagFreeData(server, tag_cache, tag, TRUE); } void LbxSendTagData(ClientPtr client, XID tag, int tagtype) { TagData td; unsigned long len; pointer tdata; PropertyTagDataPtr ptdp; if (tagtype == LbxTagTypeProperty && (td = TagGetTag(client->server, client->server->prop_cache, tag))) { ptdp = (PropertyTagDataPtr) td->tdata; tdata = ptdp->data; len = ptdp->length; } else { fprintf(stderr, "invalid SendTagData request: tag 0x%lx type %d\n", (long)tag, tagtype); len = 0; tdata = NULL; } SendTagData(client, tag, len, tdata); } extern unsigned long stream_out_compressed; extern unsigned long stream_out_uncompressed; extern unsigned long stream_out_plain; extern unsigned long stream_in_compressed; extern unsigned long stream_in_uncompressed; extern unsigned long stream_in_plain; extern unsigned long raw_stream_out; extern unsigned long raw_stream_in; void DumpCompressionStats(void) { if (raw_stream_out && stream_out_plain) { fprintf(stderr, "Requests: normal = %ld, reencoded = %ld", (long)raw_stream_out, (long)stream_out_plain); stream_out_compressed += stream_out_uncompressed; if (stream_out_compressed) fprintf(stderr, ", compressed = %ld", (long)stream_out_compressed); else stream_out_compressed = stream_out_plain; fprintf(stderr, "\n %.2f:1 overall reduction ratio\n", (float)raw_stream_out / (float)stream_out_compressed); } if (raw_stream_in && stream_in_plain) { fprintf(stderr, "Responses: normal = %ld, reencoded = %ld", (long)raw_stream_in, (long)stream_in_plain); stream_in_compressed += stream_in_uncompressed; if (stream_in_compressed) fprintf(stderr, ", compressed = %ld", (long)stream_in_compressed); else stream_in_compressed = stream_in_plain; fprintf(stderr, "\n %.2f:1 overall reduction ratio\n", (float)raw_stream_in / (float)stream_in_compressed); } } void ZeroCompressionStats(void) { stream_out_compressed = 0; stream_out_uncompressed = 0; stream_out_plain = 0; stream_in_compressed = 0; stream_in_uncompressed = 0; stream_in_plain = 0; raw_stream_out = 0; raw_stream_in = 0; } #ifdef LBX_STATS int intern_good, intern_miss; int getatom_good, getatom_miss; int luc_good, luc_miss; int ac_good, ac_miss; int anc_good, anc_miss; int getmodmap_tag, /* tag only */ getmodmap_full; int getkeymap_tag, /* tag only */ getkeymap_full; int queryfont_tag, /* tag only */ queryfont_full; int getsetup_tag, /* tag only */ getsetup_full; int getprop_tag, getprop_full; int tag_bytes_unsent; /* approx data kept off wire by tags */ int delta_out_total; int delta_out_attempts; int delta_out_hits; int delta_in_total; int delta_in_attempts; int delta_in_hits; void DumpOtherStats(void) { fprintf(stderr, "Short-circuit stats\n"); fprintf(stderr, "InternAtom cache hits %d misses %d\n", intern_good, intern_miss); fprintf(stderr, "GetAtomName cache hits %d misses %d\n", getatom_good, getatom_miss); fprintf(stderr, "LookupColor cache hits %d misses %d\n", luc_good, luc_miss); fprintf(stderr, "AllocColor cache hits %d misses %d\n", ac_good, ac_miss); fprintf(stderr, "AllocNamedColor cache hits %d misses %d\n", anc_good, anc_miss); fprintf(stderr, "Tag stats\n"); fprintf(stderr, "GetModifierMapping used tag %d, full data %d\n", getmodmap_tag, getmodmap_full); fprintf(stderr, "GetKeyboardMapping used tag %d, full data %d\n", getkeymap_tag, getkeymap_full); fprintf(stderr, "QueryFont used tag %d, full data %d\n", queryfont_tag, queryfont_full); fprintf(stderr, "GetProperty used tag %d, full data %d\n", getprop_tag, getprop_full); fprintf(stderr, "ConnectionSetup used tag %d, full data %d\n", getsetup_tag, getsetup_full); fprintf(stderr, "Approx bytes kept off wire by tags %d\n", tag_bytes_unsent); fprintf(stderr, "Delta Compressor stats\n"); fprintf(stderr, "Sent: total msgs = %d, cacheable = %d, cache hits = %d\n", delta_out_total, delta_out_attempts, delta_out_hits); fprintf(stderr, "Received: total = %d, cacheable = %d, cache hits = %d\n", delta_in_total, delta_in_attempts, delta_in_hits); fprintf(stderr, "GFX Cache stats\n"); fprintf(stderr, "Reencoded = %d\n", gfx_total); #define percent(s,t) ((t) ? ((s) * 100) / (t) : 0) #define ratios(h,m) (h), percent (h, (h)+(m)), (m), percent (m, (h) + (m)) fprintf(stderr, "Draw hit = %d (%d%%) miss = %d (%d%%) GC hit = %d (%d%%) miss = %d (%d%%)\n", ratios (gfx_draw_hit, gfx_draw_miss), ratios (gfx_gc_hit, gfx_gc_miss)); #define savings(h,m) (((h) + (m)) * 4) - ((h) + (m) * 5) fprintf(stderr, "Total bytes saved = %d Draw = %d GC = %d\n", savings (gfx_gc_hit + gfx_draw_hit, gfx_gc_miss + gfx_draw_miss), savings (gfx_draw_hit, gfx_draw_miss), savings (gfx_gc_hit, gfx_gc_miss)); } void ZeroOtherStats(void) { intern_good = intern_miss = 0; getatom_good = getatom_miss = 0; luc_good = luc_miss = 0; ac_good = ac_miss = 0; anc_good = anc_miss = 0; getmodmap_tag = 0; getmodmap_full = 0; getkeymap_tag = 0; getkeymap_full = 0; getprop_tag = 0; getprop_full = 0; getsetup_tag = 0; getsetup_full = 0; delta_out_total = delta_out_attempts = delta_out_hits = 0; delta_in_total = delta_in_attempts = delta_in_hits = 0; gfx_gc_hit = 0; gfx_gc_miss = 0; gfx_draw_hit = 0; gfx_draw_miss = 0; gfx_total = 0; } #endif void SendInitLBXPackets(XServerPtr server) { ZeroCompressionStats(); #ifdef LBX_STATS ZeroOtherStats(); #endif AllowMotion(server->serverClient, lbxMaxMotionEvents); } void LbxCleanupSession(void) { if (compStats) { DumpCompressionStats(); ZeroCompressionStats(); } #ifdef LBX_STATS DumpOtherStats(); ZeroOtherStats(); #endif }