-
Notifications
You must be signed in to change notification settings - Fork 2
/
power.jl
154 lines (140 loc) · 4.68 KB
/
power.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
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
module Power
using ..LIKWID:
LibLikwid, power_initialized, topo_initialized, _powerinfo, powerinfo,
TurboBoost, PowerDomain, PowerInfo, init_topology
using Unitful
const POWER_DOMAIN_SUPPORT_STATUS = UInt64(1) << 0
const POWER_DOMAIN_SUPPORT_LIMIT = UInt64(1) << 1
const POWER_DOMAIN_SUPPORT_POLICY = UInt64(1) << 2
const POWER_DOMAIN_SUPPORT_PERF = UInt64(1) << 3
const POWER_DOMAIN_SUPPORT_INFO = UInt64(1) << 4
"""
Initialize power measurements for the given CPU.
Returns the RAPL status, i.e. `false` (no RAPL) or `true` (RAPL working).
"""
function init(cpuid::Integer)
power_initialized[] && return true
hasRAPL = LibLikwid.power_init(cpuid)
if Bool(hasRAPL)
_powerinfo[] = unsafe_load(LibLikwid.get_powerInfo())
_build_jl_power()
power_initialized[] = true
return true
end
return false
end
function init()
power_initialized[] && return true
init_topology()
return init(0)
end
"Finalize power measurements."
function finalize()
LibLikwid.power_finalize()
power_initialized[] = false
_powerinfo[] = nothing
return nothing
end
function _build_jl_power()
pi = _powerinfo[]
tb = TurboBoost(pi.turbo.numSteps,
unsafe_wrap(Array, pi.turbo.steps, pi.turbo.numSteps))
pds = ntuple(i -> begin
p = pi.domains[i]
PowerDomain(p.type,
p.type,
p.supportFlags,
p.energyUnit,
p.tdp,
p.minPower,
p.maxPower,
p.maxTimeWindow,
!iszero(p.supportFlags & POWER_DOMAIN_SUPPORT_INFO),
!iszero(p.supportFlags & POWER_DOMAIN_SUPPORT_STATUS),
!iszero(p.supportFlags & POWER_DOMAIN_SUPPORT_PERF),
!iszero(p.supportFlags & POWER_DOMAIN_SUPPORT_POLICY),
!iszero(p.supportFlags & POWER_DOMAIN_SUPPORT_LIMIT))
end,
5)
powerinfo[] = PowerInfo(pi.baseFrequency,
pi.minFrequency,
tb,
pi.hasRAPL,
pi.powerUnit,
pi.timeUnit,
pi.uncoreMinFreq,
pi.uncoreMaxFreq,
pi.perfBias,
pds)
return nothing
end
"""
get_power_info() -> LIKWID.PowerInfo
Get power / energy information.
"""
function get_power_info()
if !topo_initialized[]
init_topology() || error("Couldn't init topology.")
end
if !power_initialized[]
init(0) || error("Couldn't init power.")
end
return powerinfo[]
end
"""
Return the start value for a cpu (`cpuid`) for the domain with `domainid`.
"""
function start_power(cpuid::Integer, domainid::Integer)
pt = LibLikwid.PowerType(domainid)
pd = LibLikwid.PowerData(pt, 0, 0)
pd_ref = Ref(pd)
LibLikwid.power_start(pd_ref, cpuid, pt)
return Int(pd_ref[].before)
end
"""
Return the stop value for a cpu (`cpuid`) for the domain with `domainid`.
"""
function stop_power(cpuid::Integer, domainid::Integer)
pt = LibLikwid.PowerType(domainid)
pd = LibLikwid.PowerData(pt, 0, 0)
pd_ref = Ref(pd)
LibLikwid.power_stop(pd_ref, cpuid, pt)
return Int(pd_ref[].after)
end
"""
get_power(p_start::Integer, p_stop::Integer, domainid::Integer)
Calculate the μJ from the values retrieved by `start_power()`
and `stop_power()`.
"""
function get_power(p_start::Integer, p_stop::Integer, domainid::Integer)
pt = LibLikwid.PowerType(domainid)
pd = LibLikwid.PowerData(pt, p_start, p_stop)
energy = LibLikwid.power_printEnergy(Ref(pd))
return energy * u"μJ"
end
"""
measure(f; cpuid::Integer=0, domainid::Integer)
Measure / calculate the energy for the given `cpuid` and `domainid`
over the execution of the function `f` using [`Power.start_power`](@ref),
[`Power.stop_power`](@ref), etc. under the hood. Automatically
initializes and finalizes the power module.
# Examples
```julia
julia> LIKWID.Power.measure(; cpuid=0, domainid=0) do
sleep(1)
end
15.13702392578125 μJ
```
"""
function measure(f; cpuid::Integer = 0, domainid::Integer)
init(cpuid) || error("Couldn't init LIKWIDs power module.")
try
p_start = start_power(cpuid, domainid)
f()
p_stop = stop_power(cpuid, domainid)
return get_power(p_start, p_stop, domainid)
finally
finalize()
end
end
end # module