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

Improve memory management #6

Open
lucifer1004 opened this issue Jan 5, 2023 · 4 comments
Open

Improve memory management #6

lucifer1004 opened this issue Jan 5, 2023 · 4 comments
Assignees
Labels
bug Something isn't working enhancement New feature or request
Milestone

Comments

@lucifer1004
Copy link
Owner

Currently, there is no special handling of memory management. jlrs has set an outstanding example, and we can learn from it.

@lucifer1004 lucifer1004 added bug Something isn't working enhancement New feature or request labels Jan 5, 2023
@lucifer1004 lucifer1004 self-assigned this Jan 5, 2023
@lucifer1004 lucifer1004 added this to the 0.1 milestone Jan 5, 2023
@lucifer1004
Copy link
Owner Author

lucifer1004 commented Jan 5, 2023

For example, the following C code would crash at a certain point:

#include <julia.h>

const int N = 1000000;

int main() {
    jl_init();
    jl_value_t *int1d = jl_apply_array_type((jl_value_t *)jl_float64_type, 1);
    jl_array_t *arr = jl_alloc_array_1d(int1d, N);
    for (int i = 0; i < N; i++) {
        jl_arrayset(arr, jl_box_float64(i), i);
    }

    jl_function_t *sqrt = jl_get_function(jl_base_module, "sqrt");
    for (int i = 0; i < N; i++) {
        printf("%.6f\n", jl_unbox_float64(jl_call1(sqrt, jl_arrayref(arr, i))));
    }
    jl_atexit_hook(0);
    return 0;
}

And so will the equivalent jlbun code:

import {Julia, JuliaArray} from 'jlbun';

Julia.init();

const N = 1000000;
const a = JuliaArray.init(Julia.Float64, N);
for (let i = 0; i < N; i++) {
  a.set(i, i);
}

for (let i = 0; i < N; i++) {
  console.log(Julia.Base.sqrt(a.get(i)).value);
}
    
Julia.close();

This is due to Julia's GC. If we totally disable GC by jl_gc_enable(0), both C and jlbun codes can work. But turning off GC is obviously not the right choice for a large project.

To solve this issue properly, we need to mark the necessary variables as rooted to keep them alive, just like jlrs.

@lucifer1004
Copy link
Owner Author

lucifer1004 commented Jan 6, 2023

Reference jlrs code:

use jlrs::prelude::*;

fn main() {
    // Initializing Julia is unsafe because it can race with another crate that does
    // the same.
    let mut julia = unsafe { RuntimeBuilder::new().start().unwrap() };
    let mut frame = StackFrame::new();
    let mut julia = julia.instance(&mut frame);

    let res = julia
        .scope(|mut frame| {
            let mut array = TypedArray::<f64>::new(frame.as_extended_target(), 1_000_000).unwrap();

            unsafe {
                let mut acc = array.bits_data_mut()?;
                for i in 0..1_000_000 {
                    acc.set(i, i as f64);
                }

                let sqrt = Module::base(&frame).function(&mut frame, "sqrt")?;
                for i in 0..1_000_000 {
                    let raw = acc.get_value(&frame, i).unwrap().unwrap().unwrap().value();
                    let new = sqrt.call1(&mut frame, raw).unwrap().unbox::<f64>().unwrap();
                    println!("{}", new);
                }
            }

            Ok(())
        })
        .unwrap();
}

@lucifer1004
Copy link
Owner Author

Reference C code that does not crash:

#include <julia.h>

const int N = 1000000;

int main() {
    jl_init();
    jl_value_t *int1d = jl_apply_array_type((jl_value_t *)jl_float64_type, 1);
    jl_array_t *arr = jl_alloc_array_1d(int1d, N);
    for (int i = 0; i < N; i++) {
        jl_arrayset(arr, jl_box_float64(i), i);
    }

    jl_function_t *sqrt = jl_get_function(jl_base_module, "sqrt");
    JL_GC_PUSH2(&arr, &sqrt);
    for (int i = 0; i < N; i++) {
        jl_value_t *val = jl_arrayref(arr, i);
        jl_value_t *sval = jl_call1(sqrt, val);
        printf("%.6f\n", jl_unbox_float64(sval));
    }
    JL_GC_POP();
    jl_atexit_hook(0);
    return 0;
}

@lucifer1004
Copy link
Owner Author

Reference jlbun code that does not crash:

import {Julia, JuliaArray} from 'jlbun';

Julia.init();

const N = 1000000;
const a = JuliaArray.init(Julia.Float64, N);
Julia.setGlobal("a", a); // Avoid `a` from being GC-ed.
for (let i = 0; i < N; i++) {
  a.set(i, i);
}

for (let i = 0; i < N; i++) {
  console.log(Julia.Base.sqrt(a.get(i)).value);
}
    
Julia.close();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant