Skip to content

Conversation

@maxgolov
Copy link
Contributor

@maxgolov maxgolov commented Aug 12, 2020

This is a summary of changes needed to swap the nostd classes with std:: analogs available in C++14/C++17/C++20.

Motivation

In certain scenarios it may be of benefit to compile the OpenTelemetry SDK from source using standard library container classes (std::map, std::string_view, std::span, std::variant) instead of OpenTelemetry nostd:: analogs (which were backported to C++11 and designed as ABI-stable). This PR also can be used as a foundation for alternate approach - to also allow bindings to abseil classes. That is in environments that would rather prefer Abseil classes over the standard lib or nostd.

The approach is to provide totally opaque (from SDK code / SDK developer perspective) mapping / aliasing from nostd:: classes back to their std:: counterparts, and that is only done in environments where this is possible. We continue fully supporting both models and run CI for both.

Pros and Cons:

  • using standard library implementation classes in customer code and on API surface: certain environments would prefer to have standard instead of non-standard due to security / performance / stability / debug'ability considerations.

  • smaller binary size: no need to marshal types from standard to nostd, then back to standard library. We use standard classes used elsewhere in the app.

  • better performance: no need to transform from 'native' standard library types, e.g. std::map via KeyValueIterable - we can bypass that transformation process when we know that ABI compat is not a requirement. ETA at least 1.5% to 3% better perf since a transform / memcpy is avoided.

Standard Library build flavor works best for statically linking the SDK in a process (environment where ABI compat is not a requirement), or for "header-only" implementation of SDK. We cannot employ this approach for shared libraries in environments where ABI compatibility is required:

  • SDK binary compiled with compiler A + STL B
  • may not be ABI compatible with the main executable compiled with compiler C + STL D on a same OS.
    Thus, this approach works best for statically linking / header only, and may not work for providing 'prebuilt' SDK binary.

What's included in this proposed PR:

  • set of changes to build both flavors of SDK: nostd (OpenTelemetry backport of classes for C++11) vs stl (standard library), plus set of tests to validate both side-by-side.

  • set of changes to validate that all OpenTelemetry functionality is functional irrespective of what library you prefer.

  • aliasing from nostd:: to std:: namespace for compilers C++17 and above.

  • consistent handling of std::variant across various versions of Mac OS X. Backport of a view missing variant features, e.g. std::get and std::visit for older version of Mac OS X. Patches that enable proper handling of std::visit and std::variant irrespective of OS version to resolve this quirk.

  • ability to optionally borrow implementation of C++20 gsl::span from Microsoft Guidelines Support Library. This will no longer necessary for compilers that already natively support C++20.

  • set of tools to locally build the SDK with both options across various OS and compilers, including vs2017, vs2019, ubuntu-18.xx (C++17), ubuntu-20.xx (C++20), Mac OS X - in C++17 mode.

  • a few minor 'logistics` clean-up changes, e.g. a few compiler warning fixes.

maxgolov added 30 commits April 11, 2020 21:10
- add stdtypes.h umbrella header
- move all "optional" headers to nostd/stl
- add optional dependency on GSL for gsl::span
- add build option to build API with/without Standard Library
- improvements to EventSender example
- Visual Studio project for EventSender
- Rename stdtypes.h to stltypes.h to avoid conflict with popular header name
- Resolve an issue with backport of std::size
- Create standalone example of event sender that statically links API+SDK using standard library types
- ETW (EventWriteString in XML format)
- OutputDebugStringA (UTF-8)
- File - plain k-v pairs
- File - JSON

Plus generic framework for adding new stream types and converters.
@maxgolov maxgolov requested a review from a team August 12, 2020 07:05
@codecov
Copy link

codecov bot commented Aug 12, 2020

Codecov Report

Merging #275 into master will increase coverage by 0.04%.
The diff coverage is 97.20%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #275      +/-   ##
==========================================
+ Coverage   94.59%   94.64%   +0.04%     
==========================================
  Files         146      148       +2     
  Lines        6629     6754     +125     
==========================================
+ Hits         6271     6392     +121     
- Misses        358      362       +4     
Impacted Files Coverage Δ
api/include/opentelemetry/nostd/shared_ptr.h 100.00% <ø> (ø)
api/include/opentelemetry/nostd/span.h 89.36% <ø> (+1.36%) ⬆️
api/include/opentelemetry/nostd/string_view.h 100.00% <ø> (+2.63%) ⬆️
api/include/opentelemetry/nostd/unique_ptr.h 100.00% <ø> (ø)
api/include/opentelemetry/nostd/utility.h 83.33% <ø> (ø)
api/include/opentelemetry/nostd/variant.h 96.68% <ø> (ø)
api/include/opentelemetry/trace/noop.h 85.18% <ø> (ø)
api/include/opentelemetry/trace/span.h 100.00% <ø> (ø)
api/include/opentelemetry/trace/tracer.h 100.00% <ø> (ø)
api/test/metrics/noop_metrics_test.cc 88.63% <ø> (ø)
... and 48 more

Copy link
Contributor

@jsuereth jsuereth left a comment

Choose a reason for hiding this comment

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

A bunch of general thoughts and questions.

I appreciate how much work went into this! High level comments:

  1. can we make it explicit in tests/builds what build flags are being used?
  2. Can we document a matrix of build flags we're going to support as well as what the "DEFAULT" release is, where we expect vendors to support ABI.
  3. Is ABSEIL missing from the testing matrix for non MSVC++ compilers? Is it not needed?

Pardon me if I'm asking silly questions, still not 100% ramped up on code structure.

double,
nostd::string_view,
const char *,
#ifdef HAVE_SPAN_BYTE
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 part of this PR or noise?

If so, are there any concerns around this #ifidef causing compatibility issues with dynamic linking SDKs, or are we ONLY using this in a static-linked manner?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsuereth - apologies, I'm gonna send another PR from a separate branch to minimize the 'noise'. My master branch contained changes that I needed for some other flows, e.g. byte array support is needed for my internal customer needs, which is logged as an open issue in OT spec (but not implemented yet).

I'll try to answer your questions in the new PR.

[submodule "third_party/ms-gsl"]
path = "third_party/ms-gsl"
url = https://github.com/microsoft/GSL
branch = master
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be picking a specific version of ms-GSL for those who opt-in to it?

it wasn't clear from the repo how folks understand what version they're using and pull in bug fixes.

additionally, if we want to guarantee any kind of ABI/API compat we probably need to know exactly which version is getting linked in when the flag is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now it's pulling the latest. But since we use submodules - for CMake build we pin-point to specific commit ID. Technically the MS-GSL is only needed for older compilers without C++20 support, i.e. latest-latest Mac and latest gcc-9+ (as well as vs2019 with c++_latest flag) no longer require MS-GSL. As an alternative - I also want to add an option to build with ABSEIL instead of MS-GSL....

Re. pinning in Bazel - I am not sure how to do it. I wonder if we add Abseil, then test the combo of Bazel+Abseil, and CMake+GSL, that'd be covering the most needed build configurations for those who want to build statically. I can add CMake+Abseil build flavor.

option(WITH_STL "Whether to use Standard Library for C++latest features" OFF)

option(WITH_ABSEIL "Whether to use Abseil for C++latest features" OFF)

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: if both option are usable or not usable together, should we call that out?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsuereth - This is complicated, but I'll try to elaborate :)

  • technically Abseil would be best for vs2015 support, because there is no alternate good variant working with vs2015. Only absl::variant works. The one we borrowed from MPark - nostd::variant - does not compile for vs2015, to be more exact - it has problems with complex aggregate variant types.

  • now Abseil actually requires statically linked library of itself, which I 'hacked' - if we only use Abseil for variant and nothing else. Whereas GSL itself is header-only. In certain environments I'd prefer the full set of everything to be built with Standard Library and, preferably, header-only --- not needing Abseil (e.g. if I compile the OpenTelemetry SDK for inclusion in some Azure cloud Service).

So - it's problematic on all accounts everywhere:

  • nostd::variant - the one we have today, is not compiling on vs2015. The only one compiling is absl::variant
  • absl::variant - if used without any hacks, requires Abseil STATIC lib (messy)
  • whereas GSL only has gsl::span and does not have gsl::variant :(

So -- to answer your question, in my setup I would prefer:

  • just a portion of Abseil for absl::variant (but not the entire Abseil) + MS-GSL for span ... whereas
  • Google projects would probably prefer Abseil for everything ... whereas
  • dynamic libs prefer nostd:: classes... except this won't work for vs2015. We may need to borrow just the variant from Abseil, tweak it so that it doesn't require static linking of the core Abseil, and replace MPark (nostd::variant) with Abseil... Which I wanted to do in a separate PR.

add_subdirectory(test)
endif()

if(WITH_STL)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: can we include ABSEIL here too?

static bool Detach(Token &token) noexcept { return ContextHandler()->InternalDetach(token); }

static RuntimeContext *context_handler_;
static inline IRuntimeContext *ContextHandler(IRuntimeContext *context_handler = nullptr)
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 new, and/or part of this PR (or just merge conflict overreporting?)

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'll clean it. Sorry, this is messy - I was showing an alternate implementation of context. I'll resend the PR from a clean branch.

@@ -0,0 +1,63 @@
# Usage example for nostd classes
Copy link
Contributor

Choose a reason for hiding this comment

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

nice writeup!

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'll send this in a separate PR.

"@com_google_googletest//:gtest_main",
],
)
# cc_test(
Copy link
Contributor

Choose a reason for hiding this comment

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

why is this disabled?

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'll reenable it.

const opentelemetry::common::AttributeValue &value)
{

#if 0 // FIXME
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 because of the HAVE_COLLECTIONS flag?

set "CMAKE_GEN=Visual Studio 14 2015 Win64"
cd %~dp0
call setup-buildtools.cmd
call build.cmd -DWITH_ABSEIL:BOOL=ON
Copy link
Contributor

Choose a reason for hiding this comment

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

I wasn't sure what you meant originally around having multiple builds.

I thought you were implying we'd have a matrix of builds

Compiler x ABSEIL_FLAG x STD_FLAG

It looks like, instead, each version of VisualStudio gets a configuration. Do we need to make a visual matrix of that for users? While I definitely want the ability to statically link against STD we should make sure it's obvious which configurations support which and what you get out of the box.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Basically if we want to produce a static lib linkable with anything vs2015|vs2017|vs2019, then it MUST be built using vs2015. This is quite silly linker limitation. For example, if we statically produce a lib with vs2019, then it just won't link with older compilers!!! That's because the latest vs2019 has a bit different exception handling semantics.

I do want to have a matrix doc created.

make
}

build_configuration nostd '-DWITH_STL:BOOL=OFF'
Copy link
Contributor

Choose a reason for hiding this comment

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

do we also need ABSEIL ON/OFF permutations here?

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'll elaborate in the new PR.

@maxgolov maxgolov closed this Oct 26, 2020
GerHobbelt pushed a commit to GerHobbelt/opentelemetry-cpp that referenced this pull request Jun 17, 2025
chore(deps): update ubuntu:24.04 docker digest to 6015f66
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants