| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <gfcpp/gfcpp_globals.hpp> |
| |
| #if defined(_SOLARIS) |
| #include <ace/OS_NS_sys_utsname.h> |
| #include <ace/OS_NS_errno.h> |
| #include "HostStatHelperSolaris.hpp" |
| #include <procfs.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <sys/systeminfo.h> |
| #include <sys/proc.h> |
| #include <sys/kstat.h> |
| #include <glob.h> |
| #include <gfcpp/ExceptionTypes.hpp> |
| #include "SolarisProcessStats.hpp" |
| #include <ace/OS.h> |
| |
| using namespace apache::geode::statistics; |
| |
| uint8_t HostStatHelperSolaris::m_logStatErrorCountDown = 5; |
| uint32_t HostStatHelperSolaris::m_cpuUtilPrev[CPU_STATES] = {0}; |
| bool HostStatHelperSolaris::m_initialized = false; |
| kstat_ctl_t* HostStatHelperSolaris::m_kstat = NULL; |
| |
| void HostStatHelperSolaris::refreshProcess(ProcessStats* processStats) { |
| static bool threadCountMissingWarning = false; |
| // Get pid, SolarisProcessStats |
| SolarisProcessStats* solProcessStat = |
| dynamic_cast<SolarisProcessStats*>(processStats); |
| if (solProcessStat == NULL) { |
| LOGFINE( |
| "HostStatHelperSolaris::refreshProcess failed due to null processStat"); |
| return; |
| } |
| Statistics* stats = solProcessStat->stats; |
| int32 thePid = (int32)stats->getNumericId(); // int64 is converted to int |
| |
| int32 pid = 0; |
| uint32 userTime = 0; |
| uint32 sysTime = 0; |
| uint32 vsize = 0; |
| int32 rss = 0; |
| uint32 tempimageSize = 0; |
| uint32 temprssSize = 0; |
| int32_t cpuUsage = 0; |
| int32_t processCpuUsage = 0; |
| char procFileName[64]; |
| int fPtr; |
| prusage_t currentUsage; |
| psinfo_t currentInfo; |
| |
| ACE_OS::snprintf(procFileName, 64, "/proc/%lu/psinfo", (uint32)thePid); |
| // fread was returning errno 2 FILENOTFOUND so it was switched to read |
| // This matches what was done in the Geode Project also |
| fPtr = open(procFileName, O_RDONLY, 0); /* read only */ |
| if (fPtr != -1) { |
| if (read(fPtr, ¤tInfo, sizeof(currentInfo)) != sizeof(currentInfo)) { |
| int32 errNum = errno; // for debugging |
| if (m_logStatErrorCountDown-- > 0) { |
| LOGFINE("Error reading procFileName %s, errno %d pid %lu", procFileName, |
| errNum, (uint32)thePid); |
| } |
| } else { |
| tempimageSize = currentInfo.pr_size / 1024UL; |
| temprssSize = currentInfo.pr_rssize / 1024UL; |
| processCpuUsage = (int)((currentInfo.pr_pctcpu / 32768.0) * 100); |
| } |
| close(fPtr); |
| } |
| ACE_OS::snprintf(procFileName, 64, "/proc/%u/usage", (uint32)thePid); |
| fPtr = open(procFileName, O_RDONLY, 0); |
| if (fPtr != -1) { |
| if (read(fPtr, ¤tUsage, sizeof(currentUsage)) != |
| sizeof(currentUsage)) { |
| int32 errNum = errno; // for debugging |
| if (m_logStatErrorCountDown-- > 0) { |
| LOGFINE("Error reading procFileName %s, errno %d pid %lu", procFileName, |
| errNum, (uint32)thePid); |
| } |
| } else { |
| uint32 usrTimeSecs = currentUsage.pr_utime.tv_sec; |
| uint32 usrTimeNanos = currentUsage.pr_utime.tv_nsec; |
| userTime = (usrTimeSecs * 1000 * 1000) + (usrTimeNanos / (1000)); |
| |
| uint32 sysTimeSecs = currentUsage.pr_stime.tv_sec; |
| uint32 sysTimeNanos = currentUsage.pr_stime.tv_nsec; |
| sysTime = (sysTimeSecs * 1000 * 1000) + (sysTimeNanos / (1000)); |
| } |
| close(fPtr); |
| } |
| uint32_t cpuUtil[CPU_STATES] = {0}; |
| try { |
| getKernelStats(cpuUtil); |
| if (m_initialized) { |
| uint32_t idleDelta = cpuUtil[CPU_IDLE] - m_cpuUtilPrev[CPU_IDLE]; |
| double timeDelta = idleDelta; |
| timeDelta += (cpuUtil[CPU_USER] - m_cpuUtilPrev[CPU_USER]); |
| timeDelta += (cpuUtil[CPU_KERNEL] - m_cpuUtilPrev[CPU_KERNEL]); |
| timeDelta += (cpuUtil[CPU_WAIT] - m_cpuUtilPrev[CPU_WAIT]); |
| if (timeDelta > CPU_USAGE_STAT_THRESHOLD) { |
| // Math is equivalent to 100*(timeDelta-idleDelta)/timeDelta, rounding |
| // aside |
| cpuUsage = 100 - 100 * (idleDelta) / timeDelta; |
| // Update the previous copy |
| memcpy(m_cpuUtilPrev, cpuUtil, sizeof(uint32_t[CPU_STATES])); |
| } else { |
| if (m_logStatErrorCountDown-- > 0) { |
| LOGFINE( |
| "Kernel stat sampling failed to meet CPU_USAGE_THRESHOLD, " |
| "reporting 100%% cpu load"); |
| } |
| cpuUsage = 100; |
| } |
| } else { |
| // Update the previous copy |
| memcpy(m_cpuUtilPrev, cpuUtil, sizeof(uint32_t[CPU_STATES])); |
| m_initialized = true; |
| } |
| } catch (NullPointerException npe) { |
| if (m_logStatErrorCountDown-- > 0) { |
| LOGERROR(npe.getMessage()); |
| } |
| } |
| // thread count |
| int threadCount = 0; |
| glob_t g; |
| if (glob("/proc/self/lwp/*", 0, NULL, &g) == 0) { |
| threadCount = g.gl_pathc; |
| // LOGDEBUG("gl_pathc: %d",g.gl_pathc); |
| // for( unsigned int i =0; i < g.gl_pathc; i++ ) { |
| // LOGDEBUG(" LWP: %s ",g.gl_pathv[i]); |
| //} |
| } else { |
| if (threadCountMissingWarning == false) { |
| threadCountMissingWarning = true; |
| LOGWARN("Stats: Number of threads in process are not available."); |
| } |
| } |
| globfree(&g); |
| |
| stats->setInt(solProcessStat->imageSizeINT, tempimageSize); |
| stats->setInt(solProcessStat->rssSizeINT, temprssSize); |
| stats->setInt(solProcessStat->userTimeINT, userTime); |
| stats->setInt(solProcessStat->systemTimeINT, sysTime); |
| stats->setInt(solProcessStat->hostCpuUsageINT, cpuUsage); |
| stats->setInt(solProcessStat->processCpuUsageINT, processCpuUsage); |
| stats->setInt(solProcessStat->threadsINT, threadCount); |
| } |
| |
| void HostStatHelperSolaris::getKernelStats(uint32_t* cpuUtil) { |
| if (m_kstat == NULL) { |
| m_kstat = kstat_open(); |
| if (m_kstat == NULL) { |
| char buf[128]; |
| ACE_OS::snprintf(buf, 128, "Unable to obtain kstat data, errno %d", |
| errno); |
| throw NullPointerException(buf); |
| } |
| } |
| kstat_ctl_t wkc; |
| kstat_t* ksp; |
| kstat_t* wksp; |
| cpu_stat_t rcw_cpu_stat_t; |
| char module[KSTAT_STRLEN + 1]; |
| kid_t kcid; |
| |
| // Make a copy of it. |
| memcpy(&wkc, m_kstat, sizeof(kstat_ctl_t)); |
| // Walk the chain. |
| for (ksp = wkc.kc_chain; ksp != NULL; ksp = ksp->ks_next) { |
| // Header information |
| // kstats are identified by module, instance, class, and name. |
| strncpy(module, ksp->ks_module, KSTAT_STRLEN); |
| module[KSTAT_STRLEN] = '\0'; |
| // With raw data you must know what to expect. |
| if (ksp->ks_type == KSTAT_TYPE_RAW) { |
| if (strcmp(module, "cpu_stat") == 0) { |
| wksp = ksp; |
| // Read the data corresponding to the pointer. cpu_stat modules deliver |
| // cpu_stat_t data. |
| kcid = kstat_read(&wkc, wksp, &rcw_cpu_stat_t); |
| if (kcid == -1) { |
| LOGERROR("Error reading stats, errno \"%d\"", errno); |
| throw NullPointerException( |
| "Error reading cpu_stat struct from kernal stats"); |
| } |
| /* |
| LOGDEBUG("rcw_cpu_stat_t cpu idle= %u, user= %u, sys=%u, wait=%u, \n", |
| rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_IDLE], |
| rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_USER], |
| rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_KERNEL], |
| rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_WAIT] ); |
| */ |
| cpuUtil[CPU_IDLE] = rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_IDLE]; |
| cpuUtil[CPU_USER] = rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_USER]; |
| cpuUtil[CPU_KERNEL] = rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_KERNEL]; |
| cpuUtil[CPU_WAIT] = rcw_cpu_stat_t.cpu_sysinfo.cpu[CPU_WAIT]; |
| } |
| } |
| } |
| } |
| |
| void HostStatHelperSolaris::closeHostStatHelperSolaris() { |
| if (m_kstat != NULL) { |
| kstat_close(m_kstat); |
| m_kstat = NULL; |
| } |
| } |
| #endif /* SOLARIS */ |