summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/opentelemetry-cpp/api/test/common
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/jaegertracing/opentelemetry-cpp/api/test/common
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/api/test/common')
-rw-r--r--src/jaegertracing/opentelemetry-cpp/api/test/common/BUILD41
-rw-r--r--src/jaegertracing/opentelemetry-cpp/api/test/common/CMakeLists.txt15
-rw-r--r--src/jaegertracing/opentelemetry-cpp/api/test/common/kv_properties_test.cc235
-rw-r--r--src/jaegertracing/opentelemetry-cpp/api/test/common/spinlock_benchmark.cc152
-rw-r--r--src/jaegertracing/opentelemetry-cpp/api/test/common/string_util_test.cc47
5 files changed, 490 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/common/BUILD b/src/jaegertracing/opentelemetry-cpp/api/test/common/BUILD
new file mode 100644
index 000000000..5bfc1115d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/api/test/common/BUILD
@@ -0,0 +1,41 @@
+load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")
+
+otel_cc_benchmark(
+ name = "spinlock_benchmark",
+ srcs = ["spinlock_benchmark.cc"],
+ tags = [
+ "api",
+ "test",
+ ],
+ deps = ["//api"],
+)
+
+cc_test(
+ name = "kv_properties_test",
+ srcs = [
+ "kv_properties_test.cc",
+ ],
+ tags = [
+ "api",
+ "test",
+ ],
+ deps = [
+ "//api",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "string_util_test",
+ srcs = [
+ "string_util_test.cc",
+ ],
+ tags = [
+ "api",
+ "test",
+ ],
+ deps = [
+ "//api",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/common/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/api/test/common/CMakeLists.txt
new file mode 100644
index 000000000..5816b64b1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/api/test/common/CMakeLists.txt
@@ -0,0 +1,15 @@
+include(GoogleTest)
+
+foreach(testname kv_properties_test string_util_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX common.
+ TEST_LIST ${testname})
+endforeach()
+
+add_executable(spinlock_benchmark spinlock_benchmark.cc)
+target_link_libraries(spinlock_benchmark benchmark::benchmark
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api)
diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/common/kv_properties_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/common/kv_properties_test.cc
new file mode 100644
index 000000000..e5d9a2439
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/api/test/common/kv_properties_test.cc
@@ -0,0 +1,235 @@
+
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <gtest/gtest.h>
+#include <opentelemetry/common/kv_properties.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+// ------------------------- Entry class tests ---------------------------------
+
+using namespace opentelemetry;
+using opentelemetry::common::KeyValueProperties;
+// Test constructor that takes a key-value pair
+TEST(EntryTest, KeyValueConstruction)
+{
+ opentelemetry::nostd::string_view key = "test_key";
+ opentelemetry::nostd::string_view val = "test_value";
+ KeyValueProperties::Entry e(key, val);
+
+ EXPECT_EQ(key.size(), e.GetKey().size());
+ EXPECT_EQ(key, e.GetKey());
+
+ EXPECT_EQ(val.size(), e.GetValue().size());
+ EXPECT_EQ(val, e.GetValue());
+}
+
+// Test copy constructor
+TEST(EntryTest, Copy)
+{
+ KeyValueProperties::Entry e("test_key", "test_value");
+ KeyValueProperties::Entry copy(e);
+ EXPECT_EQ(copy.GetKey(), e.GetKey());
+ EXPECT_EQ(copy.GetValue(), e.GetValue());
+}
+
+// Test assignment operator
+TEST(EntryTest, Assignment)
+{
+ KeyValueProperties::Entry e("test_key", "test_value");
+ KeyValueProperties::Entry empty;
+ empty = e;
+ EXPECT_EQ(empty.GetKey(), e.GetKey());
+ EXPECT_EQ(empty.GetValue(), e.GetValue());
+}
+
+TEST(EntryTest, SetValue)
+{
+ KeyValueProperties::Entry e("test_key", "test_value");
+ opentelemetry::nostd::string_view new_val = "new_value";
+ e.SetValue(new_val);
+
+ EXPECT_EQ(new_val.size(), e.GetValue().size());
+ EXPECT_EQ(new_val, e.GetValue());
+}
+
+// ------------------------- KeyValueStringTokenizer tests ---------------------------------
+
+using opentelemetry::common::KeyValueStringTokenizer;
+using opentelemetry::common::KeyValueStringTokenizerOptions;
+
+TEST(KVStringTokenizer, SinglePair)
+{
+ bool valid_kv;
+ nostd::string_view key, value;
+ opentelemetry::nostd::string_view str = "k1=v1";
+ KeyValueStringTokenizerOptions opts;
+ KeyValueStringTokenizer tk(str, opts);
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_TRUE(valid_kv);
+ EXPECT_EQ(key, "k1");
+ EXPECT_EQ(value, "v1");
+ EXPECT_FALSE(tk.next(valid_kv, key, value));
+}
+
+TEST(KVStringTokenizer, AcceptEmptyEntries)
+{
+ bool valid_kv;
+ nostd::string_view key, value;
+ opentelemetry::nostd::string_view str = ":k1=v1::k2=v2: ";
+ KeyValueStringTokenizerOptions opts;
+ opts.member_separator = ':';
+ opts.ignore_empty_members = false;
+
+ KeyValueStringTokenizer tk(str, opts);
+ EXPECT_TRUE(tk.next(valid_kv, key, value)); // empty pair
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_TRUE(valid_kv);
+ EXPECT_EQ(key, "k1");
+ EXPECT_EQ(value, "v1");
+ EXPECT_TRUE(tk.next(valid_kv, key, value)); // empty pair
+ EXPECT_EQ(key, "");
+ EXPECT_EQ(value, "");
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_TRUE(tk.next(valid_kv, key, value)); // empty pair
+ EXPECT_FALSE(tk.next(valid_kv, key, value));
+}
+
+TEST(KVStringTokenizer, ValidPairsWithEmptyEntries)
+{
+ opentelemetry::nostd::string_view str = "k1:v1===k2:v2==";
+ bool valid_kv;
+ nostd::string_view key, value;
+ KeyValueStringTokenizerOptions opts;
+ opts.member_separator = '=';
+ opts.key_value_separator = ':';
+
+ KeyValueStringTokenizer tk(str, opts);
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_TRUE(valid_kv);
+ EXPECT_EQ(key, "k1");
+ EXPECT_EQ(value, "v1");
+
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_TRUE(valid_kv);
+ EXPECT_EQ(key, "k2");
+ EXPECT_EQ(value, "v2");
+
+ EXPECT_FALSE(tk.next(valid_kv, key, value));
+}
+
+TEST(KVStringTokenizer, InvalidPairs)
+{
+ opentelemetry::nostd::string_view str = "k1=v1,invalid ,, k2=v2 ,invalid";
+ KeyValueStringTokenizer tk(str);
+ bool valid_kv;
+ nostd::string_view key, value;
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+
+ EXPECT_TRUE(valid_kv);
+ EXPECT_EQ(key, "k1");
+ EXPECT_EQ(value, "v1");
+
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_FALSE(valid_kv);
+
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_TRUE(valid_kv);
+ EXPECT_EQ(key, "k2");
+ EXPECT_EQ(value, "v2");
+
+ EXPECT_TRUE(tk.next(valid_kv, key, value));
+ EXPECT_FALSE(valid_kv);
+
+ EXPECT_FALSE(tk.next(valid_kv, key, value));
+}
+
+TEST(KVStringTokenizer, NumTokens)
+{
+ struct
+ {
+ const char *input;
+ size_t expected;
+ } testcases[] = {{"k1=v1", 1},
+ {" ", 1},
+ {"k1=v1,k2=v2,k3=v3", 3},
+ {"k1=v1,", 1},
+ {"k1=v1,k2=v2,invalidmember", 3},
+ {"", 0}};
+ for (auto &testcase : testcases)
+ {
+ KeyValueStringTokenizer tk(testcase.input);
+ EXPECT_EQ(tk.NumTokens(), testcase.expected);
+ }
+}
+
+//------------------------- KeyValueProperties tests ---------------------------------
+
+TEST(KeyValueProperties, PopulateKVIterableContainer)
+{
+ std::vector<std::pair<std::string, std::string>> kv_pairs = {{"k1", "v1"}, {"k2", "v2"}};
+
+ auto kv_properties = KeyValueProperties(kv_pairs);
+ EXPECT_EQ(kv_properties.Size(), 2);
+
+ std::string value;
+ bool present = kv_properties.GetValue("k1", value);
+ EXPECT_TRUE(present);
+ EXPECT_EQ(value, "v1");
+
+ present = kv_properties.GetValue("k2", value);
+ EXPECT_TRUE(present);
+ EXPECT_EQ(value, "v2");
+}
+
+TEST(KeyValueProperties, AddEntry)
+{
+ auto kv_properties = KeyValueProperties(1);
+ kv_properties.AddEntry("k1", "v1");
+ std::string value;
+ bool present = kv_properties.GetValue("k1", value);
+ EXPECT_TRUE(present);
+ EXPECT_EQ(value, "v1");
+
+ kv_properties.AddEntry("k2", "v2"); // entry will not be added as max size reached.
+ EXPECT_EQ(kv_properties.Size(), 1);
+ present = kv_properties.GetValue("k2", value);
+ EXPECT_FALSE(present);
+}
+
+TEST(KeyValueProperties, GetValue)
+{
+ auto kv_properties = KeyValueProperties(1);
+ kv_properties.AddEntry("k1", "v1");
+ std::string value;
+ bool present = kv_properties.GetValue("k1", value);
+ EXPECT_TRUE(present);
+ EXPECT_EQ(value, "v1");
+
+ present = kv_properties.GetValue("k3", value);
+ EXPECT_FALSE(present);
+}
+
+TEST(KeyValueProperties, GetAllEntries)
+{
+ std::vector<std::pair<std::string, std::string>> kv_pairs = {
+ {"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}};
+ const size_t kNumPairs = 3;
+ opentelemetry::nostd::string_view keys[kNumPairs] = {"k1", "k2", "k3"};
+ opentelemetry::nostd::string_view values[kNumPairs] = {"v1", "v2", "v3"};
+ auto kv_properties = KeyValueProperties(kv_pairs);
+
+ size_t index = 0;
+ kv_properties.GetAllEntries(
+ [&keys, &values, &index](nostd::string_view key, nostd::string_view value) {
+ EXPECT_EQ(key, keys[index]);
+ EXPECT_EQ(value, values[index]);
+ index++;
+ return true;
+ });
+
+ EXPECT_EQ(index, kNumPairs);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/common/spinlock_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/api/test/common/spinlock_benchmark.cc
new file mode 100644
index 000000000..07579579c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/api/test/common/spinlock_benchmark.cc
@@ -0,0 +1,152 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/common/spin_lock_mutex.h"
+
+#include <benchmark/benchmark.h>
+#include <mutex>
+
+namespace
+{
+using opentelemetry::common::SpinLockMutex;
+
+constexpr int TightLoopLocks = 10000;
+
+// Runs a thrash-test where we spin up N threads, each of which will
+// attempt to lock-mutate-unlock a total of `TightLoopLocks` times.
+//
+// lock: A lambda denoting how to lock. Accepts a reference to `SpinLockType`.
+// unlock: A lambda denoting how to unlock. Accepts a reference to `SpinLockType`.
+template <typename SpinLockType, typename LockF, typename UnlockF>
+inline void SpinThrash(benchmark::State &s, SpinLockType &spinlock, LockF lock, UnlockF unlock)
+{
+ auto num_threads = s.range(0);
+ // Value we will increment, fighting over a spinlock.
+ // The contention is meant to be brief, as close to our expected
+ // use cases of "updating pointers" or "pushing an event onto a buffer".
+ std::int64_t value = 0;
+
+ std::vector<std::thread> threads;
+ threads.reserve(num_threads);
+
+ // Timing loop
+ for (auto _ : s)
+ {
+ for (auto i = 0; i < num_threads; i++)
+ {
+ threads.emplace_back([&] {
+ // Increment value once each time the lock is acquired. Spin a few times
+ // to ensure maximum thread contention.
+ for (int i = 0; i < TightLoopLocks; i++)
+ {
+ lock(spinlock);
+ value++;
+ unlock(spinlock);
+ }
+ });
+ }
+ // Join threads
+ for (auto &thread : threads)
+ thread.join();
+ threads.clear();
+ }
+}
+
+// Benchmark of full spin-lock implementation.
+static void BM_SpinLockThrashing(benchmark::State &s)
+{
+ SpinLockMutex spinlock;
+ SpinThrash(
+ s, spinlock, [](SpinLockMutex &m) { m.lock(); }, [](SpinLockMutex &m) { m.unlock(); });
+}
+
+// Naive `while(try_lock()) {}` implementation of lock.
+static void BM_NaiveSpinLockThrashing(benchmark::State &s)
+{
+ SpinLockMutex spinlock;
+ SpinThrash(
+ s, spinlock,
+ [](SpinLockMutex &m) {
+ while (!m.try_lock())
+ {
+ // Left this comment to keep the same format on old and new versions of clang-format
+ }
+ },
+ [](SpinLockMutex &m) { m.unlock(); });
+}
+
+// Simple `while(try_lock()) { yield-processor }`
+static void BM_ProcYieldSpinLockThrashing(benchmark::State &s)
+{
+ SpinLockMutex spinlock;
+ SpinThrash<SpinLockMutex>(
+ s, spinlock,
+ [](SpinLockMutex &m) {
+ while (!m.try_lock())
+ {
+#if defined(_MSC_VER)
+ YieldProcessor();
+#elif defined(__i386__) || defined(__x86_64__)
+# if defined(__clang__)
+ _mm_pause();
+# else
+ __builtin_ia32_pause();
+# endif
+#elif defined(__arm__)
+ __asm__ volatile("yield" ::: "memory");
+#endif
+ }
+ },
+ [](SpinLockMutex &m) { m.unlock(); });
+}
+
+// SpinLock thrashing with thread::yield().
+static void BM_ThreadYieldSpinLockThrashing(benchmark::State &s)
+{
+ std::atomic_flag mutex = ATOMIC_FLAG_INIT;
+ SpinThrash<std::atomic_flag>(
+ s, mutex,
+ [](std::atomic_flag &l) {
+ uint32_t try_count = 0;
+ while (l.test_and_set(std::memory_order_acq_rel))
+ {
+ ++try_count;
+ if (try_count % 32)
+ {
+ std::this_thread::yield();
+ }
+ }
+ std::this_thread::yield();
+ },
+ [](std::atomic_flag &l) { l.clear(std::memory_order_release); });
+}
+
+// Run the benchmarks at 2x thread/core and measure the amount of time to thrash around.
+BENCHMARK(BM_SpinLockThrashing)
+ ->RangeMultiplier(2)
+ ->Range(1, std::thread::hardware_concurrency())
+ ->MeasureProcessCPUTime()
+ ->UseRealTime()
+ ->Unit(benchmark::kMillisecond);
+BENCHMARK(BM_ProcYieldSpinLockThrashing)
+ ->RangeMultiplier(2)
+ ->Range(1, std::thread::hardware_concurrency())
+ ->MeasureProcessCPUTime()
+ ->UseRealTime()
+ ->Unit(benchmark::kMillisecond);
+BENCHMARK(BM_NaiveSpinLockThrashing)
+ ->RangeMultiplier(2)
+ ->Range(1, std::thread::hardware_concurrency())
+ ->MeasureProcessCPUTime()
+ ->UseRealTime()
+ ->Unit(benchmark::kMillisecond);
+BENCHMARK(BM_ThreadYieldSpinLockThrashing)
+ ->RangeMultiplier(2)
+ ->Range(1, std::thread::hardware_concurrency())
+ ->MeasureProcessCPUTime()
+ ->UseRealTime()
+ ->Unit(benchmark::kMillisecond);
+
+} // namespace
+
+BENCHMARK_MAIN();
diff --git a/src/jaegertracing/opentelemetry-cpp/api/test/common/string_util_test.cc b/src/jaegertracing/opentelemetry-cpp/api/test/common/string_util_test.cc
new file mode 100644
index 000000000..da2e63511
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/api/test/common/string_util_test.cc
@@ -0,0 +1,47 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <gtest/gtest.h>
+#include <opentelemetry/common/string_util.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+// ------------------------- StringUtil class tests ---------------------------------
+
+using opentelemetry::common::StringUtil;
+
+TEST(StringUtilTest, TrimStringWithIndex)
+{
+ struct
+ {
+ const char *input;
+ const char *expected;
+ } testcases[] = {{"k1=v1", "k1=v1"}, {"k1=v1,k2=v2, k3=v3", "k1=v1,k2=v2, k3=v3"},
+ {" k1=v1", "k1=v1"}, {"k1=v1 ", "k1=v1"},
+ {" k1=v1 ", "k1=v1"}, {" ", ""}};
+ for (auto &testcase : testcases)
+ {
+ EXPECT_EQ(StringUtil::Trim(testcase.input, 0, strlen(testcase.input) - 1), testcase.expected);
+ }
+}
+
+TEST(StringUtilTest, TrimString)
+{
+ struct
+ {
+ const char *input;
+ const char *expected;
+ } testcases[] = {{"k1=v1", "k1=v1"},
+ {"k1=v1,k2=v2, k3=v3", "k1=v1,k2=v2, k3=v3"},
+ {" k1=v1", "k1=v1"},
+ {"k1=v1 ", "k1=v1"},
+ {" k1=v1 ", "k1=v1"},
+ {" ", ""},
+ {"", ""}};
+ for (auto &testcase : testcases)
+ {
+ EXPECT_EQ(StringUtil::Trim(testcase.input), testcase.expected);
+ }
+}