1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
# Author: Roberto Polli <rpolli@redhat.com>
#
# NOTE: Edit the jcmd location according to your path or use update-alternatives.
global BIN_JCMD
BIN_JCMD = '/usr/bin/jcmd'
class dstat_plugin(dstat):
"""
This plugin gathers jvm stats via jcmd.
Usage:
JVM_PID=15123 dstat --jvm-full
Minimize the impacts of jcmd and consider using:
dstat --noupdate
For full informations on jcmd see:
- http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/jcmd.html
- https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html
This requires the presence of /tmp/hsperfdata_* directory, so
it WON'T WORK if you add -XX:-UsePerfData or -XX:+PerfDisableSharedMem.
"""
def __init__(self):
self.name = 'jvm_full'
self.vars = ('clsL', 'clsU', 'fgc', 'heap', 'heap%',
'heapmax', 'perm', 'perm%', 'permmax')
self.type = 'f'
self.width = 5
self.scale = 1000
def check(self):
"""Preliminar checks. If no pid is passed, defaults to 0.
"""
if not os.access(BIN_JCMD, os.X_OK):
raise Exception('Needs jstat binary')
try:
self.jvm_pid = int(os.environ.get('JVM_PID',0))
except Exception as e:
self.jvm_pid = 0
return True
@staticmethod
def _to_stat(k, v):
try:
return k, int(v)
except (KeyError, ValueError, AttributeError):
return k, v
@staticmethod
def _cmd_splitlines(cmd):
"""Splits a txt output of lines like key=value.
"""
for l in os.popen(cmd):
yield l.strip().split("=", 1)
def extract(self):
try:
lines = self._cmd_splitlines(
'%s %s PerfCounter.print ' % (BIN_JCMD, self.jvm_pid))
table = dict(self._to_stat(*l) for l in lines
if len(l) > 1)
if table:
# Number of loaded classes.
self.set2['clsL'] = table['java.cls.loadedClasses']
self.set2['clsU'] = table['java.cls.unloadedClasses']
# Number of Full Garbage Collection events.
self.set2['fgc'] = table['sun.gc.collector.1.invocations']
# The heap space is made up of Old Generation and Young
# Generation (which is divided in Eden, Survivor0 and
# Survivor1)
self.set2['heap'] = table['sun.gc.generation.1.capacity'] + table[
'sun.gc.generation.0.capacity']
# Usage is hidden in the nested spaces.
self.set2['heapu'] = sum(table[k] for k in table
if 'sun.gc.generation.' in k
and 'used' in k)
self.set2['heapmax'] = table['sun.gc.generation.1.maxCapacity'] + table[
'sun.gc.generation.0.maxCapacity']
# Use PermGen on jdk7 and the new metaspace on jdk8
try:
self.set2['perm'] = table['sun.gc.generation.2.capacity']
self.set2['permu'] = sum(table[k] for k in table
if 'sun.gc.generation.2.' in k
and 'used' in k)
self.set2['permmax'] = table[
'sun.gc.generation.2.maxCapacity']
except KeyError:
self.set2['perm'] = table['sun.gc.metaspace.capacity']
self.set2['permu'] = table['sun.gc.metaspace.used']
self.set2['permmax'] = table[
'sun.gc.metaspace.maxCapacity']
# Evaluate statistics on memory usage.
for name in ('heap', 'perm'):
self.set2[name + '%'] = 100 * self.set2[
name + 'u'] / self.set2[name]
for name in self.vars:
self.val[name] = self.set2[name]
if step == op.delay:
self.set1.update(self.set2)
except IOError as e:
if op.debug > 1:
print('%s: lost pipe to jstat, %s' % (self.filename, e))
for name in self.vars:
self.val[name] = -1
except Exception as e:
if op.debug > 1:
print('%s: exception' % e)
for name in self.vars:
self.val[name] = -1
# vim:ts=4:sw=4:et
|