Making the documentation generation a bit more performant

Outsource the file writing to a second thread to start the rendering earlier
This commit is contained in:
Alexander Bock
2020-08-21 14:10:33 +02:00
parent 83622ce339
commit 15e6b5519f
7 changed files with 151 additions and 63 deletions
@@ -31,6 +31,7 @@
#include <openspace/util/touch.h>
#include <openspace/util/versionchecker.h>
#include <ghoul/glm.h>
#include <future>
#include <memory>
#include <string>
#include <vector>
@@ -127,6 +128,8 @@ private:
//grabs json from each module to pass to the documentation engine.
std::string _documentationJson;
std::future<void> _writeDocumentationTask;
ShutdownInformation _shutdown;
// The first frame might take some more time in the update loop, so we need to know to
+1 -1
View File
@@ -291,7 +291,7 @@ public:
*/
void removeTag(const std::string& tag);
//Generate JSON for documentation
// Generate JSON for documentation
std::string generateJson() const override;
@@ -29,6 +29,7 @@
#include <openspace/documentation/verifier.h>
#include <ghoul/fmt.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/profiling.h>
#include <fstream>
@@ -194,6 +195,8 @@ std::vector<Documentation> DocumentationEngine::documentations() const {
void DocumentationEngine::writeDocumentationHtml(const std::string& path,
std::string data)
{
ZoneScoped
std::ifstream handlebarsInput;
handlebarsInput.exceptions(~std::ofstream::goodbit);
handlebarsInput.open(absPath(HandlebarsFilename));
+24 -4
View File
@@ -83,6 +83,7 @@
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
#include <glbinding/glbinding.h>
#include <glbinding-aux/types_to_string.h>
#include <future>
#include <numeric>
#include <sstream>
@@ -852,7 +853,7 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
runGlobalCustomizationScripts();
writeSceneDocumentation();
_writeDocumentationTask = std::async(&OpenSpaceEngine::writeSceneDocumentation, this);
LTRACE("OpenSpaceEngine::loadSingleAsset(end)");
}
@@ -1013,6 +1014,18 @@ void OpenSpaceEngine::writeSceneDocumentation() {
std::string path = global::configuration.documentation.path;
if (!path.empty()) {
std::future<std::string> root = std::async(
&properties::PropertyOwner::generateJson,
&global::rootPropertyOwner
);
std::future<std::string> scene = std::async(
&properties::PropertyOwner::generateJson,
_scene.get()
);
path = absPath(path) + "/";
_documentationJson += "{\"name\":\"Keybindings\",\"identifier\":\"";
_documentationJson += global::keybindingManager.jsonName() + "\",";
@@ -1026,11 +1039,11 @@ void OpenSpaceEngine::writeSceneDocumentation() {
_documentationJson += "},";
_documentationJson += "{\"name\":\"Scene Properties\",";
_documentationJson += "\"identifier\":\"propertylist";// + _scene->jsonName();
_documentationJson += "\",\"data\":" + global::rootPropertyOwner.generateJson();
_documentationJson += "\",\"data\":" + root.get();
_documentationJson += "},";
_documentationJson += "{\"name\":\"Scene Graph Information\",";
_documentationJson += "\"identifier\":\"propertylist";
_documentationJson += "\",\"data\":" + _scene->generateJson();
_documentationJson += "\",\"data\":" + scene.get();
_documentationJson += "}";
//add templates for the jsons we just registered
@@ -1149,7 +1162,14 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
const bool updated = _assetManager->update();
if (updated) {
writeSceneDocumentation();
if (_writeDocumentationTask.valid()) {
// If there still is a documentation creation task the previous frame, we need
// to wait for it to finish first, or else we might write to the same file
_writeDocumentationTask.wait();
}
_writeDocumentationTask = std::async(
&OpenSpaceEngine::writeSceneDocumentation, this
);
}
if (!global::windowDelegate.isMaster()) {
+3
View File
@@ -27,6 +27,7 @@
#include <openspace/engine/globals.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/misc/profiling.h>
#include <ghoul/glm.h>
#include <sstream>
@@ -170,6 +171,8 @@ KeybindingManager::keyBindings() const
}
std::string KeybindingManager::generateJson() const {
ZoneScoped
std::stringstream json;
json << "[";
bool first = true;
+114 -57
View File
@@ -35,6 +35,111 @@
namespace {
constexpr const char* _loggerCat = "PropertyOwner";
std::string escapedJson(const std::string& text) {
std::string jsonString;
for (const char& c : text) {
switch (c) {
case '\t':
jsonString += "\\t"; // Replace tab with \t.
break;
case '"':
jsonString += "\\\""; // Replace " with \".
break;
case '\\':
jsonString += "\\\\"; // Replace \ with \\.
break;
case '\n':
jsonString += "\\\\n"; // Replace newline with \n.
break;
case '\r':
jsonString += "\\r"; // Replace carriage return with \r.
break;
default:
jsonString += c;
}
}
return jsonString;
}
void createJson(openspace::properties::PropertyOwner* owner, std::vector<char>& buf) {
ZoneScoped
using namespace openspace;
constexpr const char* replStr = R"("{}": "{}")";
//std::stringstream json;
//json << "{";
buf.push_back('{');
//json << fmt::format(replStr, "name", owner->identifier()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "name", owner->identifier());
buf.push_back(',');
constexpr const char propertiesText[] = "\"properties\": [";
//constexpr const std::array<char, 16> propertiesText = { "\"properties\": [" };
buf.insert(buf.end(), std::begin(propertiesText), std::end(propertiesText) - 1);
//json << "\"properties\": [";
const std::vector<properties::Property*>& properties = owner->properties();
for (properties::Property* p : properties) {
//json << "{";
buf.push_back('{');
//json << fmt::format(replStr, "id", p->identifier()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "id", p->identifier());
buf.push_back(',');
//json << fmt::format(replStr, "type", p->className()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "type", p->className());
buf.push_back(',');
//json << fmt::format(
// replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
//) << ",";
fmt::format_to(
std::back_inserter(buf),
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
);
buf.push_back(',');
//json << fmt::format(replStr, "guiName", p->guiName()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "guiName", p->guiName());
buf.push_back(',');
//json << fmt::format(replStr, "description", escapedJson(p->description()));
fmt::format_to(
std::back_inserter(buf),
replStr, "description", escapedJson(p->description())
);
//json << "}";
buf.push_back('}');
if (p != properties.back()) {
//json << ",";
buf.push_back(',');
}
}
//json << "],";
buf.push_back(']');
buf.push_back(',');
constexpr const char propertyOwnersText[] = "\"propertyOwners\": [";
//constexpr const std::array<char, 20> propertyOwnersText = { "\"propertyOwners\": [" };
//json << "\"propertyOwners\": [";
buf.insert(buf.end(), std::begin(propertyOwnersText), std::end(propertyOwnersText) - 1);
auto propertyOwners = owner->propertySubOwners();
for (properties::PropertyOwner* o : propertyOwners) {
createJson(o, buf);
//json << createJson(o);
if (o != propertyOwners.back()) {
//json << ",";
buf.push_back(',');
}
}
//json << "]";
buf.push_back(']');
//json << "}";
buf.push_back('}');
//return json.str();
};
} // namespace
namespace openspace::properties {
@@ -356,67 +461,19 @@ void PropertyOwner::removeTag(const std::string& tag) {
}
std::string PropertyOwner::generateJson() const {
std::function<std::string(properties::PropertyOwner*)> createJson =
[&createJson](properties::PropertyOwner* owner) -> std::string
{
constexpr const char* replStr = R"("{}": "{}")";
ZoneScoped
std::stringstream json;
json << "{";
json << fmt::format(replStr, "name", owner->identifier()) << ",";
json << "\"properties\": [";
const std::vector<properties::Property*>& properties = owner->properties();
for (properties::Property* p : properties) {
json << "{";
json << fmt::format(replStr, "id", p->identifier()) << ",";
json << fmt::format(replStr, "type", p->className()) << ",";
json << fmt::format(
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
) << ",";
json << fmt::format(replStr, "guiName", p->guiName()) << ",";
json << fmt::format(replStr, "description", escapedJson(p->description()));
json << "}";
if (p != properties.back()) {
json << ",";
}
}
json << "],";
json << "\"propertyOwners\": [";
auto propertyOwners = owner->propertySubOwners();
for (properties::PropertyOwner* o : propertyOwners) {
json << createJson(o);
if (o != propertyOwners.back()) {
json << ",";
}
}
json << "]";
json << "}";
return json.str();
};
std::stringstream json;
json << "[";
std::vector<char> res;
res.reserve(5 * 51024 * 1024); // 5 MB
res.push_back('[');
std::vector<PropertyOwner*> subOwners = propertySubOwners();
if (!subOwners.empty()) {
json << std::accumulate(
std::next(subOwners.begin()),
subOwners.end(),
createJson(*subOwners.begin()),
[createJson](std::string a, PropertyOwner* n) {
//TODO figure out how to ignore scene when its not the root
//right now will be done on client side
return a + "," + createJson(n);
}
);
for (PropertyOwner* owner : subOwners) {
createJson(owner, res);
res.push_back(',');
}
res.back() = ']';
json << "]";
return json.str();
return std::string(res.begin(), res.end());
}
} // namespace openspace::properties
+3 -1
View File
@@ -28,8 +28,8 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/scene/asset.h>
#include <openspace/scene/assetmanager.h>
#include <ghoul/fmt.h>
#include <ghoul/misc/profiling.h>
#include <sstream>
namespace openspace {
@@ -45,6 +45,8 @@ SceneLicenseWriter::SceneLicenseWriter()
{}
std::string SceneLicenseWriter::generateJson() const {
ZoneScoped
std::stringstream json;
json << "[";