Skip to content
Open
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
97 changes: 64 additions & 33 deletions packages/react-native-executorch/cpp/core/dtype.cpp
Original file line number Diff line number Diff line change
@@ -1,65 +1,96 @@
#include "dtype.h"
#include <stdexcept>

namespace rnexecutorch::core::types {
DType parseDType(const std::string &s) {
if (s == "uint8") {
return DType::uint8;
}
if (s == "int32") {
return DType::int32;
}
if (s == "float32") {
return DType::float32;
namespace rnexecutorch::core {

DType::DType(const std::string &s) {
if (s == "bool") {
v_ = DType::bool_;
} else if (s == "uint8") {
v_ = DType::uint8;
} else if (s == "int32") {
v_ = DType::int32;
} else if (s == "int64") {
v_ = DType::int64;
} else if (s == "float32") {
v_ = DType::float32;
} else {
throw std::invalid_argument(
"Unsupported dtype: '" + s + "'. Expected 'bool', 'uint8', 'int32', 'int64', or 'float32'");
}
throw std::invalid_argument("Unsupported dtype: '" + s + "'. Expected 'uint8', 'int32', or 'float32'");
}

std::string toString(DType dtype) {
switch (dtype) {
case DType::uint8:
return "uint8";
case DType::int32:
return "int32";
case DType::float32:
return "float32";
DType::DType(executorch::aten::ScalarType st) {
switch (st) {
case executorch::aten::ScalarType::Bool:
v_ = DType::bool_;
break;
case executorch::aten::ScalarType::Byte:
v_ = DType::uint8;
break;
case executorch::aten::ScalarType::Int:
v_ = DType::int32;
break;
case executorch::aten::ScalarType::Long:
v_ = DType::int64;
break;
case executorch::aten::ScalarType::Float:
v_ = DType::float32;
break;
default:
throw std::invalid_argument("Unsupported ScalarType");
}
}

executorch::aten::ScalarType toScalarType(DType dtype) {
switch (dtype) {
DType::operator executorch::aten::ScalarType() const {
switch (v_) {
case DType::bool_:
return executorch::aten::ScalarType::Bool;
case DType::uint8:
return executorch::aten::ScalarType::Byte;
case DType::int32:
return executorch::aten::ScalarType::Int;
case DType::int64:
return executorch::aten::ScalarType::Long;
case DType::float32:
return executorch::aten::ScalarType::Float;
default:
throw std::invalid_argument("Unsupported dtype");
}
}

DType fromScalarType(executorch::aten::ScalarType st) {
switch (st) {
case executorch::aten::ScalarType::Byte:
return DType::uint8;
case executorch::aten::ScalarType::Int:
return DType::int32;
case executorch::aten::ScalarType::Float:
return DType::float32;
DType::operator std::string() const {
switch (v_) {
case DType::bool_:
return "bool";
case DType::uint8:
return "uint8";
case DType::int32:
return "int32";
case DType::int64:
return "int64";
case DType::float32:
return "float32";
default:
throw std::invalid_argument("Unsupported ScalarType");
throw std::invalid_argument("Unsupported dtype");
}
}

size_t elementSize(DType dtype) {
switch (dtype) {
size_t DType::size() const {
switch (v_) {
case DType::bool_:
case DType::uint8:
return 1;
// NOLINTNEXTLINE(bugprone-branch-clone): int32 and float32 are both 4 bytes; the identical branches are intentional.
case DType::int32:
return 4;
case DType::int64:
return 8;
case DType::float32:
return 4;
default:
throw std::invalid_argument("Unsupported dtype");
}
}

} // namespace rnexecutorch::core::types
} // namespace rnexecutorch::core
41 changes: 29 additions & 12 deletions packages/react-native-executorch/cpp/core/dtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,36 @@
#include <executorch/runtime/core/exec_aten/exec_aten.h>
#include <string>

namespace rnexecutorch::core::types {
enum class DType {
uint8,
int32,
float32
};
namespace rnexecutorch::core {

class DType {
public:
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) - this enum is already inside a class, co it's effectively enum class
enum Value : uint8_t { bool_,
uint8,
int32,
int64,
float32 };

DType parseDType(const std::string &s);
std::string toString(DType dtype);
// NOLINTNEXTLINE(google-explicit-constructor) — intentional implicit conversion from Value
DType(Value v) : v_(v) {}
// NOLINTNEXTLINE(google-explicit-constructor) — intentional implicit conversion from ScalarType
DType(executorch::aten::ScalarType st);
// NOLINTNEXTLINE(google-explicit-constructor) — intentional implicit conversion from string
DType(const std::string &s);

executorch::aten::ScalarType toScalarType(DType dtype);
DType fromScalarType(executorch::aten::ScalarType st);
// Returns the size (in bytes) of the type.
[[nodiscard]] size_t size() const;

size_t elementSize(DType dtype);
// Hidden operator-like conversions provide a good layer of abstraction.
// NOLINTNEXTLINE(google-explicit-constructor) — intentional implicit conversion to Value
operator Value() const { return v_; }
explicit operator executorch::aten::ScalarType() const;
// NOLINTNEXTLINE(google-explicit-constructor) — intentional implicit conversion to string
operator std::string() const;

private:
Value v_;
};

} // namespace rnexecutorch::core::types
} // namespace rnexecutorch::core
41 changes: 9 additions & 32 deletions packages/react-native-executorch/cpp/core/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ jsi::Value ModelHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
jsTensorMeta.setProperty(rt, "nbytes", static_cast<double>(tensorMeta.nbytes()));

try {
const std::string dtypeStr = rnexecutorch::core::types::toString(rnexecutorch::core::types::fromScalarType(tensorMeta.scalar_type()));
std::string dtypeStr = DType(tensorMeta.scalar_type());
jsTensorMeta.setProperty(rt, "dtype", jsi::String::createFromUtf8(rt, dtypeStr));
} catch (const std::exception &) {
jsTensorMeta.setProperty(rt, "dtype", jsi::String::createFromUtf8(rt, "not supported"));
Expand Down Expand Up @@ -218,31 +218,6 @@ jsi::Value ModelHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
throw jsi::JSError(rt, errorMsg);
}

auto validateTensor = [](jsi::Runtime &rt,
const TensorHostObject *tensorHostObject,
const executorch::runtime::Result<executorch::runtime::TensorInfo> &tensorMeta,
const std::string &identifier) {
if (tensorMeta->scalar_type() != tensorHostObject->tensor_->dtype()) {
throw jsi::JSError(rt, "execute: Tensor dtype mismatch for " + identifier);
}

if (tensorMeta->sizes().size() != tensorHostObject->shape_.size()) {
throw jsi::JSError(rt, "execute: Tensor rank mismatch for " + identifier +
": expected rank " + std::to_string(tensorMeta->sizes().size()) +
" but got " + std::to_string(tensorHostObject->shape_.size()));
}

auto ndim = tensorHostObject->tensor_->sizes().size();
for (size_t j = 0; j < ndim; ++j) {
if (tensorMeta->sizes()[j] != tensorHostObject->shape_[j]) {
throw jsi::JSError(rt, "execute: Tensor shape mismatch for " + identifier +
": expected dimension " + std::to_string(j) + " to be " +
std::to_string(tensorMeta->sizes()[j]) + " but got " +
std::to_string(tensorHostObject->shape_[j]));
}
}
};

auto inputs = std::vector<executorch::runtime::EValue>(methodMeta->num_inputs());
std::vector<std::unique_lock<std::shared_mutex>> tensorLocks;
std::unordered_set<TensorHostObject *> lockedTensors;
Expand Down Expand Up @@ -273,7 +248,7 @@ jsi::Value ModelHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
}

auto tensorHostObject = val.asObject(rt).getHostObject<TensorHostObject>(rt);
if (!tensorHostObject->data_) {
if (!tensorHostObject->et_tensor_) {
throw jsi::JSError(rt, "execute: inputs[" + std::to_string(i) + "] has been disposed");
}

Expand All @@ -295,9 +270,10 @@ jsi::Value ModelHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
std::to_string(i) + "]: " + errorMsg);
}

validateTensor(rt, tensorHostObject.get(), tensorMeta, "inputs[" + std::to_string(i) + "]");
// TODO(igorswat): do something with it. For now must be comment for TTS to work.
// validateTensor(rt, tensorHostObject.get(), tensorMeta, "inputs[" + std::to_string(i) + "]");

inputs[i] = tensorHostObject->tensor_;
inputs[i] = tensorHostObject->et_tensor_;
break;
}
case executorch::runtime::Tag::Double: {
Expand Down Expand Up @@ -374,7 +350,7 @@ jsi::Value ModelHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
}

auto tensorHostObject = val.asObject(rt).getHostObject<TensorHostObject>(rt);
if (!tensorHostObject->data_) {
if (!tensorHostObject->et_tensor_) {
throw jsi::JSError(rt, "execute: outputTensors[" + std::to_string(tensorOutputIdx) + "] has been disposed");
}

Expand All @@ -397,9 +373,10 @@ jsi::Value ModelHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
std::to_string(index) + ": " + errorMsg);
}

validateTensor(rt, tensorHostObject.get(), tensorMeta, "outputTensors[" + std::to_string(tensorOutputIdx) + "]");
// TODO(igorswat): do something with it. For now must be comment for TTS to work.
// validateTensor(rt, tensorHostObject.get(), tensorMeta, "outputTensors[" + std::to_string(tensorOutputIdx) + "]");

std::memcpy(tensorHostObject->data_.get(),
std::memcpy(tensorHostObject->data_,
output.toTensor().const_data_ptr(),
output.toTensor().nbytes());

Expand Down
Loading
Loading