Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit 82062bf

Browse files
authored
Don't pass std::string by value to AttributeValueRef() (#41)
This causes an accidental copy of the string, and (with VS2017) frees that string before it's used: #22 * Add benchmarks for AttributeValueRef constructor. * Add tests for StrCat()ed keys and values.
1 parent 5e403e0 commit 82062bf

File tree

4 files changed

+87
-6
lines changed

4 files changed

+87
-6
lines changed

opencensus/trace/BUILD

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,20 @@ cc_test(
269269
# Benchmarks
270270
# ========================================================================= #
271271
#
272+
273+
cc_binary(
274+
name = "attribute_value_ref_benchmark",
275+
testonly = 1,
276+
srcs = ["internal/attribute_value_ref_benchmark.cc"],
277+
copts = TEST_COPTS,
278+
linkopts = ["-pthread"], # Required for absl/synchronization bits.
279+
linkstatic = 1,
280+
deps = [
281+
":trace",
282+
"@com_google_benchmark//:benchmark",
283+
],
284+
)
285+
272286
cc_binary(
273287
name = "span_benchmark",
274288
testonly = 1,

opencensus/trace/attribute_value_ref.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,19 @@ class AttributeValueRef final {
4848
// We provide implicit constructors for string, int, and bool. We work around
4949
// the compiler coercing things like pointers and ints to bool.
5050

51-
// Construct from anything that converts to absl::string_view. Otherwise we
52-
// have to handle const char[] separately.
53-
template <typename T, typename std::enable_if<std::is_constructible<
54-
absl::string_view, T>::value>::type* = nullptr>
55-
AttributeValueRef(T string_value)
56-
: string_value_(absl::string_view(string_value)), type_(Type::kString) {}
51+
// Construct from absl::string_view.
52+
AttributeValueRef(absl::string_view string_value)
53+
: string_value_(string_value), type_(Type::kString) {}
54+
55+
// Construct from C-style string.
56+
AttributeValueRef(const char* string_value)
57+
: string_value_(string_value), type_(Type::kString) {}
58+
59+
// Construct from std::string.
60+
template <typename Allocator>
61+
AttributeValueRef(const std::basic_string<char, std::char_traits<char>,
62+
Allocator>& string_value)
63+
: string_value_(string_value), type_(Type::kString) {}
5764

5865
// Construct from integer. We have to supply this form explicitly because
5966
// otherwise AttributeValueRef(int) is ambiguous between int and bool!
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2018, OpenCensus Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "benchmark/benchmark.h"
16+
#include "opencensus/trace/attribute_value_ref.h"
17+
18+
namespace opencensus {
19+
namespace trace {
20+
namespace {
21+
22+
void BM_ConstructFromLiteral(benchmark::State& state) {
23+
while (state.KeepRunning()) {
24+
benchmark::DoNotOptimize(
25+
AttributeValueRef("literal string, showing no string copy happens"));
26+
}
27+
}
28+
BENCHMARK(BM_ConstructFromLiteral);
29+
30+
void BM_ConstructFromString(benchmark::State& state) {
31+
std::string s(8192, 'a');
32+
while (state.KeepRunning()) {
33+
benchmark::DoNotOptimize(AttributeValueRef(s));
34+
}
35+
}
36+
BENCHMARK(BM_ConstructFromString);
37+
38+
} // namespace
39+
} // namespace trace
40+
} // namespace opencensus
41+
42+
BENCHMARK_MAIN();

opencensus/trace/internal/span_test.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <cstdint>
1818

19+
#include "absl/strings/str_cat.h"
1920
#include "gtest/gtest.h"
2021
#include "opencensus/trace/attribute_value_ref.h"
2122
#include "opencensus/trace/exporter/attribute_value.h"
@@ -174,6 +175,18 @@ TEST(SpanTest, FullSpanTest) {
174175
span.AddAttribute("key2", "value2");
175176
span.AddAttributes({{"key3", "value3"}, {"key4", 123}, {"key5", false}});
176177

178+
// String (as opposed to literal).
179+
std::string val = "value";
180+
val += "6";
181+
span.AddAttribute("key6", val);
182+
183+
// Test that StrCat's output outlives the AddAttribute call.
184+
span.AddAttribute(absl::StrCat("ke", "y7"), absl::StrCat("val", "ue7"));
185+
span.AddAttributes(
186+
{{absl::StrCat("key", "10"), "value10"},
187+
{"key11", absl::StrCat("value", "11")},
188+
{absl::StrCat("key", "12"), absl::StrCat("value", "12")}});
189+
177190
span.AddAnnotation("anno1");
178191
span.AddAnnotation(
179192
"anno2", {{"str_attr", "hello"}, {"int_attr", 123}, {"bool_attr", true}});
@@ -212,6 +225,11 @@ TEST(SpanTest, FullSpanTest) {
212225
EXPECT_EQ("value3", attributes.at("key3").string_value());
213226
EXPECT_EQ(123, attributes.at("key4").int_value());
214227
EXPECT_EQ(false, attributes.at("key5").bool_value());
228+
EXPECT_EQ("value6", attributes.at("key6").string_value());
229+
EXPECT_EQ("value7", attributes.at("key7").string_value());
230+
EXPECT_EQ("value10", attributes.at("key10").string_value());
231+
EXPECT_EQ("value11", attributes.at("key11").string_value());
232+
EXPECT_EQ("value12", attributes.at("key12").string_value());
215233
EXPECT_EQ(attributes.end(), attributes.find("key_invalid"));
216234

217235
EXPECT_EQ(2, data.annotations().events().size());

0 commit comments

Comments
 (0)