So I am using yaml-cpp
to be able to use yaml for my game data files in c++ however I am running into some major performance issues.
I wanted to test out a somewhat large file so I created some dummy data to write out:
Player newPlayer = Player();
newPlayer.name = "new player";
newPlayer.maximumHealth = 1000;
newPlayer.currentHealth = 1;
Inventory newInventory;
newInventory.maximumWeight = 10.9f;
for (int z = 0; z < 10000; z++) {
InventoryItem* newItem = new InventoryItem();
newItem->name = "Stone";
newItem->baseValue = 1;
newItem->weight = 0.1f;
newInventory.items.push_back(newItem);
}
YAML::Node newSavedGame;
newSavedGame["player"] = newPlayer;
newSavedGame["inventory"] = newInventory;
I then wrote this function to be able to take data and write it out to a file:
void YamlUtility::saveAsFile(YAML::Node node, std::string filePath) {
std::ofstream myfile;
myfile.open(filePath);
myfile << node << std::endl;
myfile.close();
}
Now before I added this code, the memory usage of my game was at about 22MB. After I added the newPlayer
, newInventory
and the the InventoryItems
it went to about 23MB. Then when I added in the YAML::Node newSavedGame
, the memory went up to 108MB. Also the file that is written out is only 570KB so I can't think of why it would spike the memory up by like 85MB.
The second issue is that this code takes about 8 seconds to write the file. That just seemed a bit off to me.
I decide to rewrite the save function using YAML::Emitter
, that code looks like this:
static void buildYamlManually(std::ofstream& file, YAML::Node node) {
YAML::Emitter out;
out << YAML::BeginMap << YAML::Key << "player" << YAML::Value << YAML::BeginMap << YAML::Key << "name" << YAML::Value
<< node["player"]["name"].as<std::string>() << YAML::Key << "maximumHealth" << YAML::Value
<< node["player"]["maximumHealth"].as<int>() << YAML::Key << "currentHealth" << YAML::Value
<< node["player"]["currentHealth"].as<int>() << YAML::EndMap;
out << YAML::BeginSeq;
std::vector<InventoryItem*> items = node["inventory"]["items"].as<std::vector<InventoryItem*>>();
for (InventoryItem* const value : items) {
out << YAML::BeginMap << YAML::Key << "name" << YAML::Value << value->name << YAML::Key << "baseValue"
<< YAML::Value << value->baseValue << YAML::Key << "weight" << YAML::Value << value->weight << YAML::EndMap;
}
out << YAML::EndSeq;
out << YAML::EndMap;
file << out.c_str() << std::endl;
}
This seemed to have a small effect on the performance however it was still closer to 7 seconds to save the file (instead of 8 seconds).
I then decided to just see what it would be like if I wrote the file manually without yaml-cpp
at all, that code looks like this:
static void buildYamlManually(std::ofstream& file, SavedGame savedGame) {
file << "player: \n"
<< " name: " << savedGame.player.name << "\n maximumHealth: " << savedGame.player.maximumHealth
<< "\n currentHealth: " << savedGame.player.currentHealth << "\ninventory:"
<< "\n maximumWeight: " << savedGame.inventory.maximumWeight << "\n items:";
for (InventoryItem* const value : savedGame.inventory.items) {
file << "\n - name: " << value->name << "\n baseValue: " << value->baseValue
<< "\n weight: " << value->weight;
}
}
With this code and all yaml-cpp
code removed, the memory went from 23MB to 24MB and writing the files took about 0.15 seconds.
While I would understand there being some overhead with using yaml-cpp
vs dealing with the file manually just as text, this kind of performance difference just seems wrong.
I want to say I am doing something wrong but based on the yaml-cpp
documentation, I can't see what that might be.