]> source.dussan.org Git - tigervnc.git/commitdiff
CPU load monitoring has been implemented in x0vncserver. CPU load
authorConstantin Kaplinsky <const@tightvnc.com>
Wed, 14 Sep 2005 16:11:41 +0000 (16:11 +0000)
committerConstantin Kaplinsky <const@tightvnc.com>
Wed, 14 Sep 2005 16:11:41 +0000 (16:11 +0000)
setting defaults to 35% but can be adjusted with new
-MaxProcessorUsage parameter.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@319 3789f03b-4d11-0410-bbf8-ca57d06f2519

x0vncserver/CPUMonitor.cxx [new file with mode: 0644]
x0vncserver/CPUMonitor.h [new file with mode: 0644]
x0vncserver/Makefile.in
x0vncserver/x0vncserver.cxx

diff --git a/x0vncserver/CPUMonitor.cxx b/x0vncserver/CPUMonitor.cxx
new file mode 100644 (file)
index 0000000..e5298bc
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright (C) 2005 Constantin Kaplinsky.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// CPUMonitor.cxx
+//
+
+#include "CPUMonitor.h"
+
+CPUMonitor::CPUMonitor(int optimalLevel, int updatePeriod)
+{
+  setLevel(optimalLevel);
+  setPeriod(updatePeriod);
+  update();
+}
+
+void CPUMonitor::setLevel(int optimalLevel)
+{
+  m_optimalLevel = optimalLevel;
+  if (m_optimalLevel < 0) {
+    m_optimalLevel = 0;
+  } else if (m_optimalLevel > 100) {
+    m_optimalLevel = 100;
+  }
+}
+
+void CPUMonitor::setPeriod(int updatePeriod)
+{
+  m_updatePeriod = (updatePeriod > 10) ? updatePeriod : 10;
+}
+
+void CPUMonitor::update()
+{
+  getClock(&m_savedTime, &m_savedClock);
+}
+
+int CPUMonitor::check()
+{
+  struct timeval timeNow;
+  clock_t clockNow;
+  getClock(&timeNow, &clockNow);
+
+  int coeff = 100;              // 100% means no changes.
+
+  if (m_savedClock != (clock_t)-1 && clockNow != (clock_t)-1) {
+
+    // Find out how much real time has been elapsed (in milliseconds).
+    int timeDiff = (int)((timeNow.tv_usec - m_savedTime.tv_usec + 500) / 1000 +
+                         (timeNow.tv_sec - m_savedTime.tv_sec) * 1000);
+    if (timeDiff < m_updatePeriod) {
+      // Measuring CPU usage is problematic in this case. So return
+      // 100 and do not update saved time and clock numbers.
+      return coeff;
+    }
+
+    // Calculate how much processor time has been consumed (in milliseconds).
+    unsigned int clockDiff = (unsigned int)(clockNow - m_savedClock);
+    clockDiff /= (CLOCKS_PER_SEC / 1000);
+
+    // Get actual CPU usage and convert optimal level (to 1/1000).
+    int realUsage = (clockDiff * 1000 + timeDiff/2) / timeDiff;
+    int optimalUsage = m_optimalLevel * 10;
+
+    // Compute correction coefficient (in percents).
+    if (realUsage != 0) {
+      coeff = (optimalUsage * 100 + realUsage/2) / realUsage;
+    } else {
+      coeff = 10000;
+    }
+
+  }
+
+  // Update saved time and clock numbers.
+  m_savedTime = timeNow;
+  m_savedClock = clockNow;
+
+  return coeff;
+}
+
+void CPUMonitor::getClock(struct timeval *tv, clock_t *clk)
+{
+  if (gettimeofday(tv, NULL) != 0) {
+    *clk = (clock_t)-1;
+  } else {
+    *clk = clock();
+  }
+}
diff --git a/x0vncserver/CPUMonitor.h b/x0vncserver/CPUMonitor.h
new file mode 100644 (file)
index 0000000..d1165c8
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 2005 Constantin Kaplinsky.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// CPUMonitor.h
+//
+
+#ifndef __CPUMONITOR_H__
+#define __CPUMONITOR_H__
+
+#include <sys/time.h>
+#include <time.h>
+
+class CPUMonitor {
+
+public:
+
+  CPUMonitor(int optimalLevel = 50, int updatePeriod = 1000);
+
+  //
+  // Optimal level is the CPU utilization level to maintain, in
+  // percents.
+  //
+  void setLevel(int optimalLevel);
+
+  //
+  // Update period is the minimum time in milliseconds that has to
+  // pass after update() or check() call, before next check() call
+  // will return meaningful value.
+  //
+  void setPeriod(int updatePeriod);
+
+  //
+  // Save current time and CPU clock, to use in the next check() call.
+  //
+  void update();
+
+  //
+  // This method calculates recent CPU utilization and returns a
+  // percentage factor which would convert current CPU usage into the
+  // optimal value. For example, if the optimal level was set to 40%
+  // and the real value was 50%, the function will return 80, because
+  // 50 * 80% == 40.
+  //
+  // If the CPU utilization cannot be measured, this function returns
+  // 100. This may be the case on the first call to check(), or if the
+  // time period between two successive check() calls was too small.
+  //
+  int check();
+
+protected:
+
+  static void getClock(struct timeval *tv, clock_t *clk);
+
+  int m_optimalLevel;
+  int m_updatePeriod;
+  struct timeval m_savedTime;
+  clock_t m_savedClock;
+
+};
+
+#endif // __CPUMONITOR_H__
index 2379ec0a8dcc0299a7ce8cdfbbfa84f04e57d580..57d6f22ec82d06a35aea093ed788c536a153a190 100644 (file)
@@ -1,5 +1,5 @@
 
-SRCS = Image.cxx x0vncserver.cxx
+SRCS = Image.cxx CPUMonitor.cxx x0vncserver.cxx
 
 OBJS = $(SRCS:.cxx=.o)
 
index ca96fd7c75fefc9053b2b05574e55a3c8c05f707..f429553a3532041c5a1b20f80321e534d351dce6 100644 (file)
@@ -35,6 +35,8 @@
 #include <network/TcpSocket.h>
 
 #include "Image.h"
+#include "CPUMonitor.h"
+
 #include <signal.h>
 #include <X11/X.h>
 #include <X11/Xlib.h>
@@ -51,8 +53,11 @@ using namespace network;
 
 LogWriter vlog("main");
 
-IntParameter pollingCycle("PollingCycle", "Milliseconds per one "
-                          "polling cycle", 50);
+IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
+                          "cycle; actual interval may be dynamically "
+                          "adjusted to satisfy MaxProcessorUsage setting", 50);
+IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of "
+                               "CPU time to be consumed", 35);
 BoolParameter useShm("UseSHM", "Use MIT-SHM extension if available", true);
 BoolParameter useOverlay("OverlayMode", "Use overlay mode under "
                          "IRIX or Solaris", true);
@@ -444,6 +449,9 @@ int main(int argc, char** argv)
     if (strlen(hostsFile.getData()) != 0)
       listener.setFilter(&fileTcpFilter);
 
+    CPUMonitor cpumon((int)maxProcessorUsage, 1000);
+    int dynPollingCycle = (int)pollingCycle;
+
     struct timeval timeSaved, timeNow;
     struct timezone tz;
     gettimeofday(&timeSaved, &tz);
@@ -454,7 +462,10 @@ int main(int argc, char** argv)
       struct timeval tv;
 
       tv.tv_sec = 0;
-      tv.tv_usec = (int)pollingCycle * 1000;
+      tv.tv_usec = dynPollingCycle * 1000;
+      if (tv.tv_usec > 500000) {
+        tv.tv_usec = 500000;
+      }
 
       FD_ZERO(&rfds);
       FD_SET(listener.getFd(), &rfds);
@@ -480,6 +491,7 @@ int main(int argc, char** argv)
         Socket* sock = listener.accept();
         if (sock) {
           server.addClient(sock);
+          cpumon.update();      // count time from now
         } else {
           vlog.status("Client connection rejected");
         }
@@ -502,8 +514,22 @@ int main(int argc, char** argv)
       if (gettimeofday(&timeNow, &tz) == 0) {
         int diff = (int)((timeNow.tv_usec - timeSaved.tv_usec + 500) / 1000 +
                          (timeNow.tv_sec - timeSaved.tv_sec) * 1000);
-        if (diff >= (int)pollingCycle) {
+        if (diff >= dynPollingCycle) {
           timeSaved = timeNow;
+          int coeff = cpumon.check();
+          if (coeff < 90 || coeff > 110) {
+            // Adjust polling cycle to satisfy MaxProcessorUsage setting
+            dynPollingCycle = (dynPollingCycle * 100 + coeff/2) / coeff;
+            if (dynPollingCycle < (int)pollingCycle) {
+              dynPollingCycle = (int)pollingCycle;
+            } else if (dynPollingCycle > (int)pollingCycle * 32) {
+              dynPollingCycle = (int)pollingCycle * 32;
+            }
+            // DEBUG:
+            // if (dynPollingCycle != old) {
+            //   fprintf(stderr, "[%dms]\t", dynPollingCycle);
+            // }
+          }
           desktop.poll();
         }
       } else {