Commit a76695e4 authored by Pascal Palenda's avatar Pascal Palenda
Browse files

Merge branch 'feature/json_lib_exchange' into ppa

parents c6417ca4 ab45c171
#include <ITABase/UtilsJSON.h>
#include <libjson.h>
#include <fstream>
#include<nlohmann/json.hpp>
using namespace nlohmann;
#define JSON_INDENT 3
//-----ITASpectrum-----
void ITABase::Utils::JSON::Export(const CITASpectrum* pSpectrum, const std::string& sTargetFilePath)
{
JSONNode jnRoot;
jnRoot.push_back(JSONNode("name", pSpectrum->GetName()));
jnRoot.push_back(JSONNode("num_bands", pSpectrum->GetNumBands()));
jnRoot.push_back(JSONNode("value_unit", pSpectrum->GetValueUnit()));
json jRoot;
jRoot["name"] = pSpectrum->GetName ( );
jRoot["num_bands"] = pSpectrum->GetNumBands ( );
jRoot["value_unit"] = pSpectrum->GetValueUnit ( );
JSONNode jnSpectrum;
jnSpectrum.set_name("spectrum");
for (int i = 0; i < pSpectrum->GetNumBands(); i++)
json jSpectrum;
for ( int i = 0; i < pSpectrum->GetNumBands ( ); i++ )
{
JSONNode jnBin;
jnBin.set_name("bin" + std::to_string(i));
jnBin.push_back(JSONNode("center_frequency", pSpectrum->GetCenterFrequencies()[i]));
jnBin.push_back(JSONNode("value", pSpectrum->GetValues()[i]));
jnSpectrum.push_back(jnBin);
//TODO: Why use tags for the bin index. Better would be a simple array ( jSpectrum.push_back() )
jSpectrum["bin" + std::to_string ( i )] = { { "center_frequency", pSpectrum->GetCenterFrequencies ( )[i] }, { "value", pSpectrum->GetValues ( )[i] } };
}
jnRoot.push_back(jnSpectrum);
jRoot["spectrum"] = jSpectrum;
std::ofstream fsOut(sTargetFilePath);
fsOut << jnRoot.write_formatted();
fsOut.close();
std::ofstream fsOut ( sTargetFilePath );
fsOut << jRoot.dump ( JSON_INDENT );
fsOut.close ( );
}
// Statistics
//-----Statistics-----
JSONNode StatsToJSON(const ITABase::CStatistics& oStats)
json StatsToJSON ( const ITABase::CStatistics& oStats )
{
JSONNode jnStats;
jnStats.set_name(oStats.sName);
jnStats.push_back(JSONNode("name", oStats.sName));
jnStats.push_back(JSONNode("N", oStats.uiNumSamples));
jnStats.push_back(JSONNode("units", oStats.sUnits));
jnStats.push_back(JSONNode("min", oStats.dMin));
jnStats.push_back(JSONNode("max", oStats.dMax));
jnStats.push_back(JSONNode("mean", oStats.dMean));
jnStats.push_back(JSONNode("stddev", oStats.dStdDev));
json jStats;
jStats["name"] = oStats.sName;
jStats["N"] = oStats.uiNumSamples;
jStats["units"] = oStats.sUnits;
jStats["min"] = oStats.dMin;
jStats["max"] = oStats.dMax;
jStats["mean"] = oStats.dMean;
jStats["stddev"] = oStats.dStdDev;
return jnStats;
return jStats;
}
void ITABase::Utils::JSON::Export(const ITABase::CStatistics& oStats, const std::string& sTargetFilePath)
{
std::ofstream fsOut(sTargetFilePath);
fsOut << StatsToJSON(oStats).write_formatted();
fsOut.close();
std::ofstream fsOut ( sTargetFilePath );
fsOut << StatsToJSON ( oStats ).dump ( JSON_INDENT );
fsOut.close ( );
}
void ITABase::Utils::JSON::Export(const std::vector<ITABase::CStatistics>& voStats, const std::string& sTargetFilePath)
{
JSONNode jnRoot;
jnRoot.set_name("statistics");
for (auto& oStats : voStats)
jnRoot.push_back(StatsToJSON(oStats));
json jRoot;
for ( auto& oStats : voStats )
{
// TODO: What happen if name is identical? Better would be a simple array ( jRoot.push_back() )
jRoot[oStats.sName] = StatsToJSON ( oStats );
}
std::ofstream fsOut(sTargetFilePath);
fsOut << jnRoot.write_formatted();
fsOut.close();
std::ofstream fsOut ( sTargetFilePath );
fsOut << jRoot.dump ( JSON_INDENT );
fsOut.close ( );
}
......@@ -24,7 +24,9 @@
// misc includes
#include <VistaBase/VistaTimeUtils.h>
#include <libjson.h>
#include <nlohmann/json.hpp>
using namespace nlohmann;
namespace ITAProfiler
{
......@@ -217,22 +219,15 @@ namespace ITAProfiler
///
std::stringstream ProfilerToJSON ( )
{
JSONNode jnRoot;
jnRoot.set_name ( "Profiler" );
jnRoot.push_back ( JSONNode ( "Time Unit", "us - 1e-6" ) );
jnRoot.push_back ( JSONNode ( "CPU Frequency", ITAClock::getDefaultClock ( )->getFrequency ( ) ) );
json jnRoot;
JSONNode jnSection;
jnSection.set_name ( "Profile Sections" );
JSONNode jnEventCount;
jnEventCount.set_name ( "Profile EventCounts" );
JSONNode jnValue;
jnValue.set_name ( "Profile Values" );
jnRoot["Time Unit"] = "us - 1e-6";
jnRoot["CPU Frequency"] = ITAClock::getDefaultClock ( )->getFrequency ( );
json jnSection;
json jnEventCount;
json jnValue;
// Disable profiling while we write to file.
m_bEnabled = false;
......@@ -273,22 +268,20 @@ namespace ITAProfiler
swThread.stop ( );
}
jnRoot.push_back ( JSONNode ( "Section SW", swSection.ToString ( ) ) );
jnRoot.push_back ( JSONNode ( "Event SW", swEvent.ToString ( ) ) );
jnRoot.push_back ( JSONNode ( "Value SW", swValue.ToString ( ) ) );
jnRoot.push_back ( JSONNode ( "Thread SW", swThread.ToString ( ) + ", sum=" + std::to_string ( swThread.sum ( ) ) ) );
jnRoot.push_back ( jnSection );
jnRoot["Section SW"] = swSection.ToString ( );
jnRoot["Event SW"] = swEvent.ToString ( );
jnRoot["Value SW"] = swValue.ToString ( );
jnRoot["Thread SW"] = swThread.ToString ( ) + ", sum=" + std::to_string ( swThread.sum ( ) );
jnRoot.push_back ( jnEventCount );
jnRoot.push_back ( jnValue );
jnRoot["Profile Sections"] = jnSection;
jnRoot["Profile EventCounts"] = jnEventCount;
jnRoot["Profile Values"] = jnValue;
// Reenable profiling
m_bEnabled = true;
std::stringstream ss;
ss << jnRoot.write ( );
ss << jnRoot;
return ss;
}
......@@ -298,7 +291,7 @@ namespace ITAProfiler
/// \param mThreadNames map, containing the names of the threads.
/// \return a JSON Node with the data of the given eventCount pair.
///
JSONNode ProfileEventCountToJSON ( const std::pair<ProfilerKey, ProfileEventCount>& eventCountPair,
json ProfileEventCountToJSON ( const std::pair<ProfilerKey, ProfileEventCount>& eventCountPair,
const std::unordered_map<std::thread::id, std::string>& mThreadNames )
{
std::string sThreadName;
......@@ -307,23 +300,17 @@ namespace ITAProfiler
if ( threadNameIterator != mThreadNames.end ( ) )
sThreadName = threadNameIterator->second;
json jnRoot;
jnRoot["Name"] = eventCountPair.first.sName;
jnRoot["File Name"] = eventCountPair.first.sFile;
jnRoot["Function Name"] = eventCountPair.first.sFunction;
jnRoot["Thread Id"] = std::hash<std::thread::id> ( ) ( eventCountPair.first.iThreadId );
JSONNode jnRoot;
if ( !sThreadName.empty ( ) )
jnRoot.set_name ( "[" + eventCountPair.first.sFunction + "][" + eventCountPair.first.sName + "][" + sThreadName + "]" );
else
jnRoot.set_name ( "[" + eventCountPair.first.sFunction + "][" + eventCountPair.first.sName + "][" +
std::to_string ( std::hash<std::thread::id>()(eventCountPair.first.iThreadId) ) + "]" );
jnRoot.push_back ( JSONNode ( "Name", eventCountPair.first.sName ) );
jnRoot.push_back ( JSONNode ( "File Name", eventCountPair.first.sFile ) );
jnRoot.push_back ( JSONNode ( "Function Name", eventCountPair.first.sFunction ) );
jnRoot.push_back ( JSONNode ( "Thread Id", std::hash<std::thread::id>()(eventCountPair.first.iThreadId) ) );
jnRoot["Thread Name"] = sThreadName;
if ( !sThreadName.empty ( ) )
jnRoot.push_back ( JSONNode ( "Thread Name", sThreadName ) );
jnRoot.push_back ( JSONNode ( "Count", eventCountPair.second.vTimeStamps.size ( ) ) );
jnRoot["Count"] = eventCountPair.second.vTimeStamps.size ( );
std::vector<double> vdTimeStamps ( eventCountPair.second.vTimeStamps.size ( ) );
......@@ -332,23 +319,10 @@ namespace ITAProfiler
vdTimeStamps.begin ( ),
[&] ( const double& time ) -> double { return time - m_dStartTime; } );
/*JSONNode jnTimeStampArray ( JSON_ARRAY );
jnTimeStampArray.set_name ( "TimeStamps" );
jnTimeStampArray.reserve ( vdTimeStamps.size ( ) );
JSONNode jnData ( JSON_NUMBER );
for ( const auto& timeStamp : vdTimeStamps )
{
jnData = timeStamp;
jnTimeStampArray.push_back ( jnData );
}
jnRoot.push_back ( jnTimeStampArray );*/
const int precision = 1 + std::ceil ( std::log10 ( ITAClock::getDefaultClock ( )->getFrequency ( ) ) );
jnRoot.push_back ( JSONNode ( "Time Stamps", ConvertToString ( vdTimeStamps, precision, "," ) ) );
jnRoot["Time Stamps"] = ConvertToString ( vdTimeStamps, precision, "," );
return jnRoot;
}
......@@ -360,7 +334,7 @@ namespace ITAProfiler
/// \param mThreadNames map, containing the names of the threads.
/// \return a JSON Node with the data of the given section pair.
///
JSONNode ProfileSectionToJSON ( const std::pair<ProfilerKey, ProfileSection>& sectionPair, const std::unordered_map<std::thread::id, std::string>& mThreadNames )
json ProfileSectionToJSON ( const std::pair<ProfilerKey, ProfileSection>& sectionPair, const std::unordered_map<std::thread::id, std::string>& mThreadNames )
{
std::string sThreadName;
......@@ -369,22 +343,16 @@ namespace ITAProfiler
if ( threadNameIterator != mThreadNames.end ( ) )
sThreadName = threadNameIterator->second;
JSONNode jnRoot;
if ( !sThreadName.empty ( ) )
jnRoot.set_name ( "[" + sectionPair.first.sFunction + "][" + sectionPair.first.sName + "][" + sThreadName + "]" );
else
jnRoot.set_name ( "[" + sectionPair.first.sFunction + "][" + sectionPair.first.sName + "][" + std::to_string ( std::hash<std::thread::id>()(sectionPair.first.iThreadId) ) +
"]" );
jnRoot.push_back ( JSONNode ( "Name", sectionPair.first.sName ) );
jnRoot.push_back ( JSONNode ( "File Name", sectionPair.first.sFile ) );
jnRoot.push_back ( JSONNode ( "Function Name", sectionPair.first.sFunction ) );
jnRoot.push_back ( JSONNode ( "Thread Id", std::hash<std::thread::id>()(sectionPair.first.iThreadId ) ) );
json jnRoot;
jnRoot["Name"] = sectionPair.first.sName;
jnRoot["File Name"] = sectionPair.first.sFile;
jnRoot["Function Name"] = sectionPair.first.sFunction;
jnRoot["Thread Id"] = std::hash<std::thread::id> ( ) ( sectionPair.first.iThreadId );
if ( !sThreadName.empty ( ) )
jnRoot.push_back ( JSONNode ( "Thread Name", sThreadName ) );
jnRoot["Thread Name"] = sThreadName;
jnRoot.push_back ( JSONNode ( "Count", sectionPair.second.vpStartEndTimes.size ( ) ) );
jnRoot["Count"] = sectionPair.second.vpStartEndTimes.size ( );
std::vector<double> vdStartTime ( sectionPair.second.vpStartEndTimes.size ( ) );
std::vector<double> vdEndTime ( sectionPair.second.vpStartEndTimes.size ( ) );
......@@ -399,36 +367,11 @@ namespace ITAProfiler
vdEndTime.begin ( ),
[&] ( const std::pair<double, double>& interval ) -> double { return interval.second - m_dStartTime; } );
/*JSONNode jnStartTimeArray ( JSON_ARRAY );
jnStartTimeArray.set_name ( "Start Times" );
jnStartTimeArray.reserve ( vdStartTime.size ( ) );
JSONNode jnData( JSON_NUMBER );
for ( const auto& timeStamp : vdStartTime )
{
jnData = timeStamp;
jnStartTimeArray.push_back ( jnData );
}
jnRoot.push_back ( jnStartTimeArray );
JSONNode jnEndTimeArray ( JSON_ARRAY );
jnEndTimeArray.set_name ( "End Times" );
jnEndTimeArray.reserve ( vdStartTime.size ( ) );
for ( const auto& timeStamp : vdEndTime )
{
jnData = timeStamp;
jnEndTimeArray.push_back ( jnData );
}
jnRoot.push_back ( jnEndTimeArray );*/
const int precision = 1 + std::ceil ( std::log10 ( ITAClock::getDefaultClock ( )->getFrequency ( ) ) );
jnRoot.push_back ( JSONNode ( "Start Times", ConvertToString ( vdStartTime, precision, "," ) ) );
jnRoot.push_back ( JSONNode ( "End Times", ConvertToString ( vdEndTime, precision, "," ) ) );
jnRoot["Start Times"] = ConvertToString ( vdStartTime, precision, "," );
jnRoot["End Times"] = ConvertToString ( vdEndTime, precision, "," );
return jnRoot;
}
......@@ -438,7 +381,7 @@ namespace ITAProfiler
/// \param mThreadNames map, containing the names of the threads.
/// \return a JSON Node with the data of the given ProfileValue pair.
///
JSONNode ProfileValuesToJSON ( const std::pair<ProfilerKey, ProfileValue>& valuePair, const std::unordered_map<std::thread::id, std::string>& mThreadNames )
json ProfileValuesToJSON ( const std::pair<ProfilerKey, ProfileValue>& valuePair, const std::unordered_map<std::thread::id, std::string>& mThreadNames )
{
std::string sThreadName;
......@@ -446,25 +389,19 @@ namespace ITAProfiler
if ( threadNameIterator != mThreadNames.end ( ) )
sThreadName = threadNameIterator->second;
JSONNode jnRoot;
if ( !sThreadName.empty ( ) )
jnRoot.set_name ( "[" + valuePair.first.sFunction + "][" + valuePair.first.sName + "][" + sThreadName + "]" );
else
jnRoot.set_name ( "[" + valuePair.first.sFunction + "][" + valuePair.first.sName + "][" +
std::to_string ( std::hash<std::thread::id> ( ) ( valuePair.first.iThreadId ) ) + "]" );
jnRoot.push_back ( JSONNode ( "Name", valuePair.first.sName ) );
jnRoot.push_back ( JSONNode ( "File Name", valuePair.first.sFile ) );
jnRoot.push_back ( JSONNode ( "Function Name", valuePair.first.sFunction ) );
jnRoot.push_back ( JSONNode ( "Thread Id", std::hash<std::thread::id>()(valuePair.first.iThreadId ) ) );
json jnRoot;
jnRoot["Name"] = "Name", valuePair.first.sName;
jnRoot["File Name"] = valuePair.first.sFile;
jnRoot["Function Name"] = valuePair.first.sFunction;
jnRoot["Thread Id"] = std::hash<std::thread::id> ( ) ( valuePair.first.iThreadId );
if ( !sThreadName.empty ( ) )
jnRoot.push_back ( JSONNode ( "Thread Name", sThreadName ) );
jnRoot.push_back ( JSONNode ( "Count", valuePair.second.Size ( ) ) );
jnRoot["Thread Name"] = sThreadName;
std::tuple<JSONNode, JSONNode> valueNodes;
jnRoot["Count"] = valuePair.second.Size ( );
json valueNodes;
// store the tim stamps
switch ( valuePair.second.GetDataType ( ) )
......@@ -494,9 +431,8 @@ namespace ITAProfiler
ITA_EXCEPT_INVALID_PARAMETER ( "Unkown data type" );
}
jnRoot.push_back ( std::get<0> ( valueNodes ) );
jnRoot.push_back ( std::get<1> ( valueNodes ) );
jnRoot.insert ( valueNodes.begin ( ), valueNodes.end() );
return jnRoot;
}
......@@ -507,26 +443,10 @@ namespace ITAProfiler
/// \return returns a tuple with the JSONNode for the time stamp and data.
///
template<class T>
std::tuple<JSONNode, JSONNode> ValueDataToJSON ( const ProfileValue& oProfileValue )
json ValueDataToJSON ( const ProfileValue& oProfileValue )
{
std::vector<std::pair<T, double>> dataVector = oProfileValue.GetData<T> ( m_dStartTime );
/*JSONNode jnTimeStampArray ( JSON_ARRAY );
jnTimeStampArray.set_name ( "TimeStamps" );
jnTimeStampArray.reserve ( dataVector.size ( ) );
JSONNode jnDataArray ( JSON_ARRAY );
jnDataArray.set_name ( "Data" );
jnDataArray.reserve ( dataVector.size ( ) );
JSONNode jnData ( JSON_NUMBER );
for ( const auto& data : dataVector )
{
jnData = data.first;
jnDataArray.push_back ( jnData );
jnData = data.second;
jnTimeStampArray.push_back ( jnData );
}*/
std::vector<T> vTData ( dataVector.size ( ) );
std::vector<double> vdTimeStamps ( dataVector.size ( ) );
......@@ -535,11 +455,11 @@ namespace ITAProfiler
std::transform ( dataVector.begin ( ), dataVector.end ( ), vdTimeStamps.begin ( ), [] ( const std::pair<T, double>& p ) -> double { return p.second; } );
const int precision = 1 + std::ceil ( std::log10 ( ITAClock::getDefaultClock ( )->getFrequency ( ) ) );
JSONNode jnTimeStampArray ( "Time Stamps", ConvertToString ( vdTimeStamps, precision, "," ) );
JSONNode jnDataArray ( "Data", ConvertToString ( vTData, 8, "," ) );
return std::make_pair ( jnTimeStampArray, jnDataArray );
json jnRoot;
jnRoot["Time Stamps"] = ConvertToString ( vdTimeStamps, precision, "," );
jnRoot["Data"] = ConvertToString ( vTData, 8, "," );
return jnRoot;
}
private:
......
......@@ -85,4 +85,26 @@ set_property (TARGET SplineTest PROPERTY FOLDER "Tests/ITABase")
install (TARGETS SplineTest RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# ######################################################################################################################
if (ITA_BASE_WITH_JSON_SUPPORT)
add_executable (ITABaseUtilsJSONTest ITABaseUtilsJSONTest.cpp)
target_link_libraries (ITABaseUtilsJSONTest PUBLIC ITABase::ITABase)
set_property (TARGET ITABaseUtilsJSONTest PROPERTY FOLDER "Tests/ITABase")
install (TARGETS ITABaseUtilsJSONTest RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# ######################################################################################################################
add_executable (ITABaseProfilerJSONTest ITABaseProfilerJSONTest.cpp)
target_link_libraries (ITABaseProfilerJSONTest PUBLIC ITABase::ITABase)
set_property (TARGET ITABaseProfilerJSONTest PROPERTY FOLDER "Tests/ITABase")
install (TARGETS ITABaseProfilerJSONTest RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif ()
# ######################################################################################################################
add_subdirectory (VistaTests)
#include <ITAProfiler/profiler.h>
#include <fstream>
#include <iostream>
#include <sstream>
int main ( int nArgsIn, char** pccArgs )
{
ITA_PROFILER_NAME_THREAD_MAIN ( );
ITA_PROFILER_FUNCTION ( );
ITA_PROFILER_SECTION ( "Loop" );
for ( auto i = 0; i < 10; i++ )
{
ITA_PROFILER_EVENT_COUNT ( "event" )
ITA_PROFILER_VALUE ( "i", i )
}
ITA_PROFILER_END_SECTION ( );
try
{
std::ofstream myfile;
myfile.open ( "example.json" );
myfile << ITAProfiler::ProfilerToJson ( ).str ( );
myfile.close ( );
}
catch ( const std::exception& e )
{
std::cout << e.what ( );
}
return 0;
}
#include <ITABase/UtilsJSON.h>
#include<ITAThirdOctaveMagnitudeSpectrum.h>
using namespace std;
int main( int nArgsIn, char** pccArgs )
{
ITABase::CThirdOctaveGainMagnitudeSpectrum oSpectrum;
oSpectrum.SetName ( "test_spectrum" );
for ( int idx = 0; idx < oSpectrum.GetNumBands ( ); idx++ )
oSpectrum.SetMagnitude ( idx, idx );
ITABase::Utils::JSON::Export ( &oSpectrum, "test_spectrum.json" );
ITABase::CStatistics statsTime ( "test_stats_time", "s" );
statsTime.dMax = 1;
statsTime.dMean = 1;
statsTime.dMin = 1;
statsTime.dStdDev = 1;
ITABase::CStatistics statsPressure ( "test_stats_pressure", "Pa" );
statsPressure.dMax = 2;
statsPressure.dMean = 2;
statsPressure.dMin = 2;
statsPressure.dStdDev = 2;
std::vector<ITABase::CStatistics> statsVector { statsTime, statsPressure };
ITABase::Utils::JSON::Export ( statsTime, "test_single_stats.json" );
ITABase::Utils::JSON::Export ( statsVector, "test_multiple_stats.json" );
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment