diff --git a/.gitignore b/.gitignore index fe50741bd8..75ff96dc8f 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ Ankh.NoLoad .vs out build +build-bench CMakeSettings.json enc_temp_folder CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt index ed90cdb5ef..f6967efa49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -989,6 +989,9 @@ option(RESINSIGHT_INCLUDE_APPFWK_TESTS "Enable AppFwk Tests" OFF) mark_as_advanced(FORCE RESINSIGHT_INCLUDE_APPFWK_TESTS) if(RESINSIGHT_INCLUDE_APPFWK_TESTS) + # Compile-time benchmark + add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench) + # Unit Tests add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests) add_subdirectory( @@ -997,6 +1000,7 @@ if(RESINSIGHT_INCLUDE_APPFWK_TESTS) add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) add_subdirectory(Fwk/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests) add_subdirectory(Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests) + add_subdirectory(Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests) # Executables add_subdirectory(Fwk/AppFwk/cafTests/cafTestApplication) @@ -1010,6 +1014,7 @@ if(RESINSIGHT_INCLUDE_APPFWK_TESTS) cafPdmXml_UnitTests cafPdmScripting_UnitTests cafUserInterface_UnitTests + cafPdmCvf_UnitTests cafTestApplication cafTestCvfApplication ) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt new file mode 100644 index 0000000000..d9709776c8 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.15) + +project(cafPdm_CompileBench) + +find_package( + Qt6 + COMPONENTS + REQUIRED Core Widgets +) +qt_standard_project_setup() + +set(PROJECT_FILES + bench_basic_fields.cpp bench_enum_fields.cpp bench_container_fields.cpp + bench_filepath_fields.cpp bench_mixed_fields.cpp +) + +# OBJECT library: compiles each file individually without linking. This isolates +# the compile-time cost per translation unit. +add_library(${PROJECT_NAME} OBJECT ${PROJECT_FILES}) + +# Disable unity build for this target — each file must compile independently +set_target_properties(${PROJECT_NAME} PROPERTIES UNITY_BUILD OFF) + +target_link_libraries( + ${PROJECT_NAME} PRIVATE cafProjectDataModel Qt6::Core Qt6::Widgets +) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields.cpp new file mode 100644 index 0000000000..6cbe872bfd --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields.cpp @@ -0,0 +1,59 @@ +// Compile-time benchmark: PdmObjects with basic field types (int, double, bool, QString) +// Used to measure the compile-time cost of cafPdmField.h and cafPdmFieldTraits.h + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +// clang-format off + +#define BENCH_BASIC_OBJECT( N ) \ +class BenchBasicObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchBasicObj##N() \ + { \ + CAF_PDM_InitObject( "BenchBasicObj" #N ); \ + CAF_PDM_InitField( &m_intA, "IntA", 0, "Int A" ); \ + CAF_PDM_InitField( &m_intB, "IntB", 0, "Int B" ); \ + CAF_PDM_InitField( &m_dblA, "DblA", 0.0, "Double A" ); \ + CAF_PDM_InitField( &m_dblB, "DblB", 0.0, "Double B" ); \ + CAF_PDM_InitField( &m_boolA, "BoolA", false, "Bool A" ); \ + CAF_PDM_InitField( &m_boolB, "BoolB", false, "Bool B" ); \ + CAF_PDM_InitField( &m_strA, "StrA", QString(), "String A" ); \ + CAF_PDM_InitField( &m_strB, "StrB", QString(), "String B" ); \ + } \ + caf::PdmField m_intA; \ + caf::PdmField m_intB; \ + caf::PdmField m_dblA; \ + caf::PdmField m_dblB; \ + caf::PdmField m_boolA; \ + caf::PdmField m_boolB; \ + caf::PdmField m_strA; \ + caf::PdmField m_strB; \ +}; + +BENCH_BASIC_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchBasicObj01, "BenchBasicObj01" ); +BENCH_BASIC_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchBasicObj02, "BenchBasicObj02" ); +BENCH_BASIC_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchBasicObj03, "BenchBasicObj03" ); +BENCH_BASIC_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchBasicObj04, "BenchBasicObj04" ); +BENCH_BASIC_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchBasicObj05, "BenchBasicObj05" ); +BENCH_BASIC_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchBasicObj06, "BenchBasicObj06" ); +BENCH_BASIC_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchBasicObj07, "BenchBasicObj07" ); +BENCH_BASIC_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchBasicObj08, "BenchBasicObj08" ); +BENCH_BASIC_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchBasicObj09, "BenchBasicObj09" ); +BENCH_BASIC_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchBasicObj10, "BenchBasicObj10" ); +BENCH_BASIC_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchBasicObj11, "BenchBasicObj11" ); +BENCH_BASIC_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchBasicObj12, "BenchBasicObj12" ); +BENCH_BASIC_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchBasicObj13, "BenchBasicObj13" ); +BENCH_BASIC_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchBasicObj14, "BenchBasicObj14" ); +BENCH_BASIC_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchBasicObj15, "BenchBasicObj15" ); +BENCH_BASIC_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchBasicObj16, "BenchBasicObj16" ); +BENCH_BASIC_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchBasicObj17, "BenchBasicObj17" ); +BENCH_BASIC_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchBasicObj18, "BenchBasicObj18" ); +BENCH_BASIC_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchBasicObj19, "BenchBasicObj19" ); +BENCH_BASIC_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchBasicObj20, "BenchBasicObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields.cpp new file mode 100644 index 0000000000..36c863d861 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields.cpp @@ -0,0 +1,61 @@ +// Compile-time benchmark: PdmObjects with container field types +// Used to measure the compile-time cost of std::vector, std::optional, std::pair specializations + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_CONTAINER_OBJECT( N ) \ +class BenchContainerObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchContainerObj##N() \ + { \ + CAF_PDM_InitObject( "BenchContainerObj" #N ); \ + CAF_PDM_InitFieldNoDefault( &m_vecDouble, "VecDouble", "Vector of doubles" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecInt, "VecInt", "Vector of ints" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecString, "VecString", "Vector of strings" ); \ + CAF_PDM_InitFieldNoDefault( &m_optDouble, "OptDouble", "Optional double" ); \ + CAF_PDM_InitFieldNoDefault( &m_optString, "OptString", "Optional string" ); \ + auto pairInit = std::make_pair( false, 0.0 ); \ + CAF_PDM_InitField( &m_pairBoolDbl, "PairBoolDbl", pairInit, "Pair bool/double" ); \ + auto pairStrInit = std::make_pair( false, QString() ); \ + CAF_PDM_InitField( &m_pairBoolStr, "PairBoolStr", pairStrInit, "Pair bool/string" ); \ + } \ + caf::PdmField> m_vecDouble; \ + caf::PdmField> m_vecInt; \ + caf::PdmField> m_vecString; \ + caf::PdmField> m_optDouble; \ + caf::PdmField> m_optString; \ + caf::PdmField> m_pairBoolDbl; \ + caf::PdmField> m_pairBoolStr; \ +}; + +BENCH_CONTAINER_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchContainerObj01, "BenchContainerObj01" ); +BENCH_CONTAINER_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchContainerObj02, "BenchContainerObj02" ); +BENCH_CONTAINER_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchContainerObj03, "BenchContainerObj03" ); +BENCH_CONTAINER_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchContainerObj04, "BenchContainerObj04" ); +BENCH_CONTAINER_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchContainerObj05, "BenchContainerObj05" ); +BENCH_CONTAINER_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchContainerObj06, "BenchContainerObj06" ); +BENCH_CONTAINER_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchContainerObj07, "BenchContainerObj07" ); +BENCH_CONTAINER_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchContainerObj08, "BenchContainerObj08" ); +BENCH_CONTAINER_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchContainerObj09, "BenchContainerObj09" ); +BENCH_CONTAINER_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchContainerObj10, "BenchContainerObj10" ); +BENCH_CONTAINER_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchContainerObj11, "BenchContainerObj11" ); +BENCH_CONTAINER_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchContainerObj12, "BenchContainerObj12" ); +BENCH_CONTAINER_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchContainerObj13, "BenchContainerObj13" ); +BENCH_CONTAINER_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchContainerObj14, "BenchContainerObj14" ); +BENCH_CONTAINER_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchContainerObj15, "BenchContainerObj15" ); +BENCH_CONTAINER_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchContainerObj16, "BenchContainerObj16" ); +BENCH_CONTAINER_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchContainerObj17, "BenchContainerObj17" ); +BENCH_CONTAINER_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchContainerObj18, "BenchContainerObj18" ); +BENCH_CONTAINER_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchContainerObj19, "BenchContainerObj19" ); +BENCH_CONTAINER_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchContainerObj20, "BenchContainerObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields.cpp new file mode 100644 index 0000000000..993293bbd3 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields.cpp @@ -0,0 +1,50 @@ +// Compile-time benchmark: PdmObjects with caf::AppEnum field types +// Used to measure the compile-time cost of AppEnum template instantiation + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +// clang-format off + +// Each object gets its own enum to exercise distinct AppEnum instantiations +#define BENCH_ENUM_OBJECT( N ) \ +enum class BenchEnum##N { ValueA, ValueB, ValueC, ValueD }; \ +class BenchEnumObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchEnumObj##N() \ + { \ + CAF_PDM_InitObject( "BenchEnumObj" #N ); \ + CAF_PDM_InitField( &m_enumA, "EnumA", BenchEnum##N::ValueA, "Enum A" ); \ + CAF_PDM_InitField( &m_enumB, "EnumB", BenchEnum##N::ValueB, "Enum B" ); \ + CAF_PDM_InitField( &m_enumC, "EnumC", BenchEnum##N::ValueC, "Enum C" ); \ + } \ + caf::PdmField> m_enumA; \ + caf::PdmField> m_enumB; \ + caf::PdmField> m_enumC; \ +}; + +BENCH_ENUM_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchEnumObj01, "BenchEnumObj01" ); +BENCH_ENUM_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchEnumObj02, "BenchEnumObj02" ); +BENCH_ENUM_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchEnumObj03, "BenchEnumObj03" ); +BENCH_ENUM_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchEnumObj04, "BenchEnumObj04" ); +BENCH_ENUM_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchEnumObj05, "BenchEnumObj05" ); +BENCH_ENUM_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchEnumObj06, "BenchEnumObj06" ); +BENCH_ENUM_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchEnumObj07, "BenchEnumObj07" ); +BENCH_ENUM_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchEnumObj08, "BenchEnumObj08" ); +BENCH_ENUM_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchEnumObj09, "BenchEnumObj09" ); +BENCH_ENUM_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchEnumObj10, "BenchEnumObj10" ); +BENCH_ENUM_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchEnumObj11, "BenchEnumObj11" ); +BENCH_ENUM_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchEnumObj12, "BenchEnumObj12" ); +BENCH_ENUM_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchEnumObj13, "BenchEnumObj13" ); +BENCH_ENUM_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchEnumObj14, "BenchEnumObj14" ); +BENCH_ENUM_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchEnumObj15, "BenchEnumObj15" ); +BENCH_ENUM_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchEnumObj16, "BenchEnumObj16" ); +BENCH_ENUM_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchEnumObj17, "BenchEnumObj17" ); +BENCH_ENUM_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchEnumObj18, "BenchEnumObj18" ); +BENCH_ENUM_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchEnumObj19, "BenchEnumObj19" ); +BENCH_ENUM_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchEnumObj20, "BenchEnumObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields.cpp new file mode 100644 index 0000000000..9bf9887f52 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields.cpp @@ -0,0 +1,52 @@ +// Compile-time benchmark: PdmObjects with caf::FilePath field types +// Used to measure the compile-time cost of cafFilePath.h specializations + +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +// clang-format off + +#define BENCH_FILEPATH_OBJECT( N ) \ +class BenchFilePathObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchFilePathObj##N() \ + { \ + CAF_PDM_InitObject( "BenchFilePathObj" #N ); \ + CAF_PDM_InitFieldNoDefault( &m_fileA, "FileA", "File A" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileB, "FileB", "File B" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileC, "FileC", "File C" ); \ + CAF_PDM_InitFieldNoDefault( &m_files, "Files", "File list" ); \ + } \ + caf::PdmField m_fileA; \ + caf::PdmField m_fileB; \ + caf::PdmField m_fileC; \ + caf::PdmField> m_files; \ +}; + +BENCH_FILEPATH_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj01, "BenchFilePathObj01" ); +BENCH_FILEPATH_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj02, "BenchFilePathObj02" ); +BENCH_FILEPATH_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj03, "BenchFilePathObj03" ); +BENCH_FILEPATH_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj04, "BenchFilePathObj04" ); +BENCH_FILEPATH_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj05, "BenchFilePathObj05" ); +BENCH_FILEPATH_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj06, "BenchFilePathObj06" ); +BENCH_FILEPATH_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj07, "BenchFilePathObj07" ); +BENCH_FILEPATH_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj08, "BenchFilePathObj08" ); +BENCH_FILEPATH_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj09, "BenchFilePathObj09" ); +BENCH_FILEPATH_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj10, "BenchFilePathObj10" ); +BENCH_FILEPATH_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj11, "BenchFilePathObj11" ); +BENCH_FILEPATH_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj12, "BenchFilePathObj12" ); +BENCH_FILEPATH_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj13, "BenchFilePathObj13" ); +BENCH_FILEPATH_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj14, "BenchFilePathObj14" ); +BENCH_FILEPATH_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj15, "BenchFilePathObj15" ); +BENCH_FILEPATH_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj16, "BenchFilePathObj16" ); +BENCH_FILEPATH_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj17, "BenchFilePathObj17" ); +BENCH_FILEPATH_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj18, "BenchFilePathObj18" ); +BENCH_FILEPATH_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj19, "BenchFilePathObj19" ); +BENCH_FILEPATH_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj20, "BenchFilePathObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields.cpp new file mode 100644 index 0000000000..b089c73a37 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields.cpp @@ -0,0 +1,70 @@ +// Compile-time benchmark: PdmObjects with all field types combined +// This file represents the highest-signal benchmark: the full PDM field stack +// including basic, enum, container, and FilePath types in every object. + +#include "cafAppEnum.h" +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_MIXED_OBJECT( N ) \ +enum class BenchMixedEnum##N { Alpha, Beta, Gamma, Delta }; \ +class BenchMixedObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchMixedObj##N() \ + { \ + CAF_PDM_InitObject( "BenchMixedObj" #N ); \ + CAF_PDM_InitField( &m_intVal, "IntVal", 0, "Int" ); \ + CAF_PDM_InitField( &m_dblVal, "DblVal", 0.0, "Double" ); \ + CAF_PDM_InitField( &m_boolVal, "BoolVal", false, "Bool" ); \ + CAF_PDM_InitField( &m_strVal, "StrVal", QString(), "String" ); \ + CAF_PDM_InitField( &m_enumVal, "EnumVal", BenchMixedEnum##N::Alpha, "Enum" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecDbl, "VecDbl", "Vector of doubles" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecStr, "VecStr", "Vector of strings" ); \ + CAF_PDM_InitFieldNoDefault( &m_optDbl, "OptDbl", "Optional double" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileA, "FileA", "File A" ); \ + auto pairInit = std::make_pair( false, 0.0 ); \ + CAF_PDM_InitField( &m_pairVal, "PairVal", pairInit, "Pair" ); \ + } \ + caf::PdmField m_intVal; \ + caf::PdmField m_dblVal; \ + caf::PdmField m_boolVal; \ + caf::PdmField m_strVal; \ + caf::PdmField> m_enumVal; \ + caf::PdmField> m_vecDbl; \ + caf::PdmField> m_vecStr; \ + caf::PdmField> m_optDbl; \ + caf::PdmField m_fileA; \ + caf::PdmField> m_pairVal; \ +}; + +BENCH_MIXED_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchMixedObj01, "BenchMixedObj01" ); +BENCH_MIXED_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchMixedObj02, "BenchMixedObj02" ); +BENCH_MIXED_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchMixedObj03, "BenchMixedObj03" ); +BENCH_MIXED_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchMixedObj04, "BenchMixedObj04" ); +BENCH_MIXED_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchMixedObj05, "BenchMixedObj05" ); +BENCH_MIXED_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchMixedObj06, "BenchMixedObj06" ); +BENCH_MIXED_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchMixedObj07, "BenchMixedObj07" ); +BENCH_MIXED_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchMixedObj08, "BenchMixedObj08" ); +BENCH_MIXED_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchMixedObj09, "BenchMixedObj09" ); +BENCH_MIXED_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchMixedObj10, "BenchMixedObj10" ); +BENCH_MIXED_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchMixedObj11, "BenchMixedObj11" ); +BENCH_MIXED_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchMixedObj12, "BenchMixedObj12" ); +BENCH_MIXED_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchMixedObj13, "BenchMixedObj13" ); +BENCH_MIXED_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchMixedObj14, "BenchMixedObj14" ); +BENCH_MIXED_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchMixedObj15, "BenchMixedObj15" ); +BENCH_MIXED_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchMixedObj16, "BenchMixedObj16" ); +BENCH_MIXED_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchMixedObj17, "BenchMixedObj17" ); +BENCH_MIXED_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchMixedObj18, "BenchMixedObj18" ); +BENCH_MIXED_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchMixedObj19, "BenchMixedObj19" ); +BENCH_MIXED_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchMixedObj20, "BenchMixedObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/results.md b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/results.md new file mode 100644 index 0000000000..12abebe5e6 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/results.md @@ -0,0 +1,41 @@ +# cafPdm_CompileBench — Compile Time Benchmark + +## Configuration + +| Setting | Value | +|---|---| +| Branch | `pdm-compile-bench` | +| Commit | `c7ec12fba` | +| Compiler | MSVC (cl.exe) | +| Build system | Ninja | +| Parallelism | 20 cores | +| buildcache | disabled | +| Precompiled headers | disabled | +| Unity build | disabled | +| Date | 2026-04-06 | + +The benchmark target is an `OBJECT` library with `UNITY_BUILD OFF`, so each +translation unit is compiled in isolation. Times are wall-clock milliseconds +read from `.ninja_log` (`finish_time - start_time`). + +## Raw Results (ms) + +| File | Run 1 | Run 2 | Run 3 | **Avg** | +|---|---|---|---|---| +| bench_filepath_fields.cpp | 2352 | 2278 | 2370 | **2333** | +| bench_basic_fields.cpp | 2594 | 2544 | 2603 | **2580** | +| bench_container_fields.cpp | 2749 | 2686 | 2805 | **2747** | +| bench_enum_fields.cpp | 3835 | 3703 | 3785 | **3774** | +| bench_mixed_fields.cpp | 4497 | 4323 | 4554 | **4458** | + +## Notes + +- Each run was a full clean rebuild (`ninja -t clean cafPdm_CompileBench` followed by rebuild). +- The benchmark files exercise different combinations of PDM field types: + - `bench_filepath_fields` — `caf::FilePath` fields + - `bench_basic_fields` — primitive field types (`int`, `double`, `bool`, `QString`) + - `bench_container_fields` — `std::vector` container fields + - `bench_enum_fields` — enum fields with `AppEnum` + - `bench_mixed_fields` — mix of all field types +- `bench_mixed_fields` is the heaviest translation unit (~4458 ms avg) and is the + most representative proxy for a real PDM object with diverse field usage. diff --git a/Fwk/CMakeLists.txt b/Fwk/CMakeLists.txt index 5a22abae64..92d24fc1fb 100644 --- a/Fwk/CMakeLists.txt +++ b/Fwk/CMakeLists.txt @@ -58,6 +58,9 @@ add_subdirectory(AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) add_subdirectory(AppFwk/cafPdmScripting/cafPdmScripting_UnitTests) add_subdirectory(AppFwk/cafUserInterface/cafUserInterface_UnitTests) +# Compile-time benchmark (measures per-file compile cost of PDM field types) +add_subdirectory(AppFwk/cafProjectDataModel/cafPdm_CompileBench) + # Executables add_subdirectory(AppFwk/cafTests/cafTestApplication)