Skip to content

Commit e1a38bc

Browse files
Abseil Teamcopybara-github
Abseil Team
authored andcommitted
Reland: Optimize Google Test process startup
Google Test performs hidden test registration during process startup. For test binaries that contain a large number of tests, this registration can be costly. In this CL, we reduce the overhead of registration via several tactics: - Treat CodeLocation and FilePath as value types, using std::move to pass them around. - Reduce string copies in various places by either passing std::string values via std::move, or passing const-refs to std::string instances. - Use std::to_string to stringify an int in DefaultParamName rather than a std::stringstream. - Pull some std::string instances out of nested loops in ParameterizedTestSuiteInfo::RegisterTests so as to reuse some allocations, and replace stringstream with ordinary string appends. - Use std::unordered_map in UnitTestImpl::GetTestSuite and ParameterizedTestSuiteRegistry::GetTestSuitePatternHolder to spend a little memory to turn O(N) lookups into constant time lookpus. - Use range-based for loops in a few places. - Use emplace-ish methods to add to containers where appropriate. All together, these changes reduce the overall runtime of a series of 50 death tests in a single Chromium test executable by ~38% due to the fact that the registration costs are paid in every death test's child process. PiperOrigin-RevId: 613833210 Change-Id: I51a262a770edff98ffa1e3b60c4d78a8308f9a9f
1 parent 31993df commit e1a38bc

File tree

6 files changed

+141
-144
lines changed

6 files changed

+141
-144
lines changed

googletest/include/gtest/gtest.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -607,15 +607,15 @@ class GTEST_API_ TestInfo {
607607
friend class internal::UnitTestImpl;
608608
friend class internal::StreamingListenerTest;
609609
friend TestInfo* internal::MakeAndRegisterTestInfo(
610-
const char* test_suite_name, const char* name, const char* type_param,
610+
std::string test_suite_name, const char* name, const char* type_param,
611611
const char* value_param, internal::CodeLocation code_location,
612612
internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc,
613613
internal::TearDownTestSuiteFunc tear_down_tc,
614614
internal::TestFactoryBase* factory);
615615

616616
// Constructs a TestInfo object. The newly constructed instance assumes
617617
// ownership of the factory object.
618-
TestInfo(const std::string& test_suite_name, const std::string& name,
618+
TestInfo(std::string test_suite_name, std::string name,
619619
const char* a_type_param, // NULL if not a type-parameterized test
620620
const char* a_value_param, // NULL if not a value-parameterized test
621621
internal::CodeLocation a_code_location,
@@ -683,7 +683,7 @@ class GTEST_API_ TestSuite {
683683
// this is not a type-parameterized test.
684684
// set_up_tc: pointer to the function that sets up the test suite
685685
// tear_down_tc: pointer to the function that tears down the test suite
686-
TestSuite(const char* name, const char* a_type_param,
686+
TestSuite(const std::string& name, const char* a_type_param,
687687
internal::SetUpTestSuiteFunc set_up_tc,
688688
internal::TearDownTestSuiteFunc tear_down_tc);
689689

googletest/include/gtest/internal/gtest-filepath.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
4444

4545
#include <string>
46+
#include <utility>
4647

4748
#include "gtest/internal/gtest-port.h"
4849
#include "gtest/internal/gtest-string.h"
@@ -70,15 +71,20 @@ class GTEST_API_ FilePath {
7071
public:
7172
FilePath() : pathname_("") {}
7273
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) {}
74+
FilePath(FilePath&& rhs) : pathname_(std::move(rhs.pathname_)) {}
7375

74-
explicit FilePath(const std::string& pathname) : pathname_(pathname) {
76+
explicit FilePath(std::string pathname) : pathname_(std::move(pathname)) {
7577
Normalize();
7678
}
7779

7880
FilePath& operator=(const FilePath& rhs) {
7981
Set(rhs);
8082
return *this;
8183
}
84+
FilePath& operator=(FilePath&& rhs) {
85+
pathname_ = std::move(rhs.pathname_);
86+
return *this;
87+
}
8288

8389
void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; }
8490

googletest/include/gtest/internal/gtest-internal.h

+12-17
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,8 @@ using SetUpTestSuiteFunc = void (*)();
474474
using TearDownTestSuiteFunc = void (*)();
475475

476476
struct CodeLocation {
477-
CodeLocation(const std::string& a_file, int a_line)
478-
: file(a_file), line(a_line) {}
477+
CodeLocation(std::string a_file, int a_line)
478+
: file(std::move(a_file)), line(a_line) {}
479479

480480
std::string file;
481481
int line;
@@ -564,7 +564,7 @@ struct SuiteApiResolver : T {
564564
// The newly created TestInfo instance will assume
565565
// ownership of the factory object.
566566
GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
567-
const char* test_suite_name, const char* name, const char* type_param,
567+
std::string test_suite_name, const char* name, const char* type_param,
568568
const char* value_param, CodeLocation code_location,
569569
TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
570570
TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory);
@@ -595,8 +595,7 @@ class GTEST_API_ TypedTestSuitePState {
595595
fflush(stderr);
596596
posix::Abort();
597597
}
598-
registered_tests_.insert(
599-
::std::make_pair(test_name, CodeLocation(file, line)));
598+
registered_tests_.emplace(test_name, CodeLocation(file, line));
600599
return true;
601600
}
602601

@@ -700,7 +699,7 @@ class TypeParameterizedTest {
700699
// specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite,
701700
// Types). Valid values for 'index' are [0, N - 1] where N is the
702701
// length of Types.
703-
static bool Register(const char* prefix, const CodeLocation& code_location,
702+
static bool Register(const char* prefix, CodeLocation code_location,
704703
const char* case_name, const char* test_names, int index,
705704
const std::vector<std::string>& type_names =
706705
GenerateNames<DefaultNameGenerator, Types>()) {
@@ -712,8 +711,7 @@ class TypeParameterizedTest {
712711
// list.
713712
MakeAndRegisterTestInfo(
714713
(std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name +
715-
"/" + type_names[static_cast<size_t>(index)])
716-
.c_str(),
714+
"/" + type_names[static_cast<size_t>(index)]),
717715
StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
718716
GetTypeName<Type>().c_str(),
719717
nullptr, // No value parameter.
@@ -725,21 +723,17 @@ class TypeParameterizedTest {
725723
new TestFactoryImpl<TestClass>);
726724

727725
// Next, recurses (at compile time) with the tail of the type list.
728-
return TypeParameterizedTest<Fixture, TestSel,
729-
typename Types::Tail>::Register(prefix,
730-
code_location,
731-
case_name,
732-
test_names,
733-
index + 1,
734-
type_names);
726+
return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>::
727+
Register(prefix, std::move(code_location), case_name, test_names,
728+
index + 1, type_names);
735729
}
736730
};
737731

738732
// The base case for the compile time recursion.
739733
template <GTEST_TEMPLATE_ Fixture, class TestSel>
740734
class TypeParameterizedTest<Fixture, TestSel, internal::None> {
741735
public:
742-
static bool Register(const char* /*prefix*/, const CodeLocation&,
736+
static bool Register(const char* /*prefix*/, CodeLocation,
743737
const char* /*case_name*/, const char* /*test_names*/,
744738
int /*index*/,
745739
const std::vector<std::string>& =
@@ -786,7 +780,8 @@ class TypeParameterizedTestSuite {
786780

787781
// Next, recurses (at compile time) with the tail of the test list.
788782
return TypeParameterizedTestSuite<Fixture, typename Tests::Tail,
789-
Types>::Register(prefix, code_location,
783+
Types>::Register(prefix,
784+
std::move(code_location),
790785
state, case_name,
791786
SkipComma(test_names),
792787
type_names);

0 commit comments

Comments
 (0)