-- f825cf3feb6db06522b2b4ee785de7dfa325780d by Martijn Vels <mvels@google.com>: Move Cordz test helpers to cordz_test_helpers library PiperOrigin-RevId: 370059941 -- 5080249da6a4f5cc2b546aed48503fd028670379 by Martijn Vels <mvels@google.com>: Add new Cordz instrumentation on AppendTree. PiperOrigin-RevId: 369968167 -- 21092b889fad34ec605894e311b436d5f417456f by Benjamin Barenblat <bbaren@google.com>: Round floats using round(x), not static_cast<int>(x + 0.5) Adding 0.5 to an IEEE float may cause one bit of precision loss, which is enough to change the result in certain cases. For example, static_cast<int>(std::round(0.49999999999999994)) == 0 static_cast<int>(0.49999999999999994 + 0.5) == 1 PiperOrigin-RevId: 369926519 GitOrigin-RevId: f825cf3feb6db06522b2b4ee785de7dfa325780d Change-Id: Ib78ce1faec79f06578933db5dc6fc05de043ead1pull/963/head
parent
e38e1aae38
commit
d96e287417
13 changed files with 422 additions and 84 deletions
@ -0,0 +1,92 @@ |
||||
// Copyright 2021 The Abseil Authors
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <string> |
||||
|
||||
#include "gmock/gmock.h" |
||||
#include "gtest/gtest.h" |
||||
#include "absl/base/config.h" |
||||
#include "absl/base/internal/raw_logging.h" |
||||
#include "absl/base/macros.h" |
||||
#include "absl/strings/cord.h" |
||||
#include "absl/strings/cordz_test_helpers.h" |
||||
#include "absl/strings/internal/cordz_functions.h" |
||||
#include "absl/strings/internal/cordz_info.h" |
||||
#include "absl/strings/internal/cordz_sample_token.h" |
||||
#include "absl/strings/internal/cordz_statistics.h" |
||||
#include "absl/strings/internal/cordz_update_tracker.h" |
||||
#include "absl/strings/str_cat.h" |
||||
#include "absl/strings/string_view.h" |
||||
|
||||
#ifdef ABSL_INTERNAL_CORDZ_ENABLED |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
|
||||
using cord_internal::CordzInfo; |
||||
using cord_internal::CordzSampleToken; |
||||
using cord_internal::CordzStatistics; |
||||
using cord_internal::CordzUpdateTracker; |
||||
using Method = CordzUpdateTracker::MethodIdentifier; |
||||
|
||||
namespace { |
||||
|
||||
std::string MakeString(int length) { |
||||
std::string s(length, '.'); |
||||
for (int i = 4; i < length; i += 2) { |
||||
s[i] = '\b'; |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
TEST(CordzTest, ConstructSmallStringView) { |
||||
CordzSamplingIntervalHelper sample_every(1); |
||||
Cord cord(absl::string_view(MakeString(50))); |
||||
EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); |
||||
} |
||||
|
||||
TEST(CordzTest, ConstructLargeStringView) { |
||||
CordzSamplingIntervalHelper sample_every(1); |
||||
Cord cord(absl::string_view(MakeString(5000))); |
||||
EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); |
||||
} |
||||
|
||||
TEST(CordzTest, CopyConstruct) { |
||||
CordzSamplingIntervalHelper sample_every(1); |
||||
Cord src = UnsampledCord(MakeString(5000)); |
||||
Cord cord(src); |
||||
EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorCord)); |
||||
} |
||||
|
||||
TEST(CordzTest, AppendLargeCordToEmpty) { |
||||
CordzSamplingIntervalHelper sample_every(1); |
||||
Cord cord; |
||||
Cord src = UnsampledCord(MakeString(5000)); |
||||
cord.Append(src); |
||||
EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAppendCord)); |
||||
} |
||||
|
||||
TEST(CordzTest, MoveAppendLargeCordToEmpty) { |
||||
CordzSamplingIntervalHelper sample_every(1); |
||||
Cord cord; |
||||
cord.Append(UnsampledCord(MakeString(5000))); |
||||
EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAppendCord)); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_INTERNAL_CORDZ_ENABLED
|
@ -0,0 +1,129 @@ |
||||
// Copyright 2021 The Abseil Authors
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef ABSL_STRINGS_CORDZ_TEST_HELPERS_H_ |
||||
#define ABSL_STRINGS_CORDZ_TEST_HELPERS_H_ |
||||
|
||||
#include "gmock/gmock.h" |
||||
#include "gtest/gtest.h" |
||||
#include "absl/base/config.h" |
||||
#include "absl/base/macros.h" |
||||
#include "absl/strings/cord.h" |
||||
#include "absl/strings/internal/cord_internal.h" |
||||
#include "absl/strings/internal/cordz_info.h" |
||||
#include "absl/strings/internal/cordz_sample_token.h" |
||||
#include "absl/strings/internal/cordz_statistics.h" |
||||
#include "absl/strings/internal/cordz_update_tracker.h" |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
|
||||
// Returns the CordzInfo for the cord, or nullptr if the cord is not sampled.
|
||||
inline const cord_internal::CordzInfo* GetCordzInfoForTesting( |
||||
const Cord& cord) { |
||||
return cord.contents_.cordz_info(); |
||||
} |
||||
|
||||
// Returns true if the provided cordz_info is in the list of sampled cords.
|
||||
inline bool CordzInfoIsListed(const cord_internal::CordzInfo* cordz_info, |
||||
cord_internal::CordzSampleToken token = {}) { |
||||
for (const cord_internal::CordzInfo& info : token) { |
||||
if (cordz_info == &info) return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
// Matcher on Cord that verifies all of:
|
||||
// - the cord is sampled
|
||||
// - the CordzInfo of the cord is listed / discoverable.
|
||||
// - the reported CordzStatistics match the cord's actual properties
|
||||
// - the cord has an (initial) UpdateTracker count of 1 for `method`
|
||||
MATCHER_P(HasValidCordzInfoOf, method, "CordzInfo matches cord") { |
||||
const cord_internal::CordzInfo* cord_info = GetCordzInfoForTesting(arg); |
||||
if (cord_info == nullptr) { |
||||
*result_listener << "cord is not sampled"; |
||||
return false; |
||||
} |
||||
if (!CordzInfoIsListed(cord_info)) { |
||||
*result_listener << "cord is sampled, but not listed"; |
||||
return false; |
||||
} |
||||
cord_internal::CordzStatistics stat = cord_info->GetCordzStatistics(); |
||||
if (stat.size != arg.size()) { |
||||
*result_listener << "cordz size " << stat.size |
||||
<< " does not match cord size " << arg.size(); |
||||
return false; |
||||
} |
||||
if (stat.update_tracker.Value(method) != 1) { |
||||
*result_listener << "Expected method count 1 for " << method << ", found " |
||||
<< stat.update_tracker.Value(method); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// Cordz will only update with a new rate once the previously scheduled event
|
||||
// has fired. When we disable Cordz, a long delay takes place where we won't
|
||||
// consider profiling new Cords. CordzSampleIntervalHelper will burn through
|
||||
// that interval and allow for testing that assumes that the average sampling
|
||||
// interval is a particular value.
|
||||
class CordzSamplingIntervalHelper { |
||||
public: |
||||
explicit CordzSamplingIntervalHelper(int32_t interval) |
||||
: orig_mean_interval_(absl::cord_internal::get_cordz_mean_interval()) { |
||||
absl::cord_internal::set_cordz_mean_interval(interval); |
||||
absl::cord_internal::cordz_set_next_sample_for_testing(interval); |
||||
} |
||||
|
||||
~CordzSamplingIntervalHelper() { |
||||
absl::cord_internal::set_cordz_mean_interval(orig_mean_interval_); |
||||
absl::cord_internal::cordz_set_next_sample_for_testing(orig_mean_interval_); |
||||
} |
||||
|
||||
private: |
||||
int32_t orig_mean_interval_; |
||||
}; |
||||
|
||||
// Wrapper struct managing a small CordRep `rep`
|
||||
struct TestCordRep { |
||||
cord_internal::CordRepFlat* rep; |
||||
|
||||
TestCordRep() { |
||||
rep = cord_internal::CordRepFlat::New(100); |
||||
rep->length = 100; |
||||
memset(rep->Data(), 1, 100); |
||||
} |
||||
~TestCordRep() { cord_internal::CordRep::Unref(rep); } |
||||
}; |
||||
|
||||
// Wrapper struct managing a small CordRep `rep`, and
|
||||
// an InlineData `data` initialized with that CordRep.
|
||||
struct TestCordData { |
||||
TestCordRep rep; |
||||
cord_internal::InlineData data{rep.rep}; |
||||
}; |
||||
|
||||
// Creates a Cord that is not sampled
|
||||
template <typename... Args> |
||||
Cord UnsampledCord(Args... args) { |
||||
CordzSamplingIntervalHelper never(9999); |
||||
Cord cord(std::forward<Args>(args)...); |
||||
ABSL_ASSERT(GetCordzInfoForTesting(cord) == nullptr); |
||||
return cord; |
||||
} |
||||
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_STRINGS_CORDZ_TEST_HELPERS_H_
|
Loading…
Reference in new issue