diff --git a/Control/HeapMon/HeapMon/HeapMon.h b/Control/HeapMon/HeapMon/HeapMon.h new file mode 100644 index 0000000000000000000000000000000000000000..0687a82a800024b26bc6407a03b4423a69778837 --- /dev/null +++ b/Control/HeapMon/HeapMon/HeapMon.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef HEAPMON_HEAPMON_H +#define HEAPMON_HEAPMON_H + +#if defined(__linux__) + +#define _GNU_SOURCE 1 + +#include <stdio.h> + +#ifdef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#endif + +#include "Python.h" + +/* control parameters for static data blocks */ + +/* maximum available number of check points */ +#define mm_MAX_CHECKPOINTS 10 + +/* start size of hash tables for data */ +#define mm_HASHTABLE_MINSIZE 4096 + +/* maximum total depth of tracebacks kept in memory */ +#define mm_TRACEDEPTH 12 +/* system offset: 0 == helper, 1 == hook, 2 == malloc/realloc */ +#define mm_SYSTEMOFF 3 +/* total backtrace size left: mm_TRACEDEPTH - mm_SYSTEMOFF */ +#define mm_BACKTRACE_SIZE mm_TRACEDEPTH - mm_SYSTEMOFF + +/* max size for symbols, files, and other buffers */ +#define mm_SYMBOL_BUFLEN 2048 + +#endif /* !HEAPMON_HEAPMON_H */ diff --git a/Control/HeapMon/cmt/fragments/python_extension b/Control/HeapMon/cmt/fragments/python_extension new file mode 100644 index 0000000000000000000000000000000000000000..696fd1b7850af048dd712cc17664e2a52d523a8a --- /dev/null +++ b/Control/HeapMon/cmt/fragments/python_extension @@ -0,0 +1,46 @@ +# File: HeapMon/cmt/fragments/python_extension +# Author: Wim Lavrijsen (WLavrijsen@lbl.gov) + +# Build a python extension module (i.e. shared lib w/o 'lib' prepend) and +# install it into InstallArea/python/<Package>/. Note that the full build is +# done here, rather than through CMT processing, as it's sooo much faster. + +.PHONY: ${CONSTITUENT} ${CONSTITUENT}clean + +#allfiles := $(wildcard ${FILEPATH}*.cxx) +#objects := ${allfiles:${FILEPATH}%.cxx=$(bin)%.o} +#allcfiles := $(wildcard ${FILEPATH}${files}) +allcfiles := $(wildcard ${FILEPATH}*.c) +cobjects := ${allcfiles:${FILEPATH}%.c=$(bin)%.o} +# installd := ${CMTINSTALLAREA}/$(tag)/lib/python$(Python_config_version_twodigit)/${package} +installd := ${CMTINSTALLAREA}/python/${package}/$(tag) +pyextlib := ${installd}/${CONSTITUENT}.$(shlibsuffix) + +${CONSTITUENT} :: $(bin)${CONSTITUENT}.$(shlibsuffix) ${pyextlib} + +${objects} : $(bin)%.o : ${FILEPATH}%.cxx + $(cpp_echo) $@ + $(cpp_silent) cd $(bin); $(cppcomp) -o $@ $(use_pp_cppflags) $(${CONSTITUENT}_pp_cppflags) $(app_${CONSTITUENT}_pp_cppflags) $(use_cppflags) $(${CONSTITUENT}_cppflags) $(app_${CONSTITUENT}_cppflags) ${ADDINCLUDE} $< + +${cobjects} : $(bin)%.o : ${FILEPATH}%.c + $(c_echo) $@ + $(c_silent) cd $(bin); $(ccomp) -o $@ $(use_pp_cflags) $(${CONSTITUENT}_pp_cflags) $(app_${CONSTITUENT}_pp_cflags) $(use_cflags) $(${CONSTITUENT}_cflags) $(app_${CONSTITUENT}_cflags) ${ADDINCLUDE} $< + +# explicitly linked with almost nothing (typically, $(use_linkopts) will be needed) +$(bin)${CONSTITUENT}.$(shlibsuffix): ${objects} ${cobjects} +ifeq (${objects},) + $(lib_silent) cd $(bin); $(link) $(shlibflags) ${cobjects:$(bin)%.o=%.o} $(${CONSTITUENT}_linkopts) -o ${CONSTITUENT}.$(shlibsuffix) +else + $(lib_silent) cd $(bin); $(cpplink) $(shlibflags) ${objects:$(bin)%.o=%.o} ${cobjects:$(bin)%.o=%.o} $(${CONSTITUENT}_linkopts) -o ${CONSTITUENT}.$(shlibsuffix) +endif + +${installd} : + @mkdir -p ${installd} + +# hack: gmake on lxplus (1.79.1) does not support order only targets nor realpath +${pyextlib} : $(bin)${CONSTITUENT}.$(shlibsuffix) ${installd} + @cd $(bin); test -f $(pyextlib) || ln -s `pwd`/${CONSTITUENT}.$(shlibsuffix) $(pyextlib) + +${CONSTITUENT}clean :: + $(cleanup_echo) objects + $(cleanup_silent) /bin/rm -f ${objects} $(bin)${CONSTITUENT}.$(shlibsuffix) ${pyextlib} diff --git a/Control/HeapMon/cmt/fragments/python_extension_header b/Control/HeapMon/cmt/fragments/python_extension_header new file mode 100644 index 0000000000000000000000000000000000000000..fce7b79071760841e096a4b2dfb1126fd229a944 --- /dev/null +++ b/Control/HeapMon/cmt/fragments/python_extension_header @@ -0,0 +1,4 @@ +# File: HeapMon/cmt/fragments/python_extension_header +# Author: Wim Lavrijsen (WLavrijsen@lbl.gov) + +# this file is left empty on purpose diff --git a/Control/HeapMon/cmt/requirements b/Control/HeapMon/cmt/requirements new file mode 100644 index 0000000000000000000000000000000000000000..a306d1e1484806188296720c9024b1fe083589f9 --- /dev/null +++ b/Control/HeapMon/cmt/requirements @@ -0,0 +1,52 @@ +package HeapMon + +author Mous Tatarkhanov <tmmous@berkeley.edu> + +use AtlasPolicy AtlasPolicy-* +use AtlasPython AtlasPython-* External +use AtlasGPerfTools AtlasGPerfTools-* External +#use GaudiInterface GaudiInterface-* External + +private +use AtlasROOT AtlasROOT-* External +end_private + +application MemoryScanner MemoryScanner.cxx + +#apply_pattern component_library + +# the memory marker relies on gcc (tag gcc is set in ExternalPolicy, which +# comes in from AtlasPolicy) internals: only build on that platform (there +# will be a warning on other platforms, but we don't have any others right +# now, so no worries :) ) + +# although "gcc" as tag should do, that doesn't work on gcc344 (even as the +# tag is defined according to "cmt show all_tags"), so use Linux (works, as +# empirically determined :P ) +macro python_extension_fragment "" \ + Linux "python_extension -dependencies -header=python_extension_header" \ + Darwin "python_extension -dependencies -header=python_extension_header" +make_fragment $(python_extension_fragment) + +# hack: empty document will be ignored; anything else doesn't work with CMT +document python_extension MemoryMarker files="*.c" MemoryMarker.c + +# force order between installing header files and build of .c files +macro_append MemoryMarker_dependencies " install_includes " + +# libraries for retrieving debug info +macro_append MemoryMarker_linkopts "" \ + use_bfd " -aarchive -L/usr/local/lib -L/usr/lib -lbfd -liberty " + +macro_append cflags "" \ + use_bfd " -DHEPHAESTUS_USE_BFD " + +# install python module files (actually, the .so is done in the fragment) +apply_pattern declare_python_modules files="*.py" + + +private + +# always use new ABI and force optimization, even in debug mode +macro_append cppflags " -fuse-cxa-atexit " +macro_append cflags " -O3 " diff --git a/Control/HeapMon/python/EventNotifier.py b/Control/HeapMon/python/EventNotifier.py new file mode 100644 index 0000000000000000000000000000000000000000..53efc4fa3491bb64b432c4bbcd798157492989f4 --- /dev/null +++ b/Control/HeapMon/python/EventNotifier.py @@ -0,0 +1,147 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +import AthenaPython.PyAthena as PyAthena +import sys, os + +from ROOT import TTree, TFile +from array import array + + +#from HeapMon import MemoryScanner as memscanner +#from HeapMon import MemoryMarker as memmarker +#from Hephaestus import MemoryTracker as memtracker + + +class EventExecutionNotifier( PyAthena.Alg ): + event_number = 0 + max_events = 0 + stop_scan = 1 + start_scan = 0 + report_scan_number = 0 + file_name = "heapmon.freed.root" + marker = 0xCD + + memmarker = 'HeapMon.MemoryMarker' in sys.modules and sys.modules[ 'HeapMon.MemoryMarker' ] or None + memscanner = 'HeapMon.MemoryScanner' in sys.modules and sys.modules[ 'HeapMon.MemoryScanner' ] or None + memtracker = 'Hephaestus.MemoryTracker' in sys.modules and sys.modules[ 'Hephaestus.MemoryTracker' ] or None + + #memtracker = 'Hephaestus.MemoryTracker' in sys.modules and \ + # sys.modules['Hephaestus.MemoryTracker' ] or None + + def __init__(self, name="EventExecutionNotifier"): + ## init the base class + super(EventExecutionNotifier,self).__init__() + return + + def initialize( self ): + # INITIALIZATION MARKING + print 'Notifier.initialize():' + #memmarker = 'HeapMon.MemoryMarker' in sys.modules and \ + #sys.modules[ 'HeapMon.MemoryMarker' ] or None + #if memmarker: + # memmarker.start() + + self.event_number = 0 + + print " file_name = ", self.file_name + print " self.max_events = ", self.max_events + print " report_scan_number = ", self.report_scan_number + if self.memtracker: + print(' starting memtracker - MemoryTracker ') + self.memtracker.start() + else: + print(' memtracker - MemoryTracker not loaded!') + + if self.memscanner: + #print' memscanner.memscan()' + self.memscanner.memscan(self.file_name, 2, self.event_number, self.marker); #SCAN_FLAG = 2: no holes statistics saved, just info + else: + print(' memscanner is not loaded!') + + # Extract MallocInfo and put into root file + self.mallinfo() + return PyAthena.StatusCode.Success + + def execute( self ): + print "Notifier.execute()" + self.event_number +=1 + print "Notifier.event_number = ", self.event_number + + if self.memscanner: + print ' memscanner.memscan()' + if (self.start_scan == 0): + self.memscanner.memscan(self.file_name, 2, self.event_number, self.marker); #SCAN_FLAG = 1: holes statistics saved + elif (self.start_scan == -1): + self.memscanner.memscan(self.file_name, 1, self.event_number, self.marker); #SCAN_FLAG = 2: no holes statistics saved, just info + elif ((self.event_number >= self.start_scan) + and (self.event_number <= self.stop_scan)): + self.memscanner.memscan(self.file_name, 1, self.event_number, self.marker); #SCAN_FLAG = 2: no holes statistics saved, just info + else: + self.memscanner.memscan(self.file_name, 2, self.event_number, self.marker); #SCAN_FLAG = 1: holes statistics saved + else: + print(' memscanner is not loaded!') + + + self.mallinfo() + + if self.memtracker: + if self.event_number <= self.stop_scan: + print ('MemoryTracker is marking the memory') + else: + print("MemoryTracker configure() to stop the marking"); + print ("MemoryTracker.gFlags = ", + self.memtracker.configure( + self.memtracker.LEAK_CHECK | + self.memtracker.QUICK )#| MemoryTracker.FILTER_STL) + ) + elif self.memmarker: + if (self.start_scan == 0): + print('EventNotifier.execute(): marker idling') + elif self.event_number <= self.stop_scan: + print 'EventNotifier.execute(): memmarker.start(), event_number=', self.event_number + self.memmarker.start() + else: + print('Notifier.execute(): MemoryMarker.stop() , event_number=', self.event_number) + self.memmarker.stop() + else: + print('Notifier.execute(): memmarker and memtracker are not loaded!') + + return PyAthena.StatusCode.Success + + def finalize( self ): + self.msg.info( 'finalizing [%s]', self.name() ) + if self.memmarker: + self.memmarker.stop() + if self.memtracker: + self.memtracker.stop() + if self.memscanner: + from HeapMon import HeapMonReport as memreport + memreport.report() + return PyAthena.StatusCode.Success + + + def mallinfo(self): + if self.memmarker: + print('Notifier.mallinfo(): malloc info') + (malloc_sbrk, malloc_mmap, malloc_inuse, malloc_free) = self.memmarker.get_malloc_info() + sbrk = array('I', [0]); sbrk[0] = malloc_sbrk; + mmap = array('I', [0]); mmap[0] = malloc_mmap; + inuse = array('I', [0]); inuse[0] = malloc_inuse; + free = array('I', [0]); free[0] = malloc_free; + print 'sbrk=', sbrk, ' mmap=', mmap, ' inuse=', inuse, 'free', free + scan_number = array('L', [0]); scan_number[0] = self.event_number; + memFile = TFile(self.file_name, "update") + mallocTree = memFile.Get("mallocTree"); + mallocTree.SetBranchAddress("malloc_sbrk", sbrk); + mallocTree.SetBranchAddress("malloc_mmap", mmap); + mallocTree.SetBranchAddress("malloc_inuse",inuse); + mallocTree.SetBranchAddress("malloc_free", free); + mallocTree.SetBranchAddress("scan_number", scan_number); + mallocTree.Fill() + mallocTree.Write() + mallocTree.Delete + memFile.Write() + memFile.Close() + self.memmarker.show_info() + else: + print('Notifier.mallinfo(): memmarker is not loaded!') diff --git a/Control/HeapMon/python/HeapMonReport.py b/Control/HeapMon/python/HeapMonReport.py new file mode 100644 index 0000000000000000000000000000000000000000..af1af67d2a50ec6a65ec8cdb24eb1354397f0bc5 --- /dev/null +++ b/Control/HeapMon/python/HeapMonReport.py @@ -0,0 +1,309 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +import AthenaPython.PyAthena as PyAthena +import sys, os +import math, time , array + +from ROOT import gROOT, gDirectory, gStyle, gPad +from ROOT import TFile +from ROOT import TH1I, TH2I, TF1 +from ROOT import TH1F, TH2F, TGraph, TMultiGraph +from ROOT import TCanvas, TPad, TPaveLabel, TPaveText, TLegend + +#from ROOT import TCanvas # available at startup +root_file = 'mems.root' +freed_file = 'heapmon.freed.root' + +hole_trace_start = 0 + +def iReport(file): + global root_file + root_file = file + report() + +def pReport(): + global root_file + memscanner = 'HeapMon.MemoryScanner' in sys.modules and \ + sys.modules[ 'HeapMon.MemoryScanner' ] or None + if memscanner: + holes_file = memscanner.freescan_output + #root_file = file + report() + +def findStaticHoles(): + global freed_file + global hole_trace_start + tfile = TFile(freed_file, "READ") + + #mychain = gDirectory.Get( 'memTree' ) + tree = tfile.Get("holeTree") + entry_number = tree.GetEntries() + print("There are ", entry_number , " entries in ", root_file) + previous_scan_number = -1; + + holes_dict = dict() + previous_holes_dict = dict() + + for i in xrange(entry_number): + tree.GetEntry(i) + if tree.scan_number < hole_trace_start: + continue + if previous_scan_number == tree.scan_number: + #print "add new hole ", tree.hole_start, "size ", tree.hole_size + holes_dict[tree.hole_start] = tree.hole_size; + else: + previous_scan_number = tree.scan_number + if previous_holes_dict: + print "looking for intersection with next scan dict" + intersection = dict([(item,holes_dict[item]) for item in holes_dict.keys() if previous_holes_dict.has_key(item)]) + previous_holes_dict = intersection + print len(intersection), " elements in intersection" + #print "intersection=", intersection + else: + previous_holes_dict = holes_dict + + holes_dict.clear() + + intersection = dict([(item,holes_dict[item]) for item in holes_dict.keys() if previous_holes_dict.has_key(item)]) + + print "intersection=", intersection + print len(intersection), " static holes identified" + + import cPickle + pickle_file = "mems.dat" + file = open(pickle_file, 'w') + cPickle.dump(intersection, file) + file.close() + del file + + +def report(): + global freed_file + print' HeapMonReport.report(): heapmon_file=', freed_file + + #findStaticHoles() + + tfile = TFile(freed_file, "READ") + print " root compression factor = ", tfile.GetCompressionFactor() + + mem_canvas = TCanvas("HeapMon_report", "Memory Holes Statistics", 10, 10, 800, 1034); + mem_canvas.SetFillColor(17); + mem_canvas.cd() + + pad1 = TPad("pad1","pad1",0.01,0.57,0.50,0.93,33); + pad2 = TPad("pad2","pad2",0.51,0.57,0.99,0.93,33); + pad3 = TPad("pad3","pad3",0.01,0.01,0.99,0.50,33); + pad3.SetPhi(210); + pad3.SetTheta(25); + + pad1.Draw(); pad2.Draw(); pad3.Draw(); + memTree = tfile.Get("holeTree") + infoTree = tfile.Get("infoTree") + mallocTree = tfile.Get("mallocTree") + #holesm_th1i = TH1I('holesm_th1i', 'Holes size evolution', fcount, 0, fcount) + #holesn_th1i = TH1I('holesn_th1i', 'Holes number evolution', fcount, 0, fcount) + #total_th1i = TH1I('total_th1i', 'Total memory size evolution', fcount, 0, fcount) + + max_hole_size = memTree.GetMaximum("hole_size") + print " max_hole_size=", max_hole_size, " min_hole_size", memTree.GetMinimum("hole_size") + max_scan_number = memTree.GetMaximum("scan_number") + print " max_scan_number=", max_scan_number + + memHist1 = TH2I("mem2d","Hole-sizes distribution evolution", 128, -0.5, max_hole_size - 0.5, 50, 0, max_scan_number) + memTree.Project("mem2d", "scan_number:hole_size"); + + multiGraph1 = TMultiGraph(); + multiGraph2 = TMultiGraph(); + + print " memHist.GetMaximum() = ", memHist1.GetMaximum(); + + # Working on a Report + gStyle.SetOptStat(0); + gStyle.SetPalette(1); + gStyle.SetCanvasColor(33); + gStyle.SetFrameFillColor(18); + + memHist1.SetFillColor(30); + memHist1.SetFillStyle(0); + memHist1.GetXaxis().SetTitle("Size of holes, kb"); + memHist1.GetXaxis().SetLabelOffset(0.02); + memHist1.GetXaxis().SetLabelSize(0.02); + memHist1.GetXaxis().SetTitleSize(0.04); + memHist1.GetXaxis().SetTitleColor(2); + memHist1.GetYaxis().SetTitle("Event number"); + memHist1.GetYaxis().SetLabelSize(0.04); + memHist1.GetXaxis().SetLabelOffset(0.04); + memHist1.GetYaxis().SetTitleSize(0.04); + memHist1.GetYaxis().SetTitleColor(2); + memHist1.GetZaxis().SetTitle("Number of holes"); + memHist1.GetZaxis().SetLabelSize(0.02); + memHist1.GetZaxis().SetTitleSize(0.04); + memHist1.GetZaxis().SetTitleColor(2); + + title = TPaveLabel(0.1,0.95,0.9,0.99, "Job Memory Usage Plots"); + title.SetFillColor(42); + title.SetTextFont(42); + title.Draw(); + + text_box = TPaveText(0.1,0.51,0.9,0.54); + text_box.AddText("Malloc freed ('marked') Heap Memory Profile"); + text_box.SetFillColor(42); + text_box.SetTextAlign(12); + text_box.SetTextFont(42); + text_box.Draw(); + + x1=0.2; y1=0.91; x2=0.8; y2=0.98; + +#Drawing upper-left corner Pad1 of the report + pad1.cd(); + pad1.SetGridx();pad1.SetGridy(); + infoTree.Draw("total_maps_memory:scan_number","", "goff") + mapsGraph=TGraph(int(infoTree.GetSelectedRows()), infoTree.GetV2(), infoTree.GetV1()); + mapsGraph.SetLineColor(1); mapsGraph.SetLineWidth(1); #mapsGraph.SetFillStyle(3001); mapsGraph.SetFillColor(2); + mapsGraph.SetName("total_maps_memory"); + #VmSize, VmLck, VmRSS, VmData, VmStk, VmExe, VmLib; + infoTree.Draw("VmSize:scan_number", "","goff"); + vmsizeGraph=TGraph(int(infoTree.GetSelectedRows()), infoTree.GetV2(), infoTree.GetV1()); + vmsizeGraph.SetLineColor(2); vmsizeGraph.SetLineWidth(1); #vmsizeGraph.SetFillStyle(3002); vmsizeGraph.SetFillColor(3); + vmsizeGraph.SetName("VmSize"); + + infoTree.Draw("VmRSS:scan_number", "", "goff"); + vmrssGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()); + vmrssGraph.SetLineColor(3); vmrssGraph.SetLineWidth(1); #vmrssGraph.SetFillStyle(3003); vmrssGraph.SetFillColor(4); + vmrssGraph.SetName("VmRSS"); + + infoTree.Draw("VmData:scan_number", "", "goff"); + vmdataGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()); + vmdataGraph.SetLineColor(4); vmdataGraph.SetLineWidth(1); #vmdataGraph.SetFillStyle(3004); vmdataGraph.SetFillColor(4); + vmdataGraph.SetName("VmData"); + + infoTree.Draw("VmStk:scan_number", "", "goff"); + vmstkGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()); + vmstkGraph.SetLineColor(5); vmstkGraph.SetLineWidth(1); #vmstkGraph.SetFillStyle(3005); vmstkGraph.SetFillColor(4); + vmstkGraph.SetName("VmStk") + + infoTree.Draw("VmExe:scan_number", "", "goff"); + vmexeGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()); + vmexeGraph.SetLineColor(6); vmexeGraph.SetLineWidth(1); #vmexeGraph.SetFillStyle(3003); vmexeGraph.SetFillColor(4); + vmexeGraph.SetName("VmExe"); + + infoTree.Draw("VmLib:scan_number", "", "goff"); + vmlibGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()); + vmlibGraph.SetLineColor(7); vmlibGraph.SetLineWidth(1); #vmlibGraph.SetFillStyle(3003); vmlibGraph.SetFillColor(4); + vmlibGraph.SetName("VmLib"); + + infoTree.Draw("VmLck:scan_number", "", "goff"); + vmlckGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()); + vmlckGraph.SetLineColor(8); vmlckGraph.SetLineWidth(1); #vmlckGraph.SetFillStyle(3003); vmlckGraph.SetFillColor(4); + vmlckGraph.SetName("VmLck"); + + infoTree.Draw("total_hole_memory:scan_number", "", "goff"); + holeGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()) + holeGraph.SetLineColor(9); holeGraph.SetLineWidth(1); #holeGraph.SetFillStyle(3004); holeGraph.SetFillColor(5); + holeGraph.SetName("HolesSize"); + + mallocTree.Draw("malloc_free:scan_number", "", "goff"); + freeGraph=TGraph(mallocTree.GetSelectedRows(), mallocTree.GetV2(), mallocTree.GetV1()) + freeGraph.SetLineColor(11); freeGraph.SetLineWidth(1); freeGraph.SetFillStyle(3003); freeGraph.SetFillColor(4); + freeGraph.SetName("malloc_free"); + + mallocTree.Draw("malloc_inuse:scan_number", "", "goff"); + inuseGraph=TGraph(mallocTree.GetSelectedRows(), mallocTree.GetV2(), mallocTree.GetV1()) + inuseGraph.SetLineColor(21); inuseGraph.SetLineWidth(1); inuseGraph.SetFillStyle(3003); inuseGraph.SetFillColor(4); + inuseGraph.SetName("malloc_inuse"); + + mallocTree.Draw("malloc_sbrk:scan_number", "", "goff"); + sbrkGraph=TGraph(mallocTree.GetSelectedRows(), mallocTree.GetV2(), mallocTree.GetV1()) + sbrkGraph.SetLineColor(31); sbrkGraph.SetLineWidth(1); sbrkGraph.SetFillStyle(3003); sbrkGraph.SetFillColor(4); + sbrkGraph.SetName("malloc_sbrk"); + + mallocTree.Draw("malloc_mmap:scan_number", "", "goff"); + mmapGraph=TGraph(mallocTree.GetSelectedRows(), mallocTree.GetV2(), mallocTree.GetV1()) + mmapGraph.SetLineColor(41); mmapGraph.SetLineWidth(1); mmapGraph.SetFillStyle(3003); mmapGraph.SetFillColor(4); + mmapGraph.SetName("malloc_mmap"); + + pad1.cd(); + multiGraph1.Add(mapsGraph);multiGraph1.Add(vmsizeGraph); + multiGraph1.Add(vmrssGraph);multiGraph1.Add(vmdataGraph); + multiGraph1.Add(vmlckGraph);multiGraph1.Add(vmexeGraph); + multiGraph1.Add(vmstkGraph);#multiGraph1.Add(vmlibGraph); + multiGraph1.Add(inuseGraph); + multiGraph1.Add(sbrkGraph);multiGraph1.Add(mmapGraph); + multiGraph1.Add(holeGraph);multiGraph1.Add(freeGraph); + + + + #multiGraph1.SetTitle("PROCESS VM and Malloc MEMORY USAGE"); + title.DrawPaveLabel(x1,y1,x2,y2,"PROCESS VM and Malloc MEMORY USAGE","brNDC"); + + multiGraph1.Draw("ALg") + hist = multiGraph1.GetHistogram(); hist.SetXTitle("Event Number"); hist.SetYTitle("Memory, kb"); + legend1 = TLegend(0.84,0.20,0.99,0.90); + legend1.AddEntry(mapsGraph, "Maps", "l"); + legend1.AddEntry(vmsizeGraph,"VmSize", "l"); + legend1.AddEntry(vmrssGraph, "VmRSS", "l"); + legend1.AddEntry(vmdataGraph,"VmData", "l"); + + legend1.AddEntry(sbrkGraph, "MallocSbrk", "l"); + legend1.AddEntry(inuseGraph, "MallocInuse", "l"); + #legend1.AddEntry(vmlibGraph, "VmLib", "l"); + legend1.AddEntry(mmapGraph, "MallocMmap", "l"); + legend1.AddEntry(freeGraph, "MallocFree", "l"); + legend1.AddEntry(holeGraph, "Freed-Holes", "l"); + legend1.AddEntry(vmstkGraph, "VmStk", "l"); + legend1.AddEntry(vmexeGraph, "VmExe", "l"); + legend1.AddEntry(vmlckGraph, "VmLck", "l"); + legend1.Draw(); + + #multiGraph1.Draw("ALg") + #title.DrawPaveLabel(x1,y1,x2,y2,"Process Memory Usage Charts","brNDC"); + + +#Drawing upper-left corner Pad1 of the report + pad2.cd(); + pad2.SetGridx(); pad2.SetGridy(); + + infoTree.Draw("total_hole_memory:scan_number", "", "goff"); + holeGraph=TGraph(infoTree.GetSelectedRows(), infoTree.GetV2(), infoTree.GetV1()) + holeGraph.SetLineColor(9); holeGraph.SetLineWidth(1); holeGraph.SetFillStyle(3004); holeGraph.SetFillColor(5); + holeGraph.SetName("total_hole_memory"); + + mallocTree.Draw("malloc_free:scan_number", "", "goff"); + freeGraph=TGraph(mallocTree.GetSelectedRows(), mallocTree.GetV2(), mallocTree.GetV1()) + freeGraph.SetLineColor(11); freeGraph.SetLineWidth(1); freeGraph.SetFillStyle(3004); freeGraph.SetFillColor(5); + freeGraph.SetName("malloc_free"); + + pad2.cd(); + multiGraph2.Add(holeGraph); + multiGraph2.Add(freeGraph); + #multiGraph2.Add(sbrkGraph); + #multiGraph2.Add(mmapGraph); + + #multiGraph2.SetTitle("Free and Marked Holes Memory Graph"); + title.DrawPaveLabel(x1,y1,x2,y2,"Malloc Free and Marked Holes Memory","brNDC"); + + multiGraph2.Draw("ALg") + hist = multiGraph2.GetHistogram(); hist.SetXTitle("Event Number"); hist.SetYTitle("Memory, kb"); + + legend2 = TLegend(0.9,0.30,0.99,0.90); + legend2.AddEntry(freeGraph, "Free", "l"); + legend2.AddEntry(holeGraph, "Holes", "l"); + #legend2.AddEntry(inuseGraph, "Inuse", "l"); + #legend2.AddEntry(mmapGraph, "Mmap", "l"); + #legend2.AddEntry(sbrkGraph, "Sbrk", "l"); + + legend2.Draw() + #multiGraph2.Draw("ALg") + #title.DrawPaveLabel(x1,y1,x2,y2,"Malloc Memory Usage and Deallocation Charts","brNDC"); + + #PAD3 + pad3.cd() + pad3.SetLogz() + memHist1.Draw("lego2"); + #title.DrawPaveLabel(x1,y1,x2,y2,"TH2I-LEGO2","brNDC"); + + mem_canvas.SetBorderSize(1); + #mem_canvas.Modified() + mem_canvas.Update() + mem_canvas.Print(".pdf") + mem_canvas.Print(".C") \ No newline at end of file diff --git a/Control/HeapMon/python/MemoryScanner.py b/Control/HeapMon/python/MemoryScanner.py new file mode 100644 index 0000000000000000000000000000000000000000..b565c1a40e049b0c88a488fd693c8529c27ee217 --- /dev/null +++ b/Control/HeapMon/python/MemoryScanner.py @@ -0,0 +1,72 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +import os, sys; + +memscan_output = 'heapmon.holes.root' +freescan_output = 'heapmon.freed.root' +newscan_output = 'heapmon.newed.root' + +pid = os.getpid(); +free_marker = 0xCD; +new_marker = 0xBC; +scan_number = 0; +scan_flag = 1; +free_scan_number = 0; +new_scan_number = 0; + +memmarker = 'HeapMon.MemoryMarker' in sys.modules and \ +sys.modules[ 'HeapMon.MemoryMarker' ] or None + +#meminfo_file_name = 'mem' +#print(' RunScanner is loaded: file name for memscan=', memscan_output) + +def nmemscan(file_name, scan_flag, n, id, mrkr = 0xCD): + global pid; + + try: + os.kill(id, 0) + except OSError, err: + print("pid ", id , " doesn't exist, so pid stays os.getpid()=", pid) + id = pid; + + print(' output_file ', file_name) + print ' scan_flag = ', scan_flag + print ' scan_number = ', n + + print('MemoryScanner.exe %d %d %d %s %d %s' %(id, scan_flag, n, file_name, mrkr) ); + os.system( 'MemoryScanner.exe %d %d %d %s %d %s' %(id, scan_flag, n, file_name, mrkr) ); + +def imemscan(): + global pid, free_marker, scan_number, scan_flag, memscan_output + print('MemoryScanner.exe %d %d %d %s %d' %(pid, scan_flag, scan_number, memscan_output, free_marker) ); + os.system( 'MemoryScanner.exe %d %d %d %s %d' %(pid, scan_flag, scan_number, memscan_output, free_marker) ); + scan_number+=1 + +def memscan(file_name, scan_f, scan_n, marker): + global pid + print('MemoryScanner.exe %d %d %d %s %d' %(pid, scan_f, scan_n, file_name, marker) ); + os.system( 'MemoryScanner.exe %d %d %d %s %d' %(pid, scan_f, scan_n, file_name, marker) ); + +def freescan(scan_flag): + global free_scan_number, free_marker + global freescan_output + print ('MemoryScanner.freescan(', scan_flag, ')') + print ' scan_flag = ', scan_flag + print ' scan_number = ', free_scan_number + #print ' RunScanner.memstat()' + print('MemoryScanner.exe %d %d %d %s %d' %(pid, scan_flag, free_scan_number, freescan_output, free_marker) ); + os.system( 'MemoryScanner.exe %d %d %d %s %d' %(pid, scan_flag, free_scan_number, freescan_output, free_marker) ); + + free_scan_number+=1 + +def newscan(scan_flag): + global new_scan_number, new_marker + global newscan_output + print ('MemoryScanner.newscan(', scan_flag, ')') + print ' scan_flag = ', scan_flag + print ' scan_number = ', new_scan_number + #print ' RunScanner.memstat()' + print('MemoryScanner.exe %d %d %d %s %d' %(pid, scan_flag, new_scan_number, newscan_output, new_marker) ); + os.system( 'MemoryScanner.exe %d %d %d %s %d' %(pid, scan_flag, new_scan_number, newscan_output, new_marker) ); + new_scan_number+=1 + diff --git a/Control/HeapMon/python/__init__.py b/Control/HeapMon/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a63ba62d7570caa7d1b86745aa4f5486b839063d --- /dev/null +++ b/Control/HeapMon/python/__init__.py @@ -0,0 +1,19 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# File: HeapMon/__init__.py +# Author: Mous Tatarkhanov (MMTatarkhanov@lbl.gov) + +__version__ = '0.0.1' +__author__ = 'Mous Tatarkhanov (tmmous@berkeley.edu)' + +def setup(): + import atexit, os + __path__.append( os.path.join( __path__[0], os.environ[ 'CMTCONFIG' ] ) ) + + from HeapMon import MemoryMarker + MemoryMarker.configure( MemoryMarker.IS_RUNNING ) + + atexit.register( MemoryMarker.atexit ) + +setup() +del setup diff --git a/Control/HeapMon/share/heapmon_jobo.py b/Control/HeapMon/share/heapmon_jobo.py new file mode 100755 index 0000000000000000000000000000000000000000..2f9081076d8a87523c26adca24a341ca891003e8 --- /dev/null +++ b/Control/HeapMon/share/heapmon_jobo.py @@ -0,0 +1,28 @@ +OutputLevel=INFO +doCBNT=False +EvtMax = 5 + +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() +assert( job == AlgSequence() ) # this is a singleton + +from HeapMon.EventNotifier import EventExecutionNotifier +een =EventExecutionNotifier('EventNotifier') +een.start_scan = 1 +een.stop_scan = 4 + +job.insert(0,een) + +#DetDescrVersion="ATLAS-GEO-02-01-00" +#PoolRDOInput = [ "RDO.pool.root" ] + +# DetFlags modifications are best set here (uncomment RecExCommon_flags first) +#include ("RecExCond/RecExCommon_flags.py") +# switch off ID, calo, or muons +#DetFlags.ID_setOff() +#DetFlags.Calo_setOff() +#DetFlags.Muon_setOff() +print job + +include ("jobOptions.py") +####################################################### diff --git a/Control/HeapMon/src/MemoryMarker.c b/Control/HeapMon/src/MemoryMarker.c new file mode 100644 index 0000000000000000000000000000000000000000..50e0515723ab394492227cf9e74c0eb540e62fa8 --- /dev/null +++ b/Control/HeapMon/src/MemoryMarker.c @@ -0,0 +1,877 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//#ifndef HEAPMON_HEAPMON_H +//#define HEAPMON_HEAPMON_H +#if defined(__linux__) + +#define _GNU_SOURCE 1 + +#include <stdio.h> + +#ifdef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif + +#ifdef _XOPEN_SOURCE +#undef _XOPEN_SOURCE +#endif + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#include "Python.h" + +#include <execinfo.h> +#include <malloc.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> + +#include <gperftools/malloc_hook_c.h> + +//#include <google/malloc_extension_c.h> +void MallocExtension_GetStats(char*, int); +size_t MallocExtension_GetAllocatedSize(void*); +int mm_check(int); +int mm_clearCheckPoint(int); +int mm_depth(int); +int mm_setCheckPoint(void); +void get_trace(long); +void get_key_list(void); +void trace(const char*); + + +// copied from malloc.c +/* -------------- Early definitions for debugging hooks ---------------- */ +/* Define and initialize the hook variables. These weak definitions must + appear before any use of the variables in a function (arena.c uses one). */ +#ifndef weak_variable +#ifndef _LIBC +#define weak_variable /**/ +#else +/* In GNU libc we want the hook variables to be weak definitions to + avoid a problem with Emacs. */ +#define weak_variable weak_function +#endif +#endif + + +/*- data ------------------------------------------------------------------- */ + +/* holder to locate this shared library */ +void mm_dummy() {} + +// defined below +static void tc_MallocHook(const void* ptr, size_t size); +static void tc_FreeHook(const void* ptr); + +static MallocHook_NewHook old_tcMalloc_hook_ = NULL ; +static MallocHook_DeleteHook old_tcFree_hook_ = NULL; + +/* forward declarations */ +static void mm_Hooks_uninstall(); +static void *mm_MallocHook( size_t size, const void *caller ); +static void *mm_ReallocHook( void *ptr, size_t size, const void *caller ); +static void mm_FreeHook( void *ptr, const void *caller ); + +/* holders for original hooks */ +static void *(*m_OldMallocHook) ( size_t size, const void *caller ); +static void *(*m_OldReallocHook) ( void *ptr, size_t size, const void *caller ); +static void (*m_OldFreeHook) ( void *ptr, const void *caller ); + +/* available flags */ +#define IS_RUNNING 1 +#define LEAK_CHECK 2 +#define PROFILE 4 +#define HIDEMEMADDR 8 +#define QUICK 16 +#define STL_CHECKS 32 +#define FILTER_STL 64 +#define IS_MARKING 128 + +#define SIZE_MARK '\xFB' + +static unsigned char FREE_MARKER = '\xCD'; +static unsigned char NEW_MARKER = '\xBC'; +//static short int MAX_EVENT_NUMBER = 10; + +static unsigned char USETCMALLOC = 1; + +/* module-level configuration flags */ +static long gFlags = 0; +static size_t LOWER_THREE_BITS = (0x01|0x02|0x04); +static long event_counter = 0; + +static unsigned long long total_freed = 0; +static unsigned long long total_allocated = 0; +static unsigned long long number_freed = 0; +static unsigned long long number_allocated = 0; +static unsigned long long number_zero_allocated = 0; +static unsigned long long number_zeroptr_freed = 0; +static struct mallinfo mem_struct; + +/* handle to output stream used */ +static FILE *file_output = 0; + +void * old_ptr; +static char buffer[512]; + + + +/* _________________________________________________________________________ */ +static void mm_report( void ) { + printf(" MemoryMarker->mm_report(): gFlags = %u\n", gFlags); +} + + +/* _________________________________________________________________________ */ +static void ignore( const char *name ) { + gFlags = gFlags & ~IS_MARKING; + printf(" MemoryMarker->ignore(): IS_MARKING flag dropped. gFlags = %u\n", gFlags); +} + + +/* _________________________________________________________________________ */ +static void mm_Hooks_save() { + switch(USETCMALLOC){ + case 0: + /* store old glibc hooks in buffer for reset later; prevent storing ourselves in + case of a double-call by the user (e.g. from python) */ + //printf(" MemoryMarker->mm_Hooks_save ptmalloc gFlags = %u\n", gFlags); + + /*if ( __malloc_hook != mm_MallocHook ) + m_OldMallocHook = __malloc_hook; + if ( __realloc_hook != mm_ReallocHook ) + m_OldReallocHook = __realloc_hook; */ + if ( __free_hook != mm_FreeHook ) + m_OldFreeHook = __free_hook; + break; + case 1: + printf(" MemoryMarker->mm_Hooks_save tcmalloc gFlags = %u\n", gFlags); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } +} + +/* _________________________________________________________________________ */ +static long configure( long flags ) { + gFlags |= IS_RUNNING; + gFlags |= flags; + + printf(" MemoryMarker->configure(): IS_RUNNING flag raised. gFlags = %u\n", gFlags); + + //setup(); + switch(USETCMALLOC){ + case 0: + mm_Hooks_save(); + break; + case 1: + printf(" MemoryMarker->configure() tcmalloc gFlags = %u\n", gFlags); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } + return gFlags; +} + +static void set_marker(char m) { + FREE_MARKER = m; +} + +static void get_test(long lkey) { + + struct mallinfo mem_struct; + + switch(USETCMALLOC){ + case 0: + printf("MemoryMarker->get_test()->Malloc Stats:\n"); + printf("--------------------------MALLOC INFO --------------\n"); + malloc_stats(); + + mem_struct = mallinfo(); + printf(" sbrk-Allocated Memory( ARENA) size: %lu\n", mem_struct.arena); + printf(" MMAP-Allocated Memory: %lu\n", mem_struct.hblkhd); + printf(" Number of chunks allocated by MMAP: %lu\n", mem_struct.hblks); + printf(" MALLOC-In Use: %lu\n", mem_struct.uordblks ); + printf(" MALLOC-Free: %lu\n", mem_struct.fordblks); + printf(" Number of chunks from OS not in use by MALLOC: %lu\n", mem_struct.ordblks); + printf(" Top-releasable chunk keepcost: %lu\n", mem_struct.keepcost); + + printf("-----------------------------------------------------\n\n"); + + /* + printf(" gnu_libc_version= %s\n",gnu_get_libc_version()); + printf("------------------Sizes and Ranges of Integer Types-------------------\n"); + printf(" NUMBER OF BITS in types: \n"); + + printf(" CHAR_BIT=%u, SHRT_BIT=%u, INT_BIT=%u, LONG_BIT=%u, LONG_LONG_BIT=%u\n", + CHAR_BIT, sizeof(signed short int)*CHAR_BIT,sizeof(signed int)*CHAR_BIT, + sizeof(signed long int)*CHAR_BIT, sizeof(signed long long int)*CHAR_BIT); + printf(" \n"); + printf(" sizeof(size_t)=%u\t\tsizeof(ptrdiff_t)=%u\n",sizeof(size_t), sizeof(ptrdiff_t)); + printf(" TYPE RANGES:\n"); + printf(" CHAR_MIN=%d\t\tCHAR_MAX=%d\t\tUCHAR_MAX=%u\n", CHAR_MIN, CHAR_MAX, UCHAR_MAX); + printf(" SHRT_MIN=%d\t\tSHRT_MAX=%d\t\tUINT_MAX=%u\n", SHRT_MIN, SHRT_MAX, USHRT_MAX); + printf(" INT_MIN=%d\t\tINT_MAX=%d\t\tUINT_MAX=%u\n", INT_MIN, INT_MAX, UINT_MAX); + printf(" LONG_MIN=%e\t\tLONG_MAX=%e\tULONG_MAX=%e\n", LONG_MIN*1.0, LONG_MAX*1.0,ULONG_MAX*1.0 ); + printf(" LONG_LONG_MIN=%e\tLONG_LONG_MAX=%e\tULONG_LONG_MAX=%e\n", LONG_LONG_MIN*1.0, LONG_LONG_MAX*1.0, ULONG_LONG_MAX*1.0); + printf("----------------------------------------------------------------------\n"); + */ + break; + case 1: + mem_struct = mallinfo(); + printf(" MemoryMarker->get_test tcmalloc gFlags = %u\n", gFlags); + printf(" sbrk-Allocated Memory( ARENA) size: %lu\n", mem_struct.arena); + //printf(" MMAP-Allocated Memory: %lu\n", mem_struct.hblkhd); + //printf(" Number of chunks allocated by MMAP: %lu\n", mem_struct.hblks); + printf(" MALLOC-In Use: %lu\n", mem_struct.uordblks ); + printf(" MALLOC-Free: %lu\n", mem_struct.fordblks); + //printf(" Number of chunks from OS not in use by MALLOC: %lu\n", mem_struct.ordblks); + //printf(" Top-releasable chunk keepcost: %lu\n", mem_struct.keepcost); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } + +} + +static void store_malloc_info() { + //printf("MemoryMarker->store_malloc_info() store malloc data into file:\n"); + malloc_stats(); +} + +static void show_malloc_info() { + + switch(USETCMALLOC){ + case 0: + printf("\n--------- GLIBC ptmalloc( --stdcmalloc) INFO --------\n"); + malloc_stats(); + mem_struct = mallinfo(); + printf(" SBRK-allocated memory( ARENA) size: %lu bytes\n", mem_struct.arena); + printf(" MMAP-allocated memory: %lu bytes\n", mem_struct.hblkhd); + printf(" MMAP-allocated number of chunks: %lu\n", mem_struct.hblks); + printf(" MALLOC-In-use: %lu bytes \n", mem_struct.uordblks ); + printf(" MALLOC-Free: %lu bytes\n", mem_struct.fordblks); + printf(" Number of chunks from OS not in use by MALLOC: %lu \n", mem_struct.ordblks); + printf(" TOP-releasable chunk keepcost: %lu bytes \n\n", mem_struct.keepcost); + + printf("\n-------------- HEAPMON MEMORY MARKER SPECIFIC INFO -------\n"); + printf(" Cumulative allocated memory size: %u bytes\n", total_allocated); + printf(" Cumulative deallocated memory: %u bytes \n", total_freed); + printf(" Number of allocations: %u bytes \n", number_allocated); + printf(" Number of deallocations: %u \n", number_freed); + printf(" Number of zero allocations: %u\n", number_zero_allocated); + printf(" Number of zero ptr deallocations: %u\n", number_zeroptr_freed); + printf("-----------------------------------------------------------\n\n"); + break; + case 1: + + mem_struct = mallinfo(); + printf("\n-------------- TCMALLOC INFO -------------------------\n"); + printf(" MemoryMarker->get_test tcmalloc gFlags = %u\n", gFlags); + printf(" SBRK-allocated Memory( ARENA) size: %lu bytes\n", mem_struct.arena); + //printf(" MMAP-Allocated Memory: %lu\n", mem_struct.hblkhd); + //printf(" Number of chunks allocated by MMAP: %lu\n", mem_struct.hblks); + printf(" MALLOC-In Use: %lu bytes \n", mem_struct.uordblks ); + printf(" MALLOC-Free: %lu bytes \n", mem_struct.fordblks); + //printf(" Number of chunks from OS not in use by MALLOC: %lu\n", mem_struct.ordblks); + //printf(" Top-releasable chunk keepcost: %lu\n", mem_struct.keepcost); + printf("-----------------------------------------------------------\n\n"); + + + MallocExtension_GetStats(buffer, 512); + printf(" MemoryMarker->get_malloc_info() tcmalloc gFlags = %u\n", gFlags); + printf(" tcmalloc stats: %s", buffer); + + printf("\n-------------- HEAPMON MEMORY MARKER SPECIFIC INFO -------\n"); + printf(" Cumulative allocated memory size: %u\n", total_allocated); + printf(" Cumulative deallocated memory: %u\n", total_freed); + printf(" Number of allocations: %u\n", number_allocated); + printf(" Number of deallocations: %u\n", number_freed); + printf(" Number of zero allocations: %u\n", number_zero_allocated); + printf(" Number of zero ptr deallocations: %u\n", number_zeroptr_freed); + printf("-----------------------------------------------------------\n\n"); + + + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + printf("\n-------------- HEAPMON MEMORY MARKER SPECIFIC INFO -------\n"); + printf(" Cumulative allocated memory size: %u\n", total_allocated); + printf(" Cumulative deallocated memory: %u\n", total_freed); + printf(" Number of allocations: %u\n", number_allocated); + printf(" Number of deallocations: %u\n", number_freed); + printf(" Number of zero allocations: %u\n", number_zero_allocated); + printf(" Number of zero ptr deallocations: %u\n", number_zeroptr_freed); + printf("-----------------------------------------------------------\n\n"); + + } +} + +/* _________________________________________________________________________ */ +static void mm_Hooks_install() { + + if ( gFlags & IS_RUNNING ) { + switch(USETCMALLOC){ + case 0: + //printf(" MemoryMarker->mm_Hooks_install(): mm_Hooks installed. gFlags = %u\n", gFlags); + __free_hook = mm_FreeHook; + /*__malloc_hook = mm_MallocHook; + __realloc_hook = mm_ReallocHook;*/ + break; + case 1: + printf(" MemoryMarker->mm_Hooks_install() tcmalloc gFlags = %u\n", gFlags); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } + + } else{ + printf(" MemoryMarker->mm_Hooks_install(): mm_Hooks failed to install. IS_RUNNING not set, gFlags = %u\n", gFlags); + } + return ; +} + +static void tc_Hooks_install() { + if ( gFlags & IS_RUNNING ) { + printf(" MemoryMarker->tc_Hooks_install(): do nothing! gFlags = %u\n", gFlags); + + } else{ + printf(" MemoryMarker->tc_Hooks_install(): 'IS_RUNNING' not set, gFlags = %u do nothing!\n", gFlags); + } + return ; +} + +/* _________________________________________________________________________ */ +static void mm_Hooks_uninstall() { + switch(USETCMALLOC){ + case 0: + //printf(" MemoryMarker->mm_Hooks_uninstall(), gFlags = %u\n", gFlags); + __free_hook = m_OldFreeHook; + /*__malloc_hook = m_OldMallocHook; + __realloc_hook = m_OldReallocHook;*/ + break; + case 1: + printf(" MemoryMarker->mm_Hooks_uninstall() tcmalloc gFlags = %u\n", gFlags); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } +} + +/* _________________________________________________________________________ */ +static void mm_Hooks_start() { + if ( (gFlags & IS_RUNNING) ){ + switch(USETCMALLOC){ + case 0: + printf(" MemoryMarker->mm_Hooks_start()."); + mm_Hooks_save(); + mm_Hooks_install();//__free_hook = mm_FreeHook; + break; + case 1: + if (!(gFlags & IS_MARKING)){ + printf(" MemoryMarker->tc_Hooks_start()."); + old_tcFree_hook_ = MallocHook_SetDeleteHook(tc_FreeHook); + //old_tcMalloc_hook_ = MallocHook_SetNewHook(tc_MallocHook); + if (old_tcFree_hook_) + printf(" MemoryMarker-> HeapMon Delete hook set and old_tcFree_hook successfully saved"); + //if (old_tcMalloc_hook_ != NULL) + //printf(" MemoryMarker-> HeapMon New hook set and old_tcMalloc_hook successfully saved"); + } else{ + printf(" MemoryMarker-> HeapMon hook has been already set"); + } + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } + gFlags |= IS_MARKING; + printf(" IS_MARKING flag raised, gFlags = %u!\n", gFlags); + } else { + printf(" MemoryMarker->mm_Hooks_start(): Attempt failed: IS_RUNNING flag is not set, gFlags = %u!\n", gFlags); + } +} + +/* _________________________________________________________________________ */ +static void mm_Hooks_stop() { + if (gFlags & IS_MARKING){ + switch(USETCMALLOC){ + case 0: + printf(" MemoryMarker->mm_Hooks_stop(): old hooks restored and IS_MARKING dropped"); + //__free_hook = m_OldFreeHook; + mm_Hooks_uninstall(); + break; + case 1: + printf(" MemoryMarker->mm_Hooks_stop(): old tc_hooks restored\n"); + if (MallocHook_SetDeleteHook(old_tcFree_hook_)!=NULL) + printf(" old tcmalloc Delete hook restored!\n"); + //if (MallocHook_SetNewHook(old_tcMalloc_hook_)!=NULL) + //printf(" old tcmalloc New hook restored!\n"); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } + + gFlags &= gFlags ^ IS_MARKING; + printf(", gFlags = %u\n", gFlags); + } else{ + printf(" MemoryMarker->mm_Hooks_stop(): Attempt failed (IS_MARKING not raised) gFlags = %u. \n", gFlags); + } +} + +/* _________________________________________________________________________ */ +static void mm_Hooks_atexit() { + printf(" MemoryMarker->mm_Hooks_atexit(): mm_Hooks _uninstall(). gFlags = %u\n", gFlags); + + switch(USETCMALLOC){ + case 0: + /* reset (system/NULL) hook to prevent tracking */ + mm_Hooks_uninstall(); + break; + case 1: + printf(" MemoryMarker->mm_Hooks_atexit(): tc_Hooks _uninstall()\n"); + if (old_tcFree_hook_!=NULL){ + if (MallocHook_SetDeleteHook(old_tcFree_hook_)!=NULL) + printf(" old tcmalloc Delete hook restored successfull!\n"); + //if (MallocHook_SetNewHook(old_tcMalloc_hook_)!=NULL) + //printf(" old tcmalloc New hook restored successfull!\n"); + } + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + } + + gFlags &= gFlags ^ IS_MARKING; + gFlags &= gFlags ^ IS_RUNNING; + printf(" MemoryMarker->mm_Hooks_atexit(): IS_MARKING and IS_RUNNING flags dropped gFlags = %u\n", gFlags); +} + + +/* _________________________________________________________________________ */ +static void *mm_MallocHook( size_t size, const void *unused ) { + void *result; + +/* reset (system/NULL) hook to prevent recursion */ + mm_Hooks_uninstall(); + +/* let malloc do its thing */ + result = malloc( size ); + + if (size > 8 && result!=0) + memset(result, NEW_MARKER, size - 8); + +/* store current hooks */ + mm_Hooks_save(); + +/* reset tracker hook */ + mm_Hooks_install(); + + return result; +} + +/* _________________________________________________________________________ */ +static void *mm_ReallocHook( void *ptr, size_t size, const void *unused ) { + void *result; + +/* reset (system/NULL) hook to prevent recursion */ + mm_Hooks_uninstall(); + +/* let realloc do its thing */ + result = realloc( ptr, size ); + + //memset(result, NEW_MARKER, size); + +/* store current hooks */ + mm_Hooks_save(); + +/* reset tracker hook */ + mm_Hooks_install(); + + return result; +} + +void *secureMemset(void *v, int c,size_t n) { + volatile char *p = v; + while (n--) + *p++ = c; + + return v; +} + +static void tc_MallocHook(const void* ptr, size_t size){ + if (size == 0){ + //printf(" alloc_size=0 "); + number_zero_allocated+=1; + } else { + + total_allocated +=size; + number_allocated +=1; + + /*if (size > 1) + memset(ptr, FREE_MARKER, object_size - 1);*/ + + if (size > 50000) + printf("malloc=%d", size); + } + +} + +static void tc_FreeHook(const void *ptrv) { + size_t* ptr = (size_t *) ptrv; + if( ptr!=NULL && ptr!=0){ + //printf("ptr=%x", ptr); + size_t object_size = 0; + object_size = MallocExtension_GetAllocatedSize(ptr); + + if (object_size < 1) + return; + total_freed +=object_size; + number_freed +=1; + if (object_size < 2){ + printf("free=1"); + memset(ptr , FREE_MARKER, object_size - 2 ); + } else if (object_size < 10){ + //printf("`"); + memset(ptr, FREE_MARKER, object_size - 2 ); + } else if (object_size < 250){ //14 size_t memory slots + //printf("!"); + memset(ptr , FREE_MARKER, object_size - 8 ); + } else if (object_size < 350){ + //printf("#"); + memset(ptr + 50, FREE_MARKER, 16); + memset(ptr + 52, SIZE_MARK, 12); + + char* cp_ptr = (char*)(ptr + 53); //pointer to the memory where object_size is recorded byte-by-byte + char* cp_object_size = (char *)(&object_size); // get the value stored at pI + int x = 0; + for( x = 0; x < sizeof(object_size); x++){ + char temp = *cp_object_size; // get the value of first byte of object_size + memset(cp_ptr + x, temp, 1); + cp_object_size++; // Point to next byte of object_size + } + } else { + + //printf("$"); + //memset(ptr, FREE_MARKER, object_size - 8); + memset(ptr + 50, FREE_MARKER, 16); + memset(ptr + 52, SIZE_MARK, 12); + + char* cp_ptr = (char*)(ptr + 53); //pointer to the memory where object_size is recorded byte-by-byte + char* cp_object_size = (char *)(&object_size); // get the value stored at pI + int x = 0; + for( x = 0; x < sizeof(object_size); x++){ + char temp = *cp_object_size; // get the value of the x-th byte of object_size + memset(cp_ptr + x, temp, 1); + cp_object_size++; // Point to next byte of object_size + } + /*if(object_size >= 350 && object_size <=450){ + int y=0; + for(y = 0; y < 5; y++){ + //printf(" ptr=%x, value=%u(%x) ",ptr+y, *((long *) (ptr+y)), *((long *) (ptr+y))); + } + }*/ + } + } else{ + //printf("ptr=NULL/0"); + number_zeroptr_freed += 1; + } +} + +/* _________________________________________________________________________ */ +static void mm_FreeHook( void *ptr, const void *caller ) { +/* reset (system/NULL) hook to prevent recursion */ + mm_Hooks_uninstall(); + + size_t* chunk_ptr ; + size_t* next_chunk_ptr; + unsigned long object_size = 0; + unsigned long chunk_size = 0; + + if(ptr){ + chunk_ptr = (size_t*)(ptr-1*sizeof(size_t)); + chunk_size = (*chunk_ptr) & ~LOWER_THREE_BITS; + //object_size = ((*chunk_ptr) & ~LOWER_THREE_BITS) - 2*sizeof(size_t); + object_size = chunk_size - 2*sizeof(size_t); + memset(ptr, FREE_MARKER, object_size); + } + free( ptr ); + +/* store current hooks */ + mm_Hooks_save(); + +/* reset tracker hook */ + mm_Hooks_install(); + +} + + +/*========================================================================== */ +/* startup and shutdown */ +/*========================================================================== */ +static void setup() __attribute__ ((constructor)); +static void report() __attribute__ ((destructor)); + +/* _________________________________________________________________________ */ +static void setup() { + printf("MemoryMarker->setup()->mm_Hooks_save()\n"); + //find out if tcmalloc was loaded + USETCMALLOC = strcmp(getenv("USETCMALLOC"), "true") ? 0 : 1; + printf(" USETCMALLOC=%d", USETCMALLOC); + if (USETCMALLOC) { + printf(" tcmalloc is loaded \n"); + } else { + printf(" glibc malloc is working \n"); + mm_Hooks_save(); + } + +} + +/* _________________________________________________________________________ */ +static void report() { + static int finalized = 0; + printf("MemoryMarker->report()->mm_Hooks_uninstall()\n"); + //unsigned int iname; + // finalized = 1; + + /* reset (system/NULL) as we're done now */ + mm_Hooks_uninstall(); + +} + + +/*========================================================================== */ +/* python interface module */ +/*========================================================================== */ +#define CPPTOPYTHON( fname ) \ +static PyObject* hep_##fname( PyObject* unused, PyObject* args ) { \ + if ( ! PyArg_ParseTuple( args, (char*)":"#fname ) ) \ + return 0; \ + \ + mm_Hooks_##fname(); \ + \ + Py_INCREF( Py_None ); \ + return Py_None; \ +} +CPPTOPYTHON( install ) +CPPTOPYTHON( start ) +CPPTOPYTHON( stop ) +CPPTOPYTHON( uninstall ) +CPPTOPYTHON( atexit ) + +/* _________________________________________________________________________ */ +#define CPPTOPYTHONWITHSTRING( fname ) \ +static PyObject* hep_##fname( PyObject* unused, PyObject* args ) { \ + const char *name; \ + PyStringObject* pyname = 0; \ + if ( ! PyArg_ParseTuple( args, (char*)"S:"#fname, &pyname ) ) \ + return 0; \ + \ + name = PyString_AS_STRING( pyname ); \ + fname( name ); \ + \ + Py_INCREF( Py_None ); \ + return Py_None; \ +} +CPPTOPYTHONWITHSTRING( trace ) +CPPTOPYTHONWITHSTRING( ignore ) + +/* _________________________________________________________________________ */ +#define CPPTOPYTHONWITHINT( fname ) \ +static PyObject* hep_##fname( PyObject* unused, PyObject* args ) { \ + int i,res; \ + if ( ! PyArg_ParseTuple( args, "i", &i ) ) \ + return 0; \ + \ + res = mm_##fname( i ); \ + return Py_BuildValue( "i", res ); \ +} +CPPTOPYTHONWITHINT( check ) +CPPTOPYTHONWITHINT( clearCheckPoint ) +CPPTOPYTHONWITHINT( depth ) + +static PyObject* hep_set_marker(PyObject* unused, PyObject* args ){ + char c; + if (! PyArg_ParseTuple(args, "c", &c) ) + return 0; + set_marker(c); + + Py_INCREF( Py_None ); \ + return Py_None; +} + +static PyObject* hep_get_marker(PyObject* unused, PyObject* args ){ + PyObject* py_return = 0; + py_return = Py_BuildValue("c", FREE_MARKER); + return py_return; +} + +/* _________________________________________________________________________ */ +static PyObject* hep_setCheckPoint( PyObject* unused, PyObject* args ) { + int res = mm_setCheckPoint(); + return Py_BuildValue( "i", res ); +} + +/* _________________________________________________________________________ */ +static PyObject* hep_configure( PyObject* unused, PyObject* args ) { + long flags = 0; + if ( ! PyArg_ParseTuple( args, (char*)"|l:configure", &flags ) ) + return 0; + + flags = configure( flags ); + + return PyLong_FromLong( flags ); +} + +static PyObject* hep_get_trace( PyObject* unused, PyObject* args ) { + long key = 0; + if ( ! PyArg_ParseTuple( args, (char*)"|l:get_trace", &key ) ) + return 0; + + get_trace( key ); + + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject* hep_get_test( PyObject* unused, PyObject* args ) { + long key = 0; + if ( ! PyArg_ParseTuple( args, (char*)"|l:get_test", &key ) ) + return 0; + + get_test( key ); + + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject* hep_store_malloc_info( PyObject* unused, PyObject* args ) { + unsigned int number = 0; + const char * name; + PyStringObject* pyname = 0; + + if ( ! PyArg_ParseTuple( args, (char*)"is:store_malloc_info", &number, &pyname) ) + return 0; + + name = PyString_AS_STRING( pyname ); + //store_malloc_info(number, name); + + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject* hep_get_malloc_info( PyObject* unused, PyObject* args ) { + PyStringObject* pyname = 0; + PyObject* py_return = 0; + struct mallinfo mem_struct; + mem_struct = mallinfo(); + + switch(USETCMALLOC){ + case 0: //ptmalloc(glibc) + /* reset (system/NULL) hook to prevent tracking */ + /*printf(" sbrk-Allocated Memory( ARENA) size: %lu\n", mem_struct.arena); + printf(" MMAP-Allocated Memory: %lu\n", mem_struct.hblkhd); + printf(" Number of chunks allocated by MMAP: %lu\n", mem_struct.hblks); + printf(" MALLOC-In Use: %lu\n", mem_struct.uordblks ); + printf(" MALLOC-Free: %lu\n", mem_struct.fordblks); + printf(" Number of chunks from OS not in use by MALLOC: %lu\n", mem_struct.ordblks); + printf(" Top-releasable chunk keepcost: %lu\n", mem_struct.keepcost);*/ + + py_return = Py_BuildValue("llll", + mem_struct.arena/1024, //sbrk + mem_struct.hblkhd/1024, //mmap + mem_struct.uordblks/1024, //inuse + mem_struct.fordblks/1024);//free + break; + case 1: //tcmalloc + py_return = Py_BuildValue("llll", + mem_struct.arena/1024, //sbrk + 1, //for tcmalloc not defined + mem_struct.uordblks/1024, //inuse + mem_struct.fordblks/1024);//free + //get_malloc_info(); + break; + default: + printf(" Invalid USETCMALLOC key: %d", USETCMALLOC); + show_malloc_info(); + } + + return py_return; +} + +static PyObject* hep_show_info( PyObject* unused, PyObject* args ) { + show_malloc_info( ); + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject* hep_get_key_list( PyObject* unused, PyObject* args ) { + long key = 0; + if ( ! PyArg_ParseTuple( args, (char*)"|l:get_key_list", &key ) ) + return 0; + + get_key_list( ); + + Py_INCREF( Py_None ); + return Py_None; +} + +/* _________________________________________________________________________ */ +static PyObject* hep_outstream( PyObject* unused, PyObject* args ) { + PyObject* pyfile; + if ( ! PyArg_ParseTuple( args, "O!", &PyFile_Type, &pyfile ) ) + return 0; + + FILE* fp = PyFile_AsFile( pyfile ); + if ( ! fp ) + return 0; + + int fd = dup( fileno( fp ) ); + + file_output = fdopen( fd, "w" ); + + Py_INCREF( Py_None ); + return Py_None; +} + +/* _________________________________________________________________________ */ +static PyMethodDef gMemoryMarkerMethods[] = { + { (char*)"install", (PyCFunction)hep_install, METH_VARARGS, (char*)"install/start marking" }, + { (char*)"start", (PyCFunction)hep_start, METH_VARARGS, (char*)"start marking" }, + { (char*)"stop", (PyCFunction)hep_stop, METH_VARARGS, (char*)"stop marking" }, + { (char*)"uninstall", (PyCFunction)hep_uninstall, METH_VARARGS, (char*)"uninstall marking" }, + { (char*)"atexit", (PyCFunction)hep_atexit, METH_VARARGS, (char*)"atexit handler" }, + { (char*)"ignore", (PyCFunction)hep_ignore, METH_VARARGS, (char*)"ignore memory marking by dropping IS_MARKING flag" }, + { (char*)"configure", (PyCFunction)hep_configure, METH_VARARGS, (char*)"prepare for memory marking by raising IS_MARKING flag" }, + { (char*)"outstream", (PyCFunction)hep_outstream, METH_VARARGS, (char*)"set new outstream" }, + { (char*)"get_test", (PyCFunction)hep_get_test, METH_VARARGS, (char*)"get test information" }, + { (char*)"store_malloc_info", (PyCFunction)hep_store_malloc_info, METH_VARARGS, (char*)"store Malloc-info into ROOT file using C++ extern function - doesn't work for now" }, + { (char*)"get_malloc_info", (PyCFunction)hep_get_malloc_info, METH_VARARGS, (char*)"get Malloc-info in the tuple" }, + { (char*)"show_info", (PyCFunction)hep_show_info, METH_VARARGS, (char*)"show mempory usage info" }, + { (char*)"set_marker", (PyCFunction)hep_set_marker, METH_VARARGS, (char*)"set marker_char to build marker" }, + { (char*)"get_marker", (PyCFunction)hep_get_marker, METH_VARARGS, (char*)"get current marker_char" }, + { NULL, NULL, 0, NULL } +}; + + +/* _________________________________________________________________________ */ +void initMemoryMarker() { + PyObject *memmark; + + memmark = Py_InitModule( (char*)"MemoryMarker", gMemoryMarkerMethods ); + +/* configuration flags */ + PyModule_AddObject( memmark, (char*)"LEAK_CHECK", PyLong_FromLong( LEAK_CHECK ) ); + PyModule_AddObject( memmark, (char*)"PROFILE", PyLong_FromLong( PROFILE ) ); + PyModule_AddObject( memmark, (char*)"HIDEMEMADDR",PyLong_FromLong( HIDEMEMADDR ) ); + PyModule_AddObject( memmark, (char*)"QUICK", PyLong_FromLong( QUICK ) ); + PyModule_AddObject( memmark, (char*)"STL_CHECKS", PyLong_FromLong( STL_CHECKS ) ); + PyModule_AddObject( memmark, (char*)"FILTER_STL", PyLong_FromLong( FILTER_STL ) ); + PyModule_AddObject( memmark, (char*)"IS_MARKING", PyLong_FromLong( IS_MARKING ) ); + PyModule_AddObject( memmark, (char*)"IS_RUNNING", PyLong_FromLong( IS_RUNNING ) ); +} + +#endif diff --git a/Control/HeapMon/src/MemoryScanner.cxx b/Control/HeapMon/src/MemoryScanner.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8e011ac5b52a6166e4678c5d96e1cf2d37c6048e --- /dev/null +++ b/Control/HeapMon/src/MemoryScanner.cxx @@ -0,0 +1,490 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/* +MEMORY SCANNER +*/ + +// standard includes +#include <iostream> +using namespace std; + +// C includes +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> + + +//system includes +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/wait.h> +#include <sys/stat.h> + +// STL includes +#include <map> +#include <vector> +#include <iostream> +#include <iterator> + +// ROOT includes +#include <TTree.h> +#include <TFile.h> +#include <TF1.h> +#include <TH1.h> +#include <TH2.h> +#ifdef __APPLE__ +#define PTRACE_ATTACH PT_ATTACH +#define PTRACE_DETACH PT_DETACH +#endif + +int usage( char* name ){ + cout << "usage: " << name <<" <pid> <scan_flag=0|1|2|3|4> <scan_number> <output_file_name> <marker-type(not-used-yet)>\n"; + return 2; +} + + +int main( int argc, char *argv[] ){ + typedef unsigned int ms_uint64; + typedef unsigned int ms_uint32; + + int result = -1; + FILE *maps = 0; + FILE *statusf = 0; + int mem = 0; + pid_t pid = 0; + + unsigned short int SCAN_FLAG = 0; + unsigned short int scan_number = 0; + + char mapfile[128], memfile[128], statusfile[128]; + char *buffer = NULL; + + ms_uint32 marker = 0xCDCDCDCD; // new_marker = 0xBCBCBCBC; + ms_uint32 size_mark = 0xFBFBFBFB; + ms_uint64 addr_start = 0, addr_end = 0; + + siginfo_t *infop = NULL; + char perm[3]; + + + // Parsing of arguments + if ( argc != 6 ) + return usage( argv[0] ); + +#ifndef __APPLE__ + + pid = atoi( argv[1] ); + SCAN_FLAG = atoi( argv[2]); + scan_number = atoi (argv[3]); + char* file_name = argv[4]; + unsigned char marker_char = atoi(argv[5]); // "the color" of memory painting + + marker = (marker_char << 24) + + (marker_char << 16) + + (marker_char << 8) + + marker_char; // 0xCD converted -> 0xCDCDCDCD + cout << " MemoryScanner: marker_char = " << marker_char << " marker = " + << marker << endl; + cout << " MemoryScanner: scan_flag = " << SCAN_FLAG << endl; + switch ( SCAN_FLAG ) { + case 0 : + cout << "MemoryScanner: std output, no file output produced" ; + break; + + case 1 : + cout << "MemoryScanner: full output of hole statistics and malloc/process memory info into " << file_name << "\n"; + break; + + case 2 : + cout << "MemoryScanner: malloc/process memory info output into " << file_name << "\n"; + break; + + default : + // Process for all other cases. + cout << "MemoryScanner: ERROR - Wrong scan_flag=" << SCAN_FLAG <<" provided.\n"; + return usage( argv[0] ); + + } + + cout <<"\n MemoryScanner: scan_number=" << scan_number <<" \n"; + + + //auxiliary buffer for reading bits from proc/mem file + const ms_uint64 aux_buffer_size = 1024; // 4096bytes >> 2 = 1024 size_t elements! + cout << "\n buffer_page_size =" << aux_buffer_size <<" bytes "<< endl; + size_t aux_buffer[aux_buffer_size]; + //size_t mem_size = addr_end - addr_start; + + //Declaration of counters + ms_uint64 counter = 0; // marker pieces ('CDCDCDCD') counter + ms_uint64 block_counter = 0; // marked blockes ('CDCD...CDCD') counter + ms_uint64 maprange_counter = 0; + + //Declaration of size variables + + ms_uint64 maps_total_size = 0; // Total maps in /proc/PID/maps + ms_uint64 mem_total_size = 0; // Total scanned maps (excluding the ranges with no 'wr' permission) + ms_uint64 block_total_size = 0;// Total holes size + ms_uint64 mapsSize = 0, holesSize = 0; //memSize = 0, ; + + ms_uint64 malloc_total = 0; + + //Declaration of Marked block related variables + ms_uint64 block_flag = 0; + ms_uint64 block_size = 0; + ms_uint64 block_start = 0; // auxiliary to remember block start location + size_t* block_ptr = 0; + size_t* block_end_ptr = 0; + size_t* addr = 0; + + //variables related to the TTree building + ms_uint64 hole_addr = (ms_uint64) (size_t) block_ptr; + ms_uint64 hole_size = (ms_uint64) (size_t) block_size; + + + + //--------------------------------------------------// + // ATTACHING To the pid Process + // the %pid-Process restores operation after the MemoryScanner finishes it's job + //--------------------------------------------------// + cout << "using marker: " << marker << endl; + cout << "halting process: " << pid << endl; + result = ptrace( PTRACE_ATTACH, pid, NULL, NULL ); + if ( result == -1 ) { + cerr << " MemoryScanner: ERROR - cannot attach to the " << pid << " process \n"; + exit( -1 ); + } + waitid( P_PID, pid, infop, WSTOPPED ); + + //------------------------------------------------------// + // READING /proc/%PID/status file + //------------------------------------------------------// + char line [128]; /* or other suitable maximum line size */ + char head_buffer[6];//char* head_buffer; + char tail_buffer[10];//char* tail_buffer; + snprintf( statusfile, 128, "/proc/%u/status", pid ); + statusf = fopen ( statusfile, "r" ); + cout << "opened /proc/" << pid << "/status file \n"; + + ms_uint32 tag_value; + ms_uint32 VmSize, VmLck, VmRSS, VmData, VmStk, VmExe, VmLib; + + if ( statusf != NULL ){ + while ( fgets ( line, sizeof line, statusf ) != NULL) /* read a line */{ + sscanf( line, "%5s %u %9s", head_buffer, &tag_value, tail_buffer); + //cout <<"h_buffer=" << head_buffer << " tag_value=" << tag_value << " t_buffer=" << tail_buffer << "\n"; + if (strncmp(head_buffer, "VmSize",5) == 0){ + VmSize = tag_value; + } else if (strncmp(head_buffer, "VmLck", 5) == 0){ + VmLck = tag_value; + } else if (strncmp(head_buffer, "VmRSS", 5) == 0){ + VmRSS = tag_value; + } else if (strncmp(head_buffer, "VmData",5) == 0){ + VmData = tag_value; + } else if (strncmp(head_buffer, "VmStk", 5) == 0){ + VmStk = tag_value; + } else if (strncmp(head_buffer, "VmExe", 5) == 0){ + VmExe = tag_value; + } else if (strncmp(head_buffer, "VmLib", 5) == 0){ + VmLib = tag_value; + } + } + fclose ( statusf ); + } + else{ + perror ( statusfile); /* why didn't the file open? */ + } + cout << "VmSize=" << VmSize << " VmRSS=" << VmRSS << " VmData=" << VmData + << "VmStk=" << VmStk << "VmExe=" << VmExe << "VmLib=" << VmLib << endl; + + + + //---------------------------------------------------------// + // READING /proc/%PID/maps file + //---------------------------------------------------------// + snprintf( mapfile, 128, "/proc/%u/maps", pid ); + maps = fopen( mapfile, "r" ); + if( ! maps ) { + cerr << " MemoryScanner: ERROR - accessing /proc/" << pid <<"/maps file \n"; + exit( -1 ); + } + cout << "opened mapfile:" << mapfile << "\n"; + + //-------------------------------------------------------// + // Handle to /proc/%PID/mem file + //-------------------------------------------------------// + snprintf( memfile, 128, "/proc/%u/mem", pid ); + mem = open( memfile, O_RDONLY, NULL ); + if ( mem == -1 ) { + cerr << " MemoryScanner: ERROR - accessing /proc/" << pid << "/mem file \n"; + exit( -1 ); + } + cout << "opened memfile: " << memfile << endl; + + + // ROOT Declarations + TFile *memFile ; + TTree *memTree; + TTree *infoTree; + + if (scan_number == 0){ + cout << " Prepare the memFile = " << file_name << "\n"; + TTree *mallocTree; + + memFile = new TFile(file_name, "recreate"); + + // create hole statistics tree and it's branches: + // start_addr,end_addr, scan_number, marker_char + memTree = new TTree("holeTree","memory_holes_data"); + memTree->Branch("hole_addr", &hole_addr,"hole_addr/i"); + memTree->Branch("hole_size", &hole_size, "hole_size/i"); + memTree->Branch("scan_number",&scan_number, "scan_number/s"); + memTree->Branch("hole_marker", &marker, "marker/i"); + + + // create process memory usage + hole info tree and it's branches: + infoTree = new TTree("infoTree","memory_usage_statistics"); + infoTree->Branch("total_hole_memory", &holesSize,"hole_mem/i"); + infoTree->Branch("total_hole_number", &block_counter,"hole_number/i"); + infoTree->Branch("hole_marker", &marker, "hole_marker/i"); + infoTree->Branch("total_maps_memory", &mapsSize, "maps_memory/i"); + infoTree->Branch("VmSize", &VmSize,"vmsize/i"); + infoTree->Branch("VmLck", &VmLck, "vmlck/i"); + infoTree->Branch("VmRSS", &VmRSS, "vmrss/i"); + infoTree->Branch("VmData", &VmData,"vmdata/i"); + infoTree->Branch("VmStk", &VmStk, "vmstk/i"); + infoTree->Branch("VmExe", &VmExe, "vmexe/i"); + infoTree->Branch("VmLib", &VmLib, "vmlib/i"); + infoTree->Branch("scan_number", &scan_number, "scan_number/s"); + + // create malloc info tree and it's branches: + mallocTree = new TTree("mallocTree","malloc_statistics"); + mallocTree->Branch("malloc_sbrk", &malloc_total, "sbrk/i"); + mallocTree->Branch("malloc_mmap", &malloc_total, "mmap/i"); + mallocTree->Branch("malloc_inuse", &malloc_total, "inuse/i"); + mallocTree->Branch("malloc_free", &malloc_total, "free/i"); + mallocTree->Branch("scan_number", &scan_number, "scan_number/s"); + + mallocTree->Fill(); + mallocTree->Print(); + mallocTree->Write(); + } else { + cout << " Update the memFile = " << file_name << "\n"; + memFile = TFile::Open(file_name, "update"); + memTree = (TTree*)memFile->Get("holeTree"); + infoTree = (TTree*)memFile->Get("infoTree"); + + //bind variables to the memTree for further update/filling + memTree->SetBranchAddress("hole_addr", &hole_addr); + memTree->SetBranchAddress("hole_size", &hole_size); + memTree->SetBranchAddress("scan_number",&scan_number); + memTree->SetBranchAddress("hole_marker", &marker); + + //bind variables to the infoTree for further update/filling + infoTree->SetBranchAddress("total_hole_memory", &holesSize); + infoTree->SetBranchAddress("total_hole_number", &block_counter); + infoTree->SetBranchAddress("total_maps_memory", &mapsSize); + infoTree->SetBranchAddress("hole_marker", &marker); + infoTree->SetBranchAddress("VmSize", &VmSize); + infoTree->SetBranchAddress("VmLck", &VmLck); + infoTree->SetBranchAddress("VmRSS", &VmRSS); + infoTree->SetBranchAddress("VmData", &VmData); + infoTree->SetBranchAddress("VmStk", &VmStk); + infoTree->SetBranchAddress("VmExe", &VmExe); + infoTree->SetBranchAddress("VmLib", &VmLib); + infoTree->SetBranchAddress("scan_number", &scan_number); + } + + + + + //----------------------------------------------------// + //Main Part: The actual memory scanning, first read /proc/%pid/maps file + //Then scan /proc/%pid/mem for marked holes + //----------------------------------------------------// + size_t len = 0; + while (getline(&buffer, &len, maps) > 0) { + sscanf( buffer, "%x-%x %2s", &addr_start, &addr_end, perm ); + maps_total_size += (addr_end - addr_start); + + if ( strcmp( perm, "rw" ) != 0 ){ + continue; + } + //cout << "addr_start=" << hex << addr_start << " addr_end=" << hex << addr_end << " prm=" << perm << "\n"; + + maprange_counter++; + mem_total_size += (addr_end - addr_start); + //mem_size = addr_end - addr_start; + + addr = (size_t*) (unsigned long) addr_start; + + switch ( SCAN_FLAG ) { + case 0 : + cout <<"Maps: " << hex << addr_start + << "-" << hex << addr_end + << " size=" << addr_end -addr_start << "/n"; + break; + + case 1 : + /*cout <<"Maps: " << hex << addr_start + << "-" << hex << addr_end + << " size=" << addr_end -addr_start << "/n";*/; + break; + + case 2 : + // cout << "Maps: " << hex << addr_start + break; + + default : + ;// Process for all other cases. + } + //these are auxiliary flags and variables to define the-size of CDCDCDCD and PINNED blocks + //CD blocks parameters + block_flag = 0; + block_size = 0; + block_ptr = 0; + block_end_ptr = 0; + result = 0; + + /* scan /proc/%pid/mem for marked holes */ + while ( (ms_uint64) (size_t) addr < addr_end && result != -1) { + + /*for (i=0; i<aux_buffer_size; i++) + aux_buffer[i] = 0;*/ + + result = pread( mem, &aux_buffer, sizeof(aux_buffer), (ms_uint64) (size_t) addr ); + if (result == -1){ + //cerr << " MemoryScanner: ERROR - reading mem at address" << addr << "\t" << "error=" << errno << " " << strerror(errno) << "\n"; + continue ; + } else if (result == 0){ + cerr << " MemoryScanner: WARNING - zero bytes read from mem at address" << addr <<"\n"; + continue ; + } + + int i; + + for (i=0; i<result; i++){ + if ( aux_buffer[i] == marker ) { + //Here block_flag==0 defines the beginning of the 'CDCDCDCD' memory block + if (block_flag==0) {//cout << "found CDCDCDCD block: " << endl; + block_start = counter; + block_ptr = addr + i; + block_counter++; // 'CDCDCDCD' block counter + block_flag=1; // forthcoming consecutive 'CDCDCDCD' are not the beginning + } + counter ++; //counter of 'CDCDCDCD' pieces + }else { //Here block_flag==1 defines the end of the 'CDCDCDCD' memory block + + //this condition for Tcmalloc marking of freed memmory + if (block_flag == 1) { + if (aux_buffer[i] == size_mark){ + if ((aux_buffer[i+2] == size_mark) && (aux_buffer[i+1]!=size_mark && aux_buffer[i+1] > 0)){ + if (aux_buffer[i+1] < 65000000) + counter += aux_buffer[i+1]/4 - 2; + } + } + block_flag = 0; + block_size = counter - block_start; + block_end_ptr = block_ptr + block_size; + //block_size=block_size*sizeof(size_t); + block_total_size += block_size; + hole_addr = (ms_uint64 ) (size_t) block_ptr; + //hole_end_addr = (ms_uint64 ) block_end_ptr; + //hole_size = hole_end_addr - hole_addr; + hole_size = block_size*sizeof(size_t); + + switch ( SCAN_FLAG ) { + case 0 : + cout <<"C:\t" << hex << block_ptr <<"-" << hex << block_end_ptr ; + cout << " size=" << block_size; + cout << " counter="<< counter << "\n"; + break; + + case 1 : + memTree -> Fill(); + break; + case 2 : + /*if(scan_number < report_scan_number) + memTree -> Fill()*/; + break; + + default : + ;// Process for all other cases. + } + + } + }//if + }//for + addr += aux_buffer_size; + }//inner-while-end + + //cout << "hs=" << dec << 4*block_total_size << " c=" << 4*counter << " map_range=" << hex << (size_t*) addr_start << "-" << (size_t*)addr_end << " map_size=" << dec << addr_end - addr_start << " len= "<< len<<"\n"; + len = 1; + }//outer-while-end + + +//FINISHED SCANNING of the MEMORY + close( mem ); + fclose( maps ); + cout << "resuming process:" << pid << endl ; + + result = ptrace( PTRACE_DETACH, pid, NULL, NULL ); + if ( result == -1 ) { + cerr << "MemoryScanner: ERROR " << errno << " " << strerror(errno) << "\n"; + exit( -1 ); + } + + + switch ( SCAN_FLAG ) { + case 0 : + // Process for scan_flag = 0 + cout <<"TOTAL FOUND for scan_number: " << scan_number << "\n"; + cout << maprange_counter << " MAP_RANGES scanned"<< "\n"; + cout << block_counter << " MARKED-Blocks" << "\n"; + cout << counter << " MARKED-pieces" << "\n"; + cout << maps_total_size << "(" << maps_total_size*1.0/(1048576.0) << " Mb)- TOTAL MAPS MEMORY SIZE \n"; + cout << mem_total_size << "(" << mem_total_size*1.0/(1048576.0) << " Mb)- TOTAL SCANNED MEMORY SIZE\n"; + cout <<4*block_total_size<< "(" << 4.0*block_total_size/(1048576.0) << " Mb)- MARKED blocks MEMORY SIZE\n"; + cout <<4*counter << "(" << 4.0*counter/(1048576.0) << " Mb)- MARKED pieces MEMORY SIZE\n"; + + break; + + case 1: case 2 : + // Process for scan_flag = 1 + cout <<"TOTAL FOUND for scan_number: " << scan_number << "\n"; + cout << maprange_counter << " MAP_RANGES scanned"<< "\n"; + cout << block_counter << " MARKED-Blocks" << "\n"; + cout << counter << " MARKED-pieces" << "\n"; + cout << maps_total_size << "(" << maps_total_size*1.0/(1048576.0) << " Mb)- TOTAL MAPS MEMORY SIZE \n"; + cout << mem_total_size << "(" << mem_total_size*1.0/(1048576.0) << " Mb)- TOTAL SCANNED MEMORY SIZE\n"; + cout <<4*block_total_size<< "(" << 4.0*block_total_size/(1048576.0) << " Mb)- MARKED blocks MEMORY SIZE\n"; + cout <<4*counter << "(" << 4.0*counter/(1048576.0) << " Mb)- MARKED pieces MEMORY SIZE\n"; + + memFile->cd(); + memTree->Write(); + mapsSize = maps_total_size/1024; + holesSize = 4*block_total_size/1024; + infoTree->Fill(); + infoTree->Write(); + memTree->Delete(); + infoTree->Delete(); + memFile->Close(); + break; + + default : + // Process for all other cases. + memTree->Delete(); + infoTree->Delete(); + memFile->Close(); + } +#endif + + return 0; +} + + diff --git a/Control/HeapMon/src/tcmalloc_dummy.c b/Control/HeapMon/src/tcmalloc_dummy.c new file mode 100644 index 0000000000000000000000000000000000000000..3122b45a8c3e70873602272f8616b13c37bc9cf0 --- /dev/null +++ b/Control/HeapMon/src/tcmalloc_dummy.c @@ -0,0 +1,26 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <gperftools/malloc_hook_c.h> + + +size_t MallocExtension_GetAllocatedSize(void* p){ + return 0; +} + +MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook) { + //printf("dummy"); + return 0; +} + +MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook) { + //printf("dummy"); + return 0; +} + +void MallocExtension_GetStats(char* buffer, int buffer_length){ + return ; +} + +