Skip to content

create Rust bindings #125

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

Open
1a1a11a opened this issue Feb 6, 2025 · 4 comments
Open

create Rust bindings #125

1a1a11a opened this issue Feb 6, 2025 · 4 comments
Assignees
Labels
help wanted Extra attention is needed new function

Comments

@1a1a11a
Copy link
Owner

1a1a11a commented Feb 6, 2025

No description provided.

@1a1a11a 1a1a11a added the help wanted Extra attention is needed label Feb 6, 2025
@YangLiuWillow
Copy link

I would like to work on this issue. Is it okay to assign it to me? Thank you so much!

@YangLiuWillow
Copy link

I generated rust bindings using bindgen by passing in all header files in libCacheSim/libCacheSim/include. For next step, should I go about creating a safe Rust wrapper (e.g. defining a new Rust struct Cache) on top of the bindings?

/// A safe Rust wrapper around the libCacheSim LRU cache.
pub struct Cache {
    cache_ptr: *mut cache_t,
}

impl Cache {
    /// Initializes a new LRU cache.
    pub fn LRU_init(params: common_cache_params_t, specific_params: &str) -> Option<Self> {
        let c_params = CString::new(specific_params).expect("CString conversion failed");
        let cache_ptr = unsafe { bindings::LRU_init(params, c_params.as_ptr()) };

        if cache_ptr.is_null() {
            None
        } else {
            Some(Self { cache_ptr })
        }
    }
}

// Ensure the cache gets freed properly when dropped.
impl Drop for Cache {
    fn drop(&mut self) {
        self.LRU_free();
    }
}

Or is using the raw bindings just fine (but we will need to handle unsafe every time)?

let params = bindings::common_cache_params_t { cache_size: 1024 * 1024 };
let cache_ptr = unsafe { bindings::LRU_init(params, std::ptr::null_mut()) };

Besides, I have bindgen created bindings for functions in all header files in libCacheSim/libCacheSim/include. Do I need to create safe wrappers for all functions? Or are just the Cache APIs mentioned in doc/advanced_lib.md enough?

@1a1a11a
Copy link
Owner Author

1a1a11a commented Mar 20, 2025

Awesome!

  1. I think having a safe Rust wrapper would make Rust user's life easier (although there is no difference on safety)
  2. Having a more selective / narrow interface will make documentation easier and might be more friendly when users get started. But for now, we can include everything and refine later.

@YangLiuWillow
Copy link

Sorry for the delay. I run into some problems with bindgen when handling static inline functions. Mainly, when wrap_static_fns is used with -x and c++, it does not generate the objective file needed to create a library for the static inline functions (see issue rust-lang/rust-bindgen#3157). I disabled -x and c++ when generating the bindings for now.

What I have now:
I created a new directory libcachesim-rs that looks like:

-- libcachesim-rs
     -- bindings
         -- bindings.rs
         -- libwrap_static_fns.a
         -- wrap_static_fns.c
         -- wrap_static_fns.o
     -- src
         -- lib.rs
         -- main.rs
         -- wrapper.rs
     -- build.rs
     -- cargo.toml

In the libcachesim-rs directory, if we run cargo build, the build.rs script will generate the bindings directory and all the files inside this directory. Then we can include the bindings.rs to our lib.rs and write safe Rust wrappers in wrapper.rs. For now, I have pub struct Cache, pub struct Reader, and pub struct Request with all corresponding methods. With these, I write a Rust equivalent test.c file in main.rs, that looks like this

use libcachesim_rs::bindings::*;
use libcachesim_rs::wrapper::*;

fn main() {
    // Open the trace file
    println!("Rust equivalent of test.c");

    let mut init_params_csv = Reader::default_reader_init_params();
    init_params_csv.delimiter = ',' as i8; // b',' as std::os::raw::c_char,
    init_params_csv.time_field = 2;
    init_params_csv.obj_id_field = 6;
    init_params_csv.obj_size_field = 4;
    init_params_csv.has_header = false;

    let mut reader = match Reader::open_trace("../data/trace.csv", trace_type_e_CSV_TRACE, &init_params_csv) {
        Some(r) => r,
        None => {
            eprintln!("Failed to open trace.");
            return;
        }
    };

    // Create a request container
    let req = match Request::new_request() {
        Some(r) => r,
        None => {
            eprintln!("Failed to create request.");
            return;
        }
    };

    // Define cache parameters and create the cache
    let cache_params = common_cache_params_t {
        cache_size: 1024 * 1024,
        ..Default::default()
    };
    let cache = match Cache::LRU_init(cache_params, "") {
        Some(c) => c,
        None => {
            eprintln!("Failed to initialize cache.");
            return;
        }
    };

    // Counters
    let mut n_req = 0;
    let mut n_miss = 0;

    // Loop through the trace
    while reader.read_one_req(&req) == 0 {
        if !cache.get(&req) {
            n_miss += 1;
        }
        n_req += 1;
    }

    // Print the miss ratio
    if n_req > 0 {
        println!("miss ratio: {:.4}", n_miss as f64 / n_req as f64);
    } else {
        println!("No requests were processed.");
    }

    // Clean up happens automatically due to Drop implementations
}

But I have some questions when testing things out.

  1. How should I create a VSCSI file? I've been trying to run test.c but I can't seem to figure out how to create a VSCSI file other than copy paste the existing ones in data directory and rename them :O.
  2. When I run ./test.out, it gives me this error
[WARN]  03-23-2025 19:34:11    csv.c:61   (tid=8633382976): in_buf_size 1024 is smaller than the first line size 18446744073709551615, the first line will be truncatedAssertion failed: (buf_size < 1024), function csv_detect_header, file csv.c, line 125.
zsh: abort      ../test.out

When running cargo run for main.rs, I get the same error

[WARN]  03-23-2025 19:56:08    csv.c:61   (tid=8633382976): in_buf_size 1024 is smaller than the first line size 18446744073709551615, the first line will be truncatedAssertion failed: (buf_size < 1024), function csv_detect_header, file csv.c, line 125.
zsh: abort      cargo run

So I guess I am not as familiar with the code base, but I cannot seem to figure out why for now.

Next step, I will write more Rust wrappers. I only wrote the basic ones for testing purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed new function
Projects
None yet
Development

No branches or pull requests

2 participants