From 602f34de072ce7e7cdbcb8a50d2b4e2cfe4416a5 Mon Sep 17 00:00:00 2001 From: Constantin Kaplinsky Date: Wed, 14 Sep 2005 16:11:41 +0000 Subject: [PATCH] CPU load monitoring has been implemented in x0vncserver. CPU load 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 | 102 ++++++++++++++++++++++++++++++++++++ x0vncserver/CPUMonitor.h | 77 +++++++++++++++++++++++++++ x0vncserver/Makefile.in | 2 +- x0vncserver/x0vncserver.cxx | 34 ++++++++++-- 4 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 x0vncserver/CPUMonitor.cxx create mode 100644 x0vncserver/CPUMonitor.h diff --git a/x0vncserver/CPUMonitor.cxx b/x0vncserver/CPUMonitor.cxx new file mode 100644 index 00000000..e5298bcf --- /dev/null +++ b/x0vncserver/CPUMonitor.cxx @@ -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 index 00000000..d1165c86 --- /dev/null +++ b/x0vncserver/CPUMonitor.h @@ -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 +#include + +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__ diff --git a/x0vncserver/Makefile.in b/x0vncserver/Makefile.in index 2379ec0a..57d6f22e 100644 --- a/x0vncserver/Makefile.in +++ b/x0vncserver/Makefile.in @@ -1,5 +1,5 @@ -SRCS = Image.cxx x0vncserver.cxx +SRCS = Image.cxx CPUMonitor.cxx x0vncserver.cxx OBJS = $(SRCS:.cxx=.o) diff --git a/x0vncserver/x0vncserver.cxx b/x0vncserver/x0vncserver.cxx index ca96fd7c..f429553a 100644 --- a/x0vncserver/x0vncserver.cxx +++ b/x0vncserver/x0vncserver.cxx @@ -35,6 +35,8 @@ #include #include "Image.h" +#include "CPUMonitor.h" + #include #include #include @@ -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 { -- 2.39.5