-
Notifications
You must be signed in to change notification settings - Fork 0
/
imc.jl
97 lines (82 loc) · 2.9 KB
/
imc.jl
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
# IMC Monitoring
mutable struct IMCMonitor{T,N} <: AbstractMonitor
# We have one entry in the outer tuple for each socket.
# Within each socket, we have one entry for each controller.
# Within each controller, we have one entry for each channel.
imcs::Record{:socket,T}
events::NTuple{N, UncoreSelectRegister}
cleaned::Bool
end
"""
IMCMonitor(events, socket; [program = true, finalize = true])
Monitor the Integrated Memory Controller (IMC) for `events` on a **single**
selected CPU `socket`. This can gather information such as number of DRAM read and write
operations. Argument `event` should be a `Tuple` of [`CounterTools.UncoreSelectRegister`](@ref)
and `socket` should be either an `Integer` or `IndexZero`.
If `finalize = true` is passed, a finalizer will be attached to the `IMCMonitor` to clean
up the hardware counter's state.
"""
function IMCMonitor(
events::NTuple{N, UncoreSelectRegister},
socket;
program = true,
finalize = true,
) where {N}
# Check to see if we already have an active monitor.
if IMC_RESERVATION[]
error("An active IMC Monitor already exists!")
end
# Get the mapping from socket to bus
socket_to_bus = findbusses()
# Memory Controllers
imcs = ntuple(2) do controller
# Channels
return ntuple(3) do channel
# Get the path for this particular device
bus = socket_to_bus[socket]
device = SKYLAKE_IMC_REGISTERS[controller][channel].device
fn = SKYLAKE_IMC_REGISTERS[controller][channel].fn
# Construct a monitor
handle = Handle(bus, device, fn)
pmu = IMCUncorePMU(handle)
reset!(pmu)
return Record{:channel}((pmu,))
end |> Record{:imc}
end |> Record{:socket}
monitor = IMCMonitor(
imcs,
events,
false,
)
IMC_RESERVATION[] = true
# Clean up after ourselves
finalize && finalizer(cleanup, monitor)
program && program!(monitor)
return monitor
end
const IMC_RESERVATION = Ref{Bool}(false)
# Extend `mapleaves` to broadcast across the IMCMonitor
mapleaves(f, monitor::IMCMonitor) = mapleaves(f, monitor.imcs)
program!(monitor::IMCMonitor) = mapleaves(x -> program(x, monitor.events), monitor)
function program(x::IMCUncorePMU, events)
for (i, evt) in enumerate(events)
setcontrol!(x, i, evt)
end
enable!(x)
return nothing
end
reset!(monitor::IMCMonitor) = mapleaves(reset!, monitor)
function Base.read(monitor::IMCMonitor{T,N}) where {T,N}
monitor.cleaned && error("Trying to measure a cleaned IMC Monitor")
return mapleaves(getallcounters, monitor)
end
function cleanup(monitor::IMCMonitor)
if !monitor.cleaned
# Close any open PCI file handles
reset!(monitor)
IMC_RESERVATION[] = false
mapleaves(close, monitor)
monitor.cleaned = true
end
return nothing
end