Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Deliver libddprof_ffi as a shared library #22

Merged
merged 10 commits into from
Feb 15, 2022

Conversation

nsavoire
Copy link
Contributor

@nsavoire nsavoire commented Feb 8, 2022

What does this PR do?

  • Deliver libddprof_ffi as a shared library
  • Activate LTO and reduce number of codegen units to 1
  • Add a simple exporter example executable

Motivation

Some clients prefer having a shared library rather than a static one.

@@ -8,7 +8,9 @@ edition = "2018"
license = "Apache-2.0"

[lib]
crate-type = ["lib", "staticlib"]
# LTO is ignored if "lib" is added as crate type
# cf. https://github.com/rust-lang/rust/issues/51009
Copy link
Contributor

Choose a reason for hiding this comment

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

nice referencing this

@@ -30,6 +31,7 @@ case "$target" in
"x86_64-apple-darwin")
expected_native_static_libs=" -framework Security -liconv -lSystem -lresolv -lc -lm -liconv"
native_static_libs="${expected_native_static_libs}"
shared_library_suffix=".dylib"
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for checking the mac os builds !

@@ -14,3 +14,5 @@ debug = 2 # full debug info

[profile.release]
debug = 1 # line tables only
lto = true
codegen-units = 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this something we want to put in the cargo config, or could we not make sure to have it as a command line argument in the CI ?
I'm thinking we dan't want to slow all of our build times. Only the build time to generate the github release.
WDYT ?

Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed, locally we will use the develop profile. We can leave the release profile optimised for size.

@@ -46,6 +48,10 @@ sed < ddprof_ffi.pc.in "s/@DDProf_FFI_VERSION@/${version}/g" \
| sed "s/@DDProf_FFI_LIBRARIES@/${native_static_libs}/g" \
> "$destdir/lib/pkgconfig/ddprof_ffi.pc"
Copy link
Collaborator

Choose a reason for hiding this comment

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

The concept of "native static libs" doesn't apply to a shared object. There will be dependencies, of course, but this isn't how we should be populating them for the .so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing this out. I did put them in Libs.private when I had still hope to be able to make a single pkg-config file for both shared and static library, but since I could not do it, it's better to completely remove them for the shared library.

Copy link
Contributor

@r1viollet r1viollet left a comment

Choose a reason for hiding this comment

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

LGTM !

@morrisonlevi
Copy link
Collaborator

The shared library artifact for alpine is suspicious, particularly the runpath:

# readelf -d ./libddprof-x86_64-alpine-linux-musl/lib/libddprof_ffi.so

Dynamic section at offset 0x4cf8f8 contains 24 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.musl-x86_64.so.1]
 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN/:$ORIGIN/../../../../../../../../../../usr/lib/rustlib/x86_64-alpine-linux-musl/lib:/usr/lib/rustlib/x86_64-alpine-linux-musl/lib]

@nsavoire
Copy link
Contributor Author

The shared library artifact for alpine is suspicious, particularly the runpath:

# readelf -d ./libddprof-x86_64-alpine-linux-musl/lib/libddprof_ffi.so

Dynamic section at offset 0x4cf8f8 contains 24 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.musl-x86_64.so.1]
 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN/:$ORIGIN/../../../../../../../../../../usr/lib/rustlib/x86_64-alpine-linux-musl/lib:/usr/lib/rustlib/x86_64-alpine-linux-musl/lib]

Hum, indeed this is strange. But I don't expect this to be an issue, the runpath here is not useful to find dependencies since libddprof_ffi.so depends only on libgcc/libc.
Adding rpath/runpath to cdylib seems specific to alpine-musl:

We could remove runpath from the lib just to be extra cautious. WDYT @morrisonlevi ?

* Reduce number of codegen units to further reduce ouput library size.
* Deliver shared library alongside static library
Create ddprof_ffi-static.pc for linking with static library
@nsavoire nsavoire force-pushed the nsavoire/deliver_shared_library branch 2 times, most recently from b386c52 to a3e8035 Compare February 14, 2022 10:14
@nsavoire nsavoire force-pushed the nsavoire/deliver_shared_library branch from a3e8035 to 06174b3 Compare February 14, 2022 10:36
Copy link
Member

@ivoanjo ivoanjo left a comment

Choose a reason for hiding this comment

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

Thanks for this! I left two tiny notes, and I'll try to wire this up in Ruby and report back with the experience :)

Comment on lines +10 to +20
static ddprof_ffi_ByteSlice to_byteslice(const char *s)
{
return {.ptr = (uint8_t *)s,
.len = strlen(s)};
}

static ddprof_ffi_Slice_c_char to_slice_c_char(const char *s)
{
return {.ptr = s,
.len = strlen(s)};
}
Copy link
Member

Choose a reason for hiding this comment

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

Not related to this PR, but this looks to me as a weird sharp edge in the libddprof API.

It's weird to have both ddprof_ffi_ByteSlice and ddprof_ffi_Slice_c_char when they are effectively the same (?).

Also, I had to write similar helpers for using libddprof, so perhaps it would make sense to export these (possibly as macros?) in ffi.h as well :)

Copy link
Contributor

Choose a reason for hiding this comment

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

You usually don't want to encourage people to transport strings without an actual size associated to it. strlen is also not something you want encourage, so I don't know how I feel about exposing these types of APIs.
I guess we can also mention this :-)

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm... I'm guessing the "don't want to encourage" may be related to performance -- is that the case?

If so, would it make sense to call it something like to_slice_slow? I guess for a bunch of hardcoded strings ("ruby", "wall-clock", "nanoseconds", "service", ...) we just use them once so the cost is trivial so we could have the ease of use 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.

  • I agree there is room for improvements concerning the APIs, we could provide some helpers function like to_slice_xxx on top of FFI headers. Maybe even a more friendly C++ interface.
  • It's strange that slices for type/unit/filename/build_id/name/system_name/... are different from slices used for /tags/filenames.

But this would be subject of another pull request ;)

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't feel super strongly about this, but I would usually avoid relying on C style null terminated strings. Though it is not clear how we could avoid these conversions at boundaries or how to have a common types.

ffi-build.sh Outdated Show resolved Hide resolved
Copy link
Collaborator

@morrisonlevi morrisonlevi left a comment

Choose a reason for hiding this comment

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

Did we check Alpine builds? I remember the compiler telling me it can't make shared libs on Alpine.

@nsavoire
Copy link
Contributor Author

Yes, there is a test in CI that try linking why shared library.
x86_64-unknown-linux-musl refuses to create cdylibs but x86_64-alpine-linux-musl has specific patches to allow it.

@nsavoire nsavoire merged commit ea737a1 into main Feb 15, 2022
@nsavoire nsavoire deleted the nsavoire/deliver_shared_library branch February 15, 2022 16:50
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants