Path: blob/master/runtime/compiler/env/CpuUtilization.hpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#ifndef CPUUTILIZATION_HPP23#define CPUUTILIZATION_HPP2425#include <stdint.h>26#include "jni.h"27#include "j9.h"28#include "j9port.h"29#include "env/TRMemory.hpp"30#include "il/DataTypes.hpp"3132namespace TR { class PersistentInfo; }3334// TODO: maybe move this to a global config?35#define INITIAL_USAGE (77) // assume relatively high usage at start36#define INITIAL_IDLE (100 - INITIAL_USAGE)37#define CPU_UTIL_ARRAY_DEFAULT_SIZE 123839//------------------------- class CpuUtilization ----------------------------40// Class that maintains info about CPU utilization for a given period of time41//---------------------------------------------------------------------------4243//---------------------------------------------------------------------------44// WARNING45//46// The values obtained by this class have been observed during testing to be47// inaccurate within 4% in either direction. That is, a usage value of 10%48// could actually be anywhere from 6% to 14%.49//50// This is both because integer arithmetic is used in calculations, and51// because the information returned by the portlib is slightly inconsistent52// since it is obtained from two separate calls (and the time reference comes53// from only one of the calls).54//---------------------------------------------------------------------------55class CpuUtilization56{5758public:5960TR_PERSISTENT_ALLOC(TR_Memory::PersistentInfo);6162CpuUtilization(J9JITConfig *jitConfig);6364typedef struct CpuUsageCircularBuffer65{66int64_t _timeStamp;67int64_t _sampleSystemCpu;68int64_t _sampleJvmCpu;69} CpuUsageCircularBuffer;7071bool isFunctional() const { return _isFunctional; }72int32_t getCpuUsage() const { return _cpuUsage; }73int32_t getCpuIdle() const { return _cpuIdle; }74int32_t getVmCpuUsage() const { return _vmCpuUsage; }75int32_t getAvgCpuUsage() const { return _avgCpuUsage; }76int32_t getAvgCpuIdle() const { return _avgCpuIdle; }77int64_t getUptime() const { return _prevMachineUptime; } // in nanoseconds78int64_t getLastMeasurementInterval() const { return _prevIntervalLength; } // in nanoseconds79int64_t getVmTotalCpuTime() const { return _prevVmSysTime + _prevVmUserTime; }80int32_t getCpuUtil(J9JITConfig *jitConfig, J9SysinfoCPUTime *machineCpuStats, j9thread_process_time_t *vmCpuStats);81int32_t updateCpuUtil(J9JITConfig *jitConfig);82void disable() { _isFunctional = false;83_cpuUsage = _cpuIdle = _vmCpuUsage = _avgCpuUsage = _avgCpuIdle = -1;84disableCpuUsageCircularBuffer(); }8586// Circular Buffer related functions87CpuUsageCircularBuffer *getCpuUsageCircularBuffer() const { return _cpuUsageCircularBuffer; }88void disableCpuUsageCircularBuffer() { _isCpuUsageCircularBufferFunctional = false; }89int32_t getCircularBufferIndex() const { return _cpuUsageCircularBufferIndex; }90int32_t getCircularBufferSize() const { return _cpuUsageCircularBufferSize; }91bool isCpuUsageCircularBufferFunctional() const { return (_isFunctional && _isCpuUsageCircularBufferFunctional); }92int32_t updateCpuUsageCircularBuffer(J9JITConfig *jitConfig);9394private:9596int32_t _cpuUsage; // percentage of used CPU on the whole machine for the last update interval97int32_t _cpuIdle; // percentage of idle CPU on the whole machine for the last update interval98int32_t _vmCpuUsage; // percentage of used CPU by the VM for the last update interval99int32_t _avgCpuUsage; // percentage of time each processor is used on average (0..100)100int32_t _avgCpuIdle; // percentage of time each processor is idle on average (0..100)101102int64_t _prevIntervalLength; // the duration (in ns) of the last update interval103104// values recorded at start of this update interval105int64_t _prevMachineUptime; // absolute value (in ns) of machine uptime106int64_t _prevMachineCpuTime; // absolute value (in ns) of used CPU time on the machine107int64_t _prevVmSysTime; // absolute value (in ns) of time VM spent in kernel space108int64_t _prevVmUserTime; // absolute value (in ns) of time VM spent in user space109110CpuUsageCircularBuffer *_cpuUsageCircularBuffer; // Circular buffer containing timestamp, system cpu usage sample, and jvm cpu use sample111int32_t _cpuUsageCircularBufferIndex; // Current index of the buffer; contains the oldest data. Subtract 1 to get the most recent data112int32_t _cpuUsageCircularBufferSize; // Size of the circular buffer113114bool _isFunctional;115bool _isCpuUsageCircularBufferFunctional;116117}; // class CpuUtilization118119// How to use it:120// IMPORTANT: The update() and getCpuTimeNow() routines MUST be called121// only by the thread for which we want to compute CPU utilization122// You may call the update() function as often as you want, but the update actually happens only so often.123// The update() function will return false if no update took place (too soon to be recomputed)124// Use getCpuTime() to find CPU spent in thread from the beginning of the JVM till the last update125// Use getCpuTimeNow() to find CPU spent in thread till this moment;126// - heavyweight because it invokes OS127// - must be called only by the thread for which we want CPu time128// Use getThreadLastCpuUtil() to print CPU utilization of the thread during the last interval (should be <= 100)129130namespace TR { class CompilationInfo; }131namespace TR {132class PersistentInfo;133}134extern "C" {135struct J9JITConfig;136}137class CpuSelfThreadUtilization138{139public:140TR_PERSISTENT_ALLOC(TR_Memory::PersistentInfo);141CpuSelfThreadUtilization(TR::PersistentInfo * persistentInfo, J9JITConfig * jitConfig, int64_t minPeriodNs, int32_t id);142bool update();143int64_t getCpuTime() const { return _cpuTimeAtLastUpdate; }144int64_t getCpuTimeNow() const {PORT_ACCESS_FROM_JITCONFIG(_jitConfig); return j9thread_get_self_cpu_time(j9thread_self()); } // expensive145int64_t getTimeOfLastUpdate() const { return _clockTimeAtLastUpdate; } // ns146int64_t getLowResolutionClockAtLastUpdate() const { return _lowResolutionClockAtLastUpdate; } // ms147int64_t getLastMeasurementInterval() const { return _lastIntervalLength; } // ns148int64_t getSecondLastMeasurementInterval() const { return _secondLastIntervalLength; } // ns149int64_t getCpuTimeDuringLastInterval() const { return _cpuTimeDuringLastInterval; }150int64_t getCpuTimeDuringSecondLastInterval() const { return _cpuTimeDuringSecondLastInterval; }151// getThreadLastCpuUtil() returns CPU utilization of thread as a percentage. Values greater than 100 are errors.152int32_t getThreadLastCpuUtil() const { return _lastCpuUtil; }153int32_t getThreadPrevCpuUtil() const { return _secondLastCpuUtil; }154int32_t computeThreadCpuUtilOverLastNns(int64_t validInterval) const; // this one looks at the last two intervals, but not too distant in the past155int64_t getCrtTimeNs() const { PORT_ACCESS_FROM_JITCONFIG(_jitConfig); return j9time_current_time_millis() * 1000000; /* j9time_nano_time() */}156int32_t getId() const { return _id; }157bool isFunctional() const { return _isFunctional; }158void setAsUnfunctional();159void printInfoToVlog() const;160161private:162J9JITConfig *_jitConfig;163TR::PersistentInfo *_persistentInfo;164165int64_t _minMeasurementIntervalLength; // update only if at least that much time has passed since the last update166int64_t _clockTimeAtLastUpdate; // time when stats for last interval were computed (ns)167uint64_t _lowResolutionClockAtLastUpdate; // this is based on the fast but inaccurate time maintained in persistentinfo (ms)168int64_t _cpuTimeAtLastUpdate; // cpu time spent in thread at the time of last update (since the start of the process)169int64_t _cpuTimeDuringLastInterval; // cpu time spent in thread during the last measurement interval170int64_t _lastIntervalLength; // duration of the last measurement interval171int32_t _lastCpuUtil; // CPU utilization of the thread during the last interval172173int64_t _cpuTimeDuringSecondLastInterval; // cpu time spent in thread during the second last measurement interval (precedes last interval)174int64_t _secondLastIntervalLength; // duration of the second last measurement interval175int32_t _secondLastCpuUtil; // CPU utilization of the thread during the second last interval176177int32_t _id; // some identifier; e.g. compilation thread id178bool _isFunctional;179}; // CpuSelfThreadUtilization180181182// Note, an object of this type is embedded into TR::CompilationInfo which is183// zeroed out at construction time. Thus, TR_CpuEntitlement cannot have virtual184// functions. If virtual functions are added to TR_CpuEntitlement then we need185// to allocate it dynamically and store a pointer into TR::CompilationInfo186struct TR_CpuEntitlement187{188public:189// The constructor cannot set all fields correctly because we have to make190// sure te portlib is up and running191void init(J9JITConfig *jitConfig)192{193/* Couple of issues were discovered when the support for hypervisor was enabled.194* When JVM ran on VMWare, then the port library loaded libvmGuestLib.so which195* interferes with implementation of some of j.l.Math methods.196* The library also causes JVM to core dump when an application is using libjsig.so197* for signal chaining.198* For these reasons, support for hypervisor is being disabled until the issues with199* VMWare library are resolved.200*/201_hypervisorPresent = TR_no;202_jitConfig = jitConfig;203computeAndCacheCpuEntitlement();204}205bool isHypervisorPresent();206void computeAndCacheCpuEntitlement(); // used during bootstrap and periodically in samplerThreadProc207uint32_t getNumTargetCPUs() const { return _numTargetCpu; } // num CPUs the JVM is pinned to. Guaranteed >= 1208double getGuestCpuEntitlement() const { return _guestCpuEntitlement; } // as given by the hypervisor; 0 if error or no hypervisor209double getJvmCpuEntitlement() const { return _jvmCpuEntitlement; } // smallest of _numTargetCpu and _guestCpuEntitlement210211private:212double computeGuestCpuEntitlement() const; // this does not check for isHypervisorPresent, so don't call it directly213214TR_YesNoMaybe _hypervisorPresent;215uint32_t _numTargetCpu;216double _guestCpuEntitlement;217double _jvmCpuEntitlement;218J9JITConfig * _jitConfig;219};220221#endif // CPUUTILIZATION_HPP222223224