high-performance machine gears + Ionic logo + "developers blog"

Enhancing Agent Performance in Machina Tools

SDK Agent Creation Performance

Some SDK users express concern for the overhead of managing Agent objects for bulk file encryption. Agent is a lightweight object, and the most resource-consuming operation in the default initialization case is retrieving profiles from an OS persistor or the disk. However, the agent can be initialized without profiles, and a cached profile object can be added to it making it an extremely lightweight part of the encryption process. Here we’ll analyze the performance of several different scenarios.

Creation Methods

First off, we set up a single ISAgent object outside of our testing loop.

ISAgent agent;
agent.initialize();

Then establish a baseline for some simple non-networked method call.

agent.getDeviceProfileForKeyId("notakey");

10,000 iterations of this took 0.122 seconds

Next, create a new ISAgent object and initialize it without profiles, then add a profile that was stored in a variable earlier.

ISAgent a2;
a2.initializeWithoutProfiles();
a2.addProfile(profile, true);
a2.getDeviceProfileForKeyId("notakey");

10,000 iterations took 2.45 seconds.

The next step is to create a new ISAgent and fully initialize it with the default persistor (the Windows DPAPI persistor for this test).

ISAgent a3;
a3.initialize();
a3.getDeviceProfileForKeyId("notakey");

10,000 iterations took 70.7 seconds.

The final scenario sets up a persistor that uses an encrypted file to compare disk access.

ISAgent a4;
a4.initialize(passwordpersistor);
a4.getDeviceProfileForKeyId("notakey");

10,000 iterations took 105 seconds.

Comparison with network usage

Now let’s consider each of these scenarios in the context of a network call.

First, the single-agent case with a getKey call for a key we previously created.

agent.getKey(keyId, getResponse);

10,000 iterations took 345 seconds

Creating a new agent without profiles and adding a cached profile.

ISAgent a2;
a2.initializeWithoutProfiles();
a2.addProfile(profile, true);
a2.getKey(keyId, getResponse);

10,000 iterations took 336 seconds.

A new agent using the default OS persistor.

ISAgent a3;
a3.initialize();
a3.getKey(keyId, getResponse);

10,000 iterations took 401 seconds.

Using the file-based password persistor.

ISAgent a4;
a4.initialize(passwordPersistor);
a4.getKey(keyId, getResponse);

10,000 iterations took 425 seconds.

For the sake of completeness, each case was tried again with each respective agent being used to initialize an instance of ISChunkCryptoCipherAuto that was then used to decrypt a short string encrypted earlier.

ISChunkCryptoCipherAuto c(agent);
std::string recovered;
c.decrypt(cipher, recovered);

The results for the same 10,000 iterations:

  • Single ISAgent – 321 seconds
  • New ISAgent with cached profile – 344 seconds
  • New ISAgent with default persistor – 365 seconds
  • New ISAgent with password persistor – 389 seconds

Conclusion

You can see that a call to the operating system to retrieve profile data is a reasonably expensive operation even when compared to a network call. In a case where the application architecture does not permit storing the ISAgent object, you can cheaply create a new agent. The ISAgentDeviceProfile object is a simple data holder, and it can be created from strings so long as that data is protected.

The results so far were generated in debug mode. As the results below from a program build in release mode with compiler optimization show, the cost of creating a new agent is even lower in practice. Results may vary slightly based on hardware, but network speed is more or less constant.

Code Example

You can find the source code in the Ionic Github samples repository under AgentAnalysis.cpp. Included is a modified test program that runs all these test cases together and produces prettier output. The results of running that test are included
below.

Windows x64 Release build:

  9999 tests      find     getKey   chunk
Single agent:      0.000  157.391  166.101
Cached profile:    0.084  167.897  173.226
OS persistor:     12.544  178.862  179.063
Password file:    46.457  225.098  224.128