diff --git a/Trigger/TrigDataAccess/TrigSerializeResult/CMakeLists.txt b/Trigger/TrigDataAccess/TrigSerializeResult/CMakeLists.txt index b184ca91016534ceabc75c95f1157d7f6c85a095..ef0560b21342a56acf36a02dee923697b6dc825c 100644 --- a/Trigger/TrigDataAccess/TrigSerializeResult/CMakeLists.txt +++ b/Trigger/TrigDataAccess/TrigSerializeResult/CMakeLists.txt @@ -15,6 +15,8 @@ atlas_add_library( TrigSerializeResultLib LINK_LIBRARIES AthenaBaseComps AthenaKernel GaudiKernel PRIVATE_LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} CxxUtils DataModelRoot PathResolver ) +atlas_install_python_modules( python/*.py ) + atlas_add_component( TrigSerializeResult src/components/*.cxx LINK_LIBRARIES TrigSerializeResultLib ) diff --git a/Trigger/TrigDataAccess/TrigSerializeResult/python/StreamerInfoGenerator.py b/Trigger/TrigDataAccess/TrigSerializeResult/python/StreamerInfoGenerator.py index f9094a2a94566c9a65a88bba8b2c1403250ffc92..1b1ebd2ecc3b9278c828b7da61b7ca5c21cbf30b 100755 --- a/Trigger/TrigDataAccess/TrigSerializeResult/python/StreamerInfoGenerator.py +++ b/Trigger/TrigDataAccess/TrigSerializeResult/python/StreamerInfoGenerator.py @@ -2,6 +2,7 @@ # Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration import cppyy +import ROOT class StreamerInfoGenerator: def __init__(self): @@ -13,7 +14,7 @@ class StreamerInfoGenerator: self.blacklist = ['std::', 'vector<', 'map<', 'queue<', 'list<'] self.type = cppyy.gbl.RootType self.type.EnableCintex() - cppyy.loadDict('libAtlasSTLAddReflexDict') + cppyy.load_library('libAtlasSTLAddReflexDict') #MN: switch off auto dict generation - god knows what that can mess up cppyy.gbl.gROOT.ProcessLine(".autodict") @@ -45,8 +46,24 @@ class StreamerInfoGenerator: pass try: - cl = cppyy.makeClass(typename) - if not dontAdd: self.classlist.append(typename) + # This doesn't work in ROOT 6.22 anymore + # cl = cppyy.makeClass(typename) + # + bind_name = typename + # If it's a type with template argument, replace outermost <...> with ['...'] + bind_name = bind_name.replace("<", "['", 1)[::-1].replace(">", "]'", 1)[::-1] + # Replace "::" with "." to set namespace, for the base type + base_and_arg = bind_name.split("[") + base_and_arg[0] = base_and_arg[0].replace("::", ".") + bind_name = "[".join(base_and_arg) + bind_name = "ROOT." + bind_name + print("Making class {} -> {}".format(typename, bind_name)) + print("cl = " + bind_name) + exec("cl = " + bind_name, globals()) + print(cl) + if not dontAdd: + self.classlist.append(typename) + print("appended type to the classlist") except: print('Cannot create class of ', typename) diff --git a/Trigger/TrigDataAccess/TrigSerializeResult/python/dictwrite.py b/Trigger/TrigDataAccess/TrigSerializeResult/python/dictwrite.py index 6a170cc87a0dc12df529ed34f0d40a57a894ae16..a3e8619d6cc1be136a278b7dc89b0ed7b0c7b329 100755 --- a/Trigger/TrigDataAccess/TrigSerializeResult/python/dictwrite.py +++ b/Trigger/TrigDataAccess/TrigSerializeResult/python/dictwrite.py @@ -13,17 +13,6 @@ import sys -doEDM=False -#doEDM=True -doxAODonly=False -bs_filename = 'bs-streamerinfos.root' - -import ROOT -from ROOT import TFile - -import StreamerInfoGenerator -SIG = StreamerInfoGenerator.StreamerInfoGenerator() - """ MN: NOTE about xAOD containers in ROOT5 For an xAOD container like xAOD::HIEventShapeContainer_v1 @@ -33,183 +22,195 @@ b) have a real class in the 'objects' list BEFORE the typedef (so the dict library gets loaded and the typedefs resolved) """ - -objects = [ -'xAOD::TrigEMCluster_v1', -'xAOD::TrigEMClusterContainer_v1', -'xAOD::TrigEMClusterAuxContainer_v1', -'xAOD::TrigRingerRings_v1', -'xAOD::TrigRingerRingsContainer_v1', -'xAOD::TrigRingerRingsAuxContainer_v1', -'xAOD::TrigRNNOutput_v1', -'xAOD::TrigRNNOutputContainer_v1', -'xAOD::TrigRNNOutputAuxContainer_v1', -'xAOD::CaloClusterContainer_v1', -'xAOD::CaloClusterAuxContainer_v2', -'xAOD::L2StandAloneMuonContainer_v1', -'xAOD::L2StandAloneMuonAuxContainer_v1', -'xAOD::L2StandAloneMuonAuxContainer_v2', -'xAOD::L2CombinedMuonContainer_v1', -'xAOD::L2CombinedMuonAuxContainer_v1', -'xAOD::L2IsoMuonContainer_v1', -'xAOD::L2IsoMuonAuxContainer_v1', -'xAOD::MuonContainer_v1', -'xAOD::MuonAuxContainer_v1', -'xAOD::MuonAuxContainer_v2', -'xAOD::MuonAuxContainer_v3', -'xAOD::MuonAuxContainer_v4', -'xAOD::TrackParticleContainer_v1', -'xAOD::TrackParticleAuxContainer_v1', -'xAOD::TrackParticleAuxContainer_v2', -'xAOD::TrackParticleAuxContainer_v3', -'xAOD::TauJetContainer_v2', -'xAOD::TauJetAuxContainer_v2', -'xAOD::TauJetAuxContainer_v3', -'xAOD::VertexContainer_v1', -'xAOD::VertexAuxContainer_v1', -'xAOD::TrigCompositeContainer_v1', -'xAOD::TrigCompositeAuxContainer_v1', -'xAOD::TrigCompositeAuxContainer_v2', -'xAOD::MuonRoIContainer_v1', -'xAOD::MuonRoIAuxContainer_v1', -'xAOD::EmTauRoIContainer_v2', -'xAOD::EmTauRoIAuxContainer_v2', -'xAOD::JetRoIContainer_v2', -'xAOD::JetRoIAuxContainer_v2', -'xAOD::JetEtRoI_v1', -'xAOD::JetEtRoIAuxInfo_v1', -'xAOD::EnergySumRoI_v1', -'xAOD::EnergySumRoIAuxInfo_v1', -'xAOD::TriggerTowerContainer_v2', -'xAOD::TriggerTowerAuxContainer_v2', -'xAOD::ElectronContainer_v1', -'xAOD::ElectronAuxContainer_v1', -'xAOD::PhotonContainer_v1', -'xAOD::PhotonAuxContainer_v1', -'xAOD::TrigBphysContainer_v1', -'xAOD::TrigBphysAuxContainer_v1', -'xAOD::TrigT2MbtsBitsAuxContainer_v1', -'xAOD::TrigT2MbtsBitsContainer_v1', -'xAOD::TrigSpacePointCountsContainer_v1', -'xAOD::TrigSpacePointCountsAuxContainer_v1', -'xAOD::TrigVertexCountsContainer_v1', -'xAOD::TrigVertexCountsAuxContainer_v1', -'xAOD::TrigTrackCounts_v1', -'xAOD::TrigTrackCountsAuxContainer_v1', -'xAOD::TrigMissingETContainer_v1', -'xAOD::TrigMissingETAuxContainer_v1', -'xAOD::TrigPhotonContainer_v1', -'xAOD::TrigPhotonAuxContainer_v1', -'xAOD::TrigElectronContainer_v1', -'xAOD::TrigElectronAuxContainer_v1', -'xAOD::JetContainer_v1', -'xAOD::JetTrigAuxContainer_v1', -'xAOD::JetTrigAuxContainer_v2', -'xAOD::TrigDecision_v1', -'xAOD::TrigDecisionAuxInfo_v1', -'xAOD::TrigConfKeys_v1', -'xAOD::TrigNavigation_v1', -'xAOD::TrigNavigationAuxInfo_v1', -'xAOD::BTaggingContainer_v1', -'xAOD::BTaggingAuxContainer_v1', -'xAOD::BTaggingTrigAuxContainer_v1', -'xAOD::BTagVertexContainer_v1', -'xAOD::BTagVertexAuxContainer_v1', -'xAOD::HIEventShapeAuxContainer_v2', -'xAOD::HIEventShapeContainer_v2', -'xAOD::TrigT2ZdcSignalsAuxContainer_v1', -'xAOD::TrigT2ZdcSignalsContainer_v1', -'xAOD::TrigPassBitsContainer_v1', -'xAOD::TrigPassBitsAuxContainer_v1', -'xAOD::CaloClusterTrigAuxContainer_v1', -'xAOD::ElectronTrigAuxContainer_v1', -'xAOD::PhotonTrigAuxContainer_v1', -'xAOD::TrigEMClusterAuxContainer_v2', -'xAOD::TrigRingerRingsAuxContainer_v2', -'xAOD::TrigRNNOutputAuxContainer_v2', -'xAOD::TauTrack_v1', -'xAOD::TauTrackContainer_v1', -'xAOD::TauTrackAuxContainer_v1', -#'TrigMuonEFIsolation_p2', -] - -from collections import defaultdict -streamerChecksums = defaultdict(set) -print("Reading streamerinfos from", bs_filename) -file = TFile(bs_filename, 'UPDATE') -streamer_n = 0 -if file.GetStreamerInfoList(): - for i in file.GetStreamerInfoList(): - if i.GetName() != 'listOfRules': - # print i.GetName(), "%x" % i.GetCheckSum() +def update_streamerinfos(objects, updated_objects): + doEDM=False + #doEDM=True + doxAODonly=False + bs_filename = 'bs-streamerinfos.root' + import ROOT + from ROOT import TFile + from TrigSerializeResult import StreamerInfoGenerator + SIG = StreamerInfoGenerator.StreamerInfoGenerator() + from collections import defaultdict + streamerChecksums = defaultdict(set) + print("Reading streamerinfos from", bs_filename) + file = TFile(bs_filename, 'UPDATE') + streamer_n = 0 + if file.GetStreamerInfoList(): + for i in file.GetStreamerInfoList(): + if i.GetName() != 'listOfRules': streamerChecksums[i.GetName()].add( i.GetCheckSum() ) streamer_n += 1 -print("Read", streamer_n, 'streamers for', len(streamerChecksums), 'types') -print("") + print("Read", streamer_n, 'streamers for', len(streamerChecksums), 'types') + print("") -if doEDM: - from TrigEDMConfig.TriggerEDM import EDMDetails - for item in EDMDetails.keys(): - pers = EDMDetails[item]['persistent'] - objects.append(pers) + if doEDM: + from TrigEDMConfig.TriggerEDM import EDMDetails + for item in EDMDetails.keys(): + pers = EDMDetails[item]['persistent'] + objects.append(pers) -for pers in objects: + for pers in objects: SIG.inspect(pers) print("") -fulllist = SIG.classlist -print(fulllist) -print('*******************************') - - -from CLIDComps.clidGenerator import clidGenerator -cgen = clidGenerator("") - -types_new = 0 -types_exist = 0 -types_bad = 0 -fulllist = list(set(fulllist)) -for item in fulllist: - if doxAODonly and not 'xAOD' in item: continue # current issues seen because of missing xAOD libs not being loaded - print("Trying to fill item", item, "to root file") - c_clid = cgen.genClidFromName(item) - c_typeinfo = cgen.getTidFromClid(c_clid) - print("CLID", c_clid) - print("TypeInfo", c_typeinfo) - try: - cls = ROOT.gROOT.GetClass(item) - except: - cls = ROOT.gROOT.GetClass(c_typeinfo) - print(cls) - - if cls!=None: - streamerinfo = cls.GetStreamerInfo() - if streamerinfo.GetCheckSum() == 0: - # try to patch missing checksum in DataVectors - print('Warning: no checksum in streamerinfo for type: ', cls.GetName()) - print('Attempting to fix with 0x%x' % cls.GetCheckSum()) - streamerinfo.SetCheckSum( cls.GetCheckSum() ) - - chksum = streamerinfo.GetCheckSum() - if chksum not in streamerChecksums[cls.GetName()]: - print('Writing: %s streamer size=%d, checksum=0x%x' %(cls.GetName(), streamerinfo.Sizeof(), chksum)) - obj = cls.New() - file.WriteObjectAny(obj, cls, cls.GetName()) - types_new += 1 - else: - print('Skipping', cls.GetName(), 'streamer checksum', chksum, ' - already in the file') - types_exist += 1 - - else: - print('skipping ', item) - types_bad += 1 - #sys.exit() - print('----') - -print('Wrote', types_new, 'types') -print('Skipped', types_exist, ' existing types') -print('Problems with', types_bad + len(SIG.problemclasses), ' types') -for t in SIG.problemclasses: - print(' ', t) - - + fulllist = SIG.classlist + print(fulllist) + print('*******************************') + + from CLIDComps.clidGenerator import clidGenerator + cgen = clidGenerator("") + + types_new = 0 + types_exist = 0 + types_bad = 0 + fulllist = list(set(fulllist)) + for item in fulllist: + if doxAODonly and not 'xAOD' in item: continue # current issues seen because of missing xAOD libs not being loaded + print("Trying to fill item", item, "to root file") + c_clid = cgen.genClidFromName(item) + c_typeinfo = cgen.getTidFromClid(c_clid) + print("CLID", c_clid) + print("TypeInfo", c_typeinfo) + try: + cls = ROOT.gROOT.GetClass(item) + except: + cls = ROOT.gROOT.GetClass(c_typeinfo) + print(cls) + + if cls!=None: + streamerinfo = cls.GetStreamerInfo() + if streamerinfo.GetCheckSum() == 0: + # try to patch missing checksum in DataVectors + print('Warning: no checksum in streamerinfo for type: ', cls.GetName()) + print('Attempting to fix with 0x%x' % cls.GetCheckSum()) + streamerinfo.SetCheckSum( cls.GetCheckSum() ) + + chksum = streamerinfo.GetCheckSum() + if chksum not in streamerChecksums[cls.GetName()]: + print('Writing: %s streamer size=%d, checksum=0x%x' %(cls.GetName(), streamerinfo.Sizeof(), chksum)) + obj = cls.New() + file.WriteObjectAny(obj, cls, cls.GetName()) + types_new += 1 + updated_objects.append( (cls.GetName(), chksum) ) + else: + print('Skipping {} streamer checksum 0x{:x} - already in the file'.format(cls.GetName(), chksum)) + types_exist += 1 + else: + print('skipping ', item) + types_bad += 1 + #sys.exit() + print('----') + + print('Wrote', types_new, 'types') + print('Skipped', types_exist, ' existing types') + print('Problems with', types_bad + len(SIG.problemclasses), ' types') + for t in SIG.problemclasses: + print(' ', t) + + return 0 + +def main(): + objects = [ + 'xAOD::TrigEMCluster_v1', + 'xAOD::TrigEMClusterContainer_v1', + 'xAOD::TrigEMClusterAuxContainer_v1', + 'xAOD::TrigRingerRings_v1', + 'xAOD::TrigRingerRingsContainer_v1', + 'xAOD::TrigRingerRingsAuxContainer_v1', + 'xAOD::TrigRNNOutput_v1', + 'xAOD::TrigRNNOutputContainer_v1', + 'xAOD::TrigRNNOutputAuxContainer_v1', + 'xAOD::CaloClusterContainer_v1', + 'xAOD::CaloClusterAuxContainer_v2', + 'xAOD::L2StandAloneMuonContainer_v1', + 'xAOD::L2StandAloneMuonAuxContainer_v1', + 'xAOD::L2StandAloneMuonAuxContainer_v2', + 'xAOD::L2CombinedMuonContainer_v1', + 'xAOD::L2CombinedMuonAuxContainer_v1', + 'xAOD::L2IsoMuonContainer_v1', + 'xAOD::L2IsoMuonAuxContainer_v1', + 'xAOD::MuonContainer_v1', + 'xAOD::MuonAuxContainer_v1', + 'xAOD::MuonAuxContainer_v2', + 'xAOD::MuonAuxContainer_v3', + 'xAOD::MuonAuxContainer_v4', + 'xAOD::TrackParticleContainer_v1', + 'xAOD::TrackParticleAuxContainer_v1', + 'xAOD::TrackParticleAuxContainer_v2', + 'xAOD::TrackParticleAuxContainer_v3', + 'xAOD::TauJetContainer_v2', + 'xAOD::TauJetAuxContainer_v2', + 'xAOD::TauJetAuxContainer_v3', + 'xAOD::VertexContainer_v1', + 'xAOD::VertexAuxContainer_v1', + 'xAOD::TrigCompositeContainer_v1', + 'xAOD::TrigCompositeAuxContainer_v1', + 'xAOD::TrigCompositeAuxContainer_v2', + 'xAOD::MuonRoIContainer_v1', + 'xAOD::MuonRoIAuxContainer_v1', + 'xAOD::EmTauRoIContainer_v2', + 'xAOD::EmTauRoIAuxContainer_v2', + 'xAOD::JetRoIContainer_v2', + 'xAOD::JetRoIAuxContainer_v2', + 'xAOD::JetEtRoI_v1', + 'xAOD::JetEtRoIAuxInfo_v1', + 'xAOD::EnergySumRoI_v1', + 'xAOD::EnergySumRoIAuxInfo_v1', + 'xAOD::TriggerTowerContainer_v2', + 'xAOD::TriggerTowerAuxContainer_v2', + 'xAOD::ElectronContainer_v1', + 'xAOD::ElectronAuxContainer_v1', + 'xAOD::PhotonContainer_v1', + 'xAOD::PhotonAuxContainer_v1', + 'xAOD::TrigBphysContainer_v1', + 'xAOD::TrigBphysAuxContainer_v1', + 'xAOD::TrigT2MbtsBitsAuxContainer_v1', + 'xAOD::TrigT2MbtsBitsContainer_v1', + 'xAOD::TrigSpacePointCountsContainer_v1', + 'xAOD::TrigSpacePointCountsAuxContainer_v1', + 'xAOD::TrigVertexCountsContainer_v1', + 'xAOD::TrigVertexCountsAuxContainer_v1', + 'xAOD::TrigTrackCounts_v1', + 'xAOD::TrigTrackCountsAuxContainer_v1', + 'xAOD::TrigMissingETContainer_v1', + 'xAOD::TrigMissingETAuxContainer_v1', + 'xAOD::TrigPhotonContainer_v1', + 'xAOD::TrigPhotonAuxContainer_v1', + 'xAOD::TrigElectronContainer_v1', + 'xAOD::TrigElectronAuxContainer_v1', + 'xAOD::JetContainer_v1', + 'xAOD::JetTrigAuxContainer_v1', + 'xAOD::JetTrigAuxContainer_v2', + 'xAOD::TrigDecision_v1', + 'xAOD::TrigDecisionAuxInfo_v1', + 'xAOD::TrigConfKeys_v1', + 'xAOD::TrigNavigation_v1', + 'xAOD::TrigNavigationAuxInfo_v1', + 'xAOD::BTaggingContainer_v1', + 'xAOD::BTaggingAuxContainer_v1', + 'xAOD::BTaggingTrigAuxContainer_v1', + 'xAOD::BTagVertexContainer_v1', + 'xAOD::BTagVertexAuxContainer_v1', + 'xAOD::HIEventShapeAuxContainer_v2', + 'xAOD::HIEventShapeContainer_v2', + 'xAOD::TrigT2ZdcSignalsAuxContainer_v1', + 'xAOD::TrigT2ZdcSignalsContainer_v1', + 'xAOD::TrigPassBitsContainer_v1', + 'xAOD::TrigPassBitsAuxContainer_v1', + 'xAOD::CaloClusterTrigAuxContainer_v1', + 'xAOD::ElectronTrigAuxContainer_v1', + 'xAOD::PhotonTrigAuxContainer_v1', + 'xAOD::TrigEMClusterAuxContainer_v2', + 'xAOD::TrigRingerRingsAuxContainer_v2', + 'xAOD::TrigRNNOutputAuxContainer_v2', + 'xAOD::TauTrack_v1', + 'xAOD::TauTrackContainer_v1', + 'xAOD::TauTrackAuxContainer_v1', + #'TrigMuonEFIsolation_p2', + ] + updated_objects = [] + return update_streamerinfos(objects, updated_objects) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Trigger/TrigValidation/TrigP1Test/python/DetectStreamerInfoChanges.py b/Trigger/TrigValidation/TrigP1Test/python/DetectStreamerInfoChanges.py new file mode 100755 index 0000000000000000000000000000000000000000..503ad4fc688223788076db47ff8e3379ab689e62 --- /dev/null +++ b/Trigger/TrigValidation/TrigP1Test/python/DetectStreamerInfoChanges.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +import os +import sys +import logging +import re +from shutil import copyfile +import ROOT + + +log = logging.getLogger(__name__) + +# Needed for generating TStreamerInfo of xAOD::TrigConfKeys +ROOT.gInterpreter.ProcessLine('#include "xAODTrigger/TrigConfKeys.h"') + +doTrigEDMOnly = True +bs_filename = 'bs-streamerinfos.root' + +from TrigSerializeResult.dictwrite import update_streamerinfos + + +def append_versions(objects, cname): + if "CPMTowerAuxContainer" in cname or "CMMEtSumsAuxContainer" in cname or "JEMHitsAuxContainer" in cname or "JEMEtSumsAuxContainer" in cname or "JetElementAuxContainer" in cname or "AFPDataAuxContainer" in cname or "_Alloc_hide" in cname or cname == "string" or "CMXJetTobAuxContainer" in cname or "RODHeaderAuxContainer" in cname or "CMMCPHitsAuxContainer" in cname or "CMXCPHitsAuxContainer" in cname or "TruthVertexAuxContainer" in cname or "CMXEtSumsAuxContainer" in cname or "CMXJetHitsAuxContainer" in cname or "CMMJetHitsAuxContainer" in cname or "CPMHitsAuxContain" in cname: + return + isxAOD = re.search('_v[0-9]$', class_name) + isxAODDV = re.search('_v[0-9]>$', class_name) + version = "1" + if isxAOD is not None: + version = [int(s) for s in cname.split("_v") if s.isdigit()][-1] + for i in range (1, version+1): + objects.append(cname.replace("_v"+str(version), "_v"+str(i))) + elif isxAODDV is not None: + version = [int(s) for s in re.split('_v|>',cname) if s.isdigit()][-1] + for i in range (1, version+1): + objects.append(cname.replace("_v"+str(version)+">", "_v"+str(i)+">")) + else: + pass + #objects.append(cname) + +if __name__ == '__main__': + objects = [] + if doTrigEDMOnly: + from TrigEDMConfig.TriggerEDMRun3 import TriggerHLTListRun3 + from TrigEDMConfig.DataScoutingInfo import DataScoutingIdentifiers + BS_destinations = ["BS"] + list(DataScoutingIdentifiers.keys()) + log.warning("BS_destinations = {}".format(BS_destinations)) + for item in TriggerHLTListRun3: + if any(bs in item[1].split() for bs in BS_destinations): + objects.append(item[0].split("#")[0]) + else: + # try to process all classes from the build + os.system("get_files -data clid.db") + classid = open("clid.db", "r") + for cl in classid: + items = cl.split("; ") + class_name = items[3].rstrip() + isxAOD = re.search('_v[0-9].*$', class_name) + if isxAOD is not None: + log.info (class_name + " is versioned xAOD class") + append_versions(objects, class_name) + else: + log.info (class_name + " is not an xAOD class") + + objects = list(set(objects)) + + log.warning("Will extract TStreamerInfo for the following types:") + log.warning(objects) + + copyfile(bs_filename, "original_" + bs_filename) + + updated_objects = [] + update_streamerinfos(objects, updated_objects) + + # ignore messages about these types - apparently they will always be displayed + black_list = ["string::_Alloc_hider", "string"] + new_objects = [item for item in updated_objects if item[0] not in black_list] + + if len(new_objects) > 0: + log.warning("The following {} new objects were detected:".format(len(new_objects))) + for item in new_objects: + log.warning("{}: 0x{:x}".format(item[0], item[1])) + log.warning("Please ask the Trigger EDM coordinator to add them to bs-streamerinfos.root") + else: + log.warning("No new objects detected") + + exit_code_err = len(new_objects) + if exit_code_err: + log.error("New TStreamerInfos detected") + else: + log.info("No new TStreamerInfos detected") + + log.info("DONE") + + sys.exit(exit_code_err) diff --git a/Trigger/TrigValidation/TrigP1Test/test/test_trigP1_detectStreamerInfoChanges_build.py b/Trigger/TrigValidation/TrigP1Test/test/test_trigP1_detectStreamerInfoChanges_build.py new file mode 100755 index 0000000000000000000000000000000000000000..3659ce512bd8c7eece2a05760317b64ac3cf97e7 --- /dev/null +++ b/Trigger/TrigValidation/TrigP1Test/test/test_trigP1_detectStreamerInfoChanges_build.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + +# art-description: Detect TStreamerInfo changes of classes in the given build +# art-type: build +# art-include: master/Athena +# Skipping art-output which has no effect for build tests. +# +# The test performs the following: +# 1) get the bs-streamerinfos.root from the nightly and check it +# 2) detect whether there are TStreamerInfo changes for classes that are packed to bytestream (Run 3 EDM targets BS, *DS) +# 3) if there are class changes, the test is failed, asking to update bs-streamerinfos.root +# 4) it generates a new test bs-streamerinfos.root and checks is + +from TrigValTools.TrigValSteering import Test, ExecStep, CheckSteps + +ex_get_BS_file = ExecStep.ExecStep('GetBSFile') +ex_get_BS_file.type = 'other' +ex_get_BS_file.input = '' +ex_get_BS_file.executable = 'get_files' +ex_get_BS_file.args = '-data bs-streamerinfos.root' + +ex_check_file_pre = ExecStep.ExecStep('CheckBSFilePre') +ex_check_file_pre.type = 'other' +ex_check_file_pre.input = '' +ex_check_file_pre.executable = 'python' +ex_check_file_pre.args = '-c "import sys; from TrigValTools.TrigRootUtils import check_file_subproc; sys.exit(check_file_subproc(\'bs-streamerinfos.root\'))"' + +ex_detect_new_sinfo = ExecStep.ExecStep('NewStreamerInfo') +ex_detect_new_sinfo.type = 'other' +ex_detect_new_sinfo.input = '' +ex_detect_new_sinfo.executable = 'python' +ex_detect_new_sinfo.args = '-m TrigP1Test.DetectStreamerInfoChanges' + +ex_check_file_post = ExecStep.ExecStep('CheckBSFilePost') +ex_check_file_post.type = 'other' +ex_check_file_post.input = '' +ex_check_file_post.depends_on_previous = False +ex_check_file_post.executable = 'python' +ex_check_file_post.args = '-c "import sys; from TrigValTools.TrigRootUtils import check_file_subproc; sys.exit(check_file_subproc(\'bs-streamerinfos.root\'))"' + +ex_diff_root_msg = ExecStep.ExecStep('CompRootMsg') +ex_diff_root_msg.type = 'other' +ex_diff_root_msg.input = '' +ex_diff_root_msg.depends_on_previous = False +ex_diff_root_msg.executable = 'diff' +ex_diff_root_msg.args = 'CheckBSFilePre.log CheckBSFilePost.log' + + +test = Test.Test() +test.art_type = 'build' +test.exec_steps = [ex_get_BS_file, ex_check_file_pre, ex_detect_new_sinfo, ex_check_file_post, ex_diff_root_msg] +test.check_steps = [chk for chk in CheckSteps.default_check_steps(test) + if type(chk) in (CheckSteps.LogMergeStep, CheckSteps.CheckLogStep)] + +import sys +sys.exit(test.run()) diff --git a/Trigger/TrigValidation/TrigValTools/python/TrigRootUtils.py b/Trigger/TrigValidation/TrigValTools/python/TrigRootUtils.py index 13781f4f31d66264fb9e065266529bf67ea6e1e3..4c13154cf4dc873baa1b5a6ca3faeb663e2aece5 100644 --- a/Trigger/TrigValidation/TrigValTools/python/TrigRootUtils.py +++ b/Trigger/TrigValidation/TrigValTools/python/TrigRootUtils.py @@ -1,5 +1,8 @@ # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +import logging +log = logging.getLogger(__name__) + def lsroot(dir): """Return list of all keys in 'dir' (recursively)""" @@ -26,3 +29,39 @@ def lsroot(dir): # Return sorted list with base directory removed return sorted([k.replace(basedir,"") for k in keys]) + +def check_file(path): + import ROOT + log.info('Checking file {}'.format(path)) + rfile = ROOT.TFile.Open(path, "READ") + if not rfile: + log.error('ERROR: {}: Failed to open file'.format(path)) + return 1 + if rfile.IsZombie(): + log.error('ERROR: {}: Zombie'.format(path)) + return 1 + if rfile.TestBit(ROOT.TFile.kRecovered): + log.error('ERROR: {}: Recovered'.format(path)) + return 1 + rfile.Close() + return 0 + +def check_file_subproc(path): + # Open Root file in a clean subprocess and parse error messages + from subprocess import Popen, PIPE + import time + time.sleep(5) + # Need to check the file in a clean environment, such that the classes in memory don't hide problems with classes in the file + p = Popen(['python', "-c", "from TrigValTools.TrigRootUtils import check_file; check_file('{}')".format(path)], stdout=PIPE, stderr=PIPE) + # Wait till finished + stdout, stderr = p.communicate() + rc = p.returncode + time.sleep(5) + # Detect error messages printed by ROOT when the file is opened + if "error" in stdout.decode('utf-8').lower() or "error" in stderr.decode('utf-8').lower(): + rc = 1 + log.error('ERROR: Detected errors when opening root file') + + log.error(stdout.decode('utf-8')) + log.error(stderr.decode('utf-8')) + return rc