Performance Requirements

We have a performance challenge. Our product owner indicates that we expect a large volume of users. The initial release should support tracking 50,000 users simultaneously.

We write a test that emulates scaling up to large numbers of users.

c9/3/GeoServerTest.cpp
 
TEST(AGeoServer_UsersInBox, HandlesLargeNumbersOfUsers) {
 
Location anotherLocation{aUserLocation.go(10, West)};
 
const​ ​unsigned​ ​int​ lots {500000};
 
for​ (​unsigned​ ​int​ i{0}; i < lots; i++) {
 
string​ user{​"user"​ + to_string(i)};
 
server.track(user);
 
server.updateLocation(user, anotherLocation);
 
}
 
 
auto​ users = server.usersInBox(aUser, Width, Height);
 
CHECK_EQUAL(lots, users.size());
 
}

When we run our tests, we notice a pause while CppUTest executes HandlesLargeNumbersOfUsers, perhaps a second and a half. While that doesn’t seem long, that’s one test. In a system where you’ll eventually have thousands of tests, a measly few dozen slow tests will dissuade you from running them as frequently as you must. We don’t want to run the slow HandlesLargeNumbersOfUsers test as part of our fast test suite. Still, we will likely want to run it in the future. When we’re done mucking with it, our best bet will be to move HandlesLargeNumbersOfUsers to a different test executable that runs slow tests.

Our code certainly seems slow, but are we certain it’s too slow? We rerun our tests using the -v option of CppUTest.

 
build/utest -v

Output from the test run confirms that our new test is the culprit.

 
TEST(ALocation, ProvidesPrintableRepresentation) - 0 ms
 
TEST(ALocation, IsNotVeryCloseToAnotherWhenNotSmallDistanceApart) - 0 ms
 
TEST(ALocation, IsVeryCloseToAnotherWhenSmallDistanceApart) - 0 ms
 
TEST(ALocation, CanBeAPole) - 0 ms
 
TEST(ALocation, AnswersNewLocationGivenDistanceAndBearingVerifiedByHaversine) - 0 ms
 
TEST(ALocation, AnswersNewLocationGivenDistanceAndBearing) - 0 ms
 
TEST(ALocation, IsNotEqualToAnotherWhenLatAndLongMatch) - 0 ms
 
TEST(ALocation, IsNotEqualToAnotherWhenLongDiffers) - 0 ms
 
TEST(ALocation, IsNotEqualToAnotherWhenLatDiffers) - 0 ms
 
TEST(ALocation, AnswersDistanceFromAnotherInMeters) - 0 ms
 
TEST(ALocation, IsUnknownWhenLatitudeAndLongitudeNotProvided) - 0 ms
 
TEST(ALocation, IsNotUnknownWhenLatitudeAndLongitudeProvided) - 0 ms
 
TEST(ALocation, AnswersLatitudeAndLongitude) - 0 ms
*
TEST(AGeoServer_UsersInBox, HandlesLargeNumbersOfUsers) - 1689 ms
 
TEST(AGeoServer_UsersInBox, AnswersOnlyUsersWithinSpecifiedRange) - 0 ms
 
# ... (results of other tests omitted)
 
 
OK (39 tests, 39 ran, 49 checks, 0 ignored, 0 filtered out, 1798 ms)

Still, we don’t know that the actual call to usersInBox is a problem. Perhaps the Arrange portion of the test that tracks and updates the location for half a million users is the problem. We need a more granular measurement.

As a temporary probe, we declare an instance of an RAII timer in the test HandlesLargeNumbersOfUsers. Refer to TDD and Performance for further information about the home-grown TestTimer class.

c9/4/GeoServerTest.cpp
 
TEST(AGeoServer_UsersInBox, HandlesLargeNumbersOfUsers) {
 
Location anotherLocation{aUserLocation.go(10, West)};
 
const​ ​unsigned​ ​int​ lots {500000};
 
for​ (​unsigned​ ​int​ i{0}; i < lots; i++) {
 
string​ user{​"user"​ + to_string(i)};
 
server.track(user);
 
server.updateLocation(user, anotherLocation);
 
}
 
*
TestTimer timer;
 
auto​ users = server.usersInBox(aUser, Width, Height);
 
 
CHECK_EQUAL(lots, users.size());
 
}

Our probe tells us that the call to usersInBox takes a bit longer than 200ms on average (we run the tests a few times just to make sure).

 
...​..........
 
HandlesLargeNumbersOfUsers elapsed time = 219.971ms
 
...​.......................
 
OK (39 tests, 39 ran, 49 checks, 0 ignored, 0 filtered out, 1823 ms)

We remind ourselves that this information is relative and could change dramatically when run on a different machine. But it’s enough to suggest there could be a problem.

While 200ms isn’t nearly as bad as a second and a half, our product owner is unhappy with the results. We get together with her and discuss options. Together, we derive a new story that should support our need to scale.

Story: Retrieving Nearby Users Is an Asynchronous Request

As a client user, I expect the “retrieve nearby users” request to respond almost immediately. I want to receive each element from the list of nearby users asynchronously so that I can display each on the map as I receive it.

You might have learned that stories shouldn’t be technical. That guideline exists to prevent the creation of stories that do not provide verifiable value to the business. Tasks such as “creating the database tables” or “upgrading compiler version” might be essential, but you should execute them only in the context of a business need. Our story necessarily discusses a solution in technical terms, but it does represent a feature that delivers demonstrable and verifiable business value.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.134.133