diff --git a/Trigger/TrigTools/TrigByteStreamTools/bin/trigbs_dumpHLTContentInBS_run3.py b/Trigger/TrigTools/TrigByteStreamTools/bin/trigbs_dumpHLTContentInBS_run3.py
index 4724118f9edec033134d296d17add40a92d349b8..aa6407d80f98849766e79c15c579515e70007728 100755
--- a/Trigger/TrigTools/TrigByteStreamTools/bin/trigbs_dumpHLTContentInBS_run3.py
+++ b/Trigger/TrigTools/TrigByteStreamTools/bin/trigbs_dumpHLTContentInBS_run3.py
@@ -9,6 +9,7 @@ Dump content of the HLT result and HLT related details from the event header
 
 import argparse
 import eformat
+from TrigByteStreamTools import hltResultMT
 
 from AthenaCommon.Logging import logging
 log = logging.getLogger('dumpHLTContentInBS')
@@ -100,21 +101,25 @@ def stream_tags(event):
 
 
 def hlt_result(event, print_sizes=False):
-    hlt_robs = [rob for rob in event.children()
-                if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_HLT]
-    info_str = 'Found {:d} HLT ROBs'.format(len(hlt_robs))
-    for rob in hlt_robs:
+    num_hlt_robs = 0
+    info_str = ""
+    for rob in event.children():
+        if rob.source_id().subdetector_id() != eformat.helper.SubDetector.TDAQ_HLT:
+            continue
+        num_hlt_robs += 1
         info_str += '\n-- {:s} SourceID: {:s}, Size: {:d} bytes'.format(
             rob.__class__.__name__,
             rob.source_id().human(),
             rob.fragment_size_word()*4
         )
         if print_sizes:
-            from TrigByteStreamTools import hltResultMT
-            collections = hltResultMT.get_collections(rob.rod_data())
+            raw_data = tuple(rob.rod_data())
+            collections = hltResultMT.get_collections(raw_data)
             for coll in collections:
                 indent = '----' if not coll.is_xAOD_decoration() else '------'
                 info_str += '\n{:s} {:s}'.format(indent, str(coll))
+
+    info_str = 'Found {:d} HLT ROBs'.format(num_hlt_robs) + info_str
     return info_str
 
 
@@ -131,17 +136,17 @@ def size_summary(events):
     #   }
     # }
     for event in events:
-        from TrigByteStreamTools import hltResultMT
-        hlt_robs = [rob for rob in event.children()
-                    if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_HLT]
-        for rob in hlt_robs:
+        for rob in event.children():
+            if rob.source_id().subdetector_id() != eformat.helper.SubDetector.TDAQ_HLT:
+                continue
             module = rob.source_id().module_id()
             if module not in data.keys():
                 data[module] = {'total': 0}
             data[module]['total'] += rob.fragment_size_word()*4
             if 'collections' not in data[module].keys():
                 data[module]['collections'] = {}
-            for coll in hltResultMT.get_collections(rob.rod_data()):
+            raw_data = tuple(rob.rod_data())
+            for coll in hltResultMT.get_collections(raw_data):
                 coll_name = coll.name()
                 if coll_name in data[module]['collections'].keys():
                     data[module]['collections'][coll_name] += coll.size_bytes
diff --git a/Trigger/TrigTools/TrigByteStreamTools/python/hltResultMT.py b/Trigger/TrigTools/TrigByteStreamTools/python/hltResultMT.py
index d201c423ed60e167623577e261b9bf8159a1be50..f7fa69341eaf79c684e3ed9e7dd628820ea11b14 100644
--- a/Trigger/TrigTools/TrigByteStreamTools/python/hltResultMT.py
+++ b/Trigger/TrigTools/TrigByteStreamTools/python/hltResultMT.py
@@ -8,6 +8,12 @@ Methods to deserialise HLTResultMT using Python bindings of C++ classes
 and reimplementing some logic from TriggerEDMDeserialiserAlg
 '''
 
+from ROOT import vector, StringSerializer
+from functools import lru_cache
+
+# Global StringSerialiser to avoid constructing per call
+_string_serialiser = StringSerializer()
+
 # Copy of variables defined in TrigOutputHandling/src/TriggerEDMDeserialiserAlg.h
 SizeWord = 0
 CLIDOffset = 1
@@ -49,22 +55,24 @@ class EDMCollection:
         return '_p' in self.name_persistent
 
 
+@lru_cache(maxsize=2048)
+def deserialise_name(name_words):
+    '''Use Python bindings of C++ StringSerialiser to deserialise collection type and name'''
+
+    name_raw_vec = vector['unsigned int'](name_words)
+    name_str_vec = vector['string']()
+    _string_serialiser.deserialize(name_raw_vec, name_str_vec)
+    return name_str_vec
+
+
+@lru_cache(maxsize=4096)
 def get_collection_name(raw_data_words):
-    '''Use Python bindings of C++ StringSerialiser to deserialise collection names'''
+    '''Extract type+name words from the full collection raw data and convert to string'''
 
-    from ROOT import string, vector, StringSerializer
     nw = raw_data_words[NameLengthOffset]
-    name_raw = raw_data_words[NameOffset:NameOffset+nw]
-    name_raw_vec = vector('unsigned int')()
-    for w in name_raw:
-        name_raw_vec.push_back(w)
-    name_str_vec = vector(string)()
-    ss = StringSerializer()
-    ss.deserialize(name_raw_vec, name_str_vec)
-    name_list = []
-    for s in name_str_vec:
-        name_list.append(str(s))
-    return name_list
+    name_words = raw_data_words[NameOffset:NameOffset+nw]
+    name_str_vec = deserialise_name(tuple(name_words))
+    return [str(s) for s in name_str_vec]
 
 
 def get_collections(raw_data_words):
@@ -78,8 +86,8 @@ def get_collections(raw_data_words):
     last_aux_cont = None
     while start < len(raw_data_words):
         size = raw_data_words[start+SizeWord]
-        coll_raw = raw_data_words[start:start+size]
-        coll = EDMCollection(get_collection_name(coll_raw), size)
+        coll_name = get_collection_name(tuple(raw_data_words[start:start+size]))
+        coll = EDMCollection(coll_name, size)
         if coll.is_xAOD_aux_container():
             last_aux_cont = coll
         if coll.is_xAOD_decoration():
diff --git a/Trigger/TrigValidation/TriggerTest/test/test_trig_data_v1Dev_writeBS_grid.py b/Trigger/TrigValidation/TriggerTest/test/test_trig_data_v1Dev_writeBS_grid.py
index f15f6f2a6d1ff16574a4f07b1fc8db6a9fe5016e..c0b76bd5ce62b70b224f753edbc6ef85688e54d9 100755
--- a/Trigger/TrigValidation/TriggerTest/test/test_trig_data_v1Dev_writeBS_grid.py
+++ b/Trigger/TrigValidation/TriggerTest/test/test_trig_data_v1Dev_writeBS_grid.py
@@ -33,6 +33,7 @@ checkBS = Step.Step("CheckBS")
 checkBS.executable = 'trigbs_dumpHLTContentInBS_run3.py'
 checkBS.args = ' --l1 --hlt --hltres --stag --sizeSummary'
 checkBS.args += ' ' + find_file('*unknown_SingleStream.daq.RAW.*Athena.*.data')
+checkBS.timeout = 600  # 10 minutes
 checkBS.required = True
 checkBS.auto_report_result = True
 
diff --git a/Trigger/TrigValidation/TriggerTest/test/test_trig_mc_v1Dev_writeBS_grid.py b/Trigger/TrigValidation/TriggerTest/test/test_trig_mc_v1Dev_writeBS_grid.py
index 6ca904ae31fc88c28b4cbea0a06252c25ba13741..dbea883df517d7009893fe7ae475cade00e7025d 100755
--- a/Trigger/TrigValidation/TriggerTest/test/test_trig_mc_v1Dev_writeBS_grid.py
+++ b/Trigger/TrigValidation/TriggerTest/test/test_trig_mc_v1Dev_writeBS_grid.py
@@ -33,6 +33,7 @@ checkBS = Step.Step("CheckBS")
 checkBS.executable = 'trigbs_dumpHLTContentInBS_run3.py'
 checkBS.args = ' --l1 --hlt --hltres --stag --sizeSummary'
 checkBS.args += ' ' + find_file('*unknown_SingleStream.daq.RAW.*Athena.*.data')
+checkBS.timeout = 600  # 10 minutes
 checkBS.required = True
 checkBS.auto_report_result = True