OpenSurgSim list,
We have recently done a performance test (code below) of caching the indices into NamedData, which are the work-horses of DataGroups.
On my Win64 system with strings of length 10, name-based access is about 3-4 times slower than index-based access, and the time per call to NamedData::get is between 11 nanoseconds and 2.4 microseconds. Specifically:
In a Debug build, 2 million calls to NamedData::get (100,000 loops over 20 entries) is taking 4.7 seconds for access by name, vs 1.7 seconds for access by index.
In Release the same code takes 81 milliseconds vs 21 milliseconds, respectively.
Note that in these tests the values may be getting accessed from the cache when they might have been flushed in normal code. For this and other reasons, measured testing times may be lower (i.e., faster) than performance "in the field".
Based on the above numbers for the Release target, 20 calls to NamedData::get would take 0.81 microseconds by name or 0.21 microseconds by index, a difference of 0.6 microsecond. If 1000 Hz is the target update rate then the target period is 1 millisecond, so that difference is three orders of magnitude smaller than the target period.
Based on these results, caching indices from NamedData is considered a low priority and only recommended if indicated by performance analysis.
Sincerely,
Ryan Beasley
Computer Scientist
SimQuest
namespace
{
const std::string array[] =
{"uzgfk1f41V",
"PbpZficBR2",
"M3OYjZgHXX",
"WVIEjG3QaX",
"2o6nN2nuaW",
"3rWXCXR2gi",
"XO2dATxWFq",
"M2xpjE6PAL",
"cT1Bmj3Z1U",
"65UtrrfXn7",
"tNltVIcurd",
"jFVkKzn17i",
"0QlA0FAPc3",
"jCXGBopngK",
"GTwY4YyVnC",
"0uVPK4S9Le",
"iNdq3p6ZQb",
"LfREPeFczN",
"9RKdlFnm1I",
"N2acPVhGY2"};
const std::vector<std::string> names(std::begin(array), std::end(array));
const int numberOfLoops = 100000;
};
namespace SurgSim
{
namespace DataStructures
{
class NamedDataTest : public ::testing::Test
{
public:
virtual void SetUp()
{
NamedDataBuilder<int> builder;
for (std::string name : names)
{
builder.addEntry(name);
}
data = builder.createData();
for (int i = 0; i < names.size(); ++i)
{
ASSERT_TRUE(data.set(i, i));
indices.push_back(i);
}
}
virtual void TearDown()
{
}
NamedData<int> data;
std::vector<int> indices;
};
TEST_F(NamedDataTest, GetByName)
{
int value;
const int numberOfEntries = static_cast<int>(names.size());
SurgSim::Framework::Timer timer;
for (int i = 0; i < numberOfLoops; ++i)
{
for (int j = 0; j < numberOfEntries; ++j)
{
ASSERT_TRUE(data.get(names[j], &value));
}
}
timer.endFrame();
}
TEST_F(NamedDataTest, GetByIndex)
{
int value;
const int numberOfEntries = static_cast<int>(indices.size());
SurgSim::Framework::Timer timer;
for (int i = 0; i < numberOfLoops; ++i)
{
for (int j = 0; j < numberOfEntries; ++j)
{
ASSERT_TRUE(data.get(indices[j], &value));
}
}
timer.endFrame();
}
} // namespace DataStructures
} // namespace SurgSim