clr_rapl.py 6.88 KB
Newer Older
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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
#!/usr/bin/env python
#
# coolr rapl related codes
#
# This code requires the intel_powerclamp module.
#
# Contact: Kazutomo Yoshii <ky@anl.gov>
#

import os, sys, re, time, getopt


class rapl_reader:
    dryrun = False
    rapldir='/sys/devices/virtual/powercap/intel-rapl'
    # 
    # e.g.,
    # intel-rapl:0/name
    # intel-rapl:0/intel-rapl:0:0/name
    # intel-rapl:0/intel-rapl:0:1/name
    def __init__ (self):
        self.dirs = {}
        self.max_energy_range_uj_d = {}

        if self.dryrun :
            return 

        self.init = False
        if not os.path.exists(self.rapldir):
            return
        self.init = True

        for d1 in os.listdir(self.rapldir):
            dn = "%s/%s" % (self.rapldir,d1)
            fn = dn + "/name"
            if os.access( fn , os.R_OK ) :
                f = open( fn)
                l = f.readline().strip()
                f.close()
                if re.search('package-[0-9]+', l):
                    self.dirs[l] = dn
                    pkg=l
                    for d2 in os.listdir("%s/%s" % (self.rapldir,d1) ):
                        dn = "%s/%s/%s" % (self.rapldir,d1,d2)
                        fn = dn + "/name"
                        if os.access( fn, os.R_OK ) :
                            f = open(fn)
                            l = f.readline().strip()
                            f.close
                            if re.search('core|dram', l):
                                self.dirs['%s/%s' % (pkg,l)] = dn


        for k in sorted(self.dirs.keys()):
            fn = self.dirs[k] + "/max_energy_range_uj"
            try:
                f = open( fn )
            except:
                print 'Unable to open', fn
                sys.exit(0)
            self.max_energy_range_uj_d[k] = int(f.readline())
            f.close()

        self.start_energy_counter()

    def initialized(self):
        return self.init

    def shortenkey(self,str):
        return str.replace('package-','p')

#        for k in sorted(self.dirs.keys()):
#            print k, self.max_energy_range_uj_d[k]


    def readenergy(self):
        if not self.init:
            return

        ret = {}
        ret['time'] = time.time()
        if self.dryrun:
            ret['package-0'] = readuptime()*1000.0*1000.0
            return ret
        for k in sorted(self.dirs.keys()):
            fn = self.dirs[k] + "/energy_uj"
            v = -1
            for retry in range(0,10):
                try:
                    f = open( fn )
                    v = int(f.readline())
                    f.close()
                except:
                    continue
            ret[k] = v
        return ret

    def readpowerlimit(self):
        if not self.init:
            return

        ret = {}
        if self.dryrun:
            ret['package-0'] = 100.0
            return ret
        for k in sorted(self.dirs.keys()):
            fn = self.dirs[k] + '/constraint_0_power_limit_uw'
            v = -1
            for retry in range(0,10):
                try:
                    f = open( fn )
                    v = int(f.readline())
                    f.close()
                except:
                    continue
            ret[k] = v / (1000.0 * 1000.0) # uw to w
        return ret

    def diffenergy(self,e1,e2): # e1 is prev and e2 is not
        ret = {}
        ret['time'] = e2['time'] - e1['time']
        for k in self.max_energy_range_uj_d:
            if e2[k]>=e1[k]:
                ret[k] = e2[k] - e1[k]
            else:
                ret[k] = (self.max_energy_range_uj_d[k]-e1[k]) + e2[k]
        return ret

    # calculate the average power from two energy values
    # e1 and e2 are the value returned from readenergy()
    # e1 should be sampled before e2
    def calcpower(self,e1,e2): 
        ret = {}
        delta = e2['time'] - e1['time']  # assume 'time' never wrap around
        ret['delta']  = delta
        if self.dryrun:
            k = 'package-0'
            ret[k] = e2[k] - e1[k]
            ret[k] /= (1000.0*1000.0) # conv. [uW] to [W]
            return ret

        for k in self.max_energy_range_uj_d:
            if e2[k]>=e1[k]:
                ret[k] = e2[k] - e1[k]
            else:
                ret[k] = (self.max_energy_range_uj_d[k]-e1[k]) + e2[k]
            ret[k] /= delta
            ret[k] /= (1000.0*1000.0) # conv. [uW] to [W]
        return ret

    # this should be renamed to reset_...
    def start_energy_counter(self):
        if not self.initialized():
            return

        self.start_time_e = time.time()
        self.totalenergy = {}
        self.lastpower = {}

        e = self.readenergy()
        for k in sorted(e.keys()):
            if k != 'time':
                self.totalenergy[k] = 0.0
                self.lastpower[k] = 0.0
        self.prev_e = e

    # XXX: fix the total energy tracking later
    def read_energy_acc(self):
        if not self.initialized():
            return

        e = self.readenergy()

        de = self.diffenergy(self.prev_e, e)

        for k in sorted(e.keys()):
            if k != 'time':
                self.totalenergy[k] += de[k]
                self.lastpower[k] = de[k]/de['time']/1000.0/1000.0;
        self.prev_e = e

        return e

    def stop_energy_counter(self):
        if not self.initialized():
            return

        e = self.read_energy_acc()
        self.stop_time = time.time()

191
    def sample(self, accflag=False):
192 193 194 195 196 197 198 199 200 201 202
        if not self.initialized():
            return

        e = self.readenergy()

        de = self.diffenergy(self.prev_e, e)

        for k in sorted(e.keys()):
            if k != 'time':
                if accflag:
                    self.totalenergy[k] += de[k]
203
                self.lastpower[k] = de[k]/de['time']/1000.0/1000.0
204 205
        self.prev_e = e

206 207
        ret = dict()
        ret['energy'] = dict()
208 209
        for k in sorted(e.keys()):
            if k != 'time':
210
                ret['energy'][self.shortenkey(k)] = e[k]
211

212
        ret['power'] = dict()
213 214 215
        totalpower = 0.0
        for k in sorted(self.lastpower.keys()):
            if k != 'time':
216
                ret['power'][self.shortenkey(k)] = self.lastpower[k]
217 218 219
                # this is a bit ad hoc way to calculate the total. needs to be fixed later
                if k.find("core") == -1:
                    totalpower += self.lastpower[k]
220
        ret['power']['total'] = totalpower
221

222
        ret['powercap'] = dict()
223 224
        rlimit = self.readpowerlimit()
        for k in sorted(rlimit.keys()):
225
            ret['powercap'][self.shortenkey(k)] = rlimit[k]
226

227
        return ret
228 229 230 231 232 233 234 235 236 237 238 239 240 241

    def total_energy_json(self):
        if not self.initialized():
            return ''

        dt = self.stop_time - self.start_time_e
        # constructing a json output
        e = self.totalenergy
        s  = '{"total":"energy","difftime":%f' % (dt)
        for k in sorted(e.keys()):
            if k != 'time':
                s += ',"%s":%d' % (self.shortenkey(k), e[k])
        s += '}'
        return s