Skip to content

Commit

Permalink
opt: try to optimize cgo
Browse files Browse the repository at this point in the history
  • Loading branch information
liuq19 committed Mar 6, 2024
1 parent 589cb58 commit 672f332
Show file tree
Hide file tree
Showing 16 changed files with 1,394 additions and 40 deletions.
3 changes: 1 addition & 2 deletions dev/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ linux_x86:
mkdir -p ./rs_wrapper/lib/linux
cd rs_wrapper && cargo update --package sonic-rs && RUSTFLAGS="-C target-cpu=haswell" cargo build --target=x86_64-unknown-linux-gnu --release && cp -a target/x86_64-unknown-linux-gnu/release/librs_wrapper.a ./lib/linux/libsonic_rs_x86_64-unknown-linux-gnu.a


linux_aarch64:
mkdir -p ./rs_wrapper/lib/linux
cd rs_wrapper && cargo update --package sonic-rs && RUSTFLAGS="-C target-feature=+neon" cargo build --target=aarch64-unknown-linux-gnu --release && cp -a target/aarch64-unknown-linux-gnu/release/librs_wrapper.a ./lib/linux/libsonic_rs_aarch64-unknown-linux-gnu.a
cd rs_wrapper && cargo update --package sonic-rs && RUSTFLAGS="-C target-feature=+neon" cargo build --target=aarch64-unknown-linux-gnu --release && cp -a target/aarch64-unknown-linux-gnu/release/librs_wrapper.so ../internal/link/librs_wrapper.so && cp -a target/aarch64-unknown-linux-gnu/release/librs_wrapper.so ./lib/linux/libsonic_rs_aarch64-unknown-linux-gnu.so

darwin_x86:
mkdir -p ./rs_wrapper/lib/darwin
Expand Down
84 changes: 84 additions & 0 deletions dev/ccall/asm.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

#include "go_asm.h"
#include "funcdata.h"
#include "textflag.h"

/*
This function should only used in user goroutine, it will spin the P until finish.
TODO: support signal
func __c_systemstack_1arg(
arg unsafe.Pointer
fn unsafe.Pointer
) uintptr
*/
TEXT ·__c_systemstack_1arg(SB), NOSPLIT, $16-24
MOVD arg0+0(FP), R0
MOVD fn+8(FP), R1
MOVD 48(g), R2 // R2 = g.m
MOVD 0(R2), R3 // R3 = m.g0

// store caller's fp and lr
STP (R29, R30), 16(RSP)

// switch to g0
MOVD R3, g
MOVD 0x38(g), R4 // g_sched+gobuf_sp

// call cb in system stack
MOVD RSP, R29 // mov fp, sp
MOVD R4, RSP
WORD $0xd63f0020 // blr x2

// restore sp
MOVD R29, RSP // mov sp, fp

// restore caller's fp and lr
LDP 16(RSP), (R29, R30)

// back to usrg
MOVD 0x30(g), R2 // R2 = g_m
MOVD 0xc0(R2), g // g = m_curg

// restore ret
MOVD R0, ret+16(FP)
RET


/*
This function should only used in user goroutine, it will spin the P until finish.
func __c_systemstack_1arg(
arg unsafe.Pointer
fn unsafe.Pointer
) uintptr
*/
TEXT ·__c_systemstack_2arg(SB), NOSPLIT, $16-24
MOVD arg0+0(FP), R0
MOVD fn+8(FP), R1
MOVD 48(g), R2 // R2 = g.m
MOVD 0(R2), R3 // R3 = m.g0

// store caller's fp and lr
STP (R29, R30), 16(RSP)

// switch to g0
MOVD R3, g
MOVD 0x38(g), R4 // g_sched+gobuf_sp

// call cb in system stack
MOVD RSP, R29 // mov fp, sp
MOVD R4, RSP
WORD $0xd63f0020 // blr x2

// restore sp
MOVD R29, RSP // mov sp, fp

// restore caller's fp and lr
LDP 16(RSP), (R29, R30)

// back to usrg
MOVD 0x30(g), R2 // R2 = g_m
MOVD 0xc0(R2), g // g = m_curg

// restore ret
MOVD R0, ret+16(FP)
RET
17 changes: 17 additions & 0 deletions dev/ccall/ccall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ccall

import (
"unsafe"
)

//go:nosplit
func C_systemstack_1arg(arg0 uintptr, callback unsafe.Pointer) uintptr {
return __c_systemstack_1arg(arg0, callback)

// TODO: keepalive
}

//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __c_systemstack_1arg(arg0 uintptr, callback unsafe.Pointer) uintptr
11 changes: 11 additions & 0 deletions dev/internal/link/blob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package link


import (
_ "embed"
)

//go:embed librs_wrapper.so

Check failure on line 8 in dev/internal/link/blob.go

View workflow job for this annotation

GitHub Actions / build (1.17.x)

pattern librs_wrapper.so: no matching files found

Check failure on line 8 in dev/internal/link/blob.go

View workflow job for this annotation

GitHub Actions / build (1.18.x)

pattern librs_wrapper.so: no matching files found

Check failure on line 8 in dev/internal/link/blob.go

View workflow job for this annotation

GitHub Actions / build (1.19.x)

pattern librs_wrapper.so: no matching files found

Check failure on line 8 in dev/internal/link/blob.go

View workflow job for this annotation

GitHub Actions / build (1.20.x)

pattern librs_wrapper.so: no matching files found

Check failure on line 8 in dev/internal/link/blob.go

View workflow job for this annotation

GitHub Actions / build (1.21.x)

pattern librs_wrapper.so: no matching files found
var sonic_rs_blob []byte


40 changes: 40 additions & 0 deletions dev/internal/link/dlopen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// +build cgo

package link

// #cgo LDFLAGS: -ldl
// #include <dlfcn.h>
import "C"
import "unsafe"

func DlOpen(filename string, flags int32) unsafe.Pointer {
handle := C.dlopen(C.CString(filename), C.int(flags))
if handle == nil {
panic("dlopen failed")
}
return handle
}

func DlClose(handle unsafe.Pointer) int32 {
ret := int32(C.dlclose(handle))
if ret != 0 {
panic("dlcolse failed")
}
return ret
}

func DlSym(handle unsafe.Pointer, symbol string) unsafe.Pointer {
addr := C.dlsym(handle, C.CString(symbol))
if addr == nil {
panic(DlError())
}
return addr
}

func DlError() (err string) {
cerr := C.dlerror()
if cerr != nil {
err = C.GoString(cerr)
}
return
}
30 changes: 30 additions & 0 deletions dev/internal/link/link.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package link

import (
"fmt"
"unsafe"
"os"
)

func Link(blob []byte, names []string) []unsafe.Pointer {
tmpFile, err := os.CreateTemp("/tmp", "libsonic-blob*.so")
defer os.Remove(tmpFile.Name())
if err != nil {
fmt.Println("unable to create temp files:", err)
return nil
}

if _, err := tmpFile.Write(blob); err != nil {
fmt.Println("unable to write temp file:", err)
return nil
}
handle := DlOpen(tmpFile.Name(), 2 /* RTLD_NOW */)

cfuncs := make([]unsafe.Pointer, len(names))
for i, sym := range(names) {
cfuncs[i] = DlSym(handle, sym)
}
return cfuncs
}

func AddPcSp()
50 changes: 50 additions & 0 deletions dev/internal/link/link_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package link


import (
"testing"
"unsafe"
"github.com/bytedance/sonic/dev/ccall"
"github.com/bytedance/sonic/dev/internal"
)


var cfunc unsafe.Pointer


func init() {
cfuncs := Link(sonic_rs_blob, []string{"func_1args"});
ret := ccall.C_systemstack_1arg(123, cfuncs[0])
cfunc = cfuncs[0]
println("ret is ", ret);
}

func Testx(t *testing.T) {

}


func BenchmarkFfi(b *testing.B) {
r1 := internal.Cgo_func(123)
r2 := ccall.C_systemstack_1arg(123, cfunc)
if r1 != r2 || r1 != 123 {
panic("invalid tests")
}
b.Run("Cgo", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = internal.Cgo_func(123)
}
})

b.Run("Ccall", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ccall.C_systemstack_1arg(123, cfunc)
}
})

b.Run("Asm2Asm", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ccall.C_systemstack_1arg(123, cfunc)
}
})
}
43 changes: 23 additions & 20 deletions dev/internal/sonic_rs.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
_ "github.com/davecgh/go-spew/spew"
)

func Cgo_func(arg uintptr) uintptr {
return uintptr(C.func_1args(C.size_t(arg)))
}

var parse_func func(data string, opt uint64) (Dom, error)
var delete_func func(*Dom)
Expand Down Expand Up @@ -107,29 +110,29 @@ func (arr Array) Len() int {
}

func Delete(dom *Dom) {
// C.sonic_rs_ffi_free(dom.cdom.dom, dom.cdom.str_buf, dom.cdom.error_msg_cap)
C.sonic_rs_ffi_free(dom.cdom.dom, dom.cdom.str_buf, dom.cdom.error_msg_cap)
}

func Parse(data string, opt uint64) (Dom, error) {
// var s = (*reflect.StringHeader)((unsafe.Pointer)(&data))
// cdom := C.sonic_rs_ffi_parse((*C.char)(unsafe.Pointer((s.Data))), C.size_t(s.Len), C.uint64_t(opt))
// runtime.KeepAlive(data)
// ret := Dom{
// cdom: cdom,
// }

// // parse error
// if offset := int64(cdom.error_offset); offset != -1 {
// msg := C.GoStringN(cdom.error_msg, C.int(cdom.error_msg_len))
// err := newError(msg, offset)
// ret.Delete()
// return ret, err
// }

// return ret, nil
return Dom{
cdom: C.Document {},
}, nil
var s = (*reflect.StringHeader)((unsafe.Pointer)(&data))
cdom := C.sonic_rs_ffi_parse((*C.char)(unsafe.Pointer((s.Data))), C.size_t(s.Len), C.uint64_t(opt))
runtime.KeepAlive(data)
ret := Dom{
cdom: cdom,
}

// parse error
if offset := int64(cdom.error_offset); offset != -1 {
msg := C.GoStringN(cdom.error_msg, C.int(cdom.error_msg_len))
err := newError(msg, offset)
ret.Delete()
return ret, err
}

return ret, nil
// return Dom{
// cdom: C.Document {},
// }, nil
}

// / Helper functions to eliminate CGO calls
Expand Down
4 changes: 3 additions & 1 deletion dev/rs_wrapper/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ build/


!lib/linux/*.a
!lib/darwin/*.a
!lib/darwin/*.a
!lib/linux/*.so
!lib/darwin/*.so
6 changes: 1 addition & 5 deletions dev/rs_wrapper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,4 @@ incremental = false
overflow-checks = false

[lib]
# If you only wanted dynamic library, you'd use only "cdylib".
# If you only wanted static library, you'd use only "staticlib".
# This demo shows both. See https://doc.rust-lang.org/reference/linkage.html
# for more information.
crate-type = ["staticlib"]
crate-type = ["cdylib"]
4 changes: 3 additions & 1 deletion dev/rs_wrapper/include/sonic_rs.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
#include "types.h"

Document sonic_rs_ffi_parse(const char *input, size_t len, uint64_t config);
void sonic_rs_ffi_free(void* dom, const char* msg, uint64_t msg_cap);
size_t sonic_rs_ffi_free(void* dom, const char* msg, uint64_t msg_cap);
// only used to tests
size_t func_1args(size_t arg);
Binary file modified dev/rs_wrapper/lib/linux/libsonic_rs_aarch64-unknown-linux-gnu.a
Binary file not shown.
Binary file not shown.
29 changes: 19 additions & 10 deletions dev/rs_wrapper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,24 @@ pub unsafe extern "C" fn sonic_rs_ffi_parse(json: *const u8, len: usize, config:
/// # Safety
/// FFI wrapper.
#[no_mangle]
pub unsafe extern "C" fn sonic_rs_ffi_free(dom: *mut Document, msg: *mut u8, msg_cap: u64) {
unsafe {
if !dom.is_null() {
drop(Box::from_raw(dom));
}
pub unsafe extern "C" fn sonic_rs_ffi_free(dom: *mut Document, msg: *mut u8, msg_cap: u64) -> usize {
// println!("dom is {}", dom as usize);

if !msg.is_null() {
let s = String::from_raw_parts(msg, 0, msg_cap as usize);
drop(s);
}
}
// unsafe {
// if !dom.is_null() {
// drop(Box::from_raw(dom));
// }

// if !msg.is_null() {
// let s = String::from_raw_parts(msg, 0, msg_cap as usize);
// drop(s);
// }
// }
return dom as usize;
}


#[no_mangle]
pub unsafe extern "C" fn func_1args(arg: usize) -> usize {
return arg
}
Loading

0 comments on commit 672f332

Please sign in to comment.