furiosa-ai / device-api

APIs that offers NPU devices' information and allow to control the devices
Apache License 2.0
5 stars 8 forks source link

Add c-binding for device-api #103

Closed bg-furiosa closed 10 months ago

bg-furiosa commented 12 months ago

What type of PR is this?

What this PR does / why we need it:

Note: This PR needs one more commit for applying API convention which has not been decided yet(cc @hyunsik ).

Additional documentation e.g., KEPs, usage docs, etc.:

hyunsik commented 12 months ago

아래 정리해 보았습니다. 하루 정도 드래프트 상태로 의견을 받고 확정할 계획입니다. 작업에 참고 부탁드리겠습니다. https://www.notion.so/furiosa/Draft-C-FFI-Style-Guide-in-Rust-d61d160500e741b3b54dfbcd5a1bb7be

bg-furiosa commented 11 months ago

Golang에서만 사용할것을 가정하며 Device-API의 모든 기능을 binding하지 않습니다. 추후 필요에 따라 확장해나갈 예정입니다만 근시일(1년+) 내에는 이 이상의 기능을 필요로 하지 않을거 같습니다.

C API 패턴 초기 설계시 많은 고민이 있었는대요, 결론만 말씀드리면 Rust의 API 패턴을 그대로 따라가기로 결정하였습니다.

Rust FFI에서 한번에 모든정보를 모아서 하나의 구조체로 넘겨주면 C를 사용하는 입장에서는 편할거 같습니다. 다만 그렇게 하기위해선 Rust의 FFI구현에서 여러 정보를 어그리게이션해서 하나의 구조체에 담아 넘겨주는 부분을 구현해주어야 하고 FFI 바운더리 밖(C Stack)에서 해당 구조체 메모리를 정리해주거나 Rust에서 Destroy FFI함수를 제공해주어야 합니다. 메모리 정리 측면에서 Rust에서 할당한 메모리를 FFI 바운더리 밖에서 정리할 경우 Rust내부에서 미처 정리되지 않은 메모리가 있일수 있기떄문에 많이 사용되지않는것으로 보입니다. 대부분의 경우 특정 오브젝트의 raw pointer를 handle형태로 외부로 내보내고 Rust로 다시 가지고와 원본 형태로 변환후 drop을 시키는 방식을 사용합니다. 이런 방향으로 진행하게 되면 Rust FFI에서 구현해야 하는 범위가 넓어지는대요, Rust FFI함수를 구현하면서 느낀점은, Rust의 장점은 사용하지 못하고 C의 단점을(Raw pointer, unsafe등등) Rust내부로 가지고 오는것으로 보여 이러한 부분을 최소화 하기 위해서 Rust API 패턴을 그대로 사용하기로 결정하였습니다. 이 이외에도 Native Rust API변화에 쉽게 대응하거나 Go<->C<->Rust 이렇게 세가지 언어 스택을 거쳐갈때 메모리 관련 이슈등이 발생하였을떄 분석하는대 들어가는 비용을 줄이기 위해 간결한 구조를 가져가기 위함도 있습니다. 덤으로 python바인딩과 일관성을 유지하기 위한 측면도 있구요.

bg-furiosa commented 11 months ago

그리고 Rust FFI에서 한가지 구조체에 여러 정보를 어그리게이션 해서 FFI외부로 보내고 받으려면 결국 모든 정보를 한군대 담을수 있는 Output Struct를 정의해서 바운더리 넘어로 주고 받아야 하는대요, API를 보시는 것처럼 배열을 가리키는 포인터 형태로 반환 해야하는 경우가 많습니다. Destroy함수에서 간결한 input validation을 유지하기 위해선 Output Struct사용을 지양하는게 좋다는 판단도 있었습니다.