Files
deeplearning4j--deeplearning4j/libnd4j/include/array/impl/TadPack.cpp
T
2026-07-13 12:47:05 +08:00

253 lines
7.5 KiB
C++

/* ******************************************************************************
*
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/
//
// @author raver119@gmail.com
//
#include "../TadPack.h"
#include <helpers/shape.h>
#include <system/Environment.h>
#include <sstream>
#if defined(SD_GCC_FUNCTRACE)
#include <array/TADCacheLifecycleTracker.h>
#endif
namespace sd {
TadPack::TadPack( ConstantShapeBuffer *shapes,
ConstantOffsetsBuffer *offets, LongType numTads,
LongType* dimensions, LongType dimLength)
: _tadShape(shapes),
_tadOffsets(offets) {
_numTads = numTads;
_dimensionsLength = dimLength;
if(dimensions != nullptr) {
_dimensions = new LongType[dimLength];
for(int i = 0; i < dimLength; i++) {
_dimensions[i] = dimensions[i];
}
}
computeHash();
#if defined(SD_GCC_FUNCTRACE) && !defined(__JAVACPP_HACK__)
// Track TAD cache allocation - only capture stack trace if tracking is enabled
// Stack trace capture is expensive, so skip it when tracking is disabled
auto& tracker = sd::array::TADCacheLifecycleTracker::getInstance();
if (tracker.isEnabled()) {
// Capture stack trace for this TadPack allocation
_stackTrace = backward::StackTrace();
_stackTrace.load_here(32);
}
// Always record allocation for basic counting (cheap operation)
size_t shape_info_bytes = 0;
size_t offsets_bytes = 0;
if (_tadShape != nullptr && _tadShape->primary() != nullptr) {
shape_info_bytes = shape::shapeInfoByteLength(_tadShape->primary());
}
if (_tadOffsets != nullptr && _tadOffsets->primary() != nullptr) {
offsets_bytes = _numTads * sizeof(LongType);
}
std::vector<LongType> dims;
if (_dimensions != nullptr) {
dims.assign(_dimensions, _dimensions + _dimensionsLength);
}
tracker.recordAllocation(this, _numTads, shape_info_bytes, offsets_bytes, dims);
#endif
}
TadPack::~TadPack() {
#if defined(SD_GCC_FUNCTRACE) && !defined(__JAVACPP_HACK__)
// Track TAD cache deallocation before cleanup.
// Guard must match constructor guard for proper allocation/deallocation pairing.
sd::array::TADCacheLifecycleTracker::getInstance().recordDeallocation(this);
#endif
// Clean up dimensions array that was allocated in constructor
if (_dimensions != nullptr) {
delete[] _dimensions;
_dimensions = nullptr;
}
// Clean up TAD offsets buffer if we own it
// This is owned when transferred via releaseOffsets() from TadCalculator
if (_tadOffsets != nullptr) {
delete _tadOffsets;
_tadOffsets = nullptr;
}
// DON'T delete _tadShape - it comes from ConstantShapeHelper cache
}
LongType* TadPack::primaryShapeInfo() {
if(_tadShape->primary() == nullptr)
THROW_EXCEPTION("TadPack::primaryShapeInfo: primary shape info is nullptr!");
return _tadShape->primary();
}
LongType* TadPack::primaryOffsets() {
return _tadOffsets->primary();
}
LongType* TadPack::specialShapeInfo() { return _tadShape->special(); }
LongType* TadPack::specialOffsets() { return _tadOffsets->special(); }
LongType TadPack::numberOfTads() const { return _numTads; }
LongType* TadPack::platformShapeInfo() {
return Environment::getInstance().isCPU() ? primaryShapeInfo() : specialShapeInfo();
}
LongType* TadPack::platformOffsets() {
return Environment::getInstance().isCPU() ? primaryOffsets() : specialOffsets();
}
void TadPack::print(const char* msg) {
printf("---------------------------\n");
printf("%s: ", msg);
printf("Offsets:\n");
for (int e = 0; e < _numTads; e++) {
printf("%lld, ", _tadOffsets->primary()[e]);
}
printf("\n");
printf("Dimensions:\n");
if (_dimensions == nullptr || _dimensionsLength == 0) {
printf("none\n");
} else {
for (int i = 0; i < _dimensionsLength; i++) {
printf("%lld, ", _dimensions[i]);
}
printf("\n");
}
printf("tad pack shape info:");
shape::printShapeInfo(_tadShape->primary());
printf("\n");
printf("number of tads: %lld\n", _numTads);
printf("shape info length: %lld\n", _shapeInfoLength);
printf("---------------------------\n");
}
LongType TadPack::shapeInfoLength() { return shape::shapeInfoLength(primaryShapeInfo()); }
bool TadPack::operator==( TadPack& other) {
// Compare number of TADs
if (_numTads != other._numTads)
return false;
// Compare shape information
LongType* thisShape = primaryShapeInfo();
LongType* otherShape = other.primaryShapeInfo();
// Check for null shape info
if ((thisShape == nullptr) != (otherShape == nullptr))
return false;
if (thisShape != nullptr) {
// Compare rank
const int thisRank = shape::rank(thisShape);
const int otherRank = shape::rank(otherShape);
if (thisRank != otherRank)
return false;
// Compare shape order
if (shape::order(thisShape) != shape::order(otherShape))
return false;
// Compare data type
if (ArrayOptions::dataType(thisShape) != ArrayOptions::dataType(otherShape))
return false;
// Compare shape dimensions
for (int i = 0; i < thisRank; i++) {
if (shape::shapeOf(thisShape)[i] != shape::shapeOf(otherShape)[i])
return false;
}
// Compare shape strides
for (int i = 0; i < thisRank; i++) {
if (shape::stride(thisShape)[i] != shape::stride(otherShape)[i])
return false;
}
}
// Compare dimensions array
if ((_dimensions == nullptr) != (other._dimensions == nullptr))
return false;
if (_dimensions != nullptr) {
if (_dimensionsLength != other._dimensionsLength)
return false;
for (LongType i = 0; i < _dimensionsLength; i++) {
if (_dimensions[i] != other._dimensions[i])
return false;
}
}
// Compare offsets
LongType* thisOffsets = primaryOffsets();
LongType* otherOffsets = other.primaryOffsets();
// Check for null offsets
if ((thisOffsets == nullptr) != (otherOffsets == nullptr))
return false;
if (thisOffsets != nullptr) {
for (LongType i = 0; i < _numTads; i++) {
if (thisOffsets[i] != otherOffsets[i])
return false;
}
}
return true;
}
std::string TadPack::getStackTraceAsString() const {
#if defined(SD_GCC_FUNCTRACE) && !defined(__JAVACPP_HACK__)
// Use backward::Printer to format the stack trace into a string
std::ostringstream oss;
backward::Printer p;
p.snippet = false; // Don't include source code snippets
p.address = true; // Include addresses
p.object = false; // Don't include object file info
p.color_mode = backward::ColorMode::never; // No ANSI colors in string
// Print to our string stream (we need to cast away const to use _stackTrace)
// This is safe since print doesn't modify the StackTrace
backward::StackTrace& mutable_st = const_cast<backward::StackTrace&>(_stackTrace);
p.print(mutable_st, oss);
return oss.str();
#else
return ""; // Return empty string when functrace is not enabled
#endif
}
} // namespace sd