Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,8 @@ class CHSparkPlanExecApi extends SparkPlanExecApi with Logging {
override def createColumnarBatchSerializer(
schema: StructType,
metrics: Map[String, SQLMetric],
shuffleWriterType: ShuffleWriterType): Serializer = {
shuffleWriterType: ShuffleWriterType,
enableCudf: Boolean): Serializer = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this change. Is it possible to just add one or more new ShuffleWriterType for cuff so we can avoid adding new parameters?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shuffle writer is same, only the shuffle reader is different. Each ShuffleWriterType matches to its own GpuShuffleReader

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shuffle writer type is also used on the reader side to determine which deserialiser to use. If the deserialisation are different, then would be better to have different shuffle writer type like gpu_hash, gpu_sort, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, and I notice the shuffle writer type name exists in cpp and scala code, should we use protobuf for them?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Would be nice to have a better way to align them.

val readBatchNumRows = metrics("avgReadBatchNumRows")
val numOutputRows = metrics("numOutputRows")
val dataSize = metrics("dataSize")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ private class CelebornColumnarBatchSerializerInstance(
batchSize,
readerBufferSize,
deserializerBufferSize,
shuffleWriterType.name
shuffleWriterType.name,
false
)
// Close shuffle reader instance as lately as the end of task processing,
// since the native reader could hold a reference to memory pool that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ class VeloxSparkPlanExecApi extends SparkPlanExecApi {
override def createColumnarBatchSerializer(
schema: StructType,
metrics: Map[String, SQLMetric],
shuffleWriterType: ShuffleWriterType): Serializer = {
shuffleWriterType: ShuffleWriterType,
enableCudf: Boolean): Serializer = {
val numOutputRows = metrics("numOutputRows")
val deserializeTime = metrics("deserializeTime")
val readBatchNumRows = metrics("avgReadBatchNumRows")
Expand All @@ -658,7 +659,8 @@ class VeloxSparkPlanExecApi extends SparkPlanExecApi {
numOutputRows,
deserializeTime,
decompressTime,
shuffleWriterType)
shuffleWriterType,
enableCudf)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ package org.apache.gluten.extension

import org.apache.gluten.config.{GlutenConfig, VeloxConfig}
import org.apache.gluten.cudf.VeloxCudfPlanValidatorJniWrapper
import org.apache.gluten.execution.{CudfTag, LeafTransformSupport, TransformSupport, WholeStageTransformer}
import org.apache.gluten.execution.{CudfTag, LeafTransformSupport, TransformSupport, VeloxResizeBatchesExec, WholeStageTransformer}
import org.apache.gluten.extension.CudfNodeValidationRule.setTagForWholeStageTransformer

import org.apache.spark.sql.catalyst.rules.Rule
import org.apache.spark.sql.execution.SparkPlan
import org.apache.spark.sql.execution.{ColumnarShuffleExchangeExec, GPUColumnarShuffleExchangeExec, SparkPlan}

// Add the node name prefix 'Cudf' to GlutenPlan when can offload to cudf
case class CudfNodeValidationRule(glutenConf: GlutenConfig) extends Rule[SparkPlan] {
Expand All @@ -31,33 +32,65 @@ case class CudfNodeValidationRule(glutenConf: GlutenConfig) extends Rule[SparkPl
return plan
}
plan.transformUp {
case shuffle @ ColumnarShuffleExchangeExec(
_,
v @ VeloxResizeBatchesExec(w: WholeStageTransformer, _, _),
_,
_,
_) =>
setTagForWholeStageTransformer(w)
if (w.isCudf) {
log.info("VeloxResizeBatchesExec is not supported in GPU")
}
GPUColumnarShuffleExchangeExec(
shuffle.outputPartitioning,
w,
shuffle.shuffleOrigin,
shuffle.projectOutputAttributes,
shuffle.advisoryPartitionSize)

case shuffle @ ColumnarShuffleExchangeExec(_, w: WholeStageTransformer, _, _, _) =>
setTagForWholeStageTransformer(w)
GPUColumnarShuffleExchangeExec(
shuffle.outputPartitioning,
w,
shuffle.shuffleOrigin,
shuffle.projectOutputAttributes,
shuffle.advisoryPartitionSize)

case transformer: WholeStageTransformer =>
if (!VeloxConfig.get.cudfEnableTableScan) {
// Spark3.2 does not have exists
val hasLeaf = transformer.find {
case _: LeafTransformSupport => true
case _ => false
}.isDefined
if (!hasLeaf && VeloxConfig.get.cudfEnableValidation) {
if (
VeloxCudfPlanValidatorJniWrapper.validate(
transformer.substraitPlan.toProtobuf.toByteArray)
) {
transformer.foreach {
case _: LeafTransformSupport =>
case t: TransformSupport =>
t.setTagValue(CudfTag.CudfTag, true)
case _ =>
}
transformer.setTagValue(CudfTag.CudfTag, true)
}
} else {
transformer.setTagValue(CudfTag.CudfTag, !hasLeaf)
setTagForWholeStageTransformer(transformer)
transformer
}
}
}

object CudfNodeValidationRule {
def setTagForWholeStageTransformer(transformer: WholeStageTransformer): Unit = {
if (!VeloxConfig.get.cudfEnableTableScan) {
// Spark3.2 does not have exists
val hasLeaf = transformer.find {
case _: LeafTransformSupport => true
case _ => false
}.isDefined
if (!hasLeaf && VeloxConfig.get.cudfEnableValidation) {
if (
VeloxCudfPlanValidatorJniWrapper.validate(
transformer.substraitPlan.toProtobuf.toByteArray)
) {
transformer.foreach {
case _: LeafTransformSupport =>
case t: TransformSupport =>
t.setTagValue(CudfTag.CudfTag, true)
case _ =>
}
} else {
transformer.setTagValue(CudfTag.CudfTag, true)
}
transformer
} else {
transformer.setTagValue(CudfTag.CudfTag, !hasLeaf)
}
} else {
transformer.setTagValue(CudfTag.CudfTag, true)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class ColumnarBatchSerializer(
numOutputRows: SQLMetric,
deserializeTime: SQLMetric,
decompressTime: SQLMetric,
shuffleWriterType: ShuffleWriterType)
shuffleWriterType: ShuffleWriterType,
enableCudf: Boolean)
extends Serializer
with Serializable {

Expand All @@ -63,7 +64,8 @@ class ColumnarBatchSerializer(
numOutputRows,
deserializeTime,
decompressTime,
shuffleWriterType)
shuffleWriterType,
enableCudf)
}

override def supportsRelocationOfSerializedObjects: Boolean = true
Expand All @@ -75,7 +77,8 @@ private class ColumnarBatchSerializerInstanceImpl(
numOutputRows: SQLMetric,
deserializeTime: SQLMetric,
decompressTime: SQLMetric,
shuffleWriterType: ShuffleWriterType)
shuffleWriterType: ShuffleWriterType,
enableCudf: Boolean)
extends ColumnarBatchSerializerInstance
with Logging {

Expand Down Expand Up @@ -111,7 +114,8 @@ private class ColumnarBatchSerializerInstanceImpl(
batchSize,
readerBufferSize,
deserializerBufferSize,
shuffleWriterType.name)
shuffleWriterType.name,
enableCudf)
// Close shuffle reader instance as lately as the end of task processing,
// since the native reader could hold a reference to memory pool that
// was used to create all buffers read from shuffle reader. The pool
Expand Down
4 changes: 3 additions & 1 deletion cpp/core/jni/JniWrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,8 @@ JNIEXPORT jlong JNICALL Java_org_apache_gluten_vectorized_ShuffleReaderJniWrappe
jint batchSize,
jlong readerBufferSize,
jlong deserializerBufferSize,
jstring shuffleWriterType) {
jstring shuffleWriterType,
jboolean enableCudf) {
JNI_METHOD_START
auto ctx = getRuntime(env, wrapper);

Expand All @@ -1095,6 +1096,7 @@ JNIEXPORT jlong JNICALL Java_org_apache_gluten_vectorized_ShuffleReaderJniWrappe
options.batchSize = batchSize;
options.readerBufferSize = readerBufferSize;
options.deserializerBufferSize = deserializerBufferSize;
options.enableCudf = enableCudf;

options.shuffleWriterType = ShuffleWriter::stringToType(jStringToCString(env, shuffleWriterType));
std::shared_ptr<arrow::Schema> schema =
Expand Down
5 changes: 5 additions & 0 deletions cpp/core/shuffle/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ struct ShuffleReaderOptions {

// Buffer size when deserializing rows into columnar batches. Only used for sort-based shuffle.
int64_t deserializerBufferSize = kDefaultDeserializerBufferSize;

// When true, convert the buffers to cudf table.
// Add a lock after reader produces the Vector, the next operator should be CudfFromVelox.
// After move the shuffle read operation to gpu, move the lock to start read.
bool enableCudf = false;
};

struct ShuffleWriterOptions {
Expand Down
3 changes: 2 additions & 1 deletion cpp/velox/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ if(ENABLE_S3)
endif()

if(ENABLE_GPU)
list(APPEND VELOX_SRCS cudf/CudfPlanValidator.cc)
list(APPEND VELOX_SRCS cudf/CudfPlanValidator.cc cudf/GpuLock.cc
shuffle/GpuShuffleReader.cc)
endif()

if(ENABLE_ENHANCED_FEATURES)
Expand Down
3 changes: 2 additions & 1 deletion cpp/velox/compute/VeloxRuntime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,8 @@ std::shared_ptr<ShuffleReader> VeloxRuntime::createShuffleReader(
options.readerBufferSize,
options.deserializerBufferSize,
memoryManager(),
options.shuffleWriterType);
options.shuffleWriterType,
options.enableCudf);

return std::make_shared<VeloxShuffleReader>(std::move(deserializerFactory));
}
Expand Down
30 changes: 4 additions & 26 deletions cpp/velox/compute/WholeStageResultIterator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
#include "velox/exec/PlanNodeStats.h"
#ifdef GLUTEN_ENABLE_GPU
#include <cudf/io/types.hpp>
#include <mutex>
#include "velox/experimental/cudf/CudfConfig.h"
#include "velox/experimental/cudf/connectors/hive/CudfHiveConnectorSplit.h"
#include "velox/experimental/cudf/exec/ToCudf.h"
#include "cudf/GpuLock.h"
#endif

using namespace facebook;
Expand Down Expand Up @@ -75,11 +75,11 @@ WholeStageResultIterator::WholeStageResultIterator(
: memoryManager_(memoryManager),
veloxCfg_(
std::make_shared<facebook::velox::config::ConfigBase>(std::unordered_map<std::string, std::string>(confMap))),
taskInfo_(taskInfo),
veloxPlan_(planNode),
#ifdef GLUTEN_ENABLE_GPU
lock_(mutex_, std::defer_lock),
enableCudf_(veloxCfg_->get<bool>(kCudfEnabled, kCudfEnabledDefault)),
#endif
taskInfo_(taskInfo),
veloxPlan_(planNode),
scanNodeIds_(scanNodeIds),
scanInfos_(scanInfos),
streamIds_(streamIds) {
Expand All @@ -90,13 +90,6 @@ WholeStageResultIterator::WholeStageResultIterator(
}
getOrderedNodeIds(veloxPlan_, orderedNodeIds_);

#ifdef GLUTEN_ENABLE_GPU
enableCudf_ = veloxCfg_->get<bool>(kCudfEnabled, kCudfEnabledDefault);
if (enableCudf_) {
lock_.lock();
}
#endif

auto fileSystem = velox::filesystems::getFileSystem(spillDir, nullptr);
GLUTEN_CHECK(fileSystem != nullptr, "File System for spilling is null!");
fileSystem->mkdir(spillDir);
Expand Down Expand Up @@ -213,10 +206,6 @@ WholeStageResultIterator::WholeStageResultIterator(
}
}

#ifdef GLUTEN_ENABLE_GPU
std::mutex WholeStageResultIterator::mutex_;
#endif

std::shared_ptr<velox::core::QueryCtx> WholeStageResultIterator::createNewVeloxQueryCtx() {
std::unordered_map<std::string, std::shared_ptr<velox::config::ConfigBase>> connectorConfigs;
connectorConfigs[kHiveConnectorId] = createConnectorConfig();
Expand All @@ -236,17 +225,6 @@ std::shared_ptr<velox::core::QueryCtx> WholeStageResultIterator::createNewVeloxQ
}

std::shared_ptr<ColumnarBatch> WholeStageResultIterator::next() {
auto result = nextInternal();
#ifdef GLUTEN_ENABLE_GPU
if (result == nullptr && enableCudf_) {
lock_.unlock();
}
#endif

return result;
}

std::shared_ptr<ColumnarBatch> WholeStageResultIterator::nextInternal() {
tryAddSplitsToTask();
if (task_->isFinished()) {
return nullptr;
Expand Down
19 changes: 8 additions & 11 deletions cpp/velox/compute/WholeStageResultIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
#include "velox/connectors/hive/iceberg/IcebergSplit.h"
#include "velox/core/PlanNode.h"
#include "velox/exec/Task.h"
#ifdef GLUTEN_ENABLE_GPU
#include "cudf/GpuLock.h"
#endif

namespace gluten {

Expand All @@ -48,8 +51,8 @@ class WholeStageResultIterator : public ColumnarBatchIterator {
task_->requestCancel().wait();
}
#ifdef GLUTEN_ENABLE_GPU
if (enableCudf_ && lock_.owns_lock()) {
lock_.unlock();
if (enableCudf_) {
unlockGpu();
}
#endif
}
Expand All @@ -75,8 +78,6 @@ class WholeStageResultIterator : public ColumnarBatchIterator {
}

private:
std::shared_ptr<ColumnarBatch> nextInternal();

/// Get the Spark confs to Velox query context.
std::unordered_map<std::string, std::string> getQueryContextConf();

Expand Down Expand Up @@ -113,6 +114,9 @@ class WholeStageResultIterator : public ColumnarBatchIterator {

/// Config, task and plan.
std::shared_ptr<config::ConfigBase> veloxCfg_;
#ifdef GLUTEN_ENABLE_GPU
const bool enableCudf_;
#endif
const SparkTaskInfo taskInfo_;
std::shared_ptr<facebook::velox::exec::Task> task_;
std::shared_ptr<const facebook::velox::core::PlanNode> veloxPlan_;
Expand All @@ -124,13 +128,6 @@ class WholeStageResultIterator : public ColumnarBatchIterator {
/// Metrics
std::unique_ptr<Metrics> metrics_{};

#ifdef GLUTEN_ENABLE_GPU
// Mutex for thread safety.
static std::mutex mutex_;
std::unique_lock<std::mutex> lock_;
bool enableCudf_;
#endif

/// All the children plan node ids with postorder traversal.
std::vector<facebook::velox::core::PlanNodeId> orderedNodeIds_;

Expand Down
Loading