Take a StringPiece when looking up CommandLine switches.
This avoids the string allocation when searching for a char* in a
std::map<std::string>.
CommandLine now maintains a parallel map of StringPieces that reference
the strings in |switches_|. StringPiece is trivial to construct from a
string, and only requires a strlen to construct from a char*.
On a profile with 2 extensions, HasSwitch is called ~12k times during
startup. In an ideal situation (no paging/cache pressure), the
string allocation under Windows takes ~137ns on a Xeon E5-2690 @
2.9Ghz. A strlen on a typical switch takes about 50ns, and 91% of calls
pass a char*, so there's a net saving of at least
(137 - 0.9 * 50)ns * 12k = 1.1ms from a typical startup with this
hardware. For context, Startup.BrowserMessageLoopStartTimeFromMainEntry
is typically 280-300ms on the same hardware, so we should get a ~0.4%
improvement.
BUG=472383
Review URL: https://codereview.chromium.org/1063933002
Cr-Commit-Position: refs/heads/master@{#330902}
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index db1a0b2..018d83f 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -71,7 +72,7 @@
EXPECT_TRUE(cl.HasSwitch("input-translation"));
EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
- EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+ EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
@@ -134,7 +135,7 @@
EXPECT_TRUE(cl.HasSwitch("quotes"));
EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
- EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+ EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
@@ -273,6 +274,7 @@
cl.AppendSwitchASCII(switch2, value2);
cl.AppendSwitchASCII(switch3, value3);
cl.AppendSwitchASCII(switch4, value4);
+ cl.AppendSwitchASCII(switch5, value4);
cl.AppendSwitchNative(switch5, value5);
EXPECT_TRUE(cl.HasSwitch(switch1));
@@ -291,6 +293,9 @@
L"--switch2=value "
L"--switch3=\"a value with spaces\" "
L"--switch4=\"\\\"a value with quotes\\\"\" "
+ // Even though the switches are unique, appending can add repeat
+ // switches to argv.
+ L"--quotes=\"\\\"a value with quotes\\\"\" "
L"--quotes=\"" + kTrickyQuoted + L"\"",
cl.GetCommandLineString());
#endif
@@ -379,4 +384,20 @@
EXPECT_EQ(initial, current);
}
+// Test that copies of CommandLine have a valid StringPiece map.
+TEST(CommandLineTest, Copy) {
+ scoped_ptr<CommandLine> initial(new CommandLine(CommandLine::NO_PROGRAM));
+ initial->AppendSwitch("a");
+ initial->AppendSwitch("bbbbbbbbbbbbbbb");
+ initial->AppendSwitch("c");
+ CommandLine copy_constructed(*initial);
+ CommandLine assigned = *initial;
+ CommandLine::SwitchMap switch_map = initial->GetSwitches();
+ initial.reset();
+ for (const auto& pair : switch_map)
+ EXPECT_TRUE(copy_constructed.HasSwitch(pair.first));
+ for (const auto& pair : switch_map)
+ EXPECT_TRUE(assigned.HasSwitch(pair.first));
+}
+
} // namespace base