diff --git a/src/Magnum/MeshTools/sceneconverter.cpp b/src/Magnum/MeshTools/sceneconverter.cpp index a86f75fd6..b1d58d492 100644 --- a/src/Magnum/MeshTools/sceneconverter.cpp +++ b/src/Magnum/MeshTools/sceneconverter.cpp @@ -24,7 +24,6 @@ */ #include -#include #include #include #include @@ -187,18 +186,6 @@ using namespace Magnum; namespace { -struct Duration { - explicit Duration(std::chrono::high_resolution_clock::duration& output): _output(output), _t{std::chrono::high_resolution_clock::now()} {} - - ~Duration() { - _output += std::chrono::high_resolution_clock::now() - _t; - } - - private: - std::chrono::high_resolution_clock::duration& _output; - std::chrono::high_resolution_clock::time_point _t; -}; - /** @todo const Array& doesn't work, minmax() would fail to match */ template std::string calculateBounds(Containers::Array&& attribute) { /** @todo clean up when Debug::toString() exists */ @@ -319,7 +306,7 @@ used.)") #if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) Containers::Array mapped; if(args.isSet("map")) { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(mapped = Utility::Directory::mapRead(args.value("input"))) || !importer->openMemory(mapped)) { Error() << "Cannot memory-map file" << args.value("input"); return 3; @@ -327,7 +314,7 @@ used.)") } else #endif { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!importer->openFile(args.value("input"))) { Error() << "Cannot open file" << args.value("input"); return 3; @@ -472,7 +459,7 @@ used.)") if(args.isSet("info") || args.isSet("info-animations")) for(UnsignedInt i = 0; i != importer->animationCount(); ++i) { Containers::Optional animation; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(animation = importer->animation(i))) { error = true; continue; @@ -492,7 +479,7 @@ used.)") if(args.isSet("info") || args.isSet("info-skins")) for(UnsignedInt i = 0; i != importer->skin3DCount(); ++i) { Containers::Optional skin; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(skin = importer->skin3D(i))) { error = true; continue; @@ -512,7 +499,7 @@ used.)") if(args.isSet("info") || args.isSet("info-lights")) for(UnsignedInt i = 0; i != importer->lightCount(); ++i) { Containers::Optional light; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(light = importer->light(i))) { error = true; continue; @@ -538,7 +525,7 @@ used.)") for(UnsignedInt i = 0; i != importer->materialCount(); ++i) { Containers::Optional material; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(material = importer->material(i))) { error = true; continue; @@ -576,7 +563,7 @@ used.)") for(UnsignedInt j = 0; j != importer->meshLevelCount(i); ++j) { Containers::Optional mesh; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(mesh = importer->mesh(i, j))) { error = true; continue; @@ -667,7 +654,7 @@ used.)") for(UnsignedInt i = 0; i != importer->textureCount(); ++i) { Containers::Optional texture; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!(texture = importer->texture(i))) { error = true; continue; @@ -707,7 +694,7 @@ used.)") bool compactImages = false; Containers::Array imageInfos; if(args.isSet("info") || args.isSet("info-images")) { - imageInfos = Trade::Implementation::imageInfo(*importer, error, compactImages); + imageInfos = Trade::Implementation::imageInfo(*importer, error, compactImages, importTime); } for(const SceneInfo& info: sceneInfos) { @@ -982,7 +969,7 @@ used.)") Containers::Optional mesh; { - Duration d{importTime}; + Trade::Implementation::Duration d{importTime}; if(!importer->meshCount() || !(mesh = importer->mesh(args.value("mesh"), args.value("level")))) { Error{} << "Cannot import the mesh"; return 4; @@ -1015,7 +1002,7 @@ used.)") if(args.isSet("remove-duplicates")) { const UnsignedInt beforeVertexCount = mesh->vertexCount(); { - Duration d{conversionTime}; + Trade::Implementation::Duration d{conversionTime}; mesh = MeshTools::removeDuplicates(*std::move(mesh)); } if(args.isSet("verbose")) @@ -1027,7 +1014,7 @@ used.)") if(!args.value("remove-duplicates-fuzzy").empty()) { const UnsignedInt beforeVertexCount = mesh->vertexCount(); { - Duration d{conversionTime}; + Trade::Implementation::Duration d{conversionTime}; mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value("remove-duplicates-fuzzy")); } if(args.isSet("verbose")) @@ -1065,7 +1052,7 @@ used.)") if(converterCount > 1 && args.isSet("verbose")) Debug{} << "Saving output with" << converterName << Debug::nospace << "..."; - Duration d{conversionTime}; + Trade::Implementation::Duration d{conversionTime}; if(!converter->convertToFile(*mesh, args.value("output"))) { Error{} << "Cannot save file" << args.value("output"); return 5; @@ -1085,7 +1072,7 @@ used.)") return 6; } - Duration d{conversionTime}; + Trade::Implementation::Duration d{conversionTime}; if(!(mesh = converter->convert(*mesh))) { Error{} << converterName << "cannot convert the mesh"; return 7; diff --git a/src/Magnum/Trade/Implementation/converterUtilities.h b/src/Magnum/Trade/Implementation/converterUtilities.h index c5f465342..0c59baf95 100644 --- a/src/Magnum/Trade/Implementation/converterUtilities.h +++ b/src/Magnum/Trade/Implementation/converterUtilities.h @@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE. */ +#include #include #include "Magnum/Trade/AbstractImporter.h" @@ -35,6 +36,18 @@ namespace Magnum { namespace Trade { namespace Implementation { /* Used only in executables where we don't want it to be exported */ namespace { +struct Duration { + explicit Duration(std::chrono::high_resolution_clock::duration& output): _output(output), _t{std::chrono::high_resolution_clock::now()} {} + + ~Duration() { + _output += std::chrono::high_resolution_clock::now() - _t; + } + + private: + std::chrono::high_resolution_clock::duration& _output; + std::chrono::high_resolution_clock::time_point _t; +}; + struct ImageInfo { UnsignedInt image, level; bool compressed; @@ -44,7 +57,7 @@ struct ImageInfo { std::string name; }; -Containers::Array imageInfo(AbstractImporter& importer, bool& error, bool& compact) { +Containers::Array imageInfo(AbstractImporter& importer, bool& error, bool& compact, std::chrono::high_resolution_clock::duration& importTime) { Containers::Array infos; for(UnsignedInt i = 0; i != importer.image1DCount(); ++i) { const std::string name = importer.image1DName(i); @@ -52,10 +65,13 @@ Containers::Array imageInfo(AbstractImporter& importer, bool& error, if(!name.empty() || levelCount != 1) compact = false; for(UnsignedInt j = 0; j != levelCount; ++j) { - Containers::Optional image = importer.image1D(i, j); - if(!image) { - error = true; - continue; + Containers::Optional image; + { + Duration d{importTime}; + if(!(image = importer.image1D(i, j))) { + error = true; + continue; + } } arrayAppend(infos, InPlaceInit, i, j, image->isCompressed(), @@ -73,10 +89,13 @@ Containers::Array imageInfo(AbstractImporter& importer, bool& error, if(!name.empty() || levelCount != 1) compact = false; for(UnsignedInt j = 0; j != levelCount; ++j) { - Containers::Optional image = importer.image2D(i, j); - if(!image) { - error = true; - continue; + Containers::Optional image; + { + Duration d{importTime}; + if(!(image = importer.image2D(i, j))) { + error = true; + continue; + } } arrayAppend(infos, InPlaceInit, i, j, image->isCompressed(), @@ -94,10 +113,13 @@ Containers::Array imageInfo(AbstractImporter& importer, bool& error, if(!name.empty() || levelCount != 1) compact = false; for(UnsignedInt j = 0; j != levelCount; ++j) { - Containers::Optional image = importer.image3D(i, j); - if(!image) { - error = true; - continue; + Containers::Optional image; + { + Duration d{importTime}; + if(!(image = importer.image3D(i, j))) { + error = true; + continue; + } } arrayAppend(infos, InPlaceInit, i, j, image->isCompressed(), diff --git a/src/Magnum/Trade/imageconverter.cpp b/src/Magnum/Trade/imageconverter.cpp index 2f5786abb..66cd30183 100644 --- a/src/Magnum/Trade/imageconverter.cpp +++ b/src/Magnum/Trade/imageconverter.cpp @@ -73,7 +73,7 @@ magnum-imageconverter [-h|--help] [-I|--importer PLUGIN] [-i|--importer-options key=val,key2=val2,…] [-c|--converter-options key=val,key2=val2,…] [-D|--dimensions N] [--image N] [--level N] [--layer N] [--layers] [--levels] [--in-place] - [--info] [-v|--verbose] [--] input output + [--info] [-v|--verbose] [--profile] [--] input output @endcode Arguments: @@ -102,6 +102,7 @@ Arguments: - `--in-place` --- overwrite the input image with the output - `--info` --- print info about the input file and exit - `-v`, `--verbose` --- verbose output from importer and converter plugins +- `--profile` --- measure import and conversion time Specifying `--importer raw:<format>` will treat the input as a raw tightly-packed square of pixels in given @ref PixelFormat. Specifying `-C` / @@ -282,6 +283,7 @@ int main(int argc, char** argv) { .addBooleanOption("in-place").setHelp("in-place", "overwrite the input image with the output") .addBooleanOption("info").setHelp("info", "print info about the input file and exit") .addBooleanOption('v', "verbose").setHelp("verbose", "verbose output from importer and converter plugins") + .addBooleanOption("profile").setHelp("profile", "measure import and conversion time") .setParseErrorCallback([](const Utility::Arguments& args, Utility::Arguments::ParseError error, const std::string& key) { /* If --in-place or --info is passed, we don't need the output argument */ @@ -367,6 +369,8 @@ key=true; configuration subgroups are delimited with /.)") Containers::Array images2D; Containers::Array images3D; + std::chrono::high_resolution_clock::duration importTime; + for(std::size_t i = 0, max = args.arrayValueCount("input"); i != max; ++i) { const std::string input = args.arrayValue("input", i); @@ -393,7 +397,11 @@ key=true; configuration subgroups are delimited with /.)") Error{} << "Cannot open file" << input; return 3; } - Containers::Array data = Utility::Directory::read(input); + Containers::Array data; + { + Trade::Implementation::Duration d{importTime}; + data = Utility::Directory::read(input); + } auto side = Int(std::sqrt(data.size()/pixelSize)); if(data.size() % pixelSize || side*side*pixelSize != data.size()) { Error{} << "File of size" << data.size() << "is not a tightly-packed square of" << format; @@ -403,6 +411,11 @@ key=true; configuration subgroups are delimited with /.)") /* Print image info, if requested */ if(args.isSet("info")) { Debug{} << "Image 0:\n Mip 0:" << format << Vector2i{side}; + + if(args.isSet("profile")) { + Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast(importTime).count())/1.0e3f << "seconds"; + } + return 0; } @@ -421,9 +434,12 @@ key=true; configuration subgroups are delimited with /.)") Implementation::setOptions(*importer, "AnyImageImporter", args.value("importer-options")); /* Open input file */ - if(!importer->openFile(input)) { - Error{} << "Cannot open file" << input; - return 3; + { + Trade::Implementation::Duration d{importTime}; + if(!importer->openFile(input)) { + Error{} << "Cannot open file" << input; + return 3; + } } /* Print image info, if requested. This is always done for just one @@ -442,7 +458,7 @@ key=true; configuration subgroups are delimited with /.)") levels. */ bool error = false, compact = true; Containers::Array infos = - Trade::Implementation::imageInfo(*importer, error, compact); + Trade::Implementation::imageInfo(*importer, error, compact, importTime); for(const Trade::Implementation::ImageInfo& info: infos) { Debug d; @@ -462,6 +478,10 @@ key=true; configuration subgroups are delimited with /.)") else d << Math::Vector<1, Int>(info.size.x()); } + if(args.isSet("profile")) { + Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast(importTime).count())/1.0e3f << "seconds"; + } + return error ? 1 : 0; } @@ -604,6 +624,8 @@ key=true; configuration subgroups are delimited with /.)") } } + std::chrono::high_resolution_clock::duration conversionTime; + std::string output; if(args.isSet("in-place")) { /* Should have been checked in a graceful way above */ @@ -618,6 +640,9 @@ key=true; configuration subgroups are delimited with /.)") /* Combine multiple layers into an image of one dimension more */ if(args.isSet("layers")) { + /* To include allocation + copy costs in the output */ + Trade::Implementation::Duration d{conversionTime}; + if(dimensions == 1) { if(!checkCommonFormatAndSize(args, images1D)) return 1; @@ -814,7 +839,18 @@ key=true; configuration subgroups are delimited with /.)") CORRADE_INTERNAL_ASSERT(outputImages3D.size() == 1); data = outputImages3D.front().data(); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); - return Utility::Directory::write(output, data) ? 0 : 1; + + { + Trade::Implementation::Duration d{conversionTime}; + if(!Utility::Directory::write(output, data)) return 1; + } + + if(args.isSet("profile")) { + Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast(importTime).count())/1.0e3f << "seconds, conversion" + << UnsignedInt(std::chrono::duration_cast(conversionTime).count())/1.0e3f << "seconds"; + } + + return 0; } /* Load converter plugin */ @@ -833,15 +869,23 @@ key=true; configuration subgroups are delimited with /.)") /* Save output file */ bool converted; - if(outputDimensions == 1) - converted = convertOneOrMoreImages(*converter, outputImages1D, output); - else if(outputDimensions == 2) - converted = convertOneOrMoreImages(*converter, outputImages2D, output); - else if(outputDimensions == 3) - converted = convertOneOrMoreImages(*converter, outputImages3D, output); - else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + { + Trade::Implementation::Duration d{conversionTime}; + if(outputDimensions == 1) + converted = convertOneOrMoreImages(*converter, outputImages1D, output); + else if(outputDimensions == 2) + converted = convertOneOrMoreImages(*converter, outputImages2D, output); + else if(outputDimensions == 3) + converted = convertOneOrMoreImages(*converter, outputImages3D, output); + else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + } if(!converted) { Error{} << "Cannot save file" << output; return 5; } + + if(args.isSet("profile")) { + Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast(importTime).count())/1.0e3f << "seconds, conversion" + << UnsignedInt(std::chrono::duration_cast(conversionTime).count())/1.0e3f << "seconds"; + } }