Files
2026-01-16 10:44:22 -08:00

182 lines
6.7 KiB
Diff

diff --git a/tensilelite/Tensile/Common/Utilities.py b/tensilelite/Tensile/Common/Utilities.py
index 0a9d9db5b3..cb9779eaac 100644
--- a/tensilelite/Tensile/Common/Utilities.py
+++ b/tensilelite/Tensile/Common/Utilities.py
@@ -24,6 +24,7 @@
import functools
import math
+import operator
import os
import sys
import time
@@ -269,8 +270,20 @@ def state(obj):
def state_key_ordering(cls):
- def tup(obj):
- return tuple([getattr(obj, k) for k in cls.StateKeys])
+ # Use operator.attrgetter for efficiency if __slots__ is defined
+ if hasattr(cls, '__slots__'):
+ # attrgetter is faster for slotted classes
+ getter = operator.attrgetter(*cls.StateKeys)
+ if len(cls.StateKeys) == 1:
+ # attrgetter returns scalar for single key, we need tuple
+ def tup(obj):
+ return (getter(obj),)
+ else:
+ tup = getter
+ else:
+ # Fallback for regular classes
+ def tup(obj):
+ return tuple([getattr(obj, k) for k in cls.StateKeys])
def lt(a, b):
return tup(a) < tup(b)
diff --git a/tensilelite/Tensile/Contractions.py b/tensilelite/Tensile/Contractions.py
index c0d4e851b1..3f2c2e98c6 100644
--- a/tensilelite/Tensile/Contractions.py
+++ b/tensilelite/Tensile/Contractions.py
@@ -37,9 +37,60 @@ from Tensile.Toolchain.Component import Assembler
from math import ceil
MIN_K_FOR_GSU = 32
+
+# Interning helpers to reduce memory usage by reusing identical objects
+_free_index_cache = {}
+def intern_free_index(isA, i=None, c=None, d=None, a=None, b=None):
+ key = (isA, i, c, d, a, b)
+ if key not in _free_index_cache:
+ obj = FreeIndex(isA, i, c, d)
+ obj.a = a
+ if b is not None:
+ obj.b = b
+ _free_index_cache[key] = obj
+ return _free_index_cache[key]
+
+_batch_index_cache = {}
+def intern_batch_index(a=None, b=None, c=None, d=None):
+ key = (a, b, c, d)
+ if key not in _batch_index_cache:
+ obj = BatchIndex(c=c, d=d)
+ obj.a = a
+ obj.b = b
+ _batch_index_cache[key] = obj
+ return _batch_index_cache[key]
+
+_bound_index_cache = {}
+def intern_bound_index(a=None, b=None, aMirror=False, bMirror=False):
+ key = (a, b, aMirror, bMirror)
+ if key not in _bound_index_cache:
+ obj = BoundIndex(aMirror=aMirror, bMirror=bMirror)
+ obj.a = a
+ obj.b = b
+ _bound_index_cache[key] = obj
+ return _bound_index_cache[key]
+
+_size_mapping_cache = {}
+def intern_size_mapping(size_mapping):
+ """Intern a SizeMapping instance to reduce redundancy."""
+ # Build hashable key from StateKeys, converting lists to tuples
+ key_parts = []
+ for attr in size_mapping.StateKeys:
+ val = getattr(size_mapping, attr)
+ # Convert lists to tuples for hashing
+ if isinstance(val, list):
+ val = tuple(val)
+ key_parts.append(val)
+ key = tuple(key_parts)
+
+ if key not in _size_mapping_cache:
+ _size_mapping_cache[key] = size_mapping
+ return _size_mapping_cache[key]
+
@state_key_ordering
class FreeIndex:
StateKeys = ['isA', 'i', 'c', 'd']
+ __slots__ = ['isA', 'i', 'c', 'd', 'a', 'b']
def __init__(self, isA, i=None, c=None, d=None):
self.isA = isA
@@ -50,6 +101,7 @@ class FreeIndex:
@state_key_ordering
class BatchIndex:
StateKeys = ['a', 'b', 'c', 'd']
+ __slots__ = ['a', 'b', 'c', 'd']
def __init__(self, a=None, b=None, c=None, d=None):
self.a = a
self.b = b
@@ -59,6 +111,7 @@ class BatchIndex:
@state_key_ordering
class BoundIndex:
StateKeys = ['a', 'b', 'aMirror', 'bMirror']
+ __slots__ = ['a', 'b', 'aMirror', 'bMirror']
def __init__(self, a=None, b=None, aMirror=False, bMirror=False):
self.a = a
self.b = b
@@ -107,6 +160,23 @@ class ProblemType:
for ib, ic in enumerate(d['IndexAssignmentsB']):
indices[ic].b = ib
+ # Now intern all indices with their final state (including .a and .b)
+ for i, idx in enumerate(indices):
+ if isinstance(idx, FreeIndex):
+ indices[i] = intern_free_index(idx.isA, idx.i, idx.c, idx.d,
+ getattr(idx, 'a', None), getattr(idx, 'b', None))
+ elif isinstance(idx, BatchIndex):
+ indices[i] = intern_batch_index(getattr(idx, 'a', None), getattr(idx, 'b', None),
+ idx.c, idx.d)
+ elif isinstance(idx, BoundIndex):
+ indices[i] = intern_bound_index(getattr(idx, 'a', None), getattr(idx, 'b', None),
+ idx.aMirror, idx.bMirror)
+
+ # Update the lists with interned versions
+ freeIndices = [idx for idx in indices if isinstance(idx, FreeIndex)]
+ batchIndices = [idx for idx in indices if isinstance(idx, BatchIndex)]
+ boundIndices = [idx for idx in indices if isinstance(idx, BoundIndex)]
+
for idx in indices:
assert idx is not None
idxState = state(idx)
@@ -596,6 +666,7 @@ class SizeMapping:
'nonTemporalA',
'nonTemporalB',
]
+ __slots__ = StateKeys
@classmethod
def FromOriginalState(cls, d):
@@ -751,7 +822,7 @@ class Solution:
info = cls.ReadOriginalInfo(d)
rv.libraryLogicIndex = int(info.get("SolutionIndex", -1))
- rv.sizeMapping = SizeMapping.FromOriginalState(d)
+ rv.sizeMapping = intern_size_mapping(SizeMapping.FromOriginalState(d))
rv.internalArgsSupport = InternalArgsSupport.FromOriginalState(d)
diff --git a/tensilelite/Tensile/TensileCreateLibrary/Run.py b/tensilelite/Tensile/TensileCreateLibrary/Run.py
index 730b6b1fff..b0068563a0 100644
--- a/tensilelite/Tensile/TensileCreateLibrary/Run.py
+++ b/tensilelite/Tensile/TensileCreateLibrary/Run.py
@@ -104,7 +104,6 @@ class KernelCodeGenResult(NamedTuple):
src: str
header: Optional[str]
name: str
- targetObjFilename: str
isa: IsaVersion
wavefrontSize: int
cuoccupancy: int
@@ -127,10 +126,9 @@ def processKernelSource(kernelWriterAssembly, data, splitGSU, kernel) -> KernelC
asmFilename = getKernelFileBase(splitGSU, kernel)
err, src = kernelWriter.getSourceFileString(kernel)
header = kernelWriter.getHeaderFileString(kernel)
- objFilename = kernel._state.get("codeObjectFile", None)
pgr = int(kernel["PrefetchGlobalRead"])
return KernelCodeGenResult(
- err, src, header, asmFilename, objFilename, tuple(kernel["ISA"]), \
+ err, src, header, asmFilename, tuple(kernel["ISA"]), \
kernel["WavefrontSize"], kernel["CUOccupancy"], \
pgr, kernel["MathClocksUnrolledLoop"]
)