Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust wrapper for porgram functionality #771

Merged
merged 20 commits into from
Mar 3, 2025
Merged

Conversation

Koren-Brand
Copy link
Contributor

Rust wrapper for program and symbol added
Fixed extension field missing from backend implementations of program executor

CUDA backend branch (Until it will be merged to main)
cuda-backend-branch: koren/register_program_execution_for_extension_field

Signed-off-by: Koren-Brand <[email protected]>
@@ -261,6 +275,31 @@ fn check_vec_ops_args_slice<F>(
setup_config(input, input, output, cfg, batch_size)
}

fn check_execute_program<F, Data>( // COMMENT do we need this check in Rust (or any of the other checks)? seems to bloat rust for stuff not even implemented in cpp.
Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you mean by "for stuff not even implemented in cpp"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

these are checks that the cpp backend doesn't do, Miki asked me whether or not do I keep this checks or not

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm keeping these checks currently to align with the vecops checks in Rust for now

return eIcicleError::SUCCESS;
}

void CONCAT_EXPAND(FIELD, generate_program)(ProgramHandle program, SymbolHandle* parameters_ptr, int nof_parameters)
Copy link
Collaborator

Choose a reason for hiding this comment

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

why no return value here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to return eIcicleError (which would return success or invalid argument)

extern "C" { // TODO remove program from names
// Symbol functions
// Constructors
SymbolHandle CONCAT_EXPAND(FIELD, create_empty_symbol)() { return new Symbol<scalar_t>(); }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you avoid empty symbol and create it as input directly? Why would you have an empty symbol in Rust?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was just propagating the public constructors from the cpp side. @mickeyasa @idanfr-ingo do you think it's relevant for a rust user?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to a create_input_symbol function instead

return this_symbol;
}

SymbolHandle CONCAT_EXPAND(FIELD, add_symbols)(const SymbolHandle op_a, const SymbolHandle op_b)
Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't check for nullptr everywhere in this file. You need to

@@ -39,6 +39,12 @@ pub trait Arithmetic: Sized + Add<Output = Self> + Sub<Output = Self> + Mul<Outp
fn pow(self, exp: usize) -> Self;
}

pub type HandleCPP = *const c_void;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a little strange. Why cpp? maybe HandleFFI? it's just a pointer, it's not necessarily c++ and the name is strange

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would you prefer not having the type at all?

Copy link
Collaborator

Choose a reason for hiding this comment

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

yes. Move it to the macros internally like other APIs

}

pub trait DeletableHandle: Handle {
fn delete_handle(handle: HandleCPP);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it should be
fn delete_handle(&mut self);
Otherwise you do something like a.delete(b) to delete b with the object a.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the function is removed

Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't need it then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nope the deleting happens in the release pool

impl Symbol<$field> for FieldSymbol {
fn new_input(in_idx: u32) -> Result<Self, eIcicleError> {
unsafe {
let handle = ffi__input_symbol(in_idx);
Copy link
Collaborator

Choose a reason for hiding this comment

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

should it be ffi_input_input_symbol with a single underscore?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It might be a typo I didn't notice

unsafe {
let ffi_status = ffi_delete_symbol(handle);
if ffi_status != eIcicleError::Success {
panic!("Couldn't delete symbol, due to {:?}", ffi_status);
Copy link
Collaborator

Choose a reason for hiding this comment

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

why panic? you can return the error instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Function removed

$field:ident
) => {
pub(crate) mod test_vecops {
use super::*;
use icicle_runtime::test_utilities;
use icicle_runtime::{device::Device, runtime};
use std::sync::Once;
// use crate::symbol::$field_prefix_ident::Symbol;
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove

Koren-Brand and others added 3 commits February 27, 2025 17:53
Signed-off-by: Koren-Brand <[email protected]>
Signed-off-by: Koren-Brand <[email protected]>

# Usage
This section will outline how to use Program and Symbol, mirroring the examples from the [cpp overview](../primitives/program.md). The program use-case splits to three steps:
1. Defining a function/lambda that describes the program to be ran (or choosing one of the predefined list?).
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should at list show how to define a program from the pre-defined enum (the same way I did it in the C++ doc).
Also remove the question mark.

Copy link
Contributor

@mickeyasa mickeyasa left a comment

Choose a reason for hiding this comment

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

comments inside

@@ -0,0 +1,150 @@
# Rust FFI Bindings for Program

>**_NOTE:_**
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is not the format for docsaurus. Should be like

## Defining a Function for Program
A function operating on a vector of symbols, with outputs being written to said input vector. The input symbols in the vector represent inputs and outputs of field elements, and will be replaced by vectors of field elements when executed.
>**_NOTE:_**
> The defined function defines arithmetic operations to be done in series, without control-flow i.e. loops, conditions etc.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This not accurate and maybe confusing. You can use control flow but the lambda is traced and the path taken is the computation that is later computed.

I suggest "The defined function performs arithmetic operations in a traced execution, meaning control flow (e.g., loops, conditions) is not parsed. Instead, the computation follows the exact execution path taken during tracing, which determines the final computation that will be performed."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed to

:::note
The defined function defines arithmetic operations to be done in series, and could be represented as set of equations (for each output). Practically, control flow (e.g., loops, conditions) is not parsed, instead the computation follows the exact execution path taken during tracing, which determines the final computation that will be performed.
:::

Copy link
Collaborator

@yshekel yshekel left a comment

Choose a reason for hiding this comment

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

You did not resolve a few things. Please do and I will approve

Signed-off-by: Koren-Brand <[email protected]>
@Koren-Brand Koren-Brand merged commit 0448e94 into main Mar 3, 2025
17 checks passed
@Koren-Brand Koren-Brand deleted the koren/program-rust-wrapper branch March 3, 2025 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants