Пример #1
0
    def bookHistos(self, monComp):
        ROOT = importRoot()
        #Analyzer.__bookHistos(self)

        #meta = self.meta.cfg.io

        from App import DataSetMgr
        for dataSetName in DataSetMgr.names():
            dataSet = DataSetMgr.instances[dataSetName]
            nEntries = len(dataSet.bins)
            minEvt = dataSet.bins[self.minEvt]
            maxEvt = dataSet.bins[-1]

            histos = monComp.data[dataSetName]['histos']

            hId = 'io_w_%s.%s' % (monComp.name, dataSetName)
            hName = 'io_w_%s' % dataSetName
            histos[hName] = ROOT.TH1F( hId,
                                       "[%s] I/O usage [%s] (W);%s;%s" % \
                                       ( monComp.name,
                                         monComp.name.replace("#","/"),
                                         "event nbr", "Timing [ms]" ),
                                       nEntries, minEvt, maxEvt )

            hId = 'io_r_%s.%s' % (monComp.name, dataSetName)
            hName = 'io_r_%s' % dataSetName
            histos[hName] = ROOT.TH1F( hId,
                                       "[%s] I/O usage [%s] (R);%s;%s" % \
                                       ( monComp.name,
                                         monComp.name.replace("#","/"),
                                         "event nbr", "Timing [ms]" ),
                                       nEntries, minEvt, maxEvt )

            hId = 'io_rr_%s.%s' % (monComp.name, dataSetName)
            hName = 'io_rr_%s' % dataSetName
            histos[hName] = ROOT.TH1F( hId,
                                       "[%s] I/O usage [%s] (RR);%s;%s" % \
                                       ( monComp.name,
                                         monComp.name.replace("#","/"),
                                         "event nbr", "Timing [ms]" ),
                                       nEntries, minEvt, maxEvt )

        return
Пример #2
0
    def fillHistos(self, monComp):

        from App import DataSetMgr
        self.msg.debug("filling histograms...")

        # short-hands

        # milliseconds
        ms = Units.ms

        dsNames = DataSetMgr.names()
        yMinRead = []
        yMaxRead = []
        yMinWrite = []
        yMaxWrite = []
        for dsName in dsNames:
            if dsName not in monComp.data:
                continue
            data = monComp.data[dsName]
            if 'evt' not in data:
                continue
            data['evt']['io/cpu/rr'] = data['evt']['io/user/rr'] \
                                     + data['evt']['io/sys/rr' ]
            data['evt']['io/cpu/r'] = data['evt']['io/user/r'] \
                                    + data['evt']['io/sys/r' ]
            yMinRead += [data['evt']['io/cpu/r'][self.minEvt:].min() * ms]
            yMaxRead += [data['evt']['io/cpu/r'][self.minEvt:].max() * ms]

            data['evt']['io/cpu/w'] = data['evt']['io/user/w'] \
                                    + data['evt']['io/sys/w' ]
            yMinWrite += [data['evt']['io/cpu/w'][self.minEvt:].min() * ms]
            yMaxWrite += [data['evt']['io/cpu/w'][self.minEvt:].max() * ms]
        yMinRead = min(yMinRead)
        yMaxRead = max(yMaxRead)
        yMinWrite = min(yMinWrite)
        yMaxWrite = max(yMaxWrite)

        for dsName in dsNames:
            if dsName not in monComp.data:
                continue
            data = monComp.data[dsName]
            if 'evt' not in data:
                continue
            bins = DataSetMgr.instances[dsName].bins
            if 'evt/io' not in monComp.figs:
                monComp.figs['evt/io'] = pylab.figure()
                monComp.figs['evt/io'].add_subplot(221).hold(True)
                monComp.figs['evt/io'].add_subplot(223).hold(True)
                monComp.figs['evt/io'].add_subplot(222).hold(True)
                monComp.figs['evt/io'].add_subplot(224).hold(True)

            ## read
            fig = monComp.figs['evt/io']
            ax = fig.axes[0]
            _iy = self.minEvt + len(bins[self.minEvt:])
            pl = ax.plot(bins[self.minEvt:],
                         data['evt']['io/cpu/r'][self.minEvt:_iy] * ms,
                         linestyle='steps',
                         label=dsName)

            ax.grid(True)
            ax.set_title("[%s]" % monComp.name)
            ax.set_ylabel('(R) CPU time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            h, b = numpy.histogram(data['evt']['io/cpu/r'][self.minEvt:] * ms +
                                   data['evt']['io/cpu/r'][self.minEvt:] * ms,
                                   bins=20,
                                   range=(yMinRead * 0.90, yMaxRead * 1.10))
            ax = fig.axes[1]
            ax.plot(b, h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('(R) CPU time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            ## write
            fig = monComp.figs['evt/io']
            ax = fig.axes[2]
            _iy = self.minEvt + len(bins[self.minEvt:])
            pl = ax.plot(bins[self.minEvt:],
                         data['evt']['io/cpu/w'][self.minEvt:_iy] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.grid(True)
            ax.set_title("[%s]" % monComp.name)
            ax.set_ylabel('(W) CPU time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            h, b = numpy.histogram(data['evt']['io/cpu/w'][self.minEvt:] * ms +
                                   data['evt']['io/cpu/w'][self.minEvt:] * ms,
                                   bins=20,
                                   range=(yMinWrite * 0.90, yMaxWrite * 1.10))
            ax = fig.axes[3]
            ax.plot(b, h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('(W) CPU time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            ## read
            h = data['histos']['io_r_%s' % dsName]
            hAvg = bookAvgHist(h, data['evt']['io/cpu/r'] * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = data['evt']['io/cpu/r'][i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            ## write
            h = data['histos']['io_w_%s' % dsName]
            hAvg = bookAvgHist(h, data['evt']['io/cpu/w'] * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = data['evt']['io/cpu/w'][i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            pass  # loop over datasets

        for ax in monComp.figs['evt/io'].axes:
            ax.legend(DataSetMgr.labels(), loc='best')

        ################################################
        # ROOT T/P separation overhead
        #
        for dsName in dsNames:
            if dsName not in monComp.data:
                continue
            data = monComp.data[dsName]
            if 'evt' not in data:
                continue
            bins = DataSetMgr.instances[dsName].bins
            if 'evt/rio' not in monComp.figs:
                monComp.figs['evt/rio'] = pylab.figure()
                monComp.figs['evt/rio'].add_subplot(221).hold(True)
                monComp.figs['evt/rio'].add_subplot(223).hold(True)
                monComp.figs['evt/rio'].add_subplot(222).hold(True)
                monComp.figs['evt/rio'].add_subplot(224).hold(True)

            ## read
            fig = monComp.figs['evt/rio']
            ax = fig.axes[0]
            _iy = self.minEvt + len(bins[self.minEvt:])
            pl = ax.plot(bins[self.minEvt:],
                         data['evt']['io/cpu/rr'][self.minEvt:_iy] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.set_title("[%s]" % monComp.name)
            ax.set_ylabel('(RR) CPU time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            h, b = numpy.histogram(
                data['evt']['io/cpu/rr'][self.minEvt:] * ms +
                data['evt']['io/cpu/rr'][self.minEvt:] * ms,
                bins=20,
                range=(yMinRead * 0.90, yMaxRead * 1.10))
            ax = fig.axes[1]
            ax.plot(b, h, label=dsName, ls='steps')
            ax.set_xlabel('(RR) CPU time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            _iy = self.minEvt + len(bins[self.minEvt:])
            ratios = []
            for idx, num in enumerate(
                    data['evt']['io/cpu/rr'][self.minEvt:_iy]):
                den = data['evt']['io/cpu/r'][idx]
                if den == 0.: r = 0
                else: r = num / den * 100.
                ratios.append(r)
##                 print "%3i %8.3f %8.3f %8.3f" % (idx,num,den,r)

            ratios = numpy.array(ratios)
            yMinRatio = min(ratios)
            yMaxRatio = max(ratios)

            ## pure ROOT read over T/P read
            fig = monComp.figs['evt/rio']
            ax = fig.axes[2]
            pl = ax.plot(bins[self.minEvt:],
                         ratios,
                         linestyle='steps',
                         label=dsName)
            ax.set_title("[%s]" % monComp.name)
            ax.set_ylabel('Pure-ROOT over Full read CPU time (%)')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            h, b = numpy.histogram(ratios + ratios,
                                   bins=20,
                                   range=(yMinRatio * 0.90, yMaxRatio * 1.10))
            ax = fig.axes[3]
            ax.plot(b, h, label=dsName, ls='steps')
            ax.set_xlabel('Pure-ROOT over Full read CPU time (%)')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            ## read
            h = data['histos']['io_rr_%s' % dsName]
            hAvg = bookAvgHist(h, data['evt']['io/cpu/rr'] * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = data['evt']['io/cpu/rr'][i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            pass  # loop over datasets

        for ax in monComp.figs['evt/io'].axes:
            ax.legend(DataSetMgr.labels(), loc='best')

        self.msg.debug("filling histograms... [DONE]")
        return
Пример #3
0
    def _top_consumers(self, dataSetMgr, monCompMgr, compTypes, title,
                       storeName, sliceName, begSlice, endSlice):
        from App import DataSetMgr
        ## fill-in the text file
        _txt = self.txt[sliceName]

        ## short-hand
        ms = Units.ms
        kb = Units.kb
        Mb = Units.Mb
        msg = self.msg

        dsNames = dataSetMgr.keys()
        dsNames.sort()

        monComps = []
        for monComp in monCompMgr.values():

            if not monComp.type in compTypes:
                continue

            monCompKeys = monComp.data.keys()
            monCompKeys.sort()
            if monCompKeys != dsNames:
                continue
            # remove AthMasterSeq and AthAlgSeq
            if monComp.name in (
                    'AthMasterSeq',
                    'AthAlgSeq',
            ):
                continue
            monComps.append(monComp)

        if len(monComps) == 0:
            msg.debug("Could not find any monitored component for"
                      " _top_consumers_ analysis !")
            return

        # create figure
        # --------------
        fig = plt.figure()
        fig.add_subplot(411).hold(True)
        fig.add_subplot(412).hold(True)
        fig.add_subplot(413).hold(True)
        fig.add_subplot(414).hold(True)
        self.sum[sliceName]['fig'] = fig

        # to hold 'cpu' for each dataSet
        axes = [[], [], [], []]

        color = DataSetMgr.colorIter()
        timings = {}

        _monComps = [m for m in monComps]
        for idx, dsName in enumerate(dsNames):

            monComps = []
            table = []
            timings[dsName] = []
            for monComp in _monComps:

                if not storeName in monComp.data[dsName]:
                    continue

                usrKey = 'cpu/user'
                sysKey = 'cpu/sys'
                realKey = 'cpu/real'
                vm0Key = 'mem/vmem/0'
                vm1Key = 'mem/vmem/1'
                malKey = 'mem/malloc/d'

                store = monComp.data[dsName][storeName]
                if store is None:
                    ## if storeName == 'evt':
                    ##     print "===",dsName,storeName,monComp.name
                    continue
                if len(store['mem']) == 0:
                    ## if storeName == 'evt':
                    ##     print "+++",dsName,storeName,monComp.name
                    continue

                cpu = store['cpu']
                cpu_u = cpu['user'][:, 2]
                cpu_s = cpu['sys'][:, 2]
                cpu_c = cpu['cpu'][:, 2]
                cpu_r = cpu['real'][:, 2]

                mem = store['mem']
                vmem = mem['vmem']
                mall = mem['mall']
                dvmem = vmem[:, 2]
                dmall = mall[:, 2]

                monComps.append(monComp)
                timings[dsName].append(monComp.name)
                table.append((
                    len(timings[dsName]) - 1,
                    cpu_u[begSlice:endSlice].mean() * ms,
                    cpu_s[begSlice:endSlice].mean() * ms,
                    (cpu_c[begSlice:endSlice] * ms).mean(),
                    (cpu_r[begSlice:endSlice] * ms).mean(),
                    (dvmem[begSlice:endSlice] * kb).mean(),
                    dmall[begSlice:endSlice].mean() * kb,
                    mem['nmall'][begSlice:endSlice, 2].mean(),
                    mem['nfree'][begSlice:endSlice, 2].mean(),
                ))
                has_nan = False
                new_value = list(table[-1])
                for ii, _vv in enumerate(new_value):
                    if numpy.isnan(_vv):
                        has_nan = True
                        new_value[ii] = 0
                        pass
                    pass
                if has_nan:
                    msg.warn("NaN in [%s]", monComp.name)
                    msg.warn(" -%s", table[-1])
                    table[-1] = tuple(new_value)
                    msg.warn(" +%s", table[-1])
                    pass

                pass  # loop over components

            descr = numpy.dtype({
                'names': ('name', 'cpu/user', 'cpu/sys', 'cpu/cpuTime',
                          'cpu/real', 'mem', 'malloc', 'nmall', 'nfree'),
                'formats': ('int32', 'float64', 'float64', 'float64',
                            'float64', 'float64', 'float64', 'int64', 'int64')
            })
            try:
                table = numpy.array(table, dtype=descr)

                nData = min(self.max,
                            len([m for m in monComps if m.type in compTypes]))
            except Exception, err:
                #msg.error("table: %s", table)
                msg.error("caught:  %s", err)
                msg.error("context: title=%s store=%s slice=%s beg=%s end=%s",
                          title, storeName, sliceName, begSlice, endSlice)
                nData = 0
                continue

            if nData == 0:
                _warn = msg.warning
                _warn("in top_consumers: no data to plot for [%s]!", title)
                _warn(
                    "** this may mean you'd have to re-run perfmon with more details enabled..."
                )
                _warn("dsname=[%s] storename=[%s]", dsName, storeName)
                _warn("no component found with type %s", compTypes)
                continue

            # linewidth for horizontal bars
            lw = 0.01
            names = timings[dsName]
            nDsNames = float(len(dsNames))

            ## CPU
            table.sort(order=('cpu/cpuTime', ))
            ax = fig.axes[0]
            ax.set_title('Top consumers during [%s]' % title)
            ax.set_xlabel('<Mean> CPU time (user+sys) [ms]')

            labels = [names[i] for i in table['name'][-nData:]]
            data = table['cpu/cpuTime'][-nData:]
            fc = color.next()
            pos = numpy.arange(nData)
            p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                        width=data,
                        height=1. / nDsNames,
                        align='edge',
                        color='r',
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            # display 'user' part only
            data = table['cpu/user'][-nData:]
            pos = numpy.arange(nData)
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=fc,
                        label=dsName,
                        lw=lw)
            axes[0] += p

            ## ==> fill ASCII
            if dsName == '000':
                _c = _txt['cpu']['comps']
                for _i in zip(table['cpu/cpuTime'], table['cpu/sys'],
                              [names[i] for i in table['name']]):
                    if not numpy.isnan(_i[0]):
                        _c += ["[cpu/sys] %10.3f %10.3f (ms) | %s" % _i]
                    else:
                        self.msg.error("%s contains weird data !!", _i[-1])
                _c.reverse()

            ## real-time
            table.sort(order=('cpu/real', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ax = fig.axes[1]
            ax.set_xlabel('<Mean> real time [ms]')
            data = table['cpu/real'][-nData:]
            pos = numpy.arange(len(data))
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=color.next(),
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            axes[1] += p

            ## virtual memory
            table.sort(order=('mem', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ax = fig.axes[2]
            #ax.set_xlabel( '$\Delta \rm{VMem}\ [kB]$' )
            ax.set_xlabel('delta VMem [kB]')
            data = table['mem'][-nData:]
            pos = numpy.arange(len(data))
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=color.next(),
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            axes[2] += p

            ## ==> fill ASCII
            if dsName == '000':
                _c = _txt['mem']['comps']
                for _i in zip(table['mem'], table['malloc'],
                              [names[i] for i in table['name']]):
                    if not numpy.isnan(_i[0]):
                        _c += ["dVmem|dMalloc %10.3f %10.3f kB | %s" % _i]
                    else:
                        self.msg.error("%s contains weird data !!", _i[-1])
                _c.reverse()

            ## malloc
            table.sort(order=('malloc', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ax = fig.axes[3]
            #ax.set_xlabel( '$\Delta \rm{Malloc}\ [kB]$' )
            ax.set_xlabel('delta Malloc [kB]')
            data = table['malloc'][-nData:]
            pos = numpy.arange(len(data))
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=color.next(),
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            axes[3] += p

            ## n-allocs
            table.sort(order=('nmall', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ## ==> fill ASCII
            if dsName == '000':
                _c = _txt['allocs']['comps']
                for _i in zip(table['nmall'], table['nfree'],
                              [names[i] for i in table['name']]):
                    if not numpy.isnan(_i[0]):
                        _c += ["alloc|free %10i %10i | %s" % _i]
                    else:
                        self.msg.error("%s contains weird data !!", _i[-1])
                _c.reverse()

            pass  # loop over data sets
Пример #4
0
        def _createFig(ioKey, speedKey, cppTypes, dsNames, figTitle):
            #print ":"*80,figTitle
            fig = plt.figure()
            fig.add_subplot(311).hold(True)
            fig.add_subplot(312).hold(True)
            fig.add_subplot(313).hold(True)

            from App import DataSetMgr
            color = DataSetMgr.colorIter()

            # to hold 'cpu' for each dataSet
            axes = [[], [], []]

            names = {}
            for idx, dsName in enumerate(dsNames):
                table = []
                names[dsName] = []
                for cppType in cppTypes.keys():
                    store = cppTypes[cppType][dsName]
                    if not store.has_key(ioKey):
                        continue
                    store = store[ioKey]
                    if len(store['size']) <= 0:
                        continue
                    names[dsName].append(cppType)
                    size = numpy.array(store['size'])
                    cTime = numpy.array([i[0] for i in store[speedKey]])
                    uTime = numpy.array([i[1] for i in store[speedKey]])
                    if speedKey == 'r':
                        cTimeR = numpy.array([i[0] for i in store['rr']])
                    else:
                        cTimeR = cTime
                    cFreq = numpy.array([1. / i for i in cTime])
                    uFreq = numpy.array([1. / i for i in uTime])
                    speed = size / cTime
                    #print cppType,store['size'],cTime.mean(),cTime,speed,speed.mean(),cFreq.mean()
                    table.append((
                        len(names[dsName]) - 1,
                        size.mean(),
                        cTimeR.mean() * ms,
                        cTime.mean() * ms,
                        uTime.mean() * ms,
                        cFreq.mean() / ms,
                        uFreq.mean() / ms,
                        speed.mean() / 1024. * 1e3,
                    ))
                    pass
                descr = numpy.dtype({
                    'names': (
                        'name',
                        'size',
                        speedKey + '/cpuRoot',
                        speedKey + '/cpu',
                        speedKey + '/user',
                        speedKey + '/cpuFreq',
                        speedKey + '/userFreq',
                        'speed',
                    ),
                    'formats': (
                        'int32',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                    ),
                })
                table = numpy.array(table, dtype=descr)
                nData = len(table)
                ##                 print speedKey,nData,names
                if nData == 0: return None

                table.sort(order=('size', ))

                # linewidth for horizontal bars
                lw = 0.01
                nDsNames = float(len(dsNames))

                ## -- processing time
                ax = fig.axes[0]
                ax.set_title(figTitle)
                xlabel = '<Mean> CPU time (user+sys) [ms]'
                if speedKey == 'r':
                    xlabel = '<Mean> CPU time (user+sys) [green=pure ROOT] [ms]'
                ax.set_xlabel(xlabel)

                labels = [names[dsName][i] for i in table['name']]
                data = table[speedKey + '/cpu']
                fc = color.next()
                pos = numpy.arange(nData)
                p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                            width=data,
                            height=1. / nDsNames,
                            color='r',
                            label=dsName,
                            lw=lw)
                ax.grid(True)
                ax.set_yticks(pos + 0.5)
                ax.set_yticklabels(labels,
                                   fontsize=6,
                                   horizontalalignment='right')

                # display 'user' part only
                data = table[speedKey + '/user']
                pos = numpy.arange(nData)
                p = ax.barh(pos + (idx * 1. / nDsNames),
                            data,
                            1. / nDsNames,
                            align='edge',
                            color=fc,
                            label=dsName,
                            lw=lw)
                axes[0] += p

                # hack to display the ROOT component (only for reading)
                if speedKey == 'r':
                    data = table[speedKey + '/cpuRoot']
                    pos = numpy.arange(nData)
                    p = ax.barh(pos + (idx * 1. / nDsNames),
                                data,
                                1. / nDsNames,
                                align='edge',
                                color='g',
                                label=dsName,
                                lw=lw)

                ## -- Speed
                ax = fig.axes[1]
                ax.set_xlabel('<Mean> Speed (user+sys) [MB/s]')

                labels = [names[dsName][i] for i in table['name']]
                data = table[speedKey + '/cpu']
                data = table['speed']
                fc = color.next()
                pos = numpy.arange(nData)
                p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                            width=data,
                            height=1. / nDsNames,
                            color='r',
                            label=dsName,
                            lw=lw)
                ax.grid(True)
                ax.set_yticks(pos + 0.5)
                ax.set_yticklabels(labels,
                                   fontsize=6,
                                   horizontalalignment='right')

                # display 'user' part only
                data = table[speedKey + '/user']
                data = table['speed']
                pos = numpy.arange(nData)
                p = ax.barh(pos + (idx * 1. / nDsNames),
                            data,
                            1. / nDsNames,
                            align='edge',
                            color=fc,
                            label=dsName,
                            lw=lw)
                axes[1] += p

                ## -- Frequency

                ax = fig.axes[2]
                ax.set_xlabel('<Mean> Frequency (user+sys) [kHz]')

                labels = [names[dsName][i] for i in table['name']]
                data = table[speedKey + '/cpuFreq']
                fc = color.next()
                pos = numpy.arange(nData)
                p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                            width=data,
                            height=1. / nDsNames,
                            color='r',
                            label=dsName,
                            lw=lw)
                ax.grid(True)
                ax.set_yticks(pos + 0.5)
                ax.set_yticklabels(labels,
                                   fontsize=6,
                                   horizontalalignment='right')

                # display 'user' part only
                data = table[speedKey + '/userFreq']
                pos = numpy.arange(nData)
                p = ax.barh(pos + (idx * 1. / nDsNames),
                            data,
                            1. / nDsNames,
                            align='edge',
                            color=fc,
                            label=dsName,
                            lw=lw)
                axes[2] += p

            for ix, ax in zip(axes, fig.axes):
                ax.legend(ix[::nData], DataSetMgr.labels(), loc='lower right')
            return fig
Пример #5
0
class SummaryCreator(object):
    def __init__(self, fitSlice):
        object.__init__(self)
        self.msg = logging.getLogger("Summary")
        self.msg.setLevel(logging.INFO)
        self.sum = {
            'ini': {},
            '1st': {},
            'evt': {},
            'fin': {},
            'io': {},
        }
        self._fitSlice = []
        for i in fitSlice.split(":"):
            try:
                self._fitSlice += [int(i)]
            except ValueError:
                self._fitSlice += [None]
        # text format of the summary
        self.txt = {}
        for i in ('ini', '1st', 'evt', 'fin'):
            self.txt[i] = {}
            for j in ('mem', 'cpu', 'allocs'):
                self.txt[i][j] = {
                    'slice': [],
                    'comps': [],
                }

        # maximal number of top-XXX consumers to display
        self.max = 20

        self.minEvt = 1
        self.maxEvt = -1
        return

    def process(self, dataSetMgr, monCompMgr):

        from PyRootLib import importRoot
        ROOT = importRoot(batch=True)
        from PyRootLib import setupRootStyle
        setupRootStyle()
        c = ROOT.TCanvas('c_default')

        for m in [
                self.processIni,
                self.processFirstEvt,
                self.processEvt,
                self.processFin,
                #self.processIo, ## FIXME
        ]:
            m(dataSetMgr, monCompMgr)
        del c
        return

    def processIni(self, dataSetMgr, monCompMgr):

        self._top_consumers(dataSetMgr,
                            monCompMgr,
                            compTypes=('alg', 'algtool', 'svc'),
                            title='initialization',
                            storeName='ini',
                            sliceName='ini',
                            begSlice=0,
                            endSlice=1)
        return

    def processFirstEvt(self, dataSetMgr, monCompMgr):

        ## get top-20 consumers
        self._top_consumers(dataSetMgr,
                            monCompMgr,
                            compTypes=('alg', ),
                            title='1st event',
                            storeName='evt',
                            sliceName='1st',
                            begSlice=0,
                            endSlice=1)
        return

    def processEvt(self, dataSetMgr, monCompMgr):
        from App import DataSetMgr

        from PyRootLib import importRoot
        ROOT = importRoot(batch=True)

        ## RootFct = ROOT.TF1
        ## dummyCanvas = ROOT.TCanvas("dummyFitCanvas")
        ## import PyRootLib as prl

        ## self.sum['evt']['histos'] = []
        ## self.sum['evt']['fig']    = []

        ## short-hand
        ms = Units.ms
        kb = Units.kb
        Mb = Units.Mb
        Mb2Kb = 1000.
        msg = self.msg

        ## get top-20 consumers
        dsNames = DataSetMgr.names()
        color = DataSetMgr.colorIter()

        _txt = self.txt['evt']

        monComp = monCompMgr['PerfMonSlice']
        yMinCpu = []
        yMaxCpu = []
        yMinIo = []
        yMaxIo = []
        for dsName in dsNames:
            data = monComp.data[dsName]
            histos = data['histos'] = {}
            if not 'evt' in data:
                continue
            data = data['evt']
            if data is None:
                continue
            cpu = data['cpu']
            cpu_u = cpu['user']
            cpu_s = cpu['sys']
            cpu_r = cpu['real']
            cpu_c = cpu['cpu']

            dcpu_u = cpu_u[:, 2]
            dcpu_s = cpu_s[:, 2]
            dcpu_r = cpu_r[:, 2]
            dcpu_c = cpu_c[:, 2]

            mem = data['mem']
            vmem = mem['vmem']
            dvmem = vmem[:, 2]
            rss = mem['rss']
            drss = rss[:, 2]
            mall = mem['mall']
            dmall = mall[:, 2]

            nallocs = mem['nmall'][:, 2]
            nfrees = mem['nfree'][:, 2]

            yMinCpu.append(dcpu_c[self.minEvt:].min() * ms)
            yMaxCpu.append(dcpu_c[self.minEvt:].max() * ms)

            io = monComp.data[dsName]['io']
            io_c = io['w']['cpu']
            yMinIo.append(io_c[self.minEvt:].min() * ms)
            yMaxIo.append(io_c[self.minEvt:].max() * ms)

            ##             data['mem/vmem/d'] = data['mem/vmem/1'] - data['mem/vmem/0']
            ##             data['mem/rss/d' ] = data['mem/rss/1' ] - data['mem/rss/0' ]

            ## fill-in some data for ASCII summary
            if dsName == '000':
                _txt['cpu']['slice'] += [
                    "%-20s %10.3f %10.3f %10.3f ms" % (
                        "[u/s/r]",
                        dcpu_u[self.minEvt:].mean() * ms,
                        dcpu_s[self.minEvt:].mean() * ms,
                        dcpu_r[self.minEvt:].mean() * ms,
                    ),
                ]
                _txt['mem']['slice'] += [
                    "%-20s %10.3f %10.3f %10.3f kB" % (
                        "[dVmem/dRss/dMalloc]",
                        dvmem[self.minEvt:].mean() * kb,
                        drss[self.minEvt:].mean() * kb,
                        dmall[self.minEvt:].mean() * kb,
                    ),
                ]
                _txt['allocs']['slice'] += [
                    "%-20s %10i %10i" % (
                        "[nallocs/nfrees]",
                        nallocs[self.minEvt:].mean(),
                        nfrees[self.minEvt:].mean(),
                    ),
                ]

            ## book ROOT histos
            nEntries = len(dataSetMgr[dsName].bins) - 1
            minEvt = dataSetMgr[dsName].bins[self.minEvt]
            maxEvt = dataSetMgr[dsName].bins[-1]

            hId = 'cpu_%s.%s' % (monComp.name, dsName)
            hName = 'cpu_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] CPU usage [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "Timing [ms]"), nEntries,
                minEvt, maxEvt)

            hId = 'vmem_%s.%s' % (monComp.name, dsName)
            hName = 'vmem_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] VMem usage [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "V-Mem [MB]"), nEntries,
                minEvt, maxEvt)

            hId = 'rss_%s.%s' % (monComp.name, dsName)
            hName = 'rss_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] RSS usage [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "RSS [MB]"), nEntries,
                minEvt, maxEvt)

            hId = 'io_%s.%s' % (monComp.name, dsName)
            hName = 'io_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] I/O time [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "I/O time [ms]"), nEntries,
                minEvt, maxEvt)
            pass

        yMinIo = min(yMinIo)
        yMaxIo = max(yMaxIo)
        yMinCpu = min(yMinCpu)
        yMaxCpu = max(yMaxCpu)

        def markForLegend(p):
            setattr(p, '_markedForLegend', True)

        def isMarked(p):
            return hasattr(p, '_markedForLegend')

        memLeak = []
        for dsName in dsNames:

            if not 'evt' in monComp.data[dsName]:
                continue

            data = monComp.data[dsName]

            cpu = data['evt']['cpu']
            cpu_c = cpu['cpu']
            dcpu_c = cpu_c[:, 2]

            ## CPU
            bins = dataSetMgr[dsName].bins
            xbins = bins[self.minEvt:]
            if not 'evt/cpu' in monComp.figs:
                monComp.figs['evt/cpu'] = plt.figure()
                monComp.figs['evt/cpu'].add_subplot(211).hold(True)
                monComp.figs['evt/cpu'].add_subplot(212).hold(True)
            fig = monComp.figs['evt/cpu']
            ax = fig.axes[0]
            pl = ax.plot(xbins,
                         dcpu_c[self.minEvt:] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.grid(True)
            ax.set_title("CPU time [Begin/End-Event]")
            ax.set_ylabel('CPU time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            markForLegend(pl[0])

            h, b = numpy.histogram(dcpu_c[self.minEvt:] * ms,
                                   bins=20,
                                   range=(yMinCpu * 0.90, yMaxCpu * 1.10))
            ax = fig.axes[1]
            pl = ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('CPU time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))
            markForLegend(pl[0])

            h = data['histos']['cpu_%s' % dsName]
            hAvg = bookAvgHist(h, dcpu_c * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = dcpu_c[i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            ## Mem
            mem = data['evt']['mem']
            vmem = mem['vmem']
            dvmem = vmem[:, 2]
            dmall = mem['mall'][:, 2]

            if not 'evt/mem' in monComp.figs:
                monComp.figs['evt/mem'] = plt.figure()
                monComp.figs['evt/mem'].add_subplot(311).hold(True)
                monComp.figs['evt/mem'].add_subplot(312).hold(True)
                monComp.figs['evt/mem'].add_subplot(313).hold(True)

            fig = monComp.figs['evt/mem']
            ax = fig.axes[0]
            pl = ax.plot(
                xbins,
                vmem[self.minEvt:, 1] * Mb,
                linestyle='steps',
                #'o',
                label=dsName)
            ax.set_title("Memory usage [Begin/End-Event]")
            ax.set_ylabel('VMem [MB]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            ## fit
            #nFit = int(len(bins)/2.)
            #x = bins[-nFit:]
            #y = data['evt']['mem/vmem/1'][-nFit:] * Mb
            begFit = self._fitSlice[0]
            endFit = self._fitSlice[1]
            x = bins[begFit:endFit]
            y = vmem[begFit:endFit, 1] * Mb
            coeffs = numpy.lib.polyfit(x, y, deg=1)
            memLeak += [coeffs[0] * kb]
            ax.plot(x, numpy.lib.polyval(coeffs, x), '-', color='y', lw=2.)
            if dsName == '000':
                _txt['mem']['slice'] += [
                    "%-20s p[0] = %8.3f MB \tp[1] = %8.3f kB" % (
                        "vmem fit:",
                        coeffs[1] * Mb,
                        coeffs[0] * kb,  #
                    )
                ]

            ax = fig.axes[1]
            pl = ax.plot(xbins,
                         mem['rss'][self.minEvt:, 1] * Mb,
                         linestyle='steps',
                         label=dsName)
            ax.set_ylabel('RSS [MB]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            ax = fig.axes[2]
            pl = ax.plot(xbins,
                         dmall[self.minEvt:] * Mb,
                         linestyle='steps',
                         label=dsName)
            ax.set_ylabel('Delta Malloc [MB]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            h = data['histos']['vmem_%s' % dsName]
            hAvg = bookAvgHist(h, mem['vmem'][:, 1] * Mb)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                vmem = mem['vmem'][i, 1] * Mb
                h.Fill(float(bins[i]), vmem)
                hAvg.Fill(vmem)

            h = data['histos']['rss_%s' % dsName]
            hAvg = bookAvgHist(h, mem['rss'][:, 1] * Mb)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                rss = mem['rss'][i, 1] * Mb
                h.Fill(float(bins[i]), rss)
                hAvg.Fill(rss)

            ## I/O
            if not 'evt/io' in monComp.figs:
                monComp.figs['evt/io'] = plt.figure()
                monComp.figs['evt/io'].add_subplot(211).hold(True)
                monComp.figs['evt/io'].add_subplot(212).hold(True)
            fig = monComp.figs['evt/io']
            ax = fig.axes[0]
            io_c = data['io']['w']['cpu']
            pl = ax.plot(xbins,
                         io_c[self.minEvt:] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.set_title("I/O time [CommitOutput]")
            ax.set_ylabel('I/O time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            yMinIo *= 0.9
            yMaxIo *= 1.1
            yMinIo, yMaxIo = min(yMinIo, yMaxIo), max(yMinIo, yMaxIo)
            h, b = numpy.histogram(io_c[self.minEvt:] * ms,
                                   bins=20,
                                   range=(yMinIo, yMaxIo))
            ax = fig.axes[1]
            pl = ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.set_xlabel('I/O time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            h = data['histos']['io_%s' % dsName]
            hAvg = bookAvgHist(h, io_c * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = io_c[i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            pass  # loop over data sets

        ## handle mem-leak text
        ax = monComp.figs['evt/mem'].axes[0]
        ax.text(
            0.025,
            0.97,
            "\n".join("[%s] Leak: %8.3f kB" % (n, leak)
                      for n, leak in zip(DataSetMgr.labels(), memLeak)),
            bbox=dict(facecolor='w'),
            #color = '',
            fontweight='bold',
            #fontsize   = 'x-larger',
            verticalalignment='top',
            transform=ax.transAxes)
        for figName, fig in monComp.figs.items():
            loc = 'best'
            if figName == 'evt/mem': loc = 'lower right'
            for ax in fig.axes:
                objs = [l for l in ax.lines if isMarked(l)]
                ax.legend(
                    objs,
                    DataSetMgr.labels(),
                    #loc='lower right'
                    #loc='best'
                    loc=loc)

        ## get top-20 consumers
        self._top_consumers(dataSetMgr,
                            monCompMgr,
                            compTypes=('alg', ),
                            title='Event loop',
                            storeName='evt',
                            sliceName='evt',
                            begSlice=self.minEvt,
                            endSlice=None)
        return

    def processFin(self, dataSetMgr, monCompMgr):

        self._top_consumers(dataSetMgr,
                            monCompMgr,
                            compTypes=('alg', 'algtool', 'svc'),
                            title="finalization",
                            storeName='fin',
                            sliceName='fin',
                            begSlice=0,
                            endSlice=None)
        return

    def processIo(self, dataSetMgr, monCompMgr):

        from App import DataSetMgr
        ## short-hand
        ms = Units.ms
        kb = Units.kb
        Mb = Units.Mb

        dsNames = dataSetMgr.keys()
        dsNames.sort()

        monComps = []
        cppTypes = {}
        for monComp in monCompMgr.values():

            if monComp.type != 'io':
                continue

            monCompKeys = monComp.data.keys()
            monCompKeys.sort()
            if monCompKeys != dsNames: continue
            monComps.append(monComp)
            cppTypes[monComp.name.split("#")[0]] = {}

        if len(monComps) == 0:
            self.msg.debug("Could not find any io-container to process !")
            return

        ## get input and/or output files
        inputFiles = {}
        outputFiles = {}
        for dsName in dsNames:
            d = dataSetMgr[dsName].data
            for k in d.keys():
                if not k.startswith( "meta://inputPoolFiles/" ) and \
                   not k.startswith( "meta://outputPoolFiles/" ):
                    continue
                n, i = k.split("PoolFiles/")
                if n.startswith("meta://input"): f = inputFiles
                elif n.startswith("meta://output"): f = outputFiles
                else: continue
                try:
                    f[dsName][int(i)] = d[k]
                except KeyError:
                    f[dsName] = {}
                    f[dsName][int(i)] = d[k]

        def _findFolders(files, pattern, dsName):
            d = {}
            cppType = pattern[0]
            sgKey = pattern[1]
            if files.has_key(dsName):
                for file in files[dsName].values():
                    ##                     print ":"*80,"-->file"
                    for f in file['data']:
                        n = f['name']
                        pat = n.startswith( cppType+"_" ) and \
                              n.endswith  ( "_"+sgKey   )
                        #                        pat = n.endswith  ( "_"+sgKey   )
                        #                        pat = n.count( sgKey   ) > 0
                        if pat:
                            size = f['diskSize'] / float(f['nEntries'])
                            try:
                                d[n] += size
                            except KeyError:
                                d[n] = size
##                         print "\t-%5s" % str(pat),n
            keys = d.keys()
            if len(keys) > 1:
                raise RuntimeError, "len(d) > 1: %r" % d
            if len(keys) == 0: return []
            else: return [d.items()[0]]

        ## helper function
        def io_proj(data, varexp):
            n, h = project(data, id="tmp", varexp=varexp)
            mean = h.GetMean()
            del h
            return mean

        ## try to find the disk-size for each container
        ## regroup everything by container type
        for monComp in monComps:
            monName = monComp.name
            cppType, sgKey = monComp.name.split("#")
            ##             print "---- %-30s %-30s ----" % (cppType,sgKey)
            #print "monComp:",monComp.name,cppType,sgKey
            #tp_pattern = re.compile( r'%s_.*?%s' % ( cppType, sgKey ) )
            tp_pattern = (cppType, sgKey)
            for dsName in dsNames:
                if not cppTypes[cppType].has_key(dsName):
                    cppTypes[cppType][dsName] = {}
                data = monComp.data[dsName]['evt']

                ior = io_proj(data, varexp=monName + ".r.cpu()") * ms
                iorr = io_proj(data, varexp=monName + ".rr.cpu()") * ms
                iow = io_proj(data, varexp=monName + ".w.cpu()") * ms

                ior = (ior, io_proj(data, varexp=monName + ".r.user") * ms)
                iorr = (iorr, io_proj(data, varexp=monName + ".rr.user") * ms)
                iow = (iow, io_proj(data, varexp=monName + ".w.user") * ms)
                ##                 print "\tio-r ",ior
                ##                 print "\tio-rr",iorr
                ##                 print "\tio-w ",iow
                if ior[0] > 0.:
                    d = {
                        'size': _findFolders(inputFiles, tp_pattern, dsName),
                        'r': ior,
                        'rr': iorr,
                    }
                    monComp.data[dsName]['io/in'] = d
                    if len(d['size']) > 0:
                        try:
                            io_in = cppTypes[cppType][dsName]['io/in']
                        except KeyError:
                            cppTypes[cppType][dsName]['io/in'] = {
                                'size': [],
                                'r': [],
                                'rr': []
                            }
                            io_in = cppTypes[cppType][dsName]['io/in']
                        io_in['size'] += [d['size'][0][1]]
                        io_in['r'] += [ior]
                        io_in['rr'] += [iorr]
                if iow[0] > 0.:
                    d = {
                        'size': _findFolders(outputFiles, tp_pattern, dsName),
                        'w': iow,
                    }
                    monComp.data[dsName]['io/out'] = d
                    if len(d['size']) > 0:
                        try:
                            io_out = cppTypes[cppType][dsName]['io/out']
                        except KeyError:
                            cppTypes[cppType][dsName]['io/out'] = {
                                'size': [],
                                'w': []
                            }
                            io_out = cppTypes[cppType][dsName]['io/out']
                        io_out['size'] += [d['size'][0][1]]
                        io_out['w'] += [iow]
##             try:
##                 print "in: ",monComp.data['000']['io/in']
##             except KeyError: print "<none>";pass
##             try:
##                 print "out:",monComp.data['000']['io/out']
##             except KeyError: print "<none>";pass
            pass

        self.sum['io']['fig'] = []

        def _createFig(ioKey, speedKey, cppTypes, dsNames, figTitle):
            #print ":"*80,figTitle
            fig = plt.figure()
            fig.add_subplot(311).hold(True)
            fig.add_subplot(312).hold(True)
            fig.add_subplot(313).hold(True)

            from App import DataSetMgr
            color = DataSetMgr.colorIter()

            # to hold 'cpu' for each dataSet
            axes = [[], [], []]

            names = {}
            for idx, dsName in enumerate(dsNames):
                table = []
                names[dsName] = []
                for cppType in cppTypes.keys():
                    store = cppTypes[cppType][dsName]
                    if not store.has_key(ioKey):
                        continue
                    store = store[ioKey]
                    if len(store['size']) <= 0:
                        continue
                    names[dsName].append(cppType)
                    size = numpy.array(store['size'])
                    cTime = numpy.array([i[0] for i in store[speedKey]])
                    uTime = numpy.array([i[1] for i in store[speedKey]])
                    if speedKey == 'r':
                        cTimeR = numpy.array([i[0] for i in store['rr']])
                    else:
                        cTimeR = cTime
                    cFreq = numpy.array([1. / i for i in cTime])
                    uFreq = numpy.array([1. / i for i in uTime])
                    speed = size / cTime
                    #print cppType,store['size'],cTime.mean(),cTime,speed,speed.mean(),cFreq.mean()
                    table.append((
                        len(names[dsName]) - 1,
                        size.mean(),
                        cTimeR.mean() * ms,
                        cTime.mean() * ms,
                        uTime.mean() * ms,
                        cFreq.mean() / ms,
                        uFreq.mean() / ms,
                        speed.mean() / 1024. * 1e3,
                    ))
                    pass
                descr = numpy.dtype({
                    'names': (
                        'name',
                        'size',
                        speedKey + '/cpuRoot',
                        speedKey + '/cpu',
                        speedKey + '/user',
                        speedKey + '/cpuFreq',
                        speedKey + '/userFreq',
                        'speed',
                    ),
                    'formats': (
                        'int32',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                        'float64',
                    ),
                })
                table = numpy.array(table, dtype=descr)
                nData = len(table)
                ##                 print speedKey,nData,names
                if nData == 0: return None

                table.sort(order=('size', ))

                # linewidth for horizontal bars
                lw = 0.01
                nDsNames = float(len(dsNames))

                ## -- processing time
                ax = fig.axes[0]
                ax.set_title(figTitle)
                xlabel = '<Mean> CPU time (user+sys) [ms]'
                if speedKey == 'r':
                    xlabel = '<Mean> CPU time (user+sys) [green=pure ROOT] [ms]'
                ax.set_xlabel(xlabel)

                labels = [names[dsName][i] for i in table['name']]
                data = table[speedKey + '/cpu']
                fc = color.next()
                pos = numpy.arange(nData)
                p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                            width=data,
                            height=1. / nDsNames,
                            color='r',
                            label=dsName,
                            lw=lw)
                ax.grid(True)
                ax.set_yticks(pos + 0.5)
                ax.set_yticklabels(labels,
                                   fontsize=6,
                                   horizontalalignment='right')

                # display 'user' part only
                data = table[speedKey + '/user']
                pos = numpy.arange(nData)
                p = ax.barh(pos + (idx * 1. / nDsNames),
                            data,
                            1. / nDsNames,
                            align='edge',
                            color=fc,
                            label=dsName,
                            lw=lw)
                axes[0] += p

                # hack to display the ROOT component (only for reading)
                if speedKey == 'r':
                    data = table[speedKey + '/cpuRoot']
                    pos = numpy.arange(nData)
                    p = ax.barh(pos + (idx * 1. / nDsNames),
                                data,
                                1. / nDsNames,
                                align='edge',
                                color='g',
                                label=dsName,
                                lw=lw)

                ## -- Speed
                ax = fig.axes[1]
                ax.set_xlabel('<Mean> Speed (user+sys) [MB/s]')

                labels = [names[dsName][i] for i in table['name']]
                data = table[speedKey + '/cpu']
                data = table['speed']
                fc = color.next()
                pos = numpy.arange(nData)
                p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                            width=data,
                            height=1. / nDsNames,
                            color='r',
                            label=dsName,
                            lw=lw)
                ax.grid(True)
                ax.set_yticks(pos + 0.5)
                ax.set_yticklabels(labels,
                                   fontsize=6,
                                   horizontalalignment='right')

                # display 'user' part only
                data = table[speedKey + '/user']
                data = table['speed']
                pos = numpy.arange(nData)
                p = ax.barh(pos + (idx * 1. / nDsNames),
                            data,
                            1. / nDsNames,
                            align='edge',
                            color=fc,
                            label=dsName,
                            lw=lw)
                axes[1] += p

                ## -- Frequency

                ax = fig.axes[2]
                ax.set_xlabel('<Mean> Frequency (user+sys) [kHz]')

                labels = [names[dsName][i] for i in table['name']]
                data = table[speedKey + '/cpuFreq']
                fc = color.next()
                pos = numpy.arange(nData)
                p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                            width=data,
                            height=1. / nDsNames,
                            color='r',
                            label=dsName,
                            lw=lw)
                ax.grid(True)
                ax.set_yticks(pos + 0.5)
                ax.set_yticklabels(labels,
                                   fontsize=6,
                                   horizontalalignment='right')

                # display 'user' part only
                data = table[speedKey + '/userFreq']
                pos = numpy.arange(nData)
                p = ax.barh(pos + (idx * 1. / nDsNames),
                            data,
                            1. / nDsNames,
                            align='edge',
                            color=fc,
                            label=dsName,
                            lw=lw)
                axes[2] += p

            for ix, ax in zip(axes, fig.axes):
                ax.legend(ix[::nData], DataSetMgr.labels(), loc='lower right')
            return fig

        fig = _createFig('io/in',
                         'r',
                         cppTypes,
                         dsNames,
                         figTitle='[P->T] transformations')
        if fig: self.sum['io']['fig'] += [fig]

        ##         fig = _createFig( 'io/in',  'rr', cppTypes, dsNames,
        ##                           figTitle = '[P->T] transformations (ROOT part)' )
        ##         if fig: self.sum['io']['fig'] += [ fig ]

        fig = _createFig('io/out',
                         'w',
                         cppTypes,
                         dsNames,
                         figTitle='[T->P] transformations')
        if fig: self.sum['io']['fig'] += [fig]

        return

    def _top_consumers(self, dataSetMgr, monCompMgr, compTypes, title,
                       storeName, sliceName, begSlice, endSlice):
        from App import DataSetMgr
        ## fill-in the text file
        _txt = self.txt[sliceName]

        ## short-hand
        ms = Units.ms
        kb = Units.kb
        Mb = Units.Mb
        msg = self.msg

        dsNames = dataSetMgr.keys()
        dsNames.sort()

        monComps = []
        for monComp in monCompMgr.values():

            if not monComp.type in compTypes:
                continue

            monCompKeys = monComp.data.keys()
            monCompKeys.sort()
            if monCompKeys != dsNames:
                continue
            # remove AthMasterSeq and AthAlgSeq
            if monComp.name in (
                    'AthMasterSeq',
                    'AthAlgSeq',
            ):
                continue
            monComps.append(monComp)

        if len(monComps) == 0:
            msg.debug("Could not find any monitored component for"
                      " _top_consumers_ analysis !")
            return

        # create figure
        # --------------
        fig = plt.figure()
        fig.add_subplot(411).hold(True)
        fig.add_subplot(412).hold(True)
        fig.add_subplot(413).hold(True)
        fig.add_subplot(414).hold(True)
        self.sum[sliceName]['fig'] = fig

        # to hold 'cpu' for each dataSet
        axes = [[], [], [], []]

        color = DataSetMgr.colorIter()
        timings = {}

        _monComps = [m for m in monComps]
        for idx, dsName in enumerate(dsNames):

            monComps = []
            table = []
            timings[dsName] = []
            for monComp in _monComps:

                if not storeName in monComp.data[dsName]:
                    continue

                usrKey = 'cpu/user'
                sysKey = 'cpu/sys'
                realKey = 'cpu/real'
                vm0Key = 'mem/vmem/0'
                vm1Key = 'mem/vmem/1'
                malKey = 'mem/malloc/d'

                store = monComp.data[dsName][storeName]
                if store is None:
                    ## if storeName == 'evt':
                    ##     print "===",dsName,storeName,monComp.name
                    continue
                if len(store['mem']) == 0:
                    ## if storeName == 'evt':
                    ##     print "+++",dsName,storeName,monComp.name
                    continue

                cpu = store['cpu']
                cpu_u = cpu['user'][:, 2]
                cpu_s = cpu['sys'][:, 2]
                cpu_c = cpu['cpu'][:, 2]
                cpu_r = cpu['real'][:, 2]

                mem = store['mem']
                vmem = mem['vmem']
                mall = mem['mall']
                dvmem = vmem[:, 2]
                dmall = mall[:, 2]

                monComps.append(monComp)
                timings[dsName].append(monComp.name)
                table.append((
                    len(timings[dsName]) - 1,
                    cpu_u[begSlice:endSlice].mean() * ms,
                    cpu_s[begSlice:endSlice].mean() * ms,
                    (cpu_c[begSlice:endSlice] * ms).mean(),
                    (cpu_r[begSlice:endSlice] * ms).mean(),
                    (dvmem[begSlice:endSlice] * kb).mean(),
                    dmall[begSlice:endSlice].mean() * kb,
                    mem['nmall'][begSlice:endSlice, 2].mean(),
                    mem['nfree'][begSlice:endSlice, 2].mean(),
                ))
                has_nan = False
                new_value = list(table[-1])
                for ii, _vv in enumerate(new_value):
                    if numpy.isnan(_vv):
                        has_nan = True
                        new_value[ii] = 0
                        pass
                    pass
                if has_nan:
                    msg.warn("NaN in [%s]", monComp.name)
                    msg.warn(" -%s", table[-1])
                    table[-1] = tuple(new_value)
                    msg.warn(" +%s", table[-1])
                    pass

                pass  # loop over components

            descr = numpy.dtype({
                'names': ('name', 'cpu/user', 'cpu/sys', 'cpu/cpuTime',
                          'cpu/real', 'mem', 'malloc', 'nmall', 'nfree'),
                'formats': ('int32', 'float64', 'float64', 'float64',
                            'float64', 'float64', 'float64', 'int64', 'int64')
            })
            try:
                table = numpy.array(table, dtype=descr)

                nData = min(self.max,
                            len([m for m in monComps if m.type in compTypes]))
            except Exception, err:
                #msg.error("table: %s", table)
                msg.error("caught:  %s", err)
                msg.error("context: title=%s store=%s slice=%s beg=%s end=%s",
                          title, storeName, sliceName, begSlice, endSlice)
                nData = 0
                continue

            if nData == 0:
                _warn = msg.warning
                _warn("in top_consumers: no data to plot for [%s]!", title)
                _warn(
                    "** this may mean you'd have to re-run perfmon with more details enabled..."
                )
                _warn("dsname=[%s] storename=[%s]", dsName, storeName)
                _warn("no component found with type %s", compTypes)
                continue

            # linewidth for horizontal bars
            lw = 0.01
            names = timings[dsName]
            nDsNames = float(len(dsNames))

            ## CPU
            table.sort(order=('cpu/cpuTime', ))
            ax = fig.axes[0]
            ax.set_title('Top consumers during [%s]' % title)
            ax.set_xlabel('<Mean> CPU time (user+sys) [ms]')

            labels = [names[i] for i in table['name'][-nData:]]
            data = table['cpu/cpuTime'][-nData:]
            fc = color.next()
            pos = numpy.arange(nData)
            p = ax.barh(bottom=pos + (idx * 1. / nDsNames),
                        width=data,
                        height=1. / nDsNames,
                        align='edge',
                        color='r',
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            # display 'user' part only
            data = table['cpu/user'][-nData:]
            pos = numpy.arange(nData)
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=fc,
                        label=dsName,
                        lw=lw)
            axes[0] += p

            ## ==> fill ASCII
            if dsName == '000':
                _c = _txt['cpu']['comps']
                for _i in zip(table['cpu/cpuTime'], table['cpu/sys'],
                              [names[i] for i in table['name']]):
                    if not numpy.isnan(_i[0]):
                        _c += ["[cpu/sys] %10.3f %10.3f (ms) | %s" % _i]
                    else:
                        self.msg.error("%s contains weird data !!", _i[-1])
                _c.reverse()

            ## real-time
            table.sort(order=('cpu/real', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ax = fig.axes[1]
            ax.set_xlabel('<Mean> real time [ms]')
            data = table['cpu/real'][-nData:]
            pos = numpy.arange(len(data))
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=color.next(),
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            axes[1] += p

            ## virtual memory
            table.sort(order=('mem', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ax = fig.axes[2]
            #ax.set_xlabel( '$\Delta \rm{VMem}\ [kB]$' )
            ax.set_xlabel('delta VMem [kB]')
            data = table['mem'][-nData:]
            pos = numpy.arange(len(data))
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=color.next(),
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            axes[2] += p

            ## ==> fill ASCII
            if dsName == '000':
                _c = _txt['mem']['comps']
                for _i in zip(table['mem'], table['malloc'],
                              [names[i] for i in table['name']]):
                    if not numpy.isnan(_i[0]):
                        _c += ["dVmem|dMalloc %10.3f %10.3f kB | %s" % _i]
                    else:
                        self.msg.error("%s contains weird data !!", _i[-1])
                _c.reverse()

            ## malloc
            table.sort(order=('malloc', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ax = fig.axes[3]
            #ax.set_xlabel( '$\Delta \rm{Malloc}\ [kB]$' )
            ax.set_xlabel('delta Malloc [kB]')
            data = table['malloc'][-nData:]
            pos = numpy.arange(len(data))
            p = ax.barh(pos + (idx * 1. / nDsNames),
                        data,
                        1. / nDsNames,
                        align='edge',
                        color=color.next(),
                        label=dsName,
                        lw=lw)
            ax.grid(True)
            ax.set_yticks(pos + 0.5)
            ax.set_yticklabels(labels, fontsize=6, horizontalalignment='right')

            axes[3] += p

            ## n-allocs
            table.sort(order=('nmall', ))
            labels = [names[i] for i in table['name'][-nData:]]
            ## ==> fill ASCII
            if dsName == '000':
                _c = _txt['allocs']['comps']
                for _i in zip(table['nmall'], table['nfree'],
                              [names[i] for i in table['name']]):
                    if not numpy.isnan(_i[0]):
                        _c += ["alloc|free %10i %10i | %s" % _i]
                    else:
                        self.msg.error("%s contains weird data !!", _i[-1])
                _c.reverse()

            pass  # loop over data sets

        if nData != 0:

            for ix, ax in zip(axes, fig.axes):
                ax.legend(ix[::nData], DataSetMgr.labels(), loc='lower right')
        else:
            ## msg.error("problem in _top_consumers: null slice array !")
            ## msg.error("dsname=[%s] compname=[%s] storename=[%s]",
            ##           dsName, monComp.name, storeName)
            ## return
            pass

        m = monCompMgr['PerfMonSlice']
        d = m.data['000'][storeName]
        cpu = "%-20s [%10.3f ms    %10.3f ms\t real=  %10.3f ms ]" % (
            "[u/s/r]",
            d['cpu']['user'][begSlice:endSlice, 2].mean() * ms,
            d['cpu']['sys'][begSlice:endSlice, 2].mean() * ms,
            d['cpu']['real'][begSlice:endSlice, 2].mean() * ms,
        )

        dvmem = d['mem']['vmem'][:, 2]
        drss = d['mem']['rss'][:, 2]
        dmall = d['mem']['mall'][:, 2]

        mem = "%-20s [%10.3f MB -> %10.3f MB\t delta= %10.3f kB ]\n" \
              "%-20s [%10.3f MB -> %10.3f MB\t delta= %10.3f kB ]\n" \
              "%-20s [%10.3f MB -> %10.3f MB\t delta= %10.3f kB ]\n" \
              "%-20s [%10i    -> %10i \t delta= %10i    ]\n" \
              "%-20s [%10i    -> %10i \t delta= %10i    ]"   % (
            "VMem",
            d['mem']['vmem'][begSlice:endSlice,0].mean()*Mb,
            d['mem']['vmem'][begSlice:endSlice,1].mean()*Mb,
            dvmem[begSlice:endSlice].mean()*kb,
            "RSS",
            d['mem']['rss'] [begSlice:endSlice,0].mean()*Mb,
            d['mem']['rss'] [begSlice:endSlice,1].mean()*Mb,
            drss[begSlice:endSlice].mean()*kb,
            "Malloc",
            d['mem']['mall'] [begSlice:endSlice,0].mean()*Mb,
            d['mem']['mall'] [begSlice:endSlice,1].mean()*Mb,
            dmall[begSlice:endSlice].mean()*kb,
            "nalloc",
            d['mem']['nmall'][begSlice:endSlice,0].mean(),
            d['mem']['nmall'][begSlice:endSlice,1].mean(),
            d['mem']['nmall'][begSlice:endSlice,2].mean(),
            "nfree",
            d['mem']['nfree'][begSlice:endSlice,0].mean(),
            d['mem']['nfree'][begSlice:endSlice,1].mean(),
            d['mem']['nfree'][begSlice:endSlice,2].mean(),
            )

        _txt['cpu']['slice'] += [cpu]
        _txt['mem']['slice'] += [mem]

        return
Пример #6
0
    def processEvt(self, dataSetMgr, monCompMgr):
        from App import DataSetMgr

        from PyRootLib import importRoot
        ROOT = importRoot(batch=True)

        ## RootFct = ROOT.TF1
        ## dummyCanvas = ROOT.TCanvas("dummyFitCanvas")
        ## import PyRootLib as prl

        ## self.sum['evt']['histos'] = []
        ## self.sum['evt']['fig']    = []

        ## short-hand
        ms = Units.ms
        kb = Units.kb
        Mb = Units.Mb
        Mb2Kb = 1000.
        msg = self.msg

        ## get top-20 consumers
        dsNames = DataSetMgr.names()
        color = DataSetMgr.colorIter()

        _txt = self.txt['evt']

        monComp = monCompMgr['PerfMonSlice']
        yMinCpu = []
        yMaxCpu = []
        yMinIo = []
        yMaxIo = []
        for dsName in dsNames:
            data = monComp.data[dsName]
            histos = data['histos'] = {}
            if not 'evt' in data:
                continue
            data = data['evt']
            if data is None:
                continue
            cpu = data['cpu']
            cpu_u = cpu['user']
            cpu_s = cpu['sys']
            cpu_r = cpu['real']
            cpu_c = cpu['cpu']

            dcpu_u = cpu_u[:, 2]
            dcpu_s = cpu_s[:, 2]
            dcpu_r = cpu_r[:, 2]
            dcpu_c = cpu_c[:, 2]

            mem = data['mem']
            vmem = mem['vmem']
            dvmem = vmem[:, 2]
            rss = mem['rss']
            drss = rss[:, 2]
            mall = mem['mall']
            dmall = mall[:, 2]

            nallocs = mem['nmall'][:, 2]
            nfrees = mem['nfree'][:, 2]

            yMinCpu.append(dcpu_c[self.minEvt:].min() * ms)
            yMaxCpu.append(dcpu_c[self.minEvt:].max() * ms)

            io = monComp.data[dsName]['io']
            io_c = io['w']['cpu']
            yMinIo.append(io_c[self.minEvt:].min() * ms)
            yMaxIo.append(io_c[self.minEvt:].max() * ms)

            ##             data['mem/vmem/d'] = data['mem/vmem/1'] - data['mem/vmem/0']
            ##             data['mem/rss/d' ] = data['mem/rss/1' ] - data['mem/rss/0' ]

            ## fill-in some data for ASCII summary
            if dsName == '000':
                _txt['cpu']['slice'] += [
                    "%-20s %10.3f %10.3f %10.3f ms" % (
                        "[u/s/r]",
                        dcpu_u[self.minEvt:].mean() * ms,
                        dcpu_s[self.minEvt:].mean() * ms,
                        dcpu_r[self.minEvt:].mean() * ms,
                    ),
                ]
                _txt['mem']['slice'] += [
                    "%-20s %10.3f %10.3f %10.3f kB" % (
                        "[dVmem/dRss/dMalloc]",
                        dvmem[self.minEvt:].mean() * kb,
                        drss[self.minEvt:].mean() * kb,
                        dmall[self.minEvt:].mean() * kb,
                    ),
                ]
                _txt['allocs']['slice'] += [
                    "%-20s %10i %10i" % (
                        "[nallocs/nfrees]",
                        nallocs[self.minEvt:].mean(),
                        nfrees[self.minEvt:].mean(),
                    ),
                ]

            ## book ROOT histos
            nEntries = len(dataSetMgr[dsName].bins) - 1
            minEvt = dataSetMgr[dsName].bins[self.minEvt]
            maxEvt = dataSetMgr[dsName].bins[-1]

            hId = 'cpu_%s.%s' % (monComp.name, dsName)
            hName = 'cpu_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] CPU usage [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "Timing [ms]"), nEntries,
                minEvt, maxEvt)

            hId = 'vmem_%s.%s' % (monComp.name, dsName)
            hName = 'vmem_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] VMem usage [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "V-Mem [MB]"), nEntries,
                minEvt, maxEvt)

            hId = 'rss_%s.%s' % (monComp.name, dsName)
            hName = 'rss_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] RSS usage [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "RSS [MB]"), nEntries,
                minEvt, maxEvt)

            hId = 'io_%s.%s' % (monComp.name, dsName)
            hName = 'io_%s' % dsName
            histos[hName] = ROOT.TH1F(
                hId, "[%s] I/O time [%s];%s;%s" %
                (monComp.name, dsName, "event nbr", "I/O time [ms]"), nEntries,
                minEvt, maxEvt)
            pass

        yMinIo = min(yMinIo)
        yMaxIo = max(yMaxIo)
        yMinCpu = min(yMinCpu)
        yMaxCpu = max(yMaxCpu)

        def markForLegend(p):
            setattr(p, '_markedForLegend', True)

        def isMarked(p):
            return hasattr(p, '_markedForLegend')

        memLeak = []
        for dsName in dsNames:

            if not 'evt' in monComp.data[dsName]:
                continue

            data = monComp.data[dsName]

            cpu = data['evt']['cpu']
            cpu_c = cpu['cpu']
            dcpu_c = cpu_c[:, 2]

            ## CPU
            bins = dataSetMgr[dsName].bins
            xbins = bins[self.minEvt:]
            if not 'evt/cpu' in monComp.figs:
                monComp.figs['evt/cpu'] = plt.figure()
                monComp.figs['evt/cpu'].add_subplot(211).hold(True)
                monComp.figs['evt/cpu'].add_subplot(212).hold(True)
            fig = monComp.figs['evt/cpu']
            ax = fig.axes[0]
            pl = ax.plot(xbins,
                         dcpu_c[self.minEvt:] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.grid(True)
            ax.set_title("CPU time [Begin/End-Event]")
            ax.set_ylabel('CPU time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            markForLegend(pl[0])

            h, b = numpy.histogram(dcpu_c[self.minEvt:] * ms,
                                   bins=20,
                                   range=(yMinCpu * 0.90, yMaxCpu * 1.10))
            ax = fig.axes[1]
            pl = ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('CPU time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))
            markForLegend(pl[0])

            h = data['histos']['cpu_%s' % dsName]
            hAvg = bookAvgHist(h, dcpu_c * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = dcpu_c[i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            ## Mem
            mem = data['evt']['mem']
            vmem = mem['vmem']
            dvmem = vmem[:, 2]
            dmall = mem['mall'][:, 2]

            if not 'evt/mem' in monComp.figs:
                monComp.figs['evt/mem'] = plt.figure()
                monComp.figs['evt/mem'].add_subplot(311).hold(True)
                monComp.figs['evt/mem'].add_subplot(312).hold(True)
                monComp.figs['evt/mem'].add_subplot(313).hold(True)

            fig = monComp.figs['evt/mem']
            ax = fig.axes[0]
            pl = ax.plot(
                xbins,
                vmem[self.minEvt:, 1] * Mb,
                linestyle='steps',
                #'o',
                label=dsName)
            ax.set_title("Memory usage [Begin/End-Event]")
            ax.set_ylabel('VMem [MB]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            ## fit
            #nFit = int(len(bins)/2.)
            #x = bins[-nFit:]
            #y = data['evt']['mem/vmem/1'][-nFit:] * Mb
            begFit = self._fitSlice[0]
            endFit = self._fitSlice[1]
            x = bins[begFit:endFit]
            y = vmem[begFit:endFit, 1] * Mb
            coeffs = numpy.lib.polyfit(x, y, deg=1)
            memLeak += [coeffs[0] * kb]
            ax.plot(x, numpy.lib.polyval(coeffs, x), '-', color='y', lw=2.)
            if dsName == '000':
                _txt['mem']['slice'] += [
                    "%-20s p[0] = %8.3f MB \tp[1] = %8.3f kB" % (
                        "vmem fit:",
                        coeffs[1] * Mb,
                        coeffs[0] * kb,  #
                    )
                ]

            ax = fig.axes[1]
            pl = ax.plot(xbins,
                         mem['rss'][self.minEvt:, 1] * Mb,
                         linestyle='steps',
                         label=dsName)
            ax.set_ylabel('RSS [MB]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            ax = fig.axes[2]
            pl = ax.plot(xbins,
                         dmall[self.minEvt:] * Mb,
                         linestyle='steps',
                         label=dsName)
            ax.set_ylabel('Delta Malloc [MB]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0] * 0.9, ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            h = data['histos']['vmem_%s' % dsName]
            hAvg = bookAvgHist(h, mem['vmem'][:, 1] * Mb)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                vmem = mem['vmem'][i, 1] * Mb
                h.Fill(float(bins[i]), vmem)
                hAvg.Fill(vmem)

            h = data['histos']['rss_%s' % dsName]
            hAvg = bookAvgHist(h, mem['rss'][:, 1] * Mb)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                rss = mem['rss'][i, 1] * Mb
                h.Fill(float(bins[i]), rss)
                hAvg.Fill(rss)

            ## I/O
            if not 'evt/io' in monComp.figs:
                monComp.figs['evt/io'] = plt.figure()
                monComp.figs['evt/io'].add_subplot(211).hold(True)
                monComp.figs['evt/io'].add_subplot(212).hold(True)
            fig = monComp.figs['evt/io']
            ax = fig.axes[0]
            io_c = data['io']['w']['cpu']
            pl = ax.plot(xbins,
                         io_c[self.minEvt:] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.set_title("I/O time [CommitOutput]")
            ax.set_ylabel('I/O time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            yMinIo *= 0.9
            yMaxIo *= 1.1
            yMinIo, yMaxIo = min(yMinIo, yMaxIo), max(yMinIo, yMaxIo)
            h, b = numpy.histogram(io_c[self.minEvt:] * ms,
                                   bins=20,
                                   range=(yMinIo, yMaxIo))
            ax = fig.axes[1]
            pl = ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.set_xlabel('I/O time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))
            ax.grid(True)
            markForLegend(pl[0])

            h = data['histos']['io_%s' % dsName]
            hAvg = bookAvgHist(h, io_c * ms)
            data['histos'][h.GetName()] = hAvg
            for i in range(len(bins)):
                cpuTime = io_c[i] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            pass  # loop over data sets

        ## handle mem-leak text
        ax = monComp.figs['evt/mem'].axes[0]
        ax.text(
            0.025,
            0.97,
            "\n".join("[%s] Leak: %8.3f kB" % (n, leak)
                      for n, leak in zip(DataSetMgr.labels(), memLeak)),
            bbox=dict(facecolor='w'),
            #color = '',
            fontweight='bold',
            #fontsize   = 'x-larger',
            verticalalignment='top',
            transform=ax.transAxes)
        for figName, fig in monComp.figs.items():
            loc = 'best'
            if figName == 'evt/mem': loc = 'lower right'
            for ax in fig.axes:
                objs = [l for l in ax.lines if isMarked(l)]
                ax.legend(
                    objs,
                    DataSetMgr.labels(),
                    #loc='lower right'
                    #loc='best'
                    loc=loc)

        ## get top-20 consumers
        self._top_consumers(dataSetMgr,
                            monCompMgr,
                            compTypes=('alg', ),
                            title='Event loop',
                            storeName='evt',
                            sliceName='evt',
                            begSlice=self.minEvt,
                            endSlice=None)
        return
Пример #7
0
    def fillHistos(self, monComp):
        
        from App import DataSetMgr
        self.msg.debug("filling histograms...")

        # short-hands
        msg = self.msg
        
        # convert page-size into MB
        Mb =  Units.Mb
        # convert page-size into kB
        kb =  Units.kb

        monName = monComp.name
        dsNames = DataSetMgr.names()
        ymin = {'vmem':[], 'malloc':[]}
        ymax = {'vmem':[], 'malloc':[]}
        allGood = True
        
        for dsName in dsNames:
            if not dsName in monComp.data:
                continue
            #print "---",dsName,monComp.name
            data = monComp.data[dsName]
            if not 'evt' in data:
                continue
            data = data['evt']
            if data is None:
                ## print "---",dsName,monComp.name,"data['evt'] is None"
                continue

            if not 'mem' in data.dtype.names:
                allGood = False
                msg.debug('component [%s] has empty mem infos for '
                          'dataset [%s]',
                          monComp.name,
                          dsName)
                ## print "--->",dsName,monComp.name,data.dtype.names
                continue

            ## print "+++",dsName,monComp.name
            mem = data['mem']
            dvmem = mem['vmem'][:,2]
            ymin['vmem'].append(dvmem[self.minEvt:].min()*kb)
            ymax['vmem'].append(dvmem[self.minEvt:].max()*kb)

            dmall = mem['mall'][:,2]
            ymin['malloc'].append(dmall[self.minEvt:].min()*kb)
            ymax['malloc'].append(dmall[self.minEvt:].max()*kb)
            pass

        if not allGood:
            msg.debug("Something bad happened for component [%s] "
                      "during 'MemAnalyzer.fillHistos' !!",
                      monComp.name)
            return

        if len(ymin['vmem']) == 0 and len(ymax['vmem']) == 0:
            self.msg.debug("Component [%s] has no 'evt' level data",
                           monComp.name)
            return
        
        for k in ymin.keys():
            ymin[k] = min(ymin[k])
            ymax[k] = max(ymax[k])
            pass

        
        for dsName in dsNames:
            if not dsName in monComp.data:
                continue
            data = monComp.data[dsName]
            if not 'evt' in data:
                continue
            data = data['evt']
            if data is None:
                continue
            
            if not 'mem' in data.dtype.names:
                continue

            bins = DataSetMgr.instances[dsName].bins
            if not 'evt/mem' in monComp.figs:
                monComp.figs['evt/mem'] = plt.figure()
                monComp.figs['evt/mem'].add_subplot(221).hold( True )
                monComp.figs['evt/mem'].add_subplot(222).hold( True )
                monComp.figs['evt/mem'].add_subplot(223).hold( True )
                monComp.figs['evt/mem'].add_subplot(224).hold( True )

            fig = monComp.figs['evt/mem']
            mem = data['mem']
            dvmem = mem['vmem'][:,2]
            dmall = mem['mall'][:,2]
            
            ## VMem
            ax = fig.axes[0]
            binMax = len(dvmem[self.minEvt:len(bins)])
            pl = ax.plot(bins[self.minEvt:binMax],
                         dvmem[self.minEvt:binMax] * kb,
                         linestyle = 'steps',
                         label     = dsName)
            ax.grid(True)
            ax.set_title ('Delta V-Mem\n[%s]' % monComp.name)
            ax.set_ylabel('Delta V-Mem [kb]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0]*0.9,
                         ax.get_ylim()[1]*1.1))
            
            h,b = numpy.histogram(
                dvmem[self.minEvt:binMax] * kb,
                bins  = 20,
                range = (ymin['vmem']*0.90, ymax['vmem']*1.10)
                )

            ax = fig.axes[2]
            ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('Delta V-Mem [kb]')
            ax.set_ylim((ax.get_ylim()[0]*0.9, ### ???
                         ax.get_ylim()[1]*1.1))

            ## Malloc
            ax = fig.axes[1]
            pl = ax.plot(bins[self.minEvt:binMax],
                         dmall[self.minEvt:binMax] * kb,
                         linestyle = 'steps',
                         label     = dsName)
            ax.grid(True)
            ax.set_title ('Delta Malloc\n[%s]' % monComp.name)
            ax.set_ylabel('Delta Malloc [kb]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0]*0.9,
                         ax.get_ylim()[1]*1.1))
            
            h,b = numpy.histogram(
                dmall[self.minEvt:binMax] * kb,
                bins  = 20,
                range = (ymin['malloc']*0.90, ymax['malloc']*1.10)
                )

            ax = fig.axes[3]
            ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('Delta Malloc [kb]')
            ax.set_ylim( (ax.get_ylim()[0]*0.9,
                          ax.get_ylim()[1]*1.1) )

            ## ROOT-histos
            data = monComp.data[dsName]
            hVmem    = data['histos']['mem_%s' % dsName]
            hAvgVmem = bookAvgHist(hVmem, dvmem * kb)
            data['histos'][hVmem.GetName()] = hAvgVmem
            hMall    = data['histos']['malloc_%s' % dsName]
            hAvgMall = bookAvgHist(hMall, dmall * kb)
            data['histos'][hMall.GetName()] = hAvgMall
            maxRange = min(len(dvmem), len(bins))

            for i in range(maxRange):
                dVmem = dvmem[i] * kb
                hVmem.Fill( float(bins[i]), dVmem )
                hAvgVmem.Fill( dVmem )
                dMall = dmall[i] * kb
                hMall.Fill( float(bins[i]), dMall )
                hAvgMall.Fill( dVmem )
            pass # loop over datasets

        for ax in monComp.figs['evt/mem'].axes:
            ax.legend(DataSetMgr.labels(), loc='best')

        self.msg.debug( "filling histograms... [DONE]" )
        return
Пример #8
0
    def fillHistos(self, monComp):

        from App import DataSetMgr
        self.msg.debug("filling histograms...")

        # short-hands
        msg = self.msg

        # milliseconds
        ms = Units.ms

        monName = monComp.name
        dsNames = DataSetMgr.names()
        yMin = []
        yMax = []
        allGood = True

        figs = monComp.figs

        for dsName in dsNames:
            if not monComp.data.has_key(dsName):
                continue
            data = monComp.data[dsName]
            ## print "..",dsName,data.keys()
            if not 'evt' in data:
                continue
            data = data['evt']
            if data is None:
                continue

            ## print "..",dsName,data.keys()

            if not 'cpu' in data.dtype.names:
                allGood = False
                msg.debug(
                    'component [%s] has empty cpu/user infos for '
                    'dataset [%s]', monComp.name, dsName)
                continue
            cpu = data['cpu']['cpu']
            yMin.append(cpu[self.minEvt:, 2].min() * ms)
            yMax.append(cpu[self.minEvt:, 2].max() * ms)

        if not allGood:
            msg.debug(
                "Something bad happened for component [%s] "
                "during 'CpuAnalyzer.fillHistos' !!", monComp.name)
            return

        if len(yMin) == 0 and len(yMax) == 0:
            msg.debug("Component [%s] has no 'evt' level data", monComp.name)
            return

        yMin = min(yMin)
        yMax = max(yMax)

        for dsName in dsNames:
            if not monComp.data.has_key(dsName):
                continue
            data = monComp.data[dsName]
            if not 'evt' in data:
                continue
            bins = DataSetMgr.instances[dsName].bins
            if not 'evt/cpu' in monComp.figs:
                monComp.figs['evt/cpu'] = plt.figure()
                monComp.figs['evt/cpu'].add_subplot(211).hold(True)
                monComp.figs['evt/cpu'].add_subplot(212).hold(True)
            fig = monComp.figs['evt/cpu']
            ax = fig.axes[0]
            cpu = data['evt']['cpu']
            cpu_c = cpu['cpu']
            cpu_u = cpu['user']
            cpu_s = cpu['sys']

            binMax = len(cpu_c[self.minEvt:len(bins)])
            pl = ax.plot(bins[self.minEvt:binMax],
                         cpu_c[self.minEvt:binMax, 2] * ms,
                         linestyle='steps',
                         label=dsName)
            ax.grid(True)
            ax.set_title("CPU time [%s]" % monComp.name)
            ax.set_ylabel('CPU time [ms]')
            ax.set_xlabel('Event number')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            h, b = numpy.histogram(cpu_c[self.minEvt:binMax, 2] * ms,
                                   bins=20,
                                   range=(yMin * 0.90, yMax * 1.10))
            ax = fig.axes[1]
            ax.plot(b[:-1], h, label=dsName, ls='steps')
            ax.grid(True)
            ax.set_xlabel('CPU time [ms]')
            ax.set_ylim((ax.get_ylim()[0], ax.get_ylim()[1] * 1.1))

            h = data['histos']['cpu_%s' % dsName]
            hAvg = bookAvgHist(h, cpu_c[:, 2] * ms)
            data['histos'][h.GetName()] = hAvg
            maxRange = min(len(cpu_c), len(bins))

            for i in range(maxRange):
                cpuTime = cpu_c[i, 2] * ms
                h.Fill(float(bins[i]), cpuTime)
                hAvg.Fill(cpuTime)

            pass  # loop over datasets

        for ax in monComp.figs['evt/cpu'].axes:
            ax.legend(DataSetMgr.labels(dsNames), loc='best')

        self.msg.debug("filling histograms... [DONE]")
        return