Utils
authorJustin Dickow <jjdickow@gmail.com>
Wed, 23 Jul 2014 15:15:00 +0000 (11:15 -0400)
committerJustin Dickow <jjdickow@gmail.com>
Wed, 23 Jul 2014 15:15:00 +0000 (11:15 -0400)
Authors:

Alexander Kutsan
Dmitriy Klimenko
Dmitriy Trunov
Dmitry Chmerev
Igor Kozyrenko
Nikita Vaganov
Vladislav Smenyuk

Signed-off-by: Justin Dickow <jjdickow@gmail.com>
src/components/utils/CMakeLists.txt
src/components/utils/include/utils/resource_usage.h [new file with mode: 0644]
src/components/utils/include/utils/system.h [new file with mode: 0644]
src/components/utils/src/resource_usage.cc [new file with mode: 0644]
src/components/utils/src/system.cc [new file with mode: 0644]

index e3a7eb8..345358f 100644 (file)
@@ -15,6 +15,8 @@ set (SOURCES
     ./src/lock_posix.cc
     ./src/date_time.cc
     ./src/signals_linux.cc
+    ./src/system.cc
+    ./src/resource_usage.cc
 )
 
 if (BUILD_BACKTRACE_SUPPORT)
@@ -38,6 +40,7 @@ else()
 endif()
 
 if(ENABLE_LOG)
-  target_link_libraries("Utils" log4cxx)
+  add_dependencies("Utils" liblog4cxx)
+  target_link_libraries("Utils" log4cxx -L${LOG4CXX_LIBS_DIRECTORY})
 endif()
 
diff --git a/src/components/utils/include/utils/resource_usage.h b/src/components/utils/include/utils/resource_usage.h
new file mode 100644 (file)
index 0000000..a8fa4aa
--- /dev/null
@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2014, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RESOURCE_USAGE_H_
+#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RESOURCE_USAGE_H_
+
+#include <sys/resource.h>
+#if defined(__QNXNTO__)
+#include <sys/procfs.h>
+#endif
+
+#include <string>
+#include <iostream>
+
+#include "utils/logger.h"
+
+#define MAX_COMM_LEN   128
+#define MAX_CMDLINE_LEN        128
+
+namespace utils {
+
+struct ResourseUsage {
+  long long int utime;
+  long long int stime;
+  long long int memory;
+};
+
+class Resources {
+  public:
+  typedef uint32_t MemInfo;
+#if defined(__QNXNTO__)
+  typedef procfs_info PidStats;
+
+#elif defined(OS_LINUX)
+
+  struct PidStats {
+    int pid;
+    char comm[MAX_COMM_LEN];
+    char state;
+    int ppid;
+    int pgrp;
+    int session;
+    int tty_nr;
+    int tpgid;
+    unsigned int flags;
+    unsigned long minflt;
+    unsigned long cminflt;
+    unsigned long majflt;
+    unsigned long cmajflt;
+    unsigned long utime;
+    long stime;
+    long cutime;
+    long cstime;
+    long priority;
+    long nice;
+    long num_threads;
+    long itrealvalue;
+    unsigned long long starttime;
+    unsigned long vsize;
+    long rss;
+    unsigned long rsslim;
+    unsigned long startcode;
+    unsigned long endcode;
+    unsigned long startstack;
+    unsigned long kstkesp;
+    unsigned long kstkeip;
+    unsigned long signal;
+    unsigned long blocked;
+    unsigned long sigignore;
+    unsigned long sigcatch;
+    unsigned long wchan;
+    unsigned long nswap;
+    unsigned long cnswap;
+    int exit_signal;
+    int processor;
+    unsigned int rt_priority;
+    unsigned int policy;
+    unsigned long long delayacct_blkio_ticks;
+    unsigned long guest_time;
+    long int cguest_time;
+    };
+#else
+
+#endif
+  public:
+    /*
+     * @brief Returns current resource usage of process
+     * @return Raw pointer on  ResourseUsage if success, otherwise return NULL
+     */
+  static ResourseUsage* getCurrentResourseUsage();
+
+private:
+
+  /*
+   * @brief reads /proc/PID/stat file on linux
+   *        do not work on QNX ( return false, output wan't be changed )
+   * @param output - storage for result string ( there will be separated content of /proc/PID/stat )
+   * @return true on succes false onb fail
+   */
+  static bool ReadStatFile(std::string& output);
+
+  /*
+   * @brief Grab information about curent process
+   * @param output - storage for result struct
+   * @return true on succes false onb fail
+   */
+  static bool GetProcInfo(PidStats& output);
+
+  /*
+   * @brief Grab process memory information
+   * @param output - storage for result struct
+   * @return true on succes false onb fail
+   */
+  static bool GetMemInfo(MemInfo& output);
+
+  /*
+   * @brief return path to /proc/PID/stat file on linux
+   *        return path to /proc/PID/as file on linux
+   * @return path to file
+   */
+  static std::string GetStatPath();
+
+  /*
+   * @brief return path to /proc/PID directry
+   * @return path to dir
+   */
+  static std::string GetProcPath();
+
+  /*
+   * path to /proc/ directory
+   */
+  static const char* proc;
+};
+
+}
+
+
+
+#endif /* SRC_COMPONENTS_UTILS_INCLUDE_UTILS_RESOURCE_USAGE_H_ */
diff --git a/src/components/utils/include/utils/system.h b/src/components/utils/include/utils/system.h
new file mode 100644 (file)
index 0000000..16bdc03
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2014, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_H_
+#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_H_
+
+#include <string>
+#include <vector>
+
+namespace utils {
+
+/**
+ * Class to execute shell scripts
+ */
+class System {
+ public:
+  /**
+   * Constructs instantiation
+   * @param command name of command for executing
+   */
+  explicit System(const std::string& command);
+
+  /**
+   * Constructs instantiation
+   * @param file name of file for executing
+   * @param command name of command
+   */
+  System(const std::string& file, const std::string& command);
+
+  /**
+   * Adds argument
+   * @param arg argument of command
+   * @return itself object
+   */
+  System& Add(const std::string& arg);
+
+  /**
+   * Executes command as new child process
+   * @return true if success
+   */
+  bool Execute();
+
+  /**
+   * Executes command
+   * @param wait if this flag is true then wait until command is terminated
+   * @return true if success
+   */
+  bool Execute(bool wait);
+
+ private:
+  /**
+   * Command for executing
+   */
+  std::string command_;
+
+  /**
+   * List of arguments
+   */
+  std::vector<std::string> argv_;
+};
+
+}  // utils
+
+#endif  // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_H_
diff --git a/src/components/utils/src/resource_usage.cc b/src/components/utils/src/resource_usage.cc
new file mode 100644 (file)
index 0000000..70bda2b
--- /dev/null
@@ -0,0 +1,192 @@
+#include "utils/resource_usage.h"
+#if defined(__QNXNTO__)
+#include <dirent.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/neutrino.h>
+#include <sys/procfs.h>
+#include <sys/stat.h>
+#include <sys/trace.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <sys/resource.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sstream>
+#include "utils/file_system.h"
+
+namespace utils {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "Utils")
+
+const char* Resources::proc = "/proc/";
+
+ResourseUsage* Resources::getCurrentResourseUsage() {
+  PidStats pid_stats;
+  if (false == GetProcInfo(pid_stats)) {
+    LOG4CXX_ERROR(logger_, "Failed to get cpu proc info");
+    return NULL;
+  }
+  MemInfo mem_info;
+  if (false == GetMemInfo(mem_info)) {
+    LOG4CXX_ERROR(logger_, "Failed to get memory info");
+    return NULL;
+  }
+  ResourseUsage* usage = new ResourseUsage();
+  usage->utime = pid_stats.utime;
+  usage->stime = pid_stats.stime;
+  usage->memory = static_cast<long long int>(mem_info);
+  return usage;
+}
+
+bool Resources::ReadStatFile(std::string& output) {
+  std::string filename = GetStatPath();
+  if (false == file_system::FileExists(filename)) {
+    return false;
+  }
+  if (false == file_system::ReadFile(filename,output)) {
+    return false;
+  }
+  return true;
+}
+
+bool Resources::GetProcInfo(Resources::PidStats& output) {
+#if defined(OS_LINUX)
+  std::string proc_buf;
+  if (false == ReadStatFile(proc_buf)) {
+    return false;
+  }
+  uint32_t num_succes = sscanf(proc_buf.c_str(),
+         "%d" //pid
+         " %*s"//com
+         " %c" //state
+         " %d" //ppid
+         " %d" //pgrp
+         " %d" //session
+         " %d" //tty_nr
+         " %d" //tpgid
+         " %u" //flags
+         " %lu" //minflt
+         " %lu" //cminflt
+         " %lu" //majflt
+         " %lu" //cmajflt
+         " %lu" //utime
+         " %lu" //stime
+         " %ld" //cutime
+         " %ld" //cstime
+         " %ld" //priority
+         " %ld" //nice
+         " %ld" //num_threads
+         " %ld" //itrealvalue
+         " %llu" //starttime
+         " %lu" //vsize
+         " %ld" //rss
+         " %lu" //rsslim
+         " %lu" //startcode
+         " %lu" //endcode
+         " %lu" //startstack
+         " %lu" //kstkesp
+         " %lu" //kstkip
+         " %lu" //signal
+         " %lu" //blocked
+         " %lu" //sigignore
+         " %lu" //sigcatch
+         " %lu" //wchan
+         " %lu" //nswap
+         " %lu" //cnswap
+         " %d" //exit_signal
+         " %d" //processor
+         " %u" //rt_priority
+         " %u" //policy
+         " %llu" //delayacct_blkio_ticks
+         " %lu" //guest_time
+         " %ld" //cguest_time
+         ,&(output.pid), &(output.state), &(output.ppid), &(output.pgrp), &(output.session),
+         &(output.tty_nr), &(output.tpgid), &(output.flags), &(output.minflt), &(output.cminflt),
+         &(output.majflt), &(output.cmajflt), &(output.utime), &(output.stime), &(output.cutime),
+         &(output.cstime), &(output.priority), &( output.nice), &(output.num_threads), &(output.itrealvalue),
+         &(output.starttime), &(output.vsize), &(output.rss), &(output.rsslim), &(output.startcode),
+         &(output.endcode), &(output.startstack), &(output.kstkesp), &(output.kstkeip), &(output.signal),
+         &(output.blocked), &(output.sigignore), &(output.sigcatch), &(output.wchan), &(output.nswap),
+         &(output.cnswap), &(output.exit_signal), &(output.processor), &(output.rt_priority), &(output.policy),
+         &(output.delayacct_blkio_ticks), &(output.guest_time), &(output.cguest_time)
+  );
+  if(num_succes != 43) { // 43 is number of iteams in Resources::PidStats
+    LOG4CXX_ERROR(logger_, "Couldn't parse all iteams in /proc/PID/stat file");
+    return false;
+  }
+  return true;
+#elif defined(__QNXNTO__)
+  int fd = open(GetProcPath().c_str(), O_RDONLY);
+  if (0 >= fd) {
+    LOG4CXX_ERROR(logger_, "Failed open process proc file : " << GetProcPath() <<
+                  "; error no : " << strerror( errno ) );
+    return false;
+  }
+  devctl(fd, DCMD_PROC_INFO, &output, sizeof(output), 0);
+  close(fd);
+  return true;
+#endif
+}
+
+bool Resources::GetMemInfo(Resources::MemInfo &output) {
+  bool result = false;
+  #if defined(OS_LINUX)
+  Resources::PidStats pid_stat;
+  if (false == GetProcInfo(pid_stat)) {
+    LOG4CXX_ERROR(logger_, "Failed to get proc info");
+    result = false;
+  } else {
+    output = pid_stat.rss;
+    result = true;
+  }
+
+#elif defined(__QNXNTO__)
+  std::string as_path = GetStatPath();
+  struct stat st;
+  struct _dir* proc_dir = 0;
+  struct dirent* proc_entry = 0;
+  if (0 == (proc_dir = opendir(proc))) {
+    LOG4CXX_ERROR(logger_, "Unable to access to " << proc);
+    result = false;
+    return result;
+  }  
+  if (0 == (proc_entry = readdir(proc_dir))) {
+    LOG4CXX_ERROR(logger_, "Unable to read : " << proc_dir);
+    result = false;
+    return result;
+  }
+  closedir(proc_dir);
+  if (-1 == stat(as_path.c_str(), &st) || 0 == st.st_size) {
+     LOG4CXX_ERROR(logger_, "Unable to stat : " << as_path.c_str());
+     result = false;
+     return result;
+  }
+  output = st.st_size;
+  result = true;
+#endif
+  return result;
+}
+
+std::string Resources::GetStatPath() {
+  std::string filename;
+#if defined(OS_LINUX)
+  filename = GetProcPath() + "/stat";
+#elif defined(__QNXNTO__)
+  filename = GetProcPath() + "/as";
+#endif
+  return filename;
+}
+
+std::string Resources::GetProcPath() {
+  char buffer[1024];
+  pid_t my_pid = getpid();
+  snprintf(buffer, sizeof(buffer), "%s%d/", proc , my_pid);
+  std::string filename(buffer);
+  return filename;
+}
+
+} // namespace utils
diff --git a/src/components/utils/src/system.cc b/src/components/utils/src/system.cc
new file mode 100644 (file)
index 0000000..fbba24c
--- /dev/null
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2014, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "utils/system.h"
+
+#ifdef __QNX__
+#  include <process.h>
+#else  // __QNX__
+#  include <sys/types.h>
+#  include <sys/wait.h>
+#  include <sys/stat.h>
+#  include <fcntl.h>
+#  include <unistd.h>
+#endif  // __QNX__
+
+#include <algorithm>
+#include <functional>
+
+#include "utils/logger.h"
+
+namespace utils {
+
+CREATE_LOGGERPTR_LOCAL(logger_, "Utils")
+
+struct GetCString {
+  char * operator ()(const std::string& string) {
+    return const_cast<char*>(string.c_str());
+  }
+};
+
+System::System(const std::string& command)
+    : command_(command) {
+  argv_.push_back(command);
+}
+
+System::System(const std::string& file, const std::string& command)
+    : command_(file) {
+  argv_.push_back(command);
+}
+
+bool System::Execute() {
+  return Execute(false);
+}
+
+System& System::Add(const std::string& arg) {
+  argv_.push_back(arg);
+  return *this;
+}
+
+#ifdef __QNX__
+
+bool System::Execute(bool wait) {
+  size_t size = argv_.size();
+  char * *argv = new char*[size + 1];
+  std::transform(argv_.begin(), argv_.end(), argv, GetCString());
+  argv[size] = NULL;
+
+  int mode = wait ? P_WAIT : P_NOWAIT;
+  int ret = spawnvp(mode, command_.c_str(), argv);
+  delete[] argv;
+
+  if (ret == -1) {
+    LOG4CXX_ERROR(logger_, "Can't execute command: " << command_);
+    return false;
+  }
+
+  if (wait) {
+    return WEXITSTATUS(ret) == 0;
+  }
+
+  return true;
+}
+
+#else  // __QNX__
+
+bool System::Execute(bool wait) {
+  // Create a child process.
+  pid_t pid_command = fork();
+
+  switch (pid_command) {
+    case -1: {  // Error
+      LOG4CXX_FATAL(logger_, "fork() failed!");
+      return false;
+    }
+    case 0: {  // Child process
+      int32_t fd_dev0 = open("/dev/null", O_RDWR, S_IWRITE);
+      if (0 > fd_dev0) {
+        LOG4CXX_FATAL(logger_, "Open dev0 failed!");
+        return false;
+      }
+      // close input/output file descriptors.
+      close(STDIN_FILENO);
+      close(STDOUT_FILENO);
+      close(STDERR_FILENO);
+
+      // move input/output to /dev/null.
+      dup2(fd_dev0, STDIN_FILENO);
+      dup2(fd_dev0, STDOUT_FILENO);
+      dup2(fd_dev0, STDERR_FILENO);
+
+      size_t size = argv_.size();
+      char * *argv = new char*[size + 1];
+      std::transform(argv_.begin(), argv_.end(), argv, GetCString());
+      argv[size] = NULL;
+
+      // Execute the program.
+      if (execvp(command_.c_str(), argv) == -1) {
+        LOG4CXX_ERROR(logger_, "Can't execute command: " << command_);
+        _exit(EXIT_FAILURE);
+      }
+      delete[] argv;
+
+      return true;
+    }
+    default: { /* Parent process */
+      LOG4CXX_INFO(logger_, "Process created with pid " << pid_command);
+      if (wait) {
+        int status;
+        pid_t wait_pid;
+        do {
+          wait_pid = waitpid(pid_command, &status, WUNTRACED | WCONTINUED);
+          if (wait_pid == -1) {
+            LOG4CXX_ERROR_WITH_ERRNO(logger_, "Can't wait");
+            _exit(EXIT_FAILURE);
+            return false;
+          }
+        } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+        return WEXITSTATUS(status) == 0;
+      }
+
+      return true;
+    }
+  }
+}
+
+#endif  // __QNX__
+
+}  // utils