blob: 9e08222c94101ab557ebd927851ac6ea0cc8bf23 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <algorithm>
#include <limits>
#include <memory>
#include <thread>
#include <gtest/gtest.h>
#include "bvar/recorder.h"
#include "bvar/reducer.h"
namespace {
struct SelectExtremum {
explicit SelectExtremum(bool select_min) : minimum(select_min) {}
void operator()(int& lhs, int rhs) const {
lhs = minimum ? std::min(lhs, rhs) : std::max(lhs, rhs);
}
bool minimum;
};
TEST(CachedAgentIdTest, unbound_slot_and_stateful_operator) {
typedef bvar::Reducer<int, SelectExtremum> Reducer;
typedef Reducer::combiner_type Combiner;
Reducer first(std::numeric_limits<int>::max(), SelectExtremum(true));
Reducer second(std::numeric_limits<int>::lowest(), SelectExtremum(false));
const bvar::detail::AgentId id = first.share_combiner()->agent_id();
ASSERT_EQ(nullptr, Combiner::get_bound_tls_agent(-1));
ASSERT_NE(nullptr, Combiner::AgentGroup::get_or_create_tls_agent(id));
ASSERT_EQ(nullptr, Combiner::get_bound_tls_agent(id));
first << 12 << 42;
second << 12 << 42;
ASSERT_NE(nullptr, Combiner::get_bound_tls_agent(id));
ASSERT_EQ(12, first.get_value());
ASSERT_EQ(42, second.get_value());
ASSERT_EQ(12, first.reset());
first << 3;
ASSERT_EQ(3, first.get_value());
}
TEST(CachedAgentIdTest, reducer_reuses_expired_slot) {
typedef bvar::Reducer<int, SelectExtremum> Reducer;
typedef Reducer::combiner_type Combiner;
bvar::detail::AgentId id;
{
Reducer old(std::numeric_limits<int>::lowest(), SelectExtremum(false));
id = old.share_combiner()->agent_id();
old << 80;
ASSERT_EQ(80, old.get_value());
}
Reducer fresh(std::numeric_limits<int>::max(), SelectExtremum(true));
ASSERT_EQ(id, fresh.share_combiner()->agent_id());
ASSERT_NE(nullptr, Combiner::AgentGroup::get_tls_agent(id));
ASSERT_EQ(nullptr, Combiner::get_bound_tls_agent(id));
fresh << 100;
ASSERT_EQ(100, fresh.get_value());
fresh << -20;
ASSERT_EQ(-20, fresh.get_value());
}
TEST(CachedAgentIdTest, retained_reducer_combiner_keeps_id_alive) {
typedef bvar::Reducer<int, SelectExtremum> Reducer;
typedef Reducer::combiner_type Combiner;
Combiner::self_shared_type held;
bvar::detail::AgentId id;
{
Reducer old(std::numeric_limits<int>::lowest(), SelectExtremum(false));
held = old.share_combiner();
id = held->agent_id();
old << 80;
}
Reducer other(std::numeric_limits<int>::max(), SelectExtremum(true));
ASSERT_NE(id, other.share_combiner()->agent_id());
other << 5;
ASSERT_EQ(80, held->combine_agents());
ASSERT_EQ(5, other.get_value());
held.reset();
Reducer fresh(std::numeric_limits<int>::lowest(), SelectExtremum(false));
ASSERT_EQ(id, fresh.share_combiner()->agent_id());
fresh << 6;
ASSERT_EQ(6, fresh.get_value());
}
#if !WITH_BABYLON_COUNTER
TEST(CachedAgentIdTest, recorder_reuses_slot_after_last_owner_releases) {
typedef bvar::IntRecorder::combiner_type Combiner;
Combiner::self_shared_type held;
bvar::detail::AgentId id;
{
bvar::IntRecorder old;
held = old.share_combiner();
id = held->agent_id();
old << 80;
}
bvar::IntRecorder other;
ASSERT_NE(id, other.share_combiner()->agent_id());
other << 5;
ASSERT_EQ(80, held->combine_agents().sum);
ASSERT_EQ(1, held->combine_agents().num);
held.reset();
bvar::IntRecorder fresh;
ASSERT_EQ(id, fresh.share_combiner()->agent_id());
ASSERT_NE(nullptr, Combiner::AgentGroup::get_tls_agent(id));
ASSERT_EQ(nullptr, Combiner::get_bound_tls_agent(id));
fresh << 6 << 7;
ASSERT_EQ(13, fresh.get_value().sum);
ASSERT_EQ(2, fresh.get_value().num);
ASSERT_EQ(13, fresh.reset().sum);
fresh << -4;
ASSERT_EQ(-4, fresh.get_value().sum);
ASSERT_EQ(1, fresh.get_value().num);
}
TEST(CachedAgentIdTest, fresh_threads_initialize_and_commit_on_exit) {
typedef bvar::IntRecorder::combiner_type RecorderCombiner;
typedef bvar::Adder<int64_t>::combiner_type AdderCombiner;
bvar::IntRecorder recorder;
bvar::Adder<int64_t> adder;
const auto recorder_id = recorder.share_combiner()->agent_id();
const auto adder_id = adder.share_combiner()->agent_id();
std::thread workers[8];
for (auto& worker : workers) {
worker = std::thread([&] {
EXPECT_EQ(nullptr,
RecorderCombiner::get_bound_tls_agent(recorder_id));
EXPECT_EQ(nullptr,
AdderCombiner::get_bound_tls_agent(adder_id));
for (int i = 0; i < 10000; ++i) {
recorder << 3;
adder << 2;
}
});
}
for (auto& worker : workers) {
worker.join();
}
ASSERT_EQ(80000, recorder.get_value().num);
ASSERT_EQ(240000, recorder.get_value().sum);
ASSERT_EQ(160000, adder.get_value());
}
#endif // !WITH_BABYLON_COUNTER
} // namespace