dmxsync.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina.
  3. *
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation on the rights to use, copy, modify, merge,
  10. * publish, distribute, sublicense, and/or sell copies of the Software,
  11. * and to permit persons to whom the Software is furnished to do so,
  12. * subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial
  16. * portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
  22. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  23. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  25. * SOFTWARE.
  26. */
  27. /*
  28. * Authors:
  29. * Rickard E. (Rik) Faith <faith@redhat.com>
  30. *
  31. */
  32. /** \file
  33. *
  34. * The DMX server code is written to call #dmxSync() whenever an XSync()
  35. * might be necessary. However, since XSync() requires a two way
  36. * communication with the other X server, eliminating unnecessary
  37. * XSync() calls is a key performance optimization. Support for this
  38. * optimization is provided here. Statistics about XSync() calls and
  39. * latency are gathered in \a dmxstat.c.
  40. *
  41. * During the initial conversion from calling XSync() immediately to the
  42. * XSync() batching method implemented in this file, it was noted that,
  43. * out of more than 300 \a x11perf tests, 8 tests became more than 100
  44. * times faster, with 68 more than 50X faster, 114 more than 10X faster,
  45. * and 181 more than 2X faster. */
  46. #ifdef HAVE_DMX_CONFIG_H
  47. #include <dmx-config.h>
  48. #endif
  49. #include "dmx.h"
  50. #include "dmxsync.h"
  51. #include "dmxstat.h"
  52. #include "dmxlog.h"
  53. #include <sys/time.h>
  54. static int dmxSyncInterval = 100; /* Default interval in milliseconds */
  55. static OsTimerPtr dmxSyncTimer;
  56. static int dmxSyncPending;
  57. static void
  58. dmxDoSync(DMXScreenInfo * dmxScreen)
  59. {
  60. dmxScreen->needsSync = FALSE;
  61. if (!dmxScreen->beDisplay)
  62. return; /* FIXME: Is this correct behavior for sync stats? */
  63. if (!dmxStatInterval) {
  64. XSync(dmxScreen->beDisplay, False);
  65. }
  66. else {
  67. struct timeval start, stop;
  68. gettimeofday(&start, 0);
  69. XSync(dmxScreen->beDisplay, False);
  70. gettimeofday(&stop, 0);
  71. dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending);
  72. }
  73. }
  74. static CARD32
  75. dmxSyncCallback(OsTimerPtr timer, CARD32 time, void *arg)
  76. {
  77. int i;
  78. if (dmxSyncPending) {
  79. for (i = 0; i < dmxNumScreens; i++) {
  80. DMXScreenInfo *dmxScreen = &dmxScreens[i];
  81. if (dmxScreen->needsSync)
  82. dmxDoSync(dmxScreen);
  83. }
  84. }
  85. dmxSyncPending = 0;
  86. return 0; /* Do not place on queue again */
  87. }
  88. static void
  89. dmxSyncBlockHandler(void *blockData, OSTimePtr pTimeout, void *pReadMask)
  90. {
  91. TimerForce(dmxSyncTimer);
  92. }
  93. static void
  94. dmxSyncWakeupHandler(void *blockData, int result, void *pReadMask)
  95. {
  96. }
  97. /** Request the XSync() batching optimization with the specified \a
  98. * interval (in mS). If the \a interval is 0, 100mS is used. If the \a
  99. * interval is less than 0, then the XSync() batching optimization is
  100. * not requested (e.g., so the -syncbatch -1 command line option can
  101. * turn off the default 100mS XSync() batching).
  102. *
  103. * Note that the parameter to this routine is a string, since it will
  104. * usually be called from #ddxProcessArgument in \a dmxinit.c */
  105. void
  106. dmxSyncActivate(const char *interval)
  107. {
  108. dmxSyncInterval = (interval ? atoi(interval) : 100);
  109. if (dmxSyncInterval < 0)
  110. dmxSyncInterval = 0;
  111. }
  112. /** Initialize the XSync() batching optimization, but only if
  113. * #dmxSyncActivate was last called with a non-negative value. */
  114. void
  115. dmxSyncInit(void)
  116. {
  117. if (dmxSyncInterval) {
  118. RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler,
  119. dmxSyncWakeupHandler, NULL);
  120. dmxLog(dmxInfo, "XSync batching with %d ms interval\n",
  121. dmxSyncInterval);
  122. }
  123. else {
  124. dmxLog(dmxInfo, "XSync batching disabled\n");
  125. }
  126. }
  127. /** Request an XSync() to the display used by \a dmxScreen. If \a now
  128. * is TRUE, call XSync() immediately instead of waiting for the next
  129. * XSync() batching point. Note that if XSync() batching was deselected
  130. * with #dmxSyncActivate() before #dmxSyncInit() was called, then no
  131. * XSync() batching is performed and this function always calles XSync()
  132. * immediately.
  133. *
  134. * (Note that this function uses TimerSet but works correctly in the
  135. * face of a server generation. See the source for details.)
  136. *
  137. * If \a dmxScreen is \a NULL, then all pending syncs will be flushed
  138. * immediately.
  139. */
  140. void
  141. dmxSync(DMXScreenInfo * dmxScreen, Bool now)
  142. {
  143. static unsigned long dmxGeneration = 0;
  144. if (dmxSyncInterval) {
  145. if (dmxGeneration != serverGeneration) {
  146. /* Server generation does a TimerInit, which frees all
  147. * timers. So, at this point dmxSyncTimer is either:
  148. * 1) NULL, iff dmxGeneration == 0,
  149. * 2) freed, if it was on a queue (dmxSyncPending != 0), or
  150. * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0)
  151. */
  152. if (dmxSyncTimer && !dmxSyncPending)
  153. free(dmxSyncTimer);
  154. dmxSyncTimer = NULL;
  155. now = TRUE;
  156. dmxGeneration = serverGeneration;
  157. }
  158. /* Queue sync */
  159. if (dmxScreen) {
  160. dmxScreen->needsSync = TRUE;
  161. ++dmxSyncPending;
  162. }
  163. /* Do sync or set time for later */
  164. if (now || !dmxScreen) {
  165. if (!TimerForce(dmxSyncTimer))
  166. dmxSyncCallback(NULL, 0, NULL);
  167. /* At this point, dmxSyncPending == 0 because
  168. * dmxSyncCallback must have been called. */
  169. if (dmxSyncPending)
  170. dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n",
  171. dmxScreen ? dmxScreen->name : "", now, dmxSyncPending);
  172. }
  173. else {
  174. dmxScreen->needsSync = TRUE;
  175. if (dmxSyncPending == 1)
  176. dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval,
  177. dmxSyncCallback, NULL);
  178. }
  179. }
  180. else {
  181. /* If dmxSyncInterval is not being used,
  182. * then all the backends are already
  183. * up-to-date. */
  184. if (dmxScreen)
  185. dmxDoSync(dmxScreen);
  186. }
  187. }