diff --git a/bin/data_frame_analyzer/CCmdLineParser.cc b/bin/data_frame_analyzer/CCmdLineParser.cc index 8c5468e3e5..c56c36b189 100644 --- a/bin/data_frame_analyzer/CCmdLineParser.cc +++ b/bin/data_frame_analyzer/CCmdLineParser.cc @@ -20,6 +20,7 @@ const std::string CCmdLineParser::DESCRIPTION = "Usage: data_frame_analyzer [opt bool CCmdLineParser::parse(int argc, const char* const* argv, std::string& configFile, + bool& memoryUsageEstimationOnly, std::string& logProperties, std::string& logPipe, bool& lengthEncodedInput, @@ -35,6 +36,7 @@ bool CCmdLineParser::parse(int argc, ("version", "Display version information and exit") ("config", boost::program_options::value(), "The configuration file") + ("memoryUsageEstimationOnly", "Whether to perform memory usage estimation only") ("logProperties", boost::program_options::value(), "Optional logger properties file") ("logPipe", boost::program_options::value(), @@ -66,6 +68,9 @@ bool CCmdLineParser::parse(int argc, if (vm.count("config") > 0) { configFile = vm["config"].as(); } + if (vm.count("memoryUsageEstimationOnly") > 0) { + memoryUsageEstimationOnly = true; + } if (vm.count("logProperties") > 0) { logProperties = vm["logProperties"].as(); } diff --git a/bin/data_frame_analyzer/CCmdLineParser.h b/bin/data_frame_analyzer/CCmdLineParser.h index b097fe166c..7623d0d07b 100644 --- a/bin/data_frame_analyzer/CCmdLineParser.h +++ b/bin/data_frame_analyzer/CCmdLineParser.h @@ -27,6 +27,7 @@ class CCmdLineParser { static bool parse(int argc, const char* const* argv, std::string& configFile, + bool& memoryUsageEstimationOnly, std::string& logProperties, std::string& logPipe, bool& lengthEncodedInput, diff --git a/bin/data_frame_analyzer/Main.cc b/bin/data_frame_analyzer/Main.cc index 90644b1ce2..94fa39fcb0 100644 --- a/bin/data_frame_analyzer/Main.cc +++ b/bin/data_frame_analyzer/Main.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include "CCmdLineParser.h" @@ -86,6 +87,7 @@ int main(int argc, char** argv) { // Read command line options std::string configFile; + bool memoryUsageEstimationOnly(false); std::string logProperties; std::string logPipe; bool lengthEncodedInput(false); @@ -94,8 +96,9 @@ int main(int argc, char** argv) { std::string outputFileName; bool isOutputFileNamedPipe(false); if (ml::data_frame_analyzer::CCmdLineParser::parse( - argc, argv, configFile, logProperties, logPipe, lengthEncodedInput, inputFileName, - isInputFileNamedPipe, outputFileName, isOutputFileNamedPipe) == false) { + argc, argv, configFile, memoryUsageEstimationOnly, logProperties, + logPipe, lengthEncodedInput, inputFileName, isInputFileNamedPipe, + outputFileName, isOutputFileNamedPipe) == false) { return EXIT_FAILURE; } @@ -127,13 +130,6 @@ int main(int argc, char** argv) { } using TInputParserUPtr = std::unique_ptr; - auto inputParser{[lengthEncodedInput, &ioMgr]() -> TInputParserUPtr { - if (lengthEncodedInput) { - return std::make_unique(ioMgr.inputStream()); - } - return std::make_unique( - ioMgr.inputStream(), ml::api::CCsvInputParser::COMMA); - }()}; std::string analysisSpecificationJson; bool couldReadConfigFile; @@ -145,6 +141,16 @@ int main(int argc, char** argv) { auto analysisSpecification = std::make_unique(analysisSpecificationJson); + + if (memoryUsageEstimationOnly) { + auto outStream = [&ioMgr]() { + return std::make_unique(ioMgr.outputStream()); + }(); + ml::api::CMemoryUsageEstimationResultJsonWriter writer(*outStream); + analysisSpecification->estimateMemoryUsage(writer); + return EXIT_SUCCESS; + } + if (analysisSpecification->numberThreads() > 1) { ml::core::startDefaultAsyncExecutor(analysisSpecification->numberThreads()); } @@ -156,6 +162,13 @@ int main(int argc, char** argv) { CCleanUpOnExit::add(dataFrameAnalyzer.dataFrameDirectory()); + auto inputParser{[lengthEncodedInput, &ioMgr]() -> TInputParserUPtr { + if (lengthEncodedInput) { + return std::make_unique(ioMgr.inputStream()); + } + return std::make_unique( + ioMgr.inputStream(), ml::api::CCsvInputParser::COMMA); + }()}; if (inputParser->readStreamIntoVecs( [&dataFrameAnalyzer](const auto& fieldNames, const auto& fieldValues) { return dataFrameAnalyzer.handleRecord(fieldNames, fieldValues); diff --git a/include/api/CDataFrameAnalysisRunner.h b/include/api/CDataFrameAnalysisRunner.h index d8838bb1af..2221e406a6 100644 --- a/include/api/CDataFrameAnalysisRunner.h +++ b/include/api/CDataFrameAnalysisRunner.h @@ -31,6 +31,7 @@ class CRowRef; } namespace api { class CDataFrameAnalysisSpecification; +class CMemoryUsageEstimationResultJsonWriter; //! \brief Hierarchy for running a specific core::CDataFrame analyses. //! @@ -75,6 +76,11 @@ class API_EXPORT CDataFrameAnalysisRunner { //! number of rows per subset. void computeAndSaveExecutionStrategy(); + //! Estimates memory usage in two cases: one partition (the whole data frame + //! fits in main memory) and maximum tolerable number of partitions (only + //! one partition needs to be loaded to main memory). + void estimateMemoryUsage(CMemoryUsageEstimationResultJsonWriter& writer) const; + //! Check if the data frame for this analysis should use in or out of core //! storage. bool storeDataFrameInMainMemory() const; diff --git a/include/api/CDataFrameAnalysisSpecification.h b/include/api/CDataFrameAnalysisSpecification.h index 238495e2e2..fd96233891 100644 --- a/include/api/CDataFrameAnalysisSpecification.h +++ b/include/api/CDataFrameAnalysisSpecification.h @@ -151,6 +151,11 @@ class API_EXPORT CDataFrameAnalysisSpecification { //! calling thread until the runner has finished. CDataFrameAnalysisRunner* run(const TStrVec& featureNames, core::CDataFrame& frame) const; + //! Estimates memory usage in two cases: one partition (the whole data frame + //! fits in main memory) and maximum tolerable number of partitions (only + //! one partition needs to be loaded to main memory). + void estimateMemoryUsage(CMemoryUsageEstimationResultJsonWriter& writer) const; + private: void initializeRunner(const rapidjson::Value& jsonAnalysis); diff --git a/include/api/CMemoryUsageEstimationResultJsonWriter.h b/include/api/CMemoryUsageEstimationResultJsonWriter.h new file mode 100644 index 0000000000..86ed172451 --- /dev/null +++ b/include/api/CMemoryUsageEstimationResultJsonWriter.h @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +#ifndef INCLUDED_ml_api_CMemoryUsageEstimationResultJsonWriter_h +#define INCLUDED_ml_api_CMemoryUsageEstimationResultJsonWriter_h + +#include +#include +#include + +#include + +#include + +namespace ml { +namespace api { + +//! \brief +//! Write memory usage estimation result in JSON format +//! +//! DESCRIPTION:\n +//! Outputs the memory usage estimation result. +//! +class API_EXPORT CMemoryUsageEstimationResultJsonWriter : private core::CNonCopyable { +public: + //! \param[in] strmOut The wrapped stream to which to write output. + CMemoryUsageEstimationResultJsonWriter(core::CJsonOutputStreamWrapper& strmOut); + + //! Writes the given memory usage estimation result in JSON format. + void write(const std::string& expectedMemoryUsageWithOnePartition, + const std::string& expectedMemoryUsageWithMaxPartitions); + +private: + //! JSON line writer + core::CRapidJsonConcurrentLineWriter m_Writer; +}; +} +} + +#endif // INCLUDED_ml_api_CMemoryUsageEstimationResultJsonWriter_h diff --git a/lib/api/CDataFrameAnalysisRunner.cc b/lib/api/CDataFrameAnalysisRunner.cc index 2217cb1501..9a3630ff2f 100644 --- a/lib/api/CDataFrameAnalysisRunner.cc +++ b/lib/api/CDataFrameAnalysisRunner.cc @@ -11,6 +11,7 @@ #include #include +#include #include @@ -24,6 +25,13 @@ std::size_t memoryLimitWithSafetyMargin(const CDataFrameAnalysisSpecification& s return static_cast(0.9 * static_cast(spec.memoryLimit()) + 0.5); } +std::size_t maximumNumberPartitions(const CDataFrameAnalysisSpecification& spec) { + // We limit the maximum number of partitions to rows^(1/2) because very + // large numbers of partitions are going to be slow and it is better to tell + // user to allocate more resources for the job in this case. + return static_cast(std::sqrt(static_cast(spec.numberRows())) + 0.5); +} + const std::size_t MAXIMUM_FRACTIONAL_PROGRESS{std::size_t{1} << ((sizeof(std::size_t) - 2) * 8)}; } @@ -36,6 +44,25 @@ CDataFrameAnalysisRunner::~CDataFrameAnalysisRunner() { this->waitToFinish(); } +void CDataFrameAnalysisRunner::estimateMemoryUsage(CMemoryUsageEstimationResultJsonWriter& writer) const { + std::size_t numberRows{m_Spec.numberRows()}; + std::size_t numberColumns{m_Spec.numberColumns() + this->numberExtraColumns()}; + std::size_t maxNumberPartitions{maximumNumberPartitions(m_Spec)}; + if (maxNumberPartitions == 0) { + writer.write("0", "0"); + return; + } + std::size_t expectedMemoryUsageWithOnePartition{ + this->estimateMemoryUsage(numberRows, numberRows, numberColumns)}; + std::size_t expectedMemoryUsageWithMaxPartitions{this->estimateMemoryUsage( + numberRows, numberRows / maxNumberPartitions, numberColumns)}; + auto roundUpToNearestKilobyte = [](std::size_t bytes) { + return std::to_string((bytes + 1024 - 1) / 1024) + "kB"; + }; + writer.write(roundUpToNearestKilobyte(expectedMemoryUsageWithOnePartition), + roundUpToNearestKilobyte(expectedMemoryUsageWithMaxPartitions)); +} + void CDataFrameAnalysisRunner::computeAndSaveExecutionStrategy() { std::size_t numberRows{m_Spec.numberRows()}; @@ -45,17 +72,12 @@ void CDataFrameAnalysisRunner::computeAndSaveExecutionStrategy() { LOG_TRACE(<< "memory limit = " << memoryLimit); // Find the smallest number of partitions such that the size per partition - // is less than the memory limit. We limit this to rows^(1/2) because very - // large numbers of partitions are going to be slow and it is better to tell - // user to allocate more resources for the job in this case. - - std::size_t maximumNumberPartitions{ - static_cast(std::sqrt(static_cast(numberRows)) + 0.5)}; + // is less than the memory limit. + std::size_t maxNumberPartitions{maximumNumberPartitions(m_Spec)}; std::size_t memoryUsage{0}; - for (m_NumberPartitions = 1; m_NumberPartitions < maximumNumberPartitions; - ++m_NumberPartitions) { + for (m_NumberPartitions = 1; m_NumberPartitions < maxNumberPartitions; ++m_NumberPartitions) { std::size_t partitionNumberRows{numberRows / m_NumberPartitions}; memoryUsage = this->estimateMemoryUsage(numberRows, partitionNumberRows, numberColumns); LOG_TRACE(<< "partition number rows = " << partitionNumberRows); diff --git a/lib/api/CDataFrameAnalysisSpecification.cc b/lib/api/CDataFrameAnalysisSpecification.cc index f9148cfa61..0aac4ddbb4 100644 --- a/lib/api/CDataFrameAnalysisSpecification.cc +++ b/lib/api/CDataFrameAnalysisSpecification.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -184,6 +185,14 @@ CDataFrameAnalysisRunner* CDataFrameAnalysisSpecification::run(const TStrVec& fe return nullptr; } +void CDataFrameAnalysisSpecification::estimateMemoryUsage(CMemoryUsageEstimationResultJsonWriter& writer) const { + if (m_Runner == nullptr) { + HANDLE_FATAL(<< "Internal error: no runner available so can't estimate memory. Please report this problem."); + return; + } + m_Runner->estimateMemoryUsage(writer); +} + void CDataFrameAnalysisSpecification::initializeRunner(const rapidjson::Value& jsonAnalysis) { // We pass of the interpretation of the parameters object to the appropriate // analysis runner. diff --git a/lib/api/CMemoryUsageEstimationResultJsonWriter.cc b/lib/api/CMemoryUsageEstimationResultJsonWriter.cc new file mode 100644 index 0000000000..8b4a3fda89 --- /dev/null +++ b/lib/api/CMemoryUsageEstimationResultJsonWriter.cc @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +#include + +namespace ml { +namespace api { +namespace { + +// JSON field names +const std::string EXPECTED_MEMORY_USAGE_WITH_ONE_PARTITION("expected_memory_usage_with_one_partition"); +const std::string EXPECTED_MEMORY_USAGE_WITH_MAX_PARTITIONS("expected_memory_usage_with_max_partitions"); +} + +CMemoryUsageEstimationResultJsonWriter::CMemoryUsageEstimationResultJsonWriter(core::CJsonOutputStreamWrapper& strmOut) + : m_Writer(strmOut) { + // Don't write any output in the constructor because, the way things work at + // the moment, the output stream might be redirected after construction +} + +void CMemoryUsageEstimationResultJsonWriter::write(const std::string& expectedMemoryUsageWithOnePartition, + const std::string& expectedMemoryUsageWithMaxPartitions) { + m_Writer.StartObject(); + m_Writer.Key(EXPECTED_MEMORY_USAGE_WITH_ONE_PARTITION); + m_Writer.String(expectedMemoryUsageWithOnePartition); + m_Writer.Key(EXPECTED_MEMORY_USAGE_WITH_MAX_PARTITIONS); + m_Writer.String(expectedMemoryUsageWithMaxPartitions); + m_Writer.EndObject(); + m_Writer.flush(); +} +} +} diff --git a/lib/api/Makefile.first b/lib/api/Makefile.first index 7745c14070..1a03be3996 100644 --- a/lib/api/Makefile.first +++ b/lib/api/Makefile.first @@ -43,6 +43,7 @@ CInputParser.cc \ CIoManager.cc \ CJsonOutputWriter.cc \ CLengthEncodedInputParser.cc \ +CMemoryUsageEstimationResultJsonWriter.cc \ CModelPlotDataJsonWriter.cc \ CModelSizeStatsJsonWriter.cc \ CModelSnapshotJsonWriter.cc \ diff --git a/lib/api/unittest/CDataFrameAnalysisRunnerTest.cc b/lib/api/unittest/CDataFrameAnalysisRunnerTest.cc index 627bd0a049..8fd6f16e92 100644 --- a/lib/api/unittest/CDataFrameAnalysisRunnerTest.cc +++ b/lib/api/unittest/CDataFrameAnalysisRunnerTest.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -121,6 +122,75 @@ void CDataFrameAnalysisRunnerTest::testComputeAndSaveExecutionStrategyDiskUsageF } } +void testEstimateMemoryUsage(int64_t numberRows, + const std::string& expected_expected_memory_usage_with_one_partition, + const std::string& expected_expected_memory_usage_with_max_partitions, + int expected_number_errors) { + + std::ostringstream sstream; + std::vector errors; + std::mutex errorsMutex; + auto errorHandler = [&errors, &errorsMutex](std::string error) { + std::lock_guard lock{errorsMutex}; + errors.push_back(error); + }; + + core::CLogger::CScopeSetFatalErrorHandler scope{errorHandler}; + + // The output writer won't close the JSON structures until is is destroyed + { + std::string jsonSpec{api::CDataFrameAnalysisSpecificationJsonWriter::jsonString( + numberRows, 5, 100000000, 1, {}, true, test::CTestTmpDir::tmpDir(), + "", "outlier_detection", "")}; + api::CDataFrameAnalysisSpecification spec{jsonSpec}; + + core::CJsonOutputStreamWrapper wrappedOutStream(sstream); + api::CMemoryUsageEstimationResultJsonWriter writer(wrappedOutStream); + + spec.estimateMemoryUsage(writer); + } + + rapidjson::Document arrayDoc; + arrayDoc.Parse(sstream.str().c_str()); + + CPPUNIT_ASSERT(arrayDoc.IsArray()); + CPPUNIT_ASSERT_EQUAL(rapidjson::SizeType(1), arrayDoc.Size()); + + const rapidjson::Value& result = arrayDoc[rapidjson::SizeType(0)]; + CPPUNIT_ASSERT(result.IsObject()); + + CPPUNIT_ASSERT(result.HasMember("expected_memory_usage_with_one_partition")); + CPPUNIT_ASSERT_EQUAL( + expected_expected_memory_usage_with_one_partition, + std::string(result["expected_memory_usage_with_one_partition"].GetString())); + CPPUNIT_ASSERT(result.HasMember("expected_memory_usage_with_max_partitions")); + CPPUNIT_ASSERT_EQUAL( + expected_expected_memory_usage_with_max_partitions, + std::string(result["expected_memory_usage_with_max_partitions"].GetString())); + + CPPUNIT_ASSERT_EQUAL(expected_number_errors, static_cast(errors.size())); +} + +void CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_0() { + testEstimateMemoryUsage(0, "0", "0", 1); +} + +void CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_1() { + testEstimateMemoryUsage(1, "6kB", "6kB", 0); +} + +void CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_10() { + testEstimateMemoryUsage(10, "15kB", "13kB", 0); +} + +void CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_100() { + testEstimateMemoryUsage(100, "62kB", "35kB", 0); +} + +void CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_1000() { + testEstimateMemoryUsage(1000, "450kB", "143kB", 0); +} + CppUnit::Test* CDataFrameAnalysisRunnerTest::suite() { CppUnit::TestSuite* suiteOfTests = new CppUnit::TestSuite("CDataFrameAnalysisRunnerTest"); @@ -130,6 +200,21 @@ CppUnit::Test* CDataFrameAnalysisRunnerTest::suite() { suiteOfTests->addTest(new CppUnit::TestCaller( "CDataFrameAnalysisRunnerTest::testComputeAndSaveExecutionStrategyDiskUsageFlag", &CDataFrameAnalysisRunnerTest::testComputeAndSaveExecutionStrategyDiskUsageFlag)); + suiteOfTests->addTest(new CppUnit::TestCaller( + "CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_0", + &CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_0)); + suiteOfTests->addTest(new CppUnit::TestCaller( + "CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_1", + &CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_1)); + suiteOfTests->addTest(new CppUnit::TestCaller( + "CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_10", + &CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_10)); + suiteOfTests->addTest(new CppUnit::TestCaller( + "CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_100", + &CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_100)); + suiteOfTests->addTest(new CppUnit::TestCaller( + "CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_1000", + &CDataFrameAnalysisRunnerTest::testEstimateMemoryUsage_1000)); return suiteOfTests; } diff --git a/lib/api/unittest/CDataFrameAnalysisRunnerTest.h b/lib/api/unittest/CDataFrameAnalysisRunnerTest.h index c2f960c105..2b3b73d9f0 100644 --- a/lib/api/unittest/CDataFrameAnalysisRunnerTest.h +++ b/lib/api/unittest/CDataFrameAnalysisRunnerTest.h @@ -13,6 +13,11 @@ class CDataFrameAnalysisRunnerTest : public CppUnit::TestFixture { public: void testComputeExecutionStrategyForOutliers(); void testComputeAndSaveExecutionStrategyDiskUsageFlag(); + void testEstimateMemoryUsage_0(); + void testEstimateMemoryUsage_1(); + void testEstimateMemoryUsage_10(); + void testEstimateMemoryUsage_100(); + void testEstimateMemoryUsage_1000(); static CppUnit::Test* suite(); diff --git a/lib/api/unittest/CMemoryUsageEstimationResultJsonWriterTest.cc b/lib/api/unittest/CMemoryUsageEstimationResultJsonWriterTest.cc new file mode 100644 index 0000000000..412429ef10 --- /dev/null +++ b/lib/api/unittest/CMemoryUsageEstimationResultJsonWriterTest.cc @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +#include "CMemoryUsageEstimationResultJsonWriterTest.h" + +#include +#include + +#include + +#include + +#include + +#include + +using namespace ml; +using namespace api; + +CppUnit::Test* CMemoryUsageEstimationResultJsonWriterTest::suite() { + CppUnit::TestSuite* suiteOfTests = + new CppUnit::TestSuite("CMemoryUsageEstimationResultJsonWriterTest"); + suiteOfTests->addTest(new CppUnit::TestCaller( + "CMemoryUsageEstimationResultJsonWriterTest::testWrite", + &CMemoryUsageEstimationResultJsonWriterTest::testWrite)); + return suiteOfTests; +} + +void CMemoryUsageEstimationResultJsonWriterTest::testWrite() { + std::ostringstream sstream; + + // The output writer won't close the JSON structures until is is destroyed + { + core::CJsonOutputStreamWrapper wrappedOutStream(sstream); + CMemoryUsageEstimationResultJsonWriter writer(wrappedOutStream); + writer.write("16kB", "8kB"); + } + + rapidjson::Document arrayDoc; + arrayDoc.Parse(sstream.str().c_str()); + + CPPUNIT_ASSERT(arrayDoc.IsArray()); + CPPUNIT_ASSERT_EQUAL(rapidjson::SizeType(1), arrayDoc.Size()); + + const rapidjson::Value& object = arrayDoc[rapidjson::SizeType(0)]; + CPPUNIT_ASSERT(object.IsObject()); + + CPPUNIT_ASSERT(object.HasMember("expected_memory_usage_with_one_partition")); + CPPUNIT_ASSERT_EQUAL( + std::string("16kB"), + std::string(object["expected_memory_usage_with_one_partition"].GetString())); + CPPUNIT_ASSERT(object.HasMember("expected_memory_usage_with_max_partitions")); + CPPUNIT_ASSERT_EQUAL( + std::string("8kB"), + std::string(object["expected_memory_usage_with_max_partitions"].GetString())); +} diff --git a/lib/api/unittest/CMemoryUsageEstimationResultJsonWriterTest.h b/lib/api/unittest/CMemoryUsageEstimationResultJsonWriterTest.h new file mode 100644 index 0000000000..def23a83c3 --- /dev/null +++ b/lib/api/unittest/CMemoryUsageEstimationResultJsonWriterTest.h @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +#ifndef INCLUDED_CMemoryUsageEstimationResultJsonWriterTest_h +#define INCLUDED_CMemoryUsageEstimationResultJsonWriterTest_h + +#include + +class CMemoryUsageEstimationResultJsonWriterTest : public CppUnit::TestFixture { +public: + void testWrite(); + + static CppUnit::Test* suite(); +}; + +#endif // INCLUDED_CMemoryUsageEstimationResultJsonWriterTest_h diff --git a/lib/api/unittest/Main.cc b/lib/api/unittest/Main.cc index 15b52853b1..46ba1a1836 100644 --- a/lib/api/unittest/Main.cc +++ b/lib/api/unittest/Main.cc @@ -22,6 +22,7 @@ #include "CIoManagerTest.h" #include "CJsonOutputWriterTest.h" #include "CLengthEncodedInputParserTest.h" +#include "CMemoryUsageEstimationResultJsonWriterTest.h" #include "CModelPlotDataJsonWriterTest.h" #include "CModelSnapshotJsonWriterTest.h" #include "CMultiFileDataAdderTest.h" @@ -57,11 +58,12 @@ int main(int argc, const char** argv) { runner.addTest(CIoManagerTest::suite()); runner.addTest(CJsonOutputWriterTest::suite()); runner.addTest(CLengthEncodedInputParserTest::suite()); - runner.addTest(CNdJsonInputParserTest::suite()); - runner.addTest(CNdJsonOutputWriterTest::suite()); + runner.addTest(CMemoryUsageEstimationResultJsonWriterTest::suite()); runner.addTest(CModelPlotDataJsonWriterTest::suite()); runner.addTest(CModelSnapshotJsonWriterTest::suite()); runner.addTest(CMultiFileDataAdderTest::suite()); + runner.addTest(CNdJsonInputParserTest::suite()); + runner.addTest(CNdJsonOutputWriterTest::suite()); runner.addTest(COutputChainerTest::suite()); runner.addTest(CPersistenceManagerTest::suite()); runner.addTest(CRestorePreviousStateTest::suite()); diff --git a/lib/api/unittest/Makefile b/lib/api/unittest/Makefile index 761b67c02c..24290e5658 100644 --- a/lib/api/unittest/Makefile +++ b/lib/api/unittest/Makefile @@ -37,6 +37,7 @@ SRCS=\ CIoManagerTest.cc \ CJsonOutputWriterTest.cc \ CLengthEncodedInputParserTest.cc \ + CMemoryUsageEstimationResultJsonWriterTest.cc \ CMockDataAdder.cc \ CMockDataProcessor.cc \ CMockSearcher.cc \