summaryrefslogtreecommitdiff
path: root/ACE/ace/Monitor_Control/CPU_Load_Monitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/Monitor_Control/CPU_Load_Monitor.cpp')
-rw-r--r--ACE/ace/Monitor_Control/CPU_Load_Monitor.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/ACE/ace/Monitor_Control/CPU_Load_Monitor.cpp b/ACE/ace/Monitor_Control/CPU_Load_Monitor.cpp
new file mode 100644
index 00000000000..afede0fc5fb
--- /dev/null
+++ b/ACE/ace/Monitor_Control/CPU_Load_Monitor.cpp
@@ -0,0 +1,254 @@
+// $Id$
+
+#include "ace/Monitor_Control/CPU_Load_Monitor.h"
+
+#if defined (ACE_HAS_MONITOR_FRAMEWORK) && (ACE_HAS_MONITOR_FRAMEWORK == 1)
+
+#if defined (ACE_HAS_KSTAT)
+#include <sys/sysinfo.h>
+#endif
+
+#if defined (linux)
+#include "ace/OS_NS_stdio.h"
+#endif
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+namespace ACE
+{
+ namespace Monitor_Control
+ {
+ const char* CPU_Load_Monitor::default_name_ =
+ "OS/Processor/CPULoad";
+
+ CPU_Load_Monitor::CPU_Load_Monitor (const char* name)
+ : Monitor_Base (name, Monitor_Control_Types::MC_NUMBER)
+#if defined (ACE_HAS_WIN32_PDH)
+ , Windows_Monitor (ACE_TEXT("\\Processor(_Total)\\% Processor Time"))
+#endif
+#if defined (linux) || defined (ACE_HAS_KSTAT)
+ , user_ (0)
+ , wait_ (0)
+ , kernel_ (0)
+ , idle_ (0)
+ , prev_idle_ (0)
+ , prev_total_ (0.0)
+#endif
+#if defined (linux)
+ , file_ptr_ (0)
+#elif defined (ACE_HAS_KSTAT)
+ , kstats_ (0)
+ , kstat_ (0)
+ , kstat_id_ (0)
+#endif
+ {
+ this->init ();
+ }
+
+ void
+ CPU_Load_Monitor::update (void)
+ {
+#if defined (ACE_HAS_WIN32_PDH)
+ this->update_i ();
+ this->receive (this->value_);
+#elif defined (linux)
+ this->access_proc_stat (&this->idle_);
+#elif defined (ACE_HAS_KSTAT)
+ this->access_kstats (&this->idle_);
+#endif
+
+#if defined (linux) || defined (ACE_HAS_KSTAT)
+ double delta_idle = this->idle_ - this->prev_idle_;
+ double total =
+ this->user_ + this->wait_ + this->kernel_ + this->idle_;
+ double delta_total = total - this->prev_total_;
+
+ if (delta_total == 0.0)
+ {
+ /// The system hasn't updated /proc/stat since the last call
+ /// to update(), we must avoid dividing by 0.
+ return;
+ }
+
+ double percent_cpu_load = 100.0 - (delta_idle / delta_total * 100.0);
+
+ /// Stores value and timestamp with thread-safety.
+ this->receive (percent_cpu_load);
+
+ this->prev_idle_ = this->idle_;
+ this->prev_total_ = total;
+#endif
+ }
+
+ const char*
+ CPU_Load_Monitor::default_name (void)
+ {
+ return CPU_Load_Monitor::default_name_;
+ }
+
+ void
+ CPU_Load_Monitor::clear_i (void)
+ {
+#if defined (ACE_HAS_WIN32_PDH)
+ this->clear_impl ();
+#endif
+
+ this->init ();
+ this->Monitor_Base::clear_i ();
+ }
+
+ void
+ CPU_Load_Monitor::init (void)
+ {
+#if defined (linux)
+ /// All data in this file are stored as running 'jiffy' totals, so we
+ /// get values here in the constructor to subtract for the difference
+ /// in subsequent calls.
+ this->access_proc_stat (&this->prev_idle_);
+
+ this->prev_total_ =
+ this->user_ + this->wait_ + this->kernel_ + this->prev_idle_;
+#elif defined (ACE_HAS_KSTAT)
+ /// Stored similarly to Linux, in a system file.
+ this->access_kstats (&this->prev_idle_);
+
+ this->prev_total_ =
+ this->user_ + this->wait_ + this->kernel_ + this->prev_idle_;
+#endif
+ }
+
+#if defined (linux)
+ void
+ CPU_Load_Monitor::access_proc_stat (unsigned long *which_idle)
+ {
+ this->file_ptr_ = ACE_OS::fopen (ACE_TEXT ("/proc/stat"),
+ ACE_TEXT ("r"));
+
+ if (this->file_ptr_ == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("CPU load - opening /proc/stat failed\n")));
+ return;
+ }
+
+ char *item = 0;
+ char *arg = 0;
+
+ while ((ACE_OS::fgets (buf_, sizeof (buf_), file_ptr_)) != 0)
+ {
+ item = ACE_OS::strtok (this->buf_, " \t\n");
+ arg = ACE_OS::strtok (0, "\n");
+
+ if (item == 0 || arg == 0)
+ {
+ continue;
+ }
+
+ if (ACE_OS::strcmp (item, "cpu") == 0)
+ {
+ sscanf (arg,
+ "%lu %lu %lu %lu",
+ &this->user_,
+ &this->wait_,
+ &this->kernel_,
+ which_idle);
+ break;
+ }
+ }
+
+ ACE_OS::fclose (this->file_ptr_);
+ }
+#endif
+
+#if defined (ACE_HAS_KSTAT)
+ void
+ CPU_Load_Monitor::access_kstats (unsigned long *which_idle)
+ {
+ this->kstats_ = kstat_open ();
+
+ if (this->kstats_ == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("opening kstats file failed\n")));
+ return;
+ }
+
+ this->kstat_id_ = this->kstats_->kc_chain_id;
+
+ while (true)
+ {
+ this->kernel_ = 0UL;
+ this->wait_ = 0UL;
+ this->user_ = 0UL;
+ (*which_idle) = 0UL;
+
+ /// Unlike Linux's "/proc/stat", there is no entry for total CPU
+ /// stats, so we have to sum them manually.
+ for (this->kstat_ = this->kstats_->kc_chain;
+ this->kstat_ != 0;
+ this->kstat_ = this->kstat_->ks_next)
+ {
+ int result = ACE_OS::strncmp (this->kstat_->ks_name,
+ "cpu_stat",
+ ACE_OS::strlen ("cpu_stat"));
+
+ if (result == 0)
+ {
+ /// Because the kstat chain can change dynamically,
+ /// watch the chain ID and restart the walk if the ID
+ /// differs from what we saw during the walk. The restart
+ /// is done by breaking from the cycle with kstat_ not 0.
+
+ kid_t kstat_id = kstat_read (this->kstats_, this->kstat_, 0);
+
+ if (kstat_id != this->kstat_id_)
+ {
+ break;
+ }
+
+ cpu_stat_t &kstat_cpu =
+ *((cpu_stat_t *) this->kstat_->ks_data);
+
+ this->kernel_ += kstat_cpu.cpu_sysinfo.cpu[CPU_KERNEL];
+ this->wait_ += kstat_cpu.cpu_sysinfo.cpu[CPU_WAIT];
+ this->user_ += kstat_cpu.cpu_sysinfo.cpu[CPU_USER];
+ (*which_idle) += kstat_cpu.cpu_sysinfo.cpu[CPU_IDLE];
+ }
+ }
+
+ if (this->kstat_ != 0)
+ {
+ /// The ID changed underneath us, so get the new one and
+ /// start again.
+ this->kstat_id_ = kstat_chain_update (this->kstats_);
+
+ if (! this->kstat_id_ > 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("kstat chain update ")
+ ACE_TEXT ("returned null id\n")));
+ return;
+ }
+ }
+ else
+ {
+ /// Clean run, exit the WHILE loop.
+ break;
+ }
+ }
+
+ int status = kstat_close (this->kstats_);
+
+ if (status != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("closing kstats file failed\n")));
+ }
+ }
+#endif
+ }
+}
+
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+#endif /* ACE_HAS_MONITOR_FRAMEWORK==1 */