1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-25 15:00:45 -08:00

New events arenapollbegin and arenapollend.

Measure fraction of CPU time in polling.
Represent the units of each TimeSeries.
Draw graphs for up to two different units using Axes.twinx.

Copied from Perforce
 Change: 194204
This commit is contained in:
Gareth Rees 2018-06-26 16:21:48 +01:00
parent 3ab13b0f27
commit e323bd2e15
3 changed files with 76 additions and 31 deletions

View file

@ -67,7 +67,7 @@
*/
#define EventNameMAX ((size_t)19)
#define EventCodeMAX ((EventCode)0x0089)
#define EventCodeMAX ((EventCode)0x008B)
#define EVENT_LIST(EVENT, X) \
/* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \
@ -182,7 +182,7 @@
EVENT(X, EventInit , 0x0074, TRUE, Arena) \
EVENT(X, EventClockSync , 0x0075, TRUE, Arena) \
EVENT(X, ArenaAccess , 0x0076, TRUE, Arena) \
EVENT(X, ArenaPoll , 0x0077, TRUE, Arena) \
/* EVENT(X, ArenaPoll , 0x0077, TRUE, Arena) */ \
EVENT(X, ArenaSetEmergency , 0x0078, TRUE, Arena) \
EVENT(X, VMCompact , 0x0079, TRUE, Arena) \
EVENT(X, amcScanNailed , 0x0080, TRUE, Seg) \
@ -195,7 +195,9 @@
/* EVENT(X, ArenaBlacklistZone , 0x0086, TRUE, Arena) */ \
EVENT(X, PauseTimeSet , 0x0087, TRUE, Arena) \
EVENT(X, TraceEndGen , 0x0088, TRUE, Trace) \
EVENT(X, LabelPointer , 0x0089, TRUE, User)
EVENT(X, LabelPointer , 0x0089, TRUE, User) \
EVENT(X, ArenaPollBegin , 0x008A, TRUE, Arena) \
EVENT(X, ArenaPollEnd , 0x008B, TRUE, Arena)
/* Remember to update EventNameMAX and EventCodeMAX above!
@ -645,11 +647,6 @@
PARAM(X, 2, P, addr) \
PARAM(X, 3, U, mode)
#define EVENT_ArenaPoll_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, start) \
PARAM(X, 2, B, workWasDone)
#define EVENT_ArenaSetEmergency_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, B, emergency)
@ -720,6 +717,12 @@
PARAM(X, 0, P, pointer) /* pointer */ \
PARAM(X, 1, W, stringId) /* string identifier of its label */
#define EVENT_ArenaPollBegin_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) /* arena about to be polled */
#define EVENT_ArenaPollEnd_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) /* arena that was polled */ \
PARAM(X, 1, B, workWasDone) /* any collection work done in poll? */
#endif /* eventdef_h */

View file

@ -747,7 +747,7 @@ void (ArenaPoll)(Globals globals)
/* fillMutatorSize has advanced; call TracePoll enough to catch up. */
start = ClockNow();
EVENT3(ArenaPoll, arena, start, FALSE);
EVENT1(ArenaPollBegin, arena);
do {
moreWork = TracePoll(&tracedWork, &worldCollected, globals,
@ -762,7 +762,7 @@ void (ArenaPoll)(Globals globals)
ArenaAccumulateTime(arena, start, ClockNow());
}
EVENT3(ArenaPoll, arena, start, BOOLOF(workWasDone));
EVENT2(ArenaPollEnd, arena, BOOLOF(workWasDone));
globals->insidePoll = FALSE;
}

View file

@ -11,7 +11,7 @@
import argparse
from collections import deque, namedtuple
from collections import defaultdict, deque, namedtuple
from itertools import cycle
import os
from struct import Struct
@ -189,6 +189,28 @@ class Accumulator(TimeSeries):
self.append(t, self.value)
class MovingAverageRatio(TimeSeries):
"Exponentially weighted moving average on/off ratio."
def __init__(self, t, alpha=0.99):
super().__init__()
self._on = self._off = 0.0
self._last = t
self._alpha = alpha
self._beta = 1 - alpha
self._ratio = 0.0
def off(self, t):
self._on = t - self._last
self._last = t
ratio = self._on / (self._on + self._off)
self._ratio = self._ratio * self._alpha + ratio * self._beta
self.append(t, self._ratio)
def on(self, t):
self._off = t - self._last
self._last = t
class EventHandler:
"""Object that handles a telemetry event by dispatching to the method
with the same name as the event.
@ -204,8 +226,8 @@ class EventHandler:
class Pool(EventHandler):
"Model of an MPS pool."
def __init__(self, arena, pointer):
"Create Pool owned by arena, at pointer."
def __init__(self, arena, pointer, t):
"Create Pool owned by arena, at pointer, at time t."
self._arena = arena # Owning arena.
self._model = arena.model # Owning model.
self._pointer = pointer # Pool's pointer.
@ -213,7 +235,7 @@ class Pool(EventHandler):
self._serial = None # Pool's serial number within arena.
self._alloc = Accumulator()
self._model.add_time_series(
self, "alloc", self._alloc,
self, self._alloc, "bytes", "alloc",
"memory allocated by the pool from the arena")
@property
@ -240,14 +262,18 @@ class Pool(EventHandler):
class Arena(EventHandler):
"Model of an MPS arena."
def __init__(self, model, pointer):
"Create Arena owned by model, at pointer."
def __init__(self, model, pointer, t):
"Create Arena owned by model, at pointer, at time t."
self.model = model # Owning model.
self._pointer = pointer # Arena's pointer.
self._arena_class = None # Arena's class pointer.
self._serial = None # Arena's serial number.
self._pools = [] # List of Pools ever belonging to arena.
self._pool = {} # pointer -> Pool (for live pools)
self._poll = MovingAverageRatio(t)
self.model.add_time_series(
self, self._poll, "fraction", "poll",
"polling fraction of CPU time (moving average)")
@property
def name(self):
@ -269,7 +295,7 @@ class Arena(EventHandler):
try:
pool = self._pool[pointer]
except KeyError:
self._pool[pointer] = pool = Pool(self, pointer)
self._pool[pointer] = pool = Pool(self, pointer, t)
self._pools.append(pool)
pool.handle(t, event)
@ -284,16 +310,23 @@ class Arena(EventHandler):
def PoolFinish(self, t, event):
del self._pool[event.pool]
def ArenaPollBegin(self, t, event):
self._poll.on(t)
def ArenaPollEnd(self, t, event):
self._poll.off(t)
class Line:
"A line in a Matplotlib plot wrapping a TimeSeries."
colors = cycle('blue orange green red purple brown pink gray olive cyan'
.split())
def __init__(self, owner, name, series, desc):
def __init__(self, owner, series, unit, name, desc):
self.owner = owner # Owning object.
self._name = name # Brief description.
self.series = series # Time series.
self.unit = unit # Unit.
self._name = name # Brief description.
self.desc = desc # Brief description.
self.draw = True # Plot this line?
self.color = next(self.colors)
@ -323,25 +356,33 @@ class Model(EventHandler):
self._label = {} # address or pointer -> stringId
self._arena = {} # pointer -> Arena (for live arenas)
self.arenas = [] # All arenas created in the model.
self.lines = [] # All time series available for plotting.
self.lines = [] # All Lines available for plotting.
self._unit_lines = defaultdict(list) # Lines collated by unit.
self._needs_redraw = True # Plot needs redrawing?
def add_time_series(self, owner, name, series, desc):
def add_time_series(self, *args):
"Add a time series to the model."
self.lines.append(Line(owner, name, series, desc))
line = Line(*args)
self.lines.append(line)
self._unit_lines[line.unit].append(line)
def label(self, pointer):
"Return string labelling address or pointer, or None if unlabelled."
return self._intern.get(self._label.get(pointer))
def plot(self, axes):
def plot(self, axes_list):
"Draw time series on the given axes."
if self._needs_redraw:
self._needs_redraw = False
if not self._needs_redraw:
return
self._needs_redraw = False
# Determine which unit to plot on each axis.
lines_list = sorted(self._unit_lines.values(), key=len, reverse=True)
for axes in axes_list:
axes.clear()
axes.set_xlabel("time (seconds)")
axes.set_ylabel("bytes")
for line in self.lines:
for axes, lines in zip(axes_list, lines_list):
axes.set_ylabel(lines[0].unit)
for line in lines:
line.plot(axes)
axes.figure.canvas.draw()
@ -363,12 +404,12 @@ class Model(EventHandler):
try:
arena = self._arena[addr]
except KeyError:
self._arena[addr] = arena = Arena(self, addr)
self._arena[addr] = arena = Arena(self, addr, t)
self.arenas.append(arena)
arena.handle(t, event)
ArenaCreateVM = ArenaCreateCL = ArenaAlloc = ArenaFree = PoolInit = \
PoolFinish = delegate_to_arena
ArenaCreateVM = ArenaCreateCL = ArenaAlloc = ArenaFree = ArenaPollBegin = \
ArenaPollEnd = PoolInit = PoolFinish = delegate_to_arena
def EventClockSync(self, t, event):
self.needs_redraw()
@ -441,6 +482,7 @@ class ApplicationWindow(QtWidgets.QMainWindow):
# Matplot canvas and toolbar.
canvas = FigureCanvas(Figure(figsize=(10, 6)))
self._axes = canvas.figure.subplots()
self._axes2 = self._axes.twinx()
main_layout.addWidget(canvas)
self._toolbar = ApplicationToolbar(canvas, self)
self.addToolBar(QtCore.Qt.BottomToolBarArea, self._toolbar)
@ -465,7 +507,7 @@ class ApplicationWindow(QtWidgets.QMainWindow):
self._home_limits = None
self._model.update()
if not self._toolbar.paused:
self._model.plot(self._axes)
self._model.plot([self._axes, self._axes2])
self._home_limits = self._limits
# Find new time series and create corresponding checkboxes.