Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions projects/hipblaslt/tensilelite/Tensile/KernelWriterAssembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -2485,9 +2485,13 @@ def calculateWG():
moduleExternalArgs.addModuleAsFlatItems(self.externalArgLoader.loadAllKernArg(sgprStart, "KernArgAddress", load, 4))
offset = self.externalArgLoader.getOffset() + self.states.bpr * (self.states.userArgsInfo.alphaMaxRegisterSize - self.states.numSgprAlpha)
self.externalArgLoader.setOffset(offset)
moduleExternalArgs.addComment("Read Beta")
moduleExternalArgs.addModuleAsFlatItems(self.externalArgLoader.loadAllKernArg(self.sgprs["Beta"], "KernArgAddress", self.states.numSgprBeta))
offset = self.externalArgLoader.getOffset() + self.states.bpr * (self.states.userArgsInfo.betaMaxRegisterSize - self.states.numSgprBeta)
if kernel["ProblemType"]["UseBeta"]:
moduleExternalArgs.addComment("Read Beta")
moduleExternalArgs.addModuleAsFlatItems(self.externalArgLoader.loadAllKernArg(self.sgprs["Beta"], "KernArgAddress", self.states.numSgprBeta))
offset = self.externalArgLoader.getOffset() + self.states.bpr * (self.states.userArgsInfo.betaMaxRegisterSize - self.states.numSgprBeta)
else:
# Even when not using Beta, we need to skip over the Beta argument space
offset = self.externalArgLoader.getOffset() + self.states.bpr * self.states.userArgsInfo.betaMaxRegisterSize
if kernel["ProblemType"]["UseScaleAB"] == "Scalar":
sgprOffset = self.externalArgLoader.getOffset()
for preloadScale, name in zip([self.states.preloadScaleA, self.states.preloadScaleB], ['A','B']):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Test for UseBeta=False functionality
# Verifies that kernels correctly handle the case where beta=0 and tensor C is not used

GlobalParameters:
MinimumRequiredVersion: 5.0.0
PrintLevel: 1
ForceRedoBenchmarkProblems: True
ForceRedoLibraryLogic: True
ForceRedoLibraryClient: True
CMakeBuildType: Release
EnqueuesPerSync: 1
SyncsPerBenchmark: 1
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated
NumElementsToValidate: 128
Platform: 0
Device: 0
KernelTime: True
SleepPercent: 0
NumBenchmarks: 1
PrintSolutionRejectionReason: True
LibraryFormat: yaml
BoundsCheck: True

BenchmarkProblems:
########################################
# UseBeta=False with batched GEMM
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
########################################
-
- # ProblemType
OperationType: GEMM
DataType: h
DestDataType: h
ComputeDataType: s
HighPrecisionAccumulate: True
TransposeA: False
TransposeB: True
UseBeta: False
Batched: True

- # Configuration
InitialSolutionParameters:
BenchmarkCommonParameters:
- KernelLanguage: ["Assembly"]
ForkParameters:
- MatrixInstruction:
- [16, 16, 16, 1, 1, 2, 2, 2, 2]
- DepthU: [16]
- VectorWidthA: [2]
- VectorWidthB: [2]
- GlobalSplitU: [1]
BenchmarkForkParameters:
JoinParameters:
BenchmarkJoinParameters:
BenchmarkFinalParameters:
- ProblemSizes:
- Exact: [256, 256, 1, 256]
- Exact: [128, 128, 1, 128]
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,13 @@ namespace TensileLite
size_t totalElements,
hipMemcpyKind kind)
{
HIP_CHECK_EXC(hipMemcpy(
dst, src, multiplyElementSize(totalElements, descriptor.elementBytes()), kind));
// Skip copy if no elements to copy or if pointers are null (e.g., when UseBeta=false, tensor C may not be allocated)
if(totalElements > 0 && dst != nullptr && src != nullptr)
{
HIP_CHECK_EXC(hipMemcpy(
dst, src, multiplyElementSize(totalElements, descriptor.elementBytes()), kind));
//HIP_CHECK_EXC(hipMemcpy(dst, src, descriptor.elementBytes() * totalElements, kind));
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated
}
return dst;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <Tensile/hip/HipUtils.hpp>

#include <cstddef>
#include <sstream>

namespace TensileLite
{
Expand Down Expand Up @@ -487,7 +488,30 @@ namespace TensileLite
std::cout << "Validating tensor " << tensor.getName() << ", cpu pointer "
<< refPtr << ", gpu pointer " << resPtr
<< ", size = " << result.maxElements[i] << std::endl;


// Skip validation if pointers are null or maxElements is 0
// Only tensor C can be null when beta is zero (UseBeta=false)
if(resPtr == nullptr || refPtr == nullptr || result.maxElements[i] == 0)
{
// Tensor C is allowed to be null when beta is zero (not used)
bool isTensorC = (static_cast<ContractionProblemGemm::TENSOR>(i) == ContractionProblemGemm::TENSOR::C);
bool isBetaZero = (problem.beta() == 0.0);

if(isTensorC && isBetaZero)
{
if(Debug::Instance().printTensorInfo())
std::cout << "Skipping validation for tensor C (beta=0, not used)" << std::endl;
continue;
}

// For all other cases, null pointers are an error
std::stringstream ss;
ss << "Unexpected null pointer or zero elements for tensor " << tensor.getName()
<< " (resPtr=" << resPtr << ", refPtr=" << refPtr
<< ", maxElements=" << result.maxElements[i] << ")";
throw std::runtime_error(ss.str());
}

rv &= checkResults(
tensor, refPtr, resPtr, result.maxElements[i], result.gpu, validationStride, threshold);
}
Expand All @@ -496,13 +520,15 @@ namespace TensileLite

void ReferenceValidator::allocateResultBuffer(size_t bytes)
{
if(m_cpuResultBufferSize == bytes)
// Only skip reallocation if size matches AND buffer is valid
if(m_cpuResultBufferSize == bytes && m_cpuResultBuffer.get() != nullptr)
return;

m_cpuResultBuffer.reset();

uint8_t* buffer;
HIP_CHECK_EXC(hipHostMalloc(&buffer, bytes, 0));
m_cpuResultBuffer.reset(buffer, hipFree);
HIP_CHECK_EXC(hipHostMalloc((void**)&buffer, bytes, 0));
m_cpuResultBuffer.reset(buffer, [](uint8_t* p) { (void)hipFree(p); });
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated
m_cpuResultBufferSize = bytes;
}

Expand Down Expand Up @@ -685,11 +711,42 @@ namespace TensileLite
size_t elementsAfterData = 0;

BoundsCheckMode boundsCheck = m_dataInit->getCurBoundsCheck();
if(boundsCheck == BoundsCheckMode::NaN)
// For output tensors, don't use maxElement with padding since the kernel only writes actual data
// Only input tensors have bounds checking padding in their buffers
if(boundsCheck == BoundsCheckMode::NaN && !tensor.isOutput())
elementsToCopy = maxElement;
size_t bytesToCopy = elementsToCopy * sizeof(ValidType);

if(m_cpuResultBufferSize < bytesToCopy)
// Skip validation if pointers are null or no bytes to copy
// Only tensor C can be null when beta is zero (UseBeta=false)
if(result == nullptr || reference == nullptr || bytesToCopy == 0 || maxElement == 0)
{
// Tensor C is allowed to be null when beta is zero (not used)
bool isTensorC = (tensor.getName() == "C");
bool isBetaZero = false;
if(m_problem != nullptr)
{
auto* gemmProblem = dynamic_cast<ContractionProblemGemm const*>(m_problem);
if(gemmProblem != nullptr)
isBetaZero = (gemmProblem->beta() == 0.0);
}

if(isTensorC && isBetaZero)
{
if(Debug::Instance().printTensorInfo())
std::cout << "Skipping validation for tensor C (beta=0, not used)" << std::endl;
return true;
}

// For all other cases, null pointers or no data to validate is an error
std::stringstream ss;
ss << "Unexpected null pointer or no data for tensor " << tensor.getName()
<< " (result=" << result << ", reference=" << reference
<< ", bytesToCopy=" << bytesToCopy << ", maxElement=" << maxElement << ")";
throw std::runtime_error(ss.str());
}
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated

if(m_cpuResultBufferSize < bytesToCopy || m_cpuResultBuffer.get() == nullptr)
allocateResultBuffer(bytesToCopy);
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated

auto copykind = isgpu ? hipMemcpyDeviceToHost : hipMemcpyHostToHost;
Expand All @@ -699,7 +756,8 @@ namespace TensileLite
HIP_CHECK_EXC(hipMemcpy(m_cpuResultBuffer.get(), result, bytesToCopy, copykind));
}

if(boundsCheck == BoundsCheckMode::NaN)
// Only check bounds for input tensors (output tensors don't have padding buffers)
Comment thread
pdhirajkumarprasad marked this conversation as resolved.
Outdated
if(boundsCheck == BoundsCheckMode::NaN && !tensor.isOutput())
{
ptrdiff_t bPadding = maxElement - tensor.totalAllocatedElements();
elementsBeforeData = bPadding / 2;
Expand Down
Loading