From e70832481d09f05ee80b0ee52c8348d12e1458bf Mon Sep 17 00:00:00 2001 From: Flavio Pisani <flavio.pisani@cern.ch> Date: Mon, 6 Dec 2021 14:24:08 +0100 Subject: [PATCH 1/4] initial version of satellite project generated with: /cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/bin/lb-dev Online/v7r13 --- .gitignore | 6 ++++++ CMakeLists.txt | 22 +++++++++++++++++++ Makefile | 45 ++++++++++++++++++++++++++++++++++++++ build.conf | 6 ++++++ run | 39 +++++++++++++++++++++++++++++++++ searchPath.cmake | 6 ++++++ searchPath.py | 9 ++++++++ toolchain.cmake | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 189 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 build.conf create mode 100755 run create mode 100644 searchPath.cmake create mode 100644 searchPath.py create mode 100644 toolchain.cmake diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..25c3c0828 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/InstallArea/ +/build.*/ +*.pyc +*~ +.*.swp +/.clang-format diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..e1601619f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,22 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5) + +#--------------------------------------------------------------- +# Load macros and functions for Gaudi-based projects +find_package(GaudiProject) +#--------------------------------------------------------------- + +if(EXISTS ${CMAKE_SOURCE_DIR}/Online/RootCnv) + set(override_subdirs RootCnv) +endif() + +# Declare project name and version +# Syntax: +# gaudi_project(this_project this_version +# USE dep_project_1 version_1 [project_2 version_2 ...] +# [DATA pkg1 [VERSION vers1] [pkg2 ...]]) +gaudi_project(OnlineDev v7r13 + USE Online v7r13) + +# Enable Ganga integration +include(/cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/lib/python3.8/site-packages/LbDevTools/data/cmake/GangaTools.cmake) +enable_ganga_integration() diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..1c80be788 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +build_tool=cmake + +DEVTOOLS_DATADIR := /cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/lib/python3.8/site-packages/LbDevTools/data + +ifeq ($(wildcard build.conf),build.conf) +include build.conf +endif + + +# Make sure BINARY_TAG and CMTCONFIG are set and consistent. +# If one is not set, take the value from the other. +# If none is set, use the default platform from build.conf. +ifeq ($(BINARY_TAG)$(CMTCONFIG),) + ifeq ($(CMTCONFIG),) + BINARY_TAG := $(platform) + else + BINARY_TAG := $(CMTCONFIG) + endif + export BINARY_TAG := $(BINARY_TAG) +endif +ifeq ($(CMTCONFIG),) + CMTCONFIG := $(BINARY_TAG) + export CMTCONFIG := $(CMTCONFIG) +endif +ifneq ($(BINARY_TAG),$(CMTCONFIG)) + $(error Invalid environment: inconsistent values for BINARY_TAG and CMTCONFIG) +endif + +ifeq ($(build_tool),cmake) +######## CMake case ######## + +include $(DEVTOOLS_DATADIR)/Makefile-cmake.mk + +else +######### CMT case ######### + +ifeq ($(wildcard build_env.sh),build_env.sh) +CMTPROJECTPATH := $(shell bash -c ". build_env.sh ; printenv CMTPROJECTPATH") +endif + +all: +%: + @env CMTPROJECTPATH="$(CMTPROJECTPATH)" DEVTOOLS_DATADIR="$(DEVTOOLS_DATADIR)" $(MAKE) -f $(DEVTOOLS_DATADIR)/Makefile-cmt.mk $* + +endif diff --git a/build.conf b/build.conf new file mode 100644 index 000000000..b8306cd26 --- /dev/null +++ b/build.conf @@ -0,0 +1,6 @@ +# WARNING: If you modify this file, you should call "make purge" before rebuilding. +nightly_slot= +nightly_day= +nightly_base= +build_tool=cmake +platform=x86_64_v2-centos7-gcc10-opt diff --git a/run b/run new file mode 100755 index 000000000..9fff2d329 --- /dev/null +++ b/run @@ -0,0 +1,39 @@ +#!/bin/sh + +root_dir=$(dirname $0) + +# Get build configuration parameters +. ${root_dir}/build.conf + +if [ -z "${BINARY_TAG}" ] ; then + export BINARY_TAG=${CMTCONFIG:-${platform}} +fi +if [ -z "${CMTCONFIG}" ] ; then + export CMTCONFIG=${BINARY_TAG:-${platform}} +fi +if [ "${BINARY_TAG}" != "${CMTCONFIG}" ] ; then + echo "error: invalid environment: inconsistent values for BINARY_TAG and CMTCONFIG" + exit 1 +fi + +if [ "$build_tool" = "cmake" ] ; then + run_cmd=${root_dir}/build.$BINARY_TAG/run + if [ ! -e "$run_cmd" ] ; then + echo "error: cannot find build.$BINARY_TAG/run, did you build?" + exit 1 + fi +else + curdir=$(pwd) + cd ${root_dir} + if [ -r ./build_env.sh ] ; then + . ./build_env.sh + fi + cd $curdir + run_cmd="lb-run" + if [ "$nightly_slot" != "" ] ; then + run_cmd+=" --nightly ${nightly_slot}/${nightly_day}" + fi + run_cmd+=" --user-area $(cd ${root_dir}/.. ; pwd) OnlineDev_v7r13" +fi + +exec $run_cmd "$@" diff --git a/searchPath.cmake b/searchPath.cmake new file mode 100644 index 000000000..63226aec4 --- /dev/null +++ b/searchPath.cmake @@ -0,0 +1,6 @@ +# Search path defined from lb-dev command line +if(NOT ENV{User_release_area}) + # use a default value + set(ENV{User_release_area} "/home/fpisani/cmtuser") +endif() +list(INSERT CMAKE_PREFIX_PATH 0 "$ENV{User_release_area}") diff --git a/searchPath.py b/searchPath.py new file mode 100644 index 000000000..8dcdf6c6e --- /dev/null +++ b/searchPath.py @@ -0,0 +1,9 @@ +from LbEnv.ProjectEnv.options import ( + SearchPath, + SearchPathEntry, + EnvSearchPathEntry, + NightlyPathEntry, + LHCbDevPathEntry, +) + +path = SearchPath([EnvSearchPathEntry('User_release_area', '/home/fpisani/cmtuser'), EnvSearchPathEntry('CMAKE_PREFIX_PATH', '/cvmfs/lhcb.cern.ch/lib/lhcb:/cvmfs/lhcb.cern.ch/lib/lcg/releases:/cvmfs/lhcb.cern.ch/lib/lcg/app/releases:/cvmfs/lhcb.cern.ch/lib/lcg/external:/cvmfs/lhcb.cern.ch/lib/contrib:/cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/lib/python3.8/site-packages/LbDevTools/data/cmake:/cvmfs/projects.cern.ch/intelsw/psxe/linux/x86_64/2019/vtune_amplifier_2019.4.0.597835'), EnvSearchPathEntry('CMTPROJECTPATH', '/cvmfs/lhcb.cern.ch/lib/lcg/releases:/cvmfs/lhcb.cern.ch/lib/lcg/app/releases:/cvmfs/lhcb.cern.ch/lib/lcg/external'), EnvSearchPathEntry('LHCBPROJECTPATH', '')]) diff --git a/toolchain.cmake b/toolchain.cmake new file mode 100644 index 000000000..58b6c139b --- /dev/null +++ b/toolchain.cmake @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.6) + +# Use lb-dev command line search path, if defined. +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/searchPath.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/searchPath.cmake) +endif() + +if(CMAKE_PREFIX_PATH) + list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH) +endif() + +# this check is needed because the toolchain is called when checking the +# compiler (without the proper cache) +if(NOT CMAKE_SOURCE_DIR MATCHES "CMakeTmp") + find_path(gaudi_cmake_modules NAMES GaudiToolchainMacros.cmake + HINTS /cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/lib/python3.8/site-packages/LbDevTools/data/cmake) + if(NOT gaudi_cmake_modules) + message(FATAL_ERROR "Cannot find GaudiToolchainMacros.cmake") + endif() + + # find the projects we use + set(CMAKE_MODULE_PATH ${gaudi_cmake_modules} ${CMAKE_MODULE_PATH}) + include(GaudiToolchainMacros) + init() + find_projects(projects tools ${CMAKE_SOURCE_DIR}/CMakeLists.txt) + + # Use the toolchain used by the project we derive from + list(GET projects 1 first_used_project) + + if(first_used_project STREQUAL "GAUDI" + OR NOT EXISTS ${${first_used_project}_ROOT_DIR}/toolchain.cmake) + # special case for Gaudi and projects without a specific toolchain + include(/cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/lib/python3.8/site-packages/LbDevTools/data/toolchain.cmake) + else() + # special case for Gauss (needs a fix in Gauss toolchain.cmake) + if(EXISTS ${${first_used_project}_ROOT_DIR}/generators_versions.txt) + file(READ ${${first_used_project}_ROOT_DIR}/generators_versions.txt generators_versions) + string(REGEX REPLACE "[ \t\n]+" ";" generators_versions "${generators_versions}") + set(generators_versions ${generators_versions}) + endif() + + set(ENV{LBUTILSROOT} /cvmfs/lhcb.cern.ch/lib/var/lib/LbEnv/2252/stable/linux-64/lib/python3.8/site-packages/LbDevTools/data/..) + message(STATUS "Using toolchain from ${${first_used_project}_ROOT_DIR}") + include(${${first_used_project}_ROOT_DIR}/toolchain.cmake) + endif() + + # FIXME: make sure we do not pick up unwanted/problematic projects from LCG + if(CMAKE_PREFIX_PATH) + # - ninja (it requires LD_LIBRARY_PATH set to run) + # - Gaudi (we do not want to use it from LCG) + # - xenv (conflicts with the version in the build environment) + # - git (requires a special environment provided only by LCG views) + # - ccache (as of 4.0 it requires a C++ compiler so LD_LIBRARY_PATH set to run) + list(FILTER CMAKE_PREFIX_PATH EXCLUDE REGEX "(LCG_|lcg/nightlies).*(ninja|Gaudi|xenv|git|ccache)/") + endif() +endif() -- GitLab From fc228470bd0c57dcc9b17dc62e9d8e87a480d191 Mon Sep 17 00:00:00 2001 From: Flavio Pisani <flavio.pisani@cern.ch> Date: Mon, 6 Dec 2021 14:25:35 +0100 Subject: [PATCH 2/4] added Online/EventBuilding from Online (Online/fpisani_eb_dev) --- .git-lb-checkout | 3 + Online/EventBuilding/.clang-format | 68 ++ Online/EventBuilding/.gitignore | 3 + Online/EventBuilding/.gitlab-ci.yml | 11 + Online/EventBuilding/CI/clang_format_test.sh | 27 + Online/EventBuilding/CMakeLists.txt | 121 +++ Online/EventBuilding/EventBuilding/BU.hpp | 166 +++ .../EventBuilding/EventBuilding/MEP_tools.hpp | 155 +++ .../EventBuilding/MFP_generator.hpp | 177 ++++ .../EventBuilding/EventBuilding/MFP_tools.hpp | 171 ++++ Online/EventBuilding/EventBuilding/RU.hpp | 158 +++ .../events_dispatch/Builder_dummy_unit.hpp | 78 ++ .../events_dispatch/Filter_unit.hpp | 126 +++ .../events_dispatch/MBM_reader_dummy_unit.hpp | 80 ++ .../events_dispatch/Manager_unit.hpp | 121 +++ .../events_dispatch/Output_unit.hpp | 111 ++ .../EventBuilding/events_dispatch/Unit.hpp | 15 + .../EventBuilding/events_dispatch/common.hpp | 214 ++++ .../events_dispatch/fbuff_api.hpp | 32 + .../events_dispatch/fbuff_api_impl.hpp | 101 ++ .../EventBuilding/generic_block.hpp | 46 + .../EventBuilding/EventBuilding/mdf_tools.hpp | 97 ++ .../EventBuilding/EventBuilding/raw_tools.hpp | 178 ++++ Online/EventBuilding/EventBuilding/tools.hpp | 118 +++ Online/EventBuilding/LICENSE | 674 ++++++++++++ .../EventBuilding/components/Components.cpp | 35 + Online/EventBuilding/include/MEP_injector.hpp | 86 ++ Online/EventBuilding/include/MFP_builder.hpp | 63 ++ .../EventBuilding/include/MFP_preloader.hpp | 54 + .../EventBuilding/include/Parallel_Comm.hpp | 85 ++ .../include/buffer_interface.hpp | 133 +++ .../include/buffer_writer_error.hpp | 25 + Online/EventBuilding/include/bw_mon.hpp | 38 + .../EventBuilding/include/circular_buffer.hpp | 28 + .../include/circular_buffer_reader.hpp | 39 + .../include/circular_buffer_reader_impl.hpp | 102 ++ .../include/circular_buffer_status.hpp | 42 + .../include/circular_buffer_writer.hpp | 43 + .../include/circular_buffer_writer_impl.hpp | 113 +++ .../include/dummy_mep_buffer_writer.hpp | 37 + .../include/dummy_mfp_buffer.hpp | 45 + Online/EventBuilding/include/file_writer.hpp | 33 + .../include/file_writer_impl.hpp | 30 + .../include/infiniband_net/ArduinoJson.h | 17 + .../include/infiniband_net/ArduinoJson.hpp | 73 ++ .../ArduinoJson/Array/ArrayFunctions.hpp | 28 + .../ArduinoJson/Array/ArrayImpl.hpp | 30 + .../ArduinoJson/Array/ArrayIterator.hpp | 96 ++ .../ArduinoJson/Array/ArrayRef.hpp | 144 +++ .../ArduinoJson/Array/ArrayShortcuts.hpp | 47 + .../ArduinoJson/Array/ElementProxy.hpp | 172 ++++ .../ArduinoJson/Array/Utilities.hpp | 160 +++ .../ArduinoJson/Collection/CollectionData.hpp | 87 ++ .../ArduinoJson/Collection/CollectionImpl.hpp | 220 ++++ .../ArduinoJson/Configuration.hpp | 236 +++++ .../Deserialization/DeserializationError.hpp | 95 ++ .../ArduinoJson/Deserialization/Filter.hpp | 52 + .../Deserialization/NestingLimit.hpp | 28 + .../ArduinoJson/Deserialization/Reader.hpp | 52 + .../Readers/ArduinoStreamReader.hpp | 29 + .../Readers/ArduinoStringReader.hpp | 14 + .../Deserialization/Readers/FlashReader.hpp | 53 + .../Readers/IteratorReader.hpp | 45 + .../Deserialization/Readers/RamReader.hpp | 47 + .../Readers/StdStreamReader.hpp | 27 + .../Deserialization/Readers/VariantReader.hpp | 31 + .../Deserialization/deserialize.hpp | 60 ++ .../Document/BasicJsonDocument.hpp | 153 +++ .../Document/DynamicJsonDocument.hpp | 23 + .../ArduinoJson/Document/JsonDocument.hpp | 301 ++++++ .../Document/StaticJsonDocument.hpp | 53 + .../ArduinoJson/Json/EscapeSequence.hpp | 37 + .../ArduinoJson/Json/JsonDeserializer.hpp | 697 +++++++++++++ .../ArduinoJson/Json/JsonSerializer.hpp | 139 +++ .../infiniband_net/ArduinoJson/Json/Latch.hpp | 53 + .../ArduinoJson/Json/PrettyJsonSerializer.hpp | 95 ++ .../ArduinoJson/Json/TextFormatter.hpp | 156 +++ .../infiniband_net/ArduinoJson/Json/Utf16.hpp | 61 ++ .../infiniband_net/ArduinoJson/Json/Utf8.hpp | 47 + .../ArduinoJson/Memory/Alignment.hpp | 60 ++ .../ArduinoJson/Memory/MemoryPool.hpp | 198 ++++ .../ArduinoJson/Misc/SerializedValue.hpp | 62 ++ .../ArduinoJson/Misc/Visitable.hpp | 28 + .../MsgPack/MsgPackDeserializer.hpp | 607 +++++++++++ .../ArduinoJson/MsgPack/MsgPackSerializer.hpp | 210 ++++ .../ArduinoJson/MsgPack/endianess.hpp | 42 + .../ArduinoJson/MsgPack/ieee754.hpp | 19 + .../infiniband_net/ArduinoJson/Namespace.hpp | 26 + .../ArduinoJson/Numbers/Float.hpp | 17 + .../ArduinoJson/Numbers/FloatParts.hpp | 89 ++ .../ArduinoJson/Numbers/FloatTraits.hpp | 208 ++++ .../ArduinoJson/Numbers/Integer.hpp | 33 + .../ArduinoJson/Numbers/arithmeticCompare.hpp | 127 +++ .../ArduinoJson/Numbers/convertNumber.hpp | 100 ++ .../ArduinoJson/Numbers/parseNumber.hpp | 142 +++ .../ArduinoJson/Object/MemberProxy.hpp | 181 ++++ .../ArduinoJson/Object/ObjectFunctions.hpp | 48 + .../ArduinoJson/Object/ObjectImpl.hpp | 71 ++ .../ArduinoJson/Object/ObjectIterator.hpp | 98 ++ .../ArduinoJson/Object/ObjectRef.hpp | 225 ++++ .../ArduinoJson/Object/ObjectShortcuts.hpp | 67 ++ .../ArduinoJson/Object/Pair.hpp | 49 + .../ArduinoJson/Polyfills/alias_cast.hpp | 30 + .../ArduinoJson/Polyfills/assert.hpp | 14 + .../ArduinoJson/Polyfills/attributes.hpp | 45 + .../ArduinoJson/Polyfills/ctype.hpp | 14 + .../ArduinoJson/Polyfills/limits.hpp | 36 + .../ArduinoJson/Polyfills/math.hpp | 29 + .../ArduinoJson/Polyfills/mpl/max.hpp | 27 + .../ArduinoJson/Polyfills/pgmspace.hpp | 78 ++ .../Polyfills/pgmspace_generic.hpp | 34 + .../ArduinoJson/Polyfills/preprocessor.hpp | 34 + .../ArduinoJson/Polyfills/safe_strcmp.hpp | 28 + .../ArduinoJson/Polyfills/static_array.hpp | 31 + .../ArduinoJson/Polyfills/type_traits.hpp | 24 + .../Polyfills/type_traits/conditional.hpp | 20 + .../Polyfills/type_traits/declval.hpp | 14 + .../Polyfills/type_traits/enable_if.hpp | 20 + .../type_traits/integral_constant.hpp | 19 + .../Polyfills/type_traits/is_array.hpp | 24 + .../Polyfills/type_traits/is_base_of.hpp | 25 + .../Polyfills/type_traits/is_class.hpp | 26 + .../Polyfills/type_traits/is_const.hpp | 19 + .../Polyfills/type_traits/is_convertible.hpp | 43 + .../Polyfills/type_traits/is_enum.hpp | 21 + .../type_traits/is_floating_point.hpp | 22 + .../Polyfills/type_traits/is_integral.hpp | 31 + .../Polyfills/type_traits/is_pointer.hpp | 18 + .../Polyfills/type_traits/is_same.hpp | 19 + .../Polyfills/type_traits/is_signed.hpp | 53 + .../Polyfills/type_traits/is_unsigned.hpp | 45 + .../Polyfills/type_traits/make_unsigned.hpp | 62 ++ .../Polyfills/type_traits/remove_const.hpp | 20 + .../type_traits/remove_reference.hpp | 20 + .../Polyfills/type_traits/type_identity.hpp | 15 + .../ArduinoJson/Polyfills/utility.hpp | 31 + .../Serialization/CountingDecorator.hpp | 27 + .../ArduinoJson/Serialization/Writer.hpp | 43 + .../Writers/ArduinoStringWriter.hpp | 50 + .../Serialization/Writers/DummyWriter.hpp | 17 + .../Serialization/Writers/PrintWriter.hpp | 22 + .../Writers/StaticStringWriter.hpp | 39 + .../Serialization/Writers/StdStreamWriter.hpp | 31 + .../Serialization/Writers/StdStringWriter.hpp | 42 + .../ArduinoJson/Serialization/measure.hpp | 19 + .../ArduinoJson/Serialization/serialize.hpp | 44 + .../StringStorage/StringCopier.hpp | 64 ++ .../ArduinoJson/StringStorage/StringMover.hpp | 32 + .../StringStorage/StringStorage.hpp | 23 + .../Strings/ArduinoStringAdapter.hpp | 56 + .../Strings/ConstRamStringAdapter.hpp | 52 + .../Strings/FlashStringAdapter.hpp | 51 + .../Strings/FlashStringIterator.hpp | 31 + .../ArduinoJson/Strings/IsString.hpp | 21 + .../ArduinoJson/Strings/IsWriteableString.hpp | 39 + .../ArduinoJson/Strings/RamStringAdapter.hpp | 40 + .../Strings/SizedFlashStringAdapter.hpp | 47 + .../Strings/SizedRamStringAdapter.hpp | 44 + .../ArduinoJson/Strings/StdStringAdapter.hpp | 57 ++ .../ArduinoJson/Strings/StoragePolicy.hpp | 18 + .../ArduinoJson/Strings/String.hpp | 62 ++ .../ArduinoJson/Strings/StringAdapters.hpp | 22 + .../ArduinoJson/Variant/SlotFunctions.hpp | 58 ++ .../ArduinoJson/Variant/VariantAs.hpp | 109 ++ .../ArduinoJson/Variant/VariantAsImpl.hpp | 59 ++ .../ArduinoJson/Variant/VariantCompare.hpp | 230 +++++ .../ArduinoJson/Variant/VariantContent.hpp | 54 + .../ArduinoJson/Variant/VariantData.hpp | 351 +++++++ .../ArduinoJson/Variant/VariantFunctions.hpp | 142 +++ .../ArduinoJson/Variant/VariantImpl.hpp | 139 +++ .../ArduinoJson/Variant/VariantOperators.hpp | 185 ++++ .../ArduinoJson/Variant/VariantRef.hpp | 386 +++++++ .../ArduinoJson/Variant/VariantShortcuts.hpp | 22 + .../ArduinoJson/Variant/VariantSlot.hpp | 94 ++ .../ArduinoJson/Variant/VariantTo.hpp | 33 + .../ArduinoJson/compatibility.hpp | 23 + .../infiniband_net/ArduinoJson/version.hpp | 10 + .../include/infiniband_net/ib.hpp | 586 +++++++++++ .../include/infiniband_net/parser.hpp | 67 ++ .../include/infiniband_net/proc.hpp | 71 ++ .../include/infiniband_net/sock.hpp | 44 + Online/EventBuilding/include/logger.hpp | 170 ++++ Online/EventBuilding/include/mbm_reader.hpp | 51 + .../EventBuilding/include/mbm_reader_impl.hpp | 85 ++ Online/EventBuilding/include/mbm_writer.hpp | 54 + .../EventBuilding/include/mbm_writer_impl.hpp | 154 +++ Online/EventBuilding/include/mdf_reader.hpp | 36 + Online/EventBuilding/include/options.hpp | 55 + .../EventBuilding/include/pcie40_reader.hpp | 178 ++++ .../include/pcie40_reader_error.hpp | 45 + .../include/shared_mem_buffer_backend.hpp | 82 ++ .../include/shared_ptr_buffer_backend.hpp | 33 + .../include/shmem_buffer_reader.hpp | 27 + .../include/shmem_buffer_writer.hpp | 28 + Online/EventBuilding/include/timer.hpp | 35 + .../EventBuilding/include/transport_unit.hpp | 98 ++ Online/EventBuilding/options/BU_0.opts | 4 + Online/EventBuilding/options/BU_1.opts | 4 + Online/EventBuilding/options/EB_BU.opts | 33 + Online/EventBuilding/options/EB_RU.opts | 24 + Online/EventBuilding/options/EB_RU_algo.opts | 9 + .../EventBuilding/options/EB_transport.opts | 10 + Online/EventBuilding/options/MFPGen.opts | 11 + .../scripts/example_debug_config.json | 33 + Online/EventBuilding/scripts/gen_config.py | 211 ++++ .../EventBuilding/scripts/monitor_couters.py | 145 +++ Online/EventBuilding/scripts/pcie_checker.py | 118 +++ .../EventBuilding/scripts/read_eb_counters.py | 138 +++ Online/EventBuilding/scripts/run.gdb | 9 + Online/EventBuilding/scripts/run_eb.py | 473 +++++++++ Online/EventBuilding/scripts/run_eb_scan.py | 465 +++++++++ Online/EventBuilding/src/BU.cpp | 959 ++++++++++++++++++ Online/EventBuilding/src/MEP_injector.cpp | 228 +++++ Online/EventBuilding/src/MEP_tools.cpp | 182 ++++ Online/EventBuilding/src/MFP_builder.cpp | 240 +++++ Online/EventBuilding/src/MFP_generator.cpp | 596 +++++++++++ Online/EventBuilding/src/MFP_preloader.cpp | 103 ++ Online/EventBuilding/src/MFP_tools.cpp | 183 ++++ Online/EventBuilding/src/Parallel_Comm.cpp | 360 +++++++ Online/EventBuilding/src/RU.cpp | 927 +++++++++++++++++ Online/EventBuilding/src/buffer_interface.cpp | 31 + .../EventBuilding/src/buffer_writer_error.cpp | 29 + Online/EventBuilding/src/bw_mon.cpp | 42 + .../src/circular_buffer_status.cpp | 56 + .../src/dummy_mep_buffer_writer.cpp | 85 ++ Online/EventBuilding/src/dummy_mfp_buffer.cpp | 86 ++ .../events_dispatch/Builder_dummy_unit.cpp | 149 +++ .../src/events_dispatch/Filter_unit.cpp | 405 ++++++++ .../events_dispatch/MBM_reader_dummy_unit.cpp | 131 +++ .../src/events_dispatch/Manager_unit.cpp | 476 +++++++++ .../src/events_dispatch/Output_unit.cpp | 524 ++++++++++ .../src/events_dispatch/common.cpp | 33 + Online/EventBuilding/src/generic_block.cpp | 27 + .../EventBuilding/src/infiniband_net/ib.cpp | 672 ++++++++++++ .../src/infiniband_net/ib_collective.cpp | 152 +++ .../src/infiniband_net/ib_comms.cpp | 127 +++ .../src/infiniband_net/ib_polling.cpp | 276 +++++ .../src/infiniband_net/ib_rdma_ops.cpp | 110 ++ .../src/infiniband_net/ib_sync.cpp | 275 +++++ .../src/infiniband_net/parser.cpp | 232 +++++ .../EventBuilding/src/infiniband_net/sock.cpp | 96 ++ Online/EventBuilding/src/logger.cpp | 188 ++++ Online/EventBuilding/src/mdf_reader.cpp | 105 ++ Online/EventBuilding/src/mdf_tools.cpp | 95 ++ Online/EventBuilding/src/options.cpp | 220 ++++ Online/EventBuilding/src/pcie40_reader.cpp | 704 +++++++++++++ .../EventBuilding/src/pcie40_reader_error.cpp | 44 + Online/EventBuilding/src/raw_tools.cpp | 141 +++ .../src/shared_mem_buffer_backend.cpp | 407 ++++++++ .../src/shared_ptr_buffer_backend.cpp | 31 + Online/EventBuilding/src/timer.cpp | 75 ++ Online/EventBuilding/src/tools.cpp | 185 ++++ Online/EventBuilding/src/transport_unit.cpp | 474 +++++++++ Online/EventBuilding/test.mdf | 0 254 files changed, 28373 insertions(+) create mode 100644 .git-lb-checkout create mode 100644 Online/EventBuilding/.clang-format create mode 100644 Online/EventBuilding/.gitignore create mode 100644 Online/EventBuilding/.gitlab-ci.yml create mode 100755 Online/EventBuilding/CI/clang_format_test.sh create mode 100644 Online/EventBuilding/CMakeLists.txt create mode 100644 Online/EventBuilding/EventBuilding/BU.hpp create mode 100644 Online/EventBuilding/EventBuilding/MEP_tools.hpp create mode 100644 Online/EventBuilding/EventBuilding/MFP_generator.hpp create mode 100644 Online/EventBuilding/EventBuilding/MFP_tools.hpp create mode 100644 Online/EventBuilding/EventBuilding/RU.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/Builder_dummy_unit.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/Filter_unit.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/MBM_reader_dummy_unit.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/Manager_unit.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/Output_unit.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/Unit.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/common.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api.hpp create mode 100644 Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api_impl.hpp create mode 100644 Online/EventBuilding/EventBuilding/generic_block.hpp create mode 100644 Online/EventBuilding/EventBuilding/mdf_tools.hpp create mode 100644 Online/EventBuilding/EventBuilding/raw_tools.hpp create mode 100644 Online/EventBuilding/EventBuilding/tools.hpp create mode 100644 Online/EventBuilding/LICENSE create mode 100644 Online/EventBuilding/components/Components.cpp create mode 100644 Online/EventBuilding/include/MEP_injector.hpp create mode 100644 Online/EventBuilding/include/MFP_builder.hpp create mode 100644 Online/EventBuilding/include/MFP_preloader.hpp create mode 100644 Online/EventBuilding/include/Parallel_Comm.hpp create mode 100644 Online/EventBuilding/include/buffer_interface.hpp create mode 100644 Online/EventBuilding/include/buffer_writer_error.hpp create mode 100644 Online/EventBuilding/include/bw_mon.hpp create mode 100644 Online/EventBuilding/include/circular_buffer.hpp create mode 100644 Online/EventBuilding/include/circular_buffer_reader.hpp create mode 100644 Online/EventBuilding/include/circular_buffer_reader_impl.hpp create mode 100644 Online/EventBuilding/include/circular_buffer_status.hpp create mode 100644 Online/EventBuilding/include/circular_buffer_writer.hpp create mode 100644 Online/EventBuilding/include/circular_buffer_writer_impl.hpp create mode 100644 Online/EventBuilding/include/dummy_mep_buffer_writer.hpp create mode 100644 Online/EventBuilding/include/dummy_mfp_buffer.hpp create mode 100644 Online/EventBuilding/include/file_writer.hpp create mode 100644 Online/EventBuilding/include/file_writer_impl.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson.h create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayFunctions.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayImpl.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayIterator.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayRef.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayShortcuts.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ElementProxy.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/Utilities.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionData.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionImpl.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Configuration.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/DeserializationError.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Filter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/NestingLimit.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Reader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/FlashReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/IteratorReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/RamReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/VariantReader.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/deserialize.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/BasicJsonDocument.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/DynamicJsonDocument.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/JsonDocument.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/StaticJsonDocument.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/EscapeSequence.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonDeserializer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonSerializer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Latch.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/PrettyJsonSerializer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/TextFormatter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf16.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf8.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/Alignment.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/MemoryPool.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/SerializedValue.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/Visitable.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackDeserializer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackSerializer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/endianess.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/ieee754.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Namespace.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Float.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatParts.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatTraits.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Integer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/arithmeticCompare.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/convertNumber.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/parseNumber.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/MemberProxy.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectFunctions.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectImpl.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectIterator.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectRef.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectShortcuts.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/Pair.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/alias_cast.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/assert.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/attributes.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/ctype.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/limits.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/math.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/mpl/max.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace_generic.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/preprocessor.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/safe_strcmp.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/static_array.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/conditional.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/declval.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/enable_if.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/integral_constant.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_array.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_base_of.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_class.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_const.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_convertible.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_enum.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_integral.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_pointer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_same.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_signed.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_const.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_reference.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/type_identity.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/utility.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/CountingDecorator.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writer.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/DummyWriter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/PrintWriter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStringWriter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/measure.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/serialize.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringCopier.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringMover.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringStorage.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ArduinoStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ConstRamStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringIterator.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsString.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsWriteableString.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/RamStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedFlashStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedRamStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StdStringAdapter.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StoragePolicy.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/String.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StringAdapters.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/SlotFunctions.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAs.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAsImpl.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantCompare.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantContent.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantData.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantFunctions.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantImpl.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantOperators.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantRef.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantShortcuts.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantSlot.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantTo.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/compatibility.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ArduinoJson/version.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/ib.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/parser.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/proc.hpp create mode 100644 Online/EventBuilding/include/infiniband_net/sock.hpp create mode 100644 Online/EventBuilding/include/logger.hpp create mode 100644 Online/EventBuilding/include/mbm_reader.hpp create mode 100644 Online/EventBuilding/include/mbm_reader_impl.hpp create mode 100644 Online/EventBuilding/include/mbm_writer.hpp create mode 100644 Online/EventBuilding/include/mbm_writer_impl.hpp create mode 100644 Online/EventBuilding/include/mdf_reader.hpp create mode 100644 Online/EventBuilding/include/options.hpp create mode 100644 Online/EventBuilding/include/pcie40_reader.hpp create mode 100644 Online/EventBuilding/include/pcie40_reader_error.hpp create mode 100644 Online/EventBuilding/include/shared_mem_buffer_backend.hpp create mode 100644 Online/EventBuilding/include/shared_ptr_buffer_backend.hpp create mode 100644 Online/EventBuilding/include/shmem_buffer_reader.hpp create mode 100644 Online/EventBuilding/include/shmem_buffer_writer.hpp create mode 100644 Online/EventBuilding/include/timer.hpp create mode 100644 Online/EventBuilding/include/transport_unit.hpp create mode 100644 Online/EventBuilding/options/BU_0.opts create mode 100644 Online/EventBuilding/options/BU_1.opts create mode 100755 Online/EventBuilding/options/EB_BU.opts create mode 100755 Online/EventBuilding/options/EB_RU.opts create mode 100644 Online/EventBuilding/options/EB_RU_algo.opts create mode 100644 Online/EventBuilding/options/EB_transport.opts create mode 100755 Online/EventBuilding/options/MFPGen.opts create mode 100644 Online/EventBuilding/scripts/example_debug_config.json create mode 100755 Online/EventBuilding/scripts/gen_config.py create mode 100644 Online/EventBuilding/scripts/monitor_couters.py create mode 100644 Online/EventBuilding/scripts/pcie_checker.py create mode 100644 Online/EventBuilding/scripts/read_eb_counters.py create mode 100644 Online/EventBuilding/scripts/run.gdb create mode 100755 Online/EventBuilding/scripts/run_eb.py create mode 100755 Online/EventBuilding/scripts/run_eb_scan.py create mode 100644 Online/EventBuilding/src/BU.cpp create mode 100644 Online/EventBuilding/src/MEP_injector.cpp create mode 100644 Online/EventBuilding/src/MEP_tools.cpp create mode 100644 Online/EventBuilding/src/MFP_builder.cpp create mode 100644 Online/EventBuilding/src/MFP_generator.cpp create mode 100644 Online/EventBuilding/src/MFP_preloader.cpp create mode 100644 Online/EventBuilding/src/MFP_tools.cpp create mode 100644 Online/EventBuilding/src/Parallel_Comm.cpp create mode 100644 Online/EventBuilding/src/RU.cpp create mode 100644 Online/EventBuilding/src/buffer_interface.cpp create mode 100644 Online/EventBuilding/src/buffer_writer_error.cpp create mode 100644 Online/EventBuilding/src/bw_mon.cpp create mode 100644 Online/EventBuilding/src/circular_buffer_status.cpp create mode 100644 Online/EventBuilding/src/dummy_mep_buffer_writer.cpp create mode 100644 Online/EventBuilding/src/dummy_mfp_buffer.cpp create mode 100644 Online/EventBuilding/src/events_dispatch/Builder_dummy_unit.cpp create mode 100644 Online/EventBuilding/src/events_dispatch/Filter_unit.cpp create mode 100644 Online/EventBuilding/src/events_dispatch/MBM_reader_dummy_unit.cpp create mode 100644 Online/EventBuilding/src/events_dispatch/Manager_unit.cpp create mode 100644 Online/EventBuilding/src/events_dispatch/Output_unit.cpp create mode 100644 Online/EventBuilding/src/events_dispatch/common.cpp create mode 100644 Online/EventBuilding/src/generic_block.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/ib.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/ib_collective.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/ib_comms.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/ib_polling.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/ib_rdma_ops.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/ib_sync.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/parser.cpp create mode 100644 Online/EventBuilding/src/infiniband_net/sock.cpp create mode 100644 Online/EventBuilding/src/logger.cpp create mode 100644 Online/EventBuilding/src/mdf_reader.cpp create mode 100644 Online/EventBuilding/src/mdf_tools.cpp create mode 100644 Online/EventBuilding/src/options.cpp create mode 100644 Online/EventBuilding/src/pcie40_reader.cpp create mode 100644 Online/EventBuilding/src/pcie40_reader_error.cpp create mode 100644 Online/EventBuilding/src/raw_tools.cpp create mode 100644 Online/EventBuilding/src/shared_mem_buffer_backend.cpp create mode 100644 Online/EventBuilding/src/shared_ptr_buffer_backend.cpp create mode 100644 Online/EventBuilding/src/timer.cpp create mode 100644 Online/EventBuilding/src/tools.cpp create mode 100644 Online/EventBuilding/src/transport_unit.cpp create mode 100644 Online/EventBuilding/test.mdf diff --git a/.git-lb-checkout b/.git-lb-checkout new file mode 100644 index 000000000..f88cba926 --- /dev/null +++ b/.git-lb-checkout @@ -0,0 +1,3 @@ +[lb-checkout "Online.Online/EventBuilding"] + base = e70832481d09f05ee80b0ee52c8348d12e1458bf + imported = af6da089bf25cd1560da4842765386550f7488b9 diff --git a/Online/EventBuilding/.clang-format b/Online/EventBuilding/.clang-format new file mode 100644 index 000000000..7e4a59599 --- /dev/null +++ b/Online/EventBuilding/.clang-format @@ -0,0 +1,68 @@ +Language: Cpp +# Refer to documentation https://clang.llvm.org/docs/ClangFormatStyleOptions.html +AccessModifierOffset: -2 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterStruct: false + BeforeElse: false + SplitEmptyFunction: false +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: AfterColon +BreakStringLiterals: true +ColumnLimit: 120 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +FixNamespaceComments: true +IndentWidth: 2 +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +# not compatible with clang 6 +# SpaceBeforeCpp11BracedList: true +# SpaceBeforeCtorInitializerColon: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never diff --git a/Online/EventBuilding/.gitignore b/Online/EventBuilding/.gitignore new file mode 100644 index 000000000..c60f1142d --- /dev/null +++ b/Online/EventBuilding/.gitignore @@ -0,0 +1,3 @@ +build* +gbd_run.gdb +.vscode/* diff --git a/Online/EventBuilding/.gitlab-ci.yml b/Online/EventBuilding/.gitlab-ci.yml new file mode 100644 index 000000000..9f628824c --- /dev/null +++ b/Online/EventBuilding/.gitlab-ci.yml @@ -0,0 +1,11 @@ +stages: + - build + +clang-format: + stage: build + + before_script: + - source /cvmfs/sft.cern.ch/lcg/releases/clang/8.0.0.1/x86_64-centos7/setup.sh + + script: + - ./CI/clang_format_test.sh diff --git a/Online/EventBuilding/CI/clang_format_test.sh b/Online/EventBuilding/CI/clang_format_test.sh new file mode 100755 index 000000000..bd55d4c74 --- /dev/null +++ b/Online/EventBuilding/CI/clang_format_test.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +modified_files=$(git ls-files -m) +if [[ -n $modified_files ]]; then + echo "ERROR this script must be applied to a clean git state" + exit 2 +fi + +find . -name '*.cpp' -o -name '*.hpp' -exec clang-format -i {} \; + +modified_files=$(git ls-files -m) + +if [[ -z $modified_files ]]; then + # send a negative message to gitlab + echo "Excellent. **VERY GOOD FORMATTING!** :thumbsup:" + exit 0; +else + echo "The following files have clang-format problems (showing patches)"; + for f in $modified_files; do + echo $f + git diff $f + done +fi + +git reset HEAD --hard + +exit 1 diff --git a/Online/EventBuilding/CMakeLists.txt b/Online/EventBuilding/CMakeLists.txt new file mode 100644 index 000000000..6e487e904 --- /dev/null +++ b/Online/EventBuilding/CMakeLists.txt @@ -0,0 +1,121 @@ +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == = +#LHCb Online software suite +#-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - +#Copyright(C) Organisation europeenne pour la Recherche nucleaire(CERN) +#All rights reserved. +# +#For the licensing terms see OnlineSys / LICENSE. +# +#Author : R.Krawczyk, based on example by M.Frank +# +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == = +# +#Package : EventBuilding +# + +### stuff from fakeeb + +gaudi_subdir(EventBuilding v0r1) +# +## Online/dim Online/GauchoBase Online/PCIE40Data +gaudi_depends_on_subdirs(Online/Dataflow + Online/OnlineBase) + +# TODO use find_package for PCIe40 libs +#Check for local PCIE40.If not present do not build event builder libraries +# TODO no cache is currently no supported by CMake < 3.21 check what it does in the future +find_path(PCIE40_DAQ_INC NAMES "daq40.hpp" "daq.h" "id.h" PATHS /usr/include/lhcb/daq40 NO_CACHE) +if ( "${PCIE40_DAQ_INC}" STREQUAL "PCIE40_DAQ_INC-NOTFOUND" ) + message(STATUS "+======================================================================+") + message(STATUS "| PCIE40 DAQ not present. Will not build EventBuilding libraries. |") + message(STATUS "+======================================================================+") + return() +else() + return() + message(STATUS "+======================================================================+") + message(STATUS "| PCIE40 DAQ found. EventBuilding libraries shall be built. |") + message(STATUS "+======================================================================+") +endif() + +#fpisani fixed find of external libraries +find_package(MPI REQUIRED) +include(Numa) +find_package(PkgConfig REQUIRED) + +set(OLD_CONFIG_PATH $ENV{PKG_CONFIG_PATH}) +#TODO check if there is a better way to identify this path +set(ENV{PKG_CONFIG_PATH} /usr/lib64/pkgconfig) +pkg_search_module(GLIB2 REQUIRED glib-2.0) +#add_definitions(${MPI_CXX_COMPILE_DEFINITIONS}) + +find_package(Boost REQUIRED COMPONENTS system filesystem regex) +find_package(ROOT REQUIRED COMPONENTS Hist) +# +#If we want to globally rename the DD4hep namespace to Online, enable the line below ! +add_definitions(-DDD4hep=Online) +# +# +#-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - +#EventBuilding basic client library +#Note : The ROOT dependency is only required to declare Monitors of type THX +#-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - +set(INFINIBAND_LIBRARIES ibverbs pthread) +set(INFINIBAND_DIRS include/infiniband_net) +set(PCIE_40_LIBRARIES pcie40_daq pcie40_id pcie40) +set(PCIE_40_INCLUDE_DIRS /usr/include/lhcb/daq40 /usr/include/lhcb) + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${MPI_CXX_INCLUDE_DIRS} ${PCIE_40_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}) + +gaudi_add_library(EventBuildingLib + src/*.cpp + src/events_dispatch/*.cpp + src/infiniband_net/*.cpp + PUBLIC_HEADERS EventBuilding EventBuilding/events_dispatch + INCLUDE_DIRS ${MPI_CXX_INCLUDE_DIRS} ${PCIE_40_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} ${INFINIBAND_DIRS} + LINK_LIBRARIES dim ROOT OnlineBase DataflowLib DAQEventLib + ${MPI_CXX_LIBRARIES} ${PCIE_40_LIBRARIES} ${GLIB2_LIBRARIES} + ${INFINIBAND_LIBRARIES}) + + +target_include_directories(EventBuildingLib BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(EventBuildingLib BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/infiniband_net) +target_compile_options(EventBuildingLib PRIVATE -std=c++2a) +if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(EventBuildingLib PRIVATE -fconcepts) +endif() + +# --------------------------------------------------------------------------------------- +# Commonly used DataflowExample components +# --------------------------------------------------------------------------------------- +gaudi_add_library(EventBuilding + components/*.cpp + INCLUDE_DIRS ${NUMA_INCLUDE_DIR} ${MPI_CXX_INCLUDE_DIRS} ${PCIE_40_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} + NO_PUBLIC_HEADERS + LINK_LIBRARIES dim Boost OnlineBase DataflowLib EventBuildingLib ${NUMA_LIBRARIES} ${GLIB2_LIBRARIES} + ${MPI_CXX_LIBRARIES} ${PCIE_40_LIBRARIES}) + +target_include_directories(EventBuilding BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(EventBuilding BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/infiniband_net) +target_compile_options(EventBuilding PRIVATE -std=c++2a) +if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(EventBuildingLib PRIVATE -fconcepts) +endif() + +# +# ---> Steer the property parser: +# If we want to rename the Gaudi namespace to Online, enable the line below! +#target_compile_definitions(DataflowExample PRIVATE -DDataflowExample_NS=Online) +gaudi_generate_componentslist(EventBuilding) +# +# --------------------------------------------------------------------------------------- +# If there is a scripts directory +#gaudi_install_scripts() +# If there are python components +#gaudi_install_python_modules() +# --------------------------------------------------------------------------------------- +# Testing +# --------------------------------------------------------------------------------------- +# Enable QMTests +#gaudi_add_test(QMTest QMTEST) + +set(ENV{PKG_CONFIG_PATH} ${OLD_CONFIG_PATH}) diff --git a/Online/EventBuilding/EventBuilding/BU.hpp b/Online/EventBuilding/EventBuilding/BU.hpp new file mode 100644 index 000000000..705446e4d --- /dev/null +++ b/Online/EventBuilding/EventBuilding/BU.hpp @@ -0,0 +1,166 @@ +#ifndef BU_H +#define BU_H 1 + +#include <memory> +#include <string> +#include <list> +#include <mutex> +#include <unordered_map> + +#include "Dataflow/DataflowComponent.h" +#include "mbm_writer.hpp" +#include "MFP_tools.hpp" +#include "MEP_tools.hpp" +#include "transport_unit.hpp" +#include "Parallel_Comm.hpp" +#include "bw_mon.hpp" +#include "timer.hpp" +#include "buffer_interface.hpp" +#include "logger.hpp" +#include "file_writer.hpp" + +namespace EB { + using namespace Online; + enum BU_buffer_types { dummy_MEP_buffer, shmem_MEP_buffer, MBM_MEP_buffer, MEP_injector_buffer }; + + constexpr std::initializer_list<BU_buffer_types> all_BU_buffer_types = + {dummy_MEP_buffer, shmem_MEP_buffer, MBM_MEP_buffer, MEP_injector_buffer}; + + constexpr auto default_BU_buffer_type = BU_buffer_types::dummy_MEP_buffer; + constexpr auto default_MBM_name = "Input"; + constexpr auto default_BU_buffer_size = 1; + + const std::string BU_buffer_type_to_string(BU_buffer_types type); + + std::ostream& operator<<(std::ostream& os, BU_buffer_types type); + + class BU : public Transport_unit { + public: + BU(const std::string& name, Context& framework); + ~BU(); + + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implemenentation: Inform that a new incident has occured + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + private: + int _my_idx; + bool _receive_MEPs = false; + bool _end_of_run = true; + + // properties + // per BU parameters + // TODO continue implementing vector params + // all the vectors are defied add length check and init value plus idx based config + std::vector<int> _buffer_type; + std::vector<int> _prop_buffer_sizes; + std::vector<size_t> _buffer_sizes; + int _prop_discard_buffer_size; + std::vector<bool> _write_to_file; + std::vector<std::string> _mbm_name; + // MEP injector properties + std::string _MDF_filename; + int _packing_factor; + int _n_meps; + // global parameters + std::string _shmem_prefix; + std::string _out_file_prefix; + int _n_meps_to_file; + int _stop_timeout; + bool _sort_src_ids; + + // this may be included in Transport_unit + // sizes of the current MFPs divided by RU and source + std::vector<uint32_t> _sizes; + // full size of the current MEP + uint32_t _full_size_words; + std::vector<EB::offset_type> _data_offset_words; + // std::vector<MEP::src_id_type> _src_ids; + std::vector<uint32_t> _dummy; + bool _discarted; + bool _incomplete; + + std::vector<EB::src_id_type> _src_ids; + std::vector<EB::src_id_type> _sorted_src_ids; + std::vector<size_t> _src_id_idx_to_ru_src_idx; + std::vector<size_t> _ru_src_idx_to_src_id_idx; + + std::vector<std::vector<int>> _shift_offset; + + int check_buffer(); + int config_buffer(); + int sort_src_ids(); + int init_shift(); + int receive_sizes(); + int receive_src_ids(); + int linear_shift(); + int receive_MFPs(const std::vector<int>& shift_off_it); + int get_next_MEP_space(); + int build_MEP_header(); + + void config_dummy(); + void config_shmem(); + void config_mbm(); + void config_MEP_injector(); + + void reset_counters() override; + void init_profiling() override; + void update_profiling() override; + + // monitoring counters + int _MEP_count = 0; + int _discarted_MEP_count = 0; + int _incomplete_MEP_count = 0; + int _corrupted_MEP_count = 0; + size_t _rcv_bytes = 0; + size_t _snd_bytes = 0; + std::unordered_map<src_id_type, int> _incomplete_MEP_srcs; + // DF monitoring counters + int _DF_events_out; + int _DF_events_in; + int _DF_events_err; + + // DEBUG counters + int _run_loop_iteration; + + // profiling counters + double _receive_size_time_counter; + double _calc_offsets_time_counter; + double _build_header_time_counter; + double _linear_shift_time_counter; + double _receive_MFPs_time_counter; + + EB::Buffer_writer<EB::MEP>* _recv_buff; + EB::Buffer_writer<EB::MEP>* _discard_buff; + EB::MEP* _curr_MEP; + + Timer _receive_size_timer; + Timer _calc_offsets_timer; + Timer _build_header_timer; + Timer _linear_shift_timer; + Timer _receive_MFPs_timer; + + std::timed_mutex _loop_lock; + std::timed_mutex _start_lock; + + // file writer + File_writer<EB::MEP> _file_writer; + int _n_meps_written_to_file; + }; +} // namespace EB + +#endif // BU_H diff --git a/Online/EventBuilding/EventBuilding/MEP_tools.hpp b/Online/EventBuilding/EventBuilding/MEP_tools.hpp new file mode 100644 index 000000000..509e21740 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/MEP_tools.hpp @@ -0,0 +1,155 @@ +#ifndef MEP_TOOLS_H +#define MEP_TOOLS_H 1 +#include <cstdint> +#include <cstdlib> +#include <iostream> +#include <iterator> +#include "MFP_tools.hpp" + +namespace EB { + typedef uint32_t offset_type; + + constexpr uint16_t MEP_magic = 0xCEFA; + constexpr uint16_t MEP_wrap = ~MEP_magic; + // size of a word in bytes (see p_words and offsets) + constexpr size_t MEP_WORD_SIZE = (32 / 8); + + struct __attribute__((__packed__)) MEP_header { + // On valid packets 0xCEFA + uint16_t magic; + // Number of MFPs in this packet + uint16_t n_MFPs; + // Size of this packet in 32-bit words + uint32_t p_words; + + // the return value of this methods is valid only id n_mps is set and they assume a contiguos memory layout + // pointer to the src IDs array + src_id_type* src_ids(); + const src_id_type* src_ids() const; + // pointer to the src offsets array + // The offset is the distance in 32-bit words between the n-th MFP in the packet and the start of this header + offset_type* offsets(); + const offset_type* offsets() const; + + // header size in bytes + size_t size() const; + // header size in bytes including padding + size_t mem_size() const; + + // print header fields + std::string print() const; + friend std::ostream& operator<<(std::ostream& os, const MEP_header& header); + }; + + // TODO find a better name for the namespace or the class the NS may be Online + struct __attribute__((__packed__)) MEP { + MEP_header header; + + // setter/getter for the validity of the MEP + bool is_magic_valid() const; + void set_magic_valid(); + + // setter/getter for the wrap condition, this condition is used internally by the EB buffering. Wrap MEPs are not + // valid and will should never go out of the EB. + bool is_wrap() const; + void set_wrap(); + + // header size in bytes + size_t header_size() const; + // header size in bytes including padding + size_t header_mem_size() const; + // packet size in bytes + size_t bytes() const; + + // setter/getter for the validity of the MEP + bool is_valid() const; + + // pointer to the begining of the payload + void* payload(); + const void* payload() const; + + EB::MFP* at(int n); + const EB::MFP* at(int n) const; + + EB::MFP* operator[](int n); + const EB::MFP* operator[](int n) const; + + // print header fields + std::string print(bool MFP_header_only = true) const; + friend std::ostream& operator<<(std::ostream& os, const MEP& mep); + + // Iterator definition + struct iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = EB::MFP; + using pointer = EB::MFP*; + using reference = EB::MFP&; + + // iterator(pointer mfp, offset_type* offset) : _offset(offset), _mfp(mfp) {} + iterator(uintptr_t base_ptr, const offset_type* offset) : _offset(offset), _base_ptr(base_ptr) {} + + reference operator*() const; + pointer operator->(); + iterator& operator++(); + + iterator operator++(int); + + friend bool operator==(const iterator& a, const iterator& b); + friend bool operator!=(const iterator& a, const iterator& b); + + private: + const offset_type* _offset; + uintptr_t _base_ptr; + pointer _get_ptr() const; + }; + + // Const iterator definition + struct const_iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = const EB::MFP; + using pointer = const EB::MFP*; + using reference = const EB::MFP&; + + const_iterator(uintptr_t base_ptr, const offset_type* offset) : _offset(offset), _base_ptr(base_ptr) {} + + reference operator*() const; + pointer operator->(); + const_iterator& operator++(); + + const_iterator operator++(int); + friend bool operator==(const const_iterator& a, const const_iterator& b); + friend bool operator!=(const const_iterator& a, const const_iterator& b); + + private: + pointer _get_ptr() const; + + const offset_type* _offset; + uintptr_t _base_ptr; + }; + + iterator begin() { return iterator(reinterpret_cast<uintptr_t>(this), header.offsets()); } + // TODO this is a bit convoluted there is probably a better way of getting a valid end iterator + iterator end() { return iterator(reinterpret_cast<uintptr_t>(this), header.offsets() + header.n_MFPs); } + const_iterator cbegin() const { return const_iterator(reinterpret_cast<uintptr_t>(this), header.offsets()); } + // TODO this is a bit convoluted there is probably a better way of getting a valid end iterator + const_iterator cend() const + { + return const_iterator(reinterpret_cast<uintptr_t>(this), header.offsets() + header.n_MFPs); + } + }; + + // calculates the size of a MEP header given the number of MFPs + size_t mep_header_size(int n_MFPs); + size_t mep_header_mem_size(int n_MFPs); + + // alignent in the mpf header in bytes + constexpr size_t MEP_alignment = 4; + + std::ostream& operator<<(std::ostream& os, const MEP_header& header); + std::ostream& operator<<(std::ostream& os, const MEP& mep); + +} // namespace EB + +#endif // MEP_TOOLS_H \ No newline at end of file diff --git a/Online/EventBuilding/EventBuilding/MFP_generator.hpp b/Online/EventBuilding/EventBuilding/MFP_generator.hpp new file mode 100644 index 000000000..1082b8807 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/MFP_generator.hpp @@ -0,0 +1,177 @@ +#ifndef MFP_GENERATOR_H +#define MFP_GENERATOR_H 1 + +#include <string> +#include <random> +#include <functional> +#include <mutex> + +#include "Dataflow/DataflowComponent.h" +#include "MFP_tools.hpp" +#include "shmem_buffer_writer.hpp" +#include "timer.hpp" +#include "logger.hpp" + +namespace EB { + class MFP_generator : public Online::DataflowComponent { + public: + MFP_generator(const std::string& name, Context& framework); + virtual ~MFP_generator(); + + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implementation: Inform that a new incident has occurredd + virtual void handle(const Online::DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + private: + void configure(); + + Log_stream logger; + + bool _generate = false; + + // properties + unsigned _prop_n_banks; + std::string _prop_src_id; + unsigned _prop_align; + unsigned _prop_block_version; + unsigned _prop_bank_type; + // In the dummy MFPs the banks have all the same size + unsigned _prop_bank_size; + // Enable the test pattern generation (This mode may slow down performance) + bool _enable_test_pattern; + + // Event rate in Hz + double _event_rate; + + // UTGUID of the SODIN data generator + std::string _sodin_utguid; + + // Random sizes props + bool _random_sizes; + unsigned _n_preloaded_sizes; // number of preloaded sizes used when generating the banks + unsigned _random_seed; + int _lambda; // lambda of the poisson distributions + int _offset; // offset fo the poisson distribution + int _multi; // multiplier of the poisson distribution + // total function _offset + poisson(_lambda)*_multi + + // subdetector specific random props + bool _sub_detector_specific_run; + + // Override list for the various SDs, the UTGUID will use the specified SD instead the default one + std::vector<std::string> _velo_utigid_override; + std::vector<std::string> _scifi_utigid_override; + std::vector<std::string> _ut_utigid_override; + std::vector<std::string> _muon_utigid_override; + std::vector<std::string> _hcal_utigid_override; + std::vector<std::string> _ecal_utigid_override; + std::vector<std::string> _rich1_utigid_override; + std::vector<std::string> _rich2_utigid_override; + + int _velo_lambda; // lambda of the poisson distributions + int _velo_offset; // offset fo the poisson distribution + int _velo_multi; // multiplier of the poisson distribution + + int _scifi_lambda; // lambda of the poisson distributions + int _scifi_offset; // offset fo the poisson distribution + int _scifi_multi; // multiplier of the poisson distribution + + int _ut_lambda; // lambda of the poisson distributions + int _ut_offset; // offset fo the poisson distribution + int _ut_multi; // multiplier of the poisson distribution + + int _muon_lambda; // lambda of the poisson distributions + int _muon_offset; // offset fo the poisson distribution + int _muon_multi; // multiplier of the poisson distribution + + int _hcal_lambda; // lambda of the poisson distributions + int _hcal_offset; // offset fo the poisson distribution + int _hcal_multi; // multiplier of the poisson distribution + + int _ecal_lambda; // lambda of the poisson distributions + int _ecal_offset; // offset fo the poisson distribution + int _ecal_multi; // multiplier of the poisson distribution + + int _rich1_lambda; // lambda of the poisson distributions + int _rich1_offset; // offset fo the poisson distribution + int _rich1_multi; // multiplier of the poisson distribution + + int _rich2_lambda; // lambda of the poisson distributions + int _rich2_offset; // offset fo the poisson distribution + int _rich2_multi; // multiplier of the poisson distribution + + // prop buffer size is in GB + size_t _prop_buffer_size; + size_t _buffer_size; + std::string _shmem_name; + std::vector<int> _numa_layout; + bool _reconnect; + int _stop_timeout; + + // MFP header fields + uint16_t _n_banks; + uint64_t _ev_id; + uint16_t _src_id; + uint8_t _align; + uint8_t _block_version; + + unsigned int _sleep_interval_ns; + + EB::bank_type_type _bank_type; + // In the dummy MFPs the banks have all the same size + EB::bank_size_type _bank_size; + + std::vector<EB::bank_size_type> _bank_sizes; + std::minstd_rand _generator; + + int init_sd(); + void init_sodin(); + void init_sizes(); + void init_sd_run(); + void write_MFP(); + void write_ODIN_banks(EB::MFP* MFP); + void write_test_pattern(EB::MFP* MFP); + void write_end_run(); + int config_numa(); + + int _numa_node; + + bool _is_sodin; + unsigned int _run_number; + + // DF monitoring counters + // TODO remove duplicates + int _DF_events_out; + int _DF_events_in; + int _DF_events_err; + + Shmem_buffer_writer<EB::MFP> _buffer; + + Timer _total_timer; + Timer _random_gen_timer; + Timer _MFP_write_timer; + Timer _dead_time_timer; + uint64_t _last_report_ev_id; + int _local_id; + std::string _sub_detector; + + std::timed_mutex _loop_lock; + std::timed_mutex _start_lock; + }; +} // namespace EB + +#endif // MFP_GENERATOR_H \ No newline at end of file diff --git a/Online/EventBuilding/EventBuilding/MFP_tools.hpp b/Online/EventBuilding/EventBuilding/MFP_tools.hpp new file mode 100644 index 000000000..91f408b02 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/MFP_tools.hpp @@ -0,0 +1,171 @@ +#ifndef MFP_TOOLS_H +#define MFP_TOOLS_H 1 + +#include "raw_tools.hpp" +#include "mdf_tools.hpp" +#include <vector> +#include <cstring> +#include <cassert> +#include <iostream> +#include <sstream> + +namespace EB { + typedef uint8_t bank_type_type; + typedef uint16_t bank_size_type; + typedef uint16_t src_id_type; + typedef uint64_t ev_id_type; + + constexpr uint16_t MFP_magic = 0x40ce; + constexpr uint16_t MFP_wrap = ~MFP_magic; + + constexpr uint64_t MFP_end_run = 0xffffffffffffffff; + + struct __attribute__((__packed__)) MFP_header { + // On valid packets 0x40CE + uint16_t magic; + // Number of banks in the MFP + uint16_t n_banks; + // size of the packet in Bytes + uint32_t packet_size; + // event ID of the first event in the packet + ev_id_type ev_id; + // Source ID of the data + src_id_type src_id; + // alignment of the fragments + uint8_t align; + // block version + uint8_t block_version; + + // the return value of those methods is valid only if n_banks and align are set and they assume contiguous memory + // layout + // pointer to the begining of the bank types array + bank_type_type* bank_types(); + const bank_type_type* bank_types() const; + // pointer to the begining of the bank sizes array + bank_size_type* bank_sizes(); + const bank_size_type* bank_sizes() const; + // pointer to the begining of the payload + + // size of the header in bytes + size_t header_size() const; + // size of the packet in bytes (same as packet size compatibility reasons) + size_t bytes() const; + + std::string print(bool verbose = false) const; + + friend std::ostream& operator<<(std::ostream& os, const MFP_header& header); + }; + + struct __attribute__((__packed__)) MFP { + MFP_header header; + + void* payload(); + const void* payload() const; + + // setter/getter for the validity of the MFP header + bool is_header_valid() const; + void set_header_valid(); + // check if the MFP is valid i.e. header_valid and size >= header_size + bool is_valid() const; + + // setter/getter for the end of run MFP (a special MPF generated by the PCIe40 on run change, it should never go out + // of the EB) + bool is_end_run() const; + void set_end_run(); + + // setter/getter for the wrap condition, this condition is used internally by the EB buffering. Wrap MPFs are not + // valid and will sould never go out of the EB. + bool is_wrap() const; + void set_wrap(); + + // TODO implement a proper class for the raw banks + void* get_bank_n(int n); + const void* get_bank_n(int n) const; + + size_t bytes() const { return header.bytes(); } + + void* operator[](int n); + const void* operator[](int n) const; + + // print header fields + std::string print(bool verbose = false) const; + friend std::ostream& operator<<(std::ostream& os, const MFP& mfp); + + // Iterator definition + struct iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + // TODO this should be a raw bank + using value_type = char; + using pointer = value_type*; + using reference = value_type&; + + iterator(pointer bank, bank_size_type* size, uint8_t align) : _size(size), _bank(bank), _align(align) {} + + reference operator*() const; + pointer operator->(); + iterator& operator++(); + + iterator operator++(int); + friend bool operator==(const iterator& a, const iterator& b); + friend bool operator!=(const iterator& a, const iterator& b); + + private: + bank_size_type* _size; + pointer _bank; + uint8_t _align; + }; + + // Const iterator definition + struct const_iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + // TODO this should be a raw bank + using value_type = char; + using pointer = const value_type*; + using reference = const value_type&; + + const_iterator(pointer bank, const bank_size_type* size, uint8_t align) : _size(size), _bank(bank), _align(align) + {} + + reference operator*() const; + pointer operator->(); + const_iterator& operator++(); + + const_iterator operator++(int); + friend bool operator==(const const_iterator& a, const const_iterator& b); + friend bool operator!=(const const_iterator& a, const const_iterator& b); + + private: + const bank_size_type* _size; + pointer _bank; + uint8_t _align; + }; + + iterator begin() { return iterator(reinterpret_cast<char*>(payload()), header.bank_sizes(), header.align); } + iterator end() + { + return iterator(reinterpret_cast<char*>(payload()), header.bank_sizes() + header.n_banks, header.align); + } + const_iterator cbegin() const + { + return const_iterator(reinterpret_cast<const char*>(payload()), header.bank_sizes(), header.align); + } + const_iterator cend() const + { + return const_iterator( + reinterpret_cast<const char*>(payload()), header.bank_sizes() + header.n_banks, header.align); + } + }; + + // calculates the size of an MFP header given the number of banks and the alignment + size_t MFP_header_size(int packing_fraction); + + // alignent in the mpf header in bytes + constexpr size_t MFP_alignment = 4; + + std::ostream& operator<<(std::ostream& os, const MFP_header& header); + std::ostream& operator<<(std::ostream& os, const MFP& mfp); +} // namespace EB + +#endif // MFP_TOOLS_H \ No newline at end of file diff --git a/Online/EventBuilding/EventBuilding/RU.hpp b/Online/EventBuilding/EventBuilding/RU.hpp new file mode 100644 index 000000000..7a20777a6 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/RU.hpp @@ -0,0 +1,158 @@ +#ifndef RU_H +#define RU_H 1 + +#include <memory> +#include <string> +#include <list> +#include <mutex> +#include <atomic> + +#include "Dataflow/DataflowComponent.h" +#include "MFP_tools.hpp" +#include "transport_unit.hpp" +#include "dummy_mfp_buffer.hpp" +#include "Parallel_Comm.hpp" +#include "bw_mon.hpp" +#include "timer.hpp" +#include "buffer_interface.hpp" +#include "pcie40_reader.hpp" +#include "file_writer.hpp" + +namespace EB { + using namespace Online; + enum RU_buffer_types { dummy_MFP_buffer, shmem_MFP_buffer, PCIe40_MFP_buffer, PCIe40_frag_buffer }; + + constexpr std::initializer_list<RU_buffer_types> all_RU_buffer_types = + {dummy_MFP_buffer, shmem_MFP_buffer, PCIe40_MFP_buffer, PCIe40_frag_buffer}; + + constexpr auto default_RU_buffer_type = RU_buffer_types::shmem_MFP_buffer; + constexpr auto default_RU_buffer_size = 1; + + const std::string RU_buffer_type_to_string(RU_buffer_types type); + + std::ostream& operator<<(std::ostream& os, RU_buffer_types type); + + class RU : public Transport_unit { + public: + RU(const std::string& name, Context& framework); + virtual ~RU(); + + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implementation: Inform that a new incident has occurred + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + private: + // there is one buffer per associated data source + std::vector<std::unique_ptr<EB::Buffer_reader<EB::MFP>>> _buffers; + int _my_idx; + std::atomic<bool> _send_MEPs = false; + bool _end_of_run = true; + bool _send_empty = false; + // true if we received at least one MFP since start + std::vector<bool> _received_data; + + // mpfs and sizes of every source for the full linear shift rotation + std::vector<const char*> selected_MFPs; + // number of loaded fragments per source + std::vector<int> _n_frags_per_dst; + std::vector<uint32_t> sizes; + // std::vector<int>::const_iterator curr_dst; + + // properties + // per RU parameters + // TODO check if signed int is enough size_t is not supported by the framework + // well it is not the buffer sizes property is now in GB + std::vector<size_t> _buffer_sizes; + std::vector<int> _prop_buffer_sizes; + std::vector<bool> _write_to_file; + std::vector<int> _PCIe40_ids; + std::vector<std::string> _PCIe40_names; + std::vector<int> _buffer_type; + std::vector<int> _dummy_src_ids; + int _SODIN_ID; + std::string _SODIN_name; + int _SODIN_stream; + // global parameters + // global parameters + int _n_fragment; + std::string _shmem_prefix; + // TODO check if the MDF_filename can be global to all the RUs + std::string _MDF_filename; + std::string _out_file_prefix; + int _n_MFPs; + int _n_MFPs_to_file; + int _stop_timeout; + + std::vector<int> _shift_offset; + + // internal states + int check_buffers(); + int stream_select(int id); + int stream_select(const std::string& name); + int config_buffers(); + void config_dummy(); + void config_shmem(); + void config_PCIe40(); + void config_PCIe40_frag(); + int init_shift(); + int send_MFPs(int shift); + int linear_shift(); + int send_sizes(); + int init_dummy_src_ids(); + int send_src_ids(); + int load_mfps(); + // preload a set on 0 sized NULL MFPs + int load_empty(); + + void reset_counters() override; + void init_profiling() override; + void update_profiling() override; + + // TODO the int counters should be uint64_t + // monitoring counter + int _MFP_count = 0; + size_t _rcv_bytes = 0; + size_t _snd_bytes = 0; + // DF monitoring counters + int _DF_events_out; + int _DF_events_in; + int _DF_events_err; + + // DEBUG counters + int _run_loop_iteration; + + // profiling counters + double _load_mpfs_time_counter; + double _send_sizes_time_counter; + double _linear_shift_time_counter; + double _send_time_counter; + + Timer _load_mpfs_timer; + Timer _send_sizes_timer; + Timer _linear_shift_timer; + Timer _send_timer; + + std::timed_mutex _loop_lock; + std::timed_mutex _start_lock; + + // file writer + File_writer<EB::MFP> _file_writer; + int _n_MFPs_written_to_file; + }; +} // namespace EB + +#endif // RU_H diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/Builder_dummy_unit.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/Builder_dummy_unit.hpp new file mode 100644 index 000000000..35a855711 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/Builder_dummy_unit.hpp @@ -0,0 +1,78 @@ +#ifndef BUILDERDUMMYUNIT_HPP +#define BUILDERDUMMYUNIT_HPP + +#include "fbuff_api.hpp" +#include "Unit.hpp" +#include "common.hpp" +#include <assert.h> +#include <ctime> +#include <malloc.h> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "shmem_buffer_writer.hpp" +#include "EventBuilding/MEP_tools.hpp" +#include "Dataflow/DataflowComponent.h" +#include "MBM/Producer.h" +#include "mbm_writer.hpp" +#include "buffer_interface.hpp" + +/// C/C++ include files +#include <memory> +#include <mutex> + +/// Forward declarations + +/// Online namespace declaration +namespace Online { + + class Builder_dummy_unit : public DataflowComponent, public Unit { + + public: + /// Initializing constructor + Builder_dummy_unit(const std::string& name, Context& framework); + /// Default destructor + virtual ~Builder_dummy_unit() = default; + + // constructor/destructor & methods + protected: + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implemenentation: Inform that a new incident has occured + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + // methods + private: + void generate_meps(); + bool time_elapsed_check(); + + // variables + private: + int64_t _now; + int64_t _timer_start; + int64_t _delay_timer; + int64_t _probe_global_start; + size_t _all_completed_bytes; + size_t _current_probe_completed_bytes; + int64_t _next_probing; + std::string _mbm_name; + EB::Buffer_writer<EB::MEP>* _buff_writer; + bool _m_receiveEvts = false; + int _buffer_type; + }; +} // end namespace Online + +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/Filter_unit.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/Filter_unit.hpp new file mode 100644 index 000000000..8791adccd --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/Filter_unit.hpp @@ -0,0 +1,126 @@ +#ifndef FILTERUNIT_HPP +#define FILTERUNIT_HPP + +#include <assert.h> +#include <chrono> +#include <ctime> +#include <glib.h> +#include <malloc.h> +#include <mpi.h> +#include <random> +#include <stdio.h> +#include <stdlib.h> +#include <tuple> +#include <unistd.h> +#include <vector> + +#include "Unit.hpp" +#include "common.hpp" +#include "Dataflow/DataflowComponent.h" +#include "MBM/Producer.h" + +#include "buffer_interface.hpp" +#include "EventBuilding/MEP_tools.hpp" +#include "mbm_writer.hpp" + +// Filter Unit class +// Used to implement Data Consumer functions + +namespace Online { + + class Filter_unit : public DataflowComponent, public Unit { + + public: + // main method to perform data consuming operations + Filter_unit(const std::string& nam, DataflowContext& ctxt); + /// Default destructor + virtual ~Filter_unit() = default; + + protected: + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implemenentation: Inform that a new incident has occured + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + // methods + private: + // start transmissions to force necessary MPI resource allocation + // invoked to mitigate / eliminate MPI init impact on the actual performance + // measurements + void mpi_warmup_run(); + // Method for nofyfing Event Manager that FU is ready fo send + void signal_readiness(DISPATCH::fu_status stat = DISPATCH::fu_status::TRANSMISSION_DONE); + // test if any of commenced MPI sends has finished + bool probe_for_completion(int* index); + // Commence data receive from ANY BU source + void recv_from_bu(size_t size, int index, int sender_rank, int tag = DISPATCH::BU_RU_DATA_TAG); + bool service_mu_alloc_call(); + // Generate new period to simulate processing time on the data consumer side + size_t get_new_processing_period(size_t new_mep_size); + // calculate index for data for next transmission + long unsigned int get_entry_address(int entry_index); + void probe_print_throughput(); + bool exchange_message_size(); + void run_recv(); + void get_meta(size_t size); + void init_new_transmission(int sender_rank); + + // variables + private: + /// Property: Buffer name for data output + std::string _mbm_name; + EB::Buffer_writer<EB::MEP>* _write_buff; + // buffer of records current pointer + unsigned int _data_buffer_current_ptr; + // counter of all finished transmissions granted to RU + int64_t _all_finished_granted_transmission; + // timestamp when the current record processing in queue was commenced + int64_t _event_started_processing_timestamp; + // MPI request for FU signalling readiness + MPI_Request _mpi_fu_ready_request; + MPI_Request _mpi_acq_request; + MPI_Request _mpi_mu_fu_alloc_request; + // MPI Message to signal FU readiness + DISPATCH::mpi_fu_ready_msg _fu_ready_message; + // MPI Message to establish message size + DISPATCH::mpi_bu_fu_mep_size_msg _ou_fu_mep_size_msg; + DISPATCH::mu_fu_alloc_msg _alloc_msg; + + // counter of all completed irecv requests to count total average FU + // throughput + size_t _all_completed_bytes; + + // counter of all completed irecv requests for the current probing period to + // caltulate current FU throughput + size_t _current_probe_completed_bytes; + + // array for holding MPI_Request structures for pending transmisisons from BU + // to FU + // Currently dimensions 1 x WINDOW_LENGTH + MPI_Request* _mpi_data_sent_requests; + + // current start time of the latest throughput probe + int64_t _probe_start; + // global start time when Event Building transmissions were commenced + int64_t _global_start; + + int64_t _next_probing; + char* _acquired_data_ptr; + DISPATCH::current_transmission_metadata _current_transmission_meta; + size_t _last_allocated_message_size; + }; +} // namespace Online + +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/MBM_reader_dummy_unit.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/MBM_reader_dummy_unit.hpp new file mode 100644 index 000000000..c2584b61e --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/MBM_reader_dummy_unit.hpp @@ -0,0 +1,80 @@ +#ifndef MBMREADERDUMMYUNIT_HPP +#define MBMREADERDUMMYUNIT_HPP + +#include "fbuff_api.hpp" +#include "Unit.hpp" +#include "common.hpp" +#include <ctime> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "EventBuilding/MEP_tools.hpp" +// Framework include files + +#include "Dataflow/Incidents.h" +#include "Dataflow/MBMClient.h" +#include "RTL/rtl.h" +#include "Dataflow/DataflowComponent.h" +#include "MBM/Consumer.h" +#include "MBM/Requirement.h" +#include "fbuff_api.hpp" +#include "shmem_buffer_reader.hpp" +#include "mbm_reader.hpp" +#include <memory> +#include <mutex> + +/// Online namespace declaration +namespace Online { + + class MBM_reader_dummy_unit : public DataflowComponent, public Unit { + + public: + /// Initializing constructor + MBM_reader_dummy_unit(const std::string& name, Context& framework); + /// Default destructor + virtual ~MBM_reader_dummy_unit() = default; + + // methods + protected: + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implemenentation: Inform that a new incident has occured + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + private: + void read_meps(); + bool time_elapsed_check(); + + // variables + private: + int64_t _now; + int64_t _timer_start; + int64_t _delay_timer; + int64_t _probe_global_start; + size_t _all_completed_bytes; + size_t _current_probe_completed_bytes; + int64_t _next_probing; + std::string _m_buffer; + /// Flag indicating that MBM event retrieval is active + bool _m_receiveEvts = false; + /// Property: Requirement as job option in string form + EB::Buffer_reader<EB::MEP>* _recv_buff; + std::string _m_req; + }; +} // end namespace Online + +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/Manager_unit.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/Manager_unit.hpp new file mode 100644 index 000000000..2ada89a2e --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/Manager_unit.hpp @@ -0,0 +1,121 @@ + + +#ifndef MANAGER_HPP +#define MANAGER_HPP + +#include "Unit.hpp" +#include "common.hpp" +#include <assert.h> +#include <ctime> +#include <glib.h> +#include <limits> +#include <malloc.h> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <thread> +#include <unistd.h> +#include <vector> + +#include "Dataflow/DataflowComponent.h" +#include "MBM/Producer.h" + +// Manager Unit class +// Used to implement Builder Units (Data Producers) to Filter Units (Data +// Consumers) scheduling +namespace Online { + + class Manager_unit : public DataflowComponent, public Unit { + + public: + /// Initializing constructor + Manager_unit(const std::string& nam, DataflowContext& ctxt); + /// Default destructor + virtual ~Manager_unit() = default; + + protected: + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implemenentation: Inform that a new incident has occured + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + // methods + private: + void get_ready_fus(); + void get_meps_bus(); + void grant_transmissions_to_bus(); + void initialize_receiving_fus(); + void initialize_receiving_bus(); + void send_bus_transmisison_grant(int buInd, int fuInd); + int get_next_bu_rank_ready(); + // get the next Builder Unit to grant the BU-FU transmission pair + bool get_next_free_fu_rank_ready_w_lowest_bytes(int* fu_index, int chosen_bu_index); + // get the next Filter Unit to grant the BU-FU transmission pair + bool get_next_bu_rank_ready_w_lowest_bytes(int* index); + int get_bu_rank_ready_with_least_rus(); + int get_next_fu_ind(); + int get_next_bu_ind(); + // start transmissions to force necessary MPI resource allocation + // invoked to mitigate / eliminate MPI init impact on the actual performance + // measurements + void mpi_warmup_run(); + // get next MEP size + size_t get_next_bu_mep_size_to_transmit(int bu_ind); + void erase_next_bu_mep_size(int bu_ind); + void get_vector_of_meps(int bu_index, int entries_no); + bool try_fu_alloc(int fu_ind, size_t size); + + // variables + private: + size_t* _ready_mep_array; + std::vector<size_t>* _bu_meps_sizes_vectors; + // variables + size_t* _bus_total_granted_bytes_array; + size_t* _fus_total_granted_bytes_array; + + int _how_many_ous; + int _how_many_fus; + + int* _free_bu_grants; + int* _trans_fu_no; + + int _bu_to_grant; + int _fu_to_grant; + // lookups for ranks that BUs have - goes togethet with busRanksReady + int* _bus_ranks; + int* _fus_ranks; + size_t* _bus_meps_granted_bytes; + int* _fus_ranks_ready; + // array to limit BUs number assigned to a given FU to one + int* _bu_grants; + + // holds which Bu has been assigned for a particular transmission to a given + // FU + int* _granted_bu_for_fu; + MPI_Request* _fu_ready_requests; + MPI_Request* _bu_ready_requests; + MPI_Request* _trans_grant_requests; + DISPATCH::mpi_fu_ready_msg* _fu_ready_messages; + DISPATCH::mpi_bu_ready_msg* _bu_ready_messages; + DISPATCH::mpi_bu_transmission_grant_msg* _trans_grant_messages; + + // global timestamp holding start of EM existence + // USED to timestamp events that happened in the EM + int64_t _start_probe; + }; +} // namespace Online + +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/Output_unit.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/Output_unit.hpp new file mode 100644 index 000000000..93837d9cf --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/Output_unit.hpp @@ -0,0 +1,111 @@ + +#ifndef OUTPUTUNIT_HPP +#define OUTPUTUNIT_HPP + +// Builder Unit class +// Used to implement Data Producer functions + +#include <assert.h> +#include <ctime> +#include <malloc.h> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "shmem_buffer_reader.hpp" +#include "mbm_reader.hpp" +#include "fbuff_api.hpp" +#include "Unit.hpp" +#include "common.hpp" +#include "EventBuilding/MEP_tools.hpp" +#include "Dataflow/DataflowComponent.h" +#include "MBM/Producer.h" +#include "buffer_interface.hpp" + +namespace Online { + + class Output_unit : public DataflowComponent, public Unit { + public: + /// Initializing constructor + Output_unit(const std::string& name, Context& framework); + /// Default destructor + virtual ~Output_unit() = default; + + protected: + /// Service implementation: initialize the service + virtual int initialize() override; + /// Service implementation: start of the service + virtual int start() override; + /// Service implementation: stop the service + virtual int stop() override; + /// Service implementation: finalize the service + virtual int finalize() override; + + /// Cancel I/O operations of the dataflow component + virtual int cancel() override; + /// Stop gracefully execution of the dataflow component + virtual int pause() override; + /// Incident handler implemenentation: Inform that a new incident has occured + virtual void handle(const DataflowIncident& inc) override; + /// IRunable implementation : Run the class implementation + virtual int run() override; + + private: + void start_send_data_to_fu(int rank, int slot); + void signal_new_meps_ready(std::vector<mep_entry> new_mep_vector); + bool time_elapsed_check(); + std::vector<mep_entry> get_meps_vector(); + void exchange_message_size(int fu_rank, size_t size); + void get_meta(size_t size, int ind); + void get_array_of_meps(std::vector<mep_entry> new_mep_vector); + + bool check_if_granted_transmission(int* ready_rank); + void update_granted_transmissions(); + void start_receive_from_mu(); + // start transmissions to force necessary MPI resource allocation + // invoked to mitigate the MPI init impact on the actual performance measurements + void mpi_warmup_run(); + int get_free_slot(); + + private: + int _buffer_type; + unsigned long int _total_serviced_events; + // counter of all completed sends to count total average OU + // throughput + size_t _all_completed_bytes; + // counter of all completed sends for the current probing period to + // caltulate current BU throughput + size_t _current_probe_completed_bytes; + + int64_t _next_probing; + int* _started_credited_transmissions; + bool* _credit_free_array; + int* _credits_to_rank_array; + + int* _pending_credits_array; + int _pending_credits_no; + + int64_t _now; + int64_t _start_timer; + int64_t _delay_timer; + + std::string _mbm_name; + MPI_Request _bu_ready_requests; + mpi_bu_ready_msg _bu_ready_message; + MPI_Request _trans_granted_requests; + mpi_bu_transmission_grant_msg _trans_granted_message; + // MPI Message to establish message size + mpi_bu_fu_mep_size_msg _bu_fu_mep_size_msg; + MPI_Request** _dataTransmissionRequests; + int64_t probe_global_start; + // vector storing MEP entries + std::vector<mep_entry> _ready_mep_vector; + size_t* _ready_mep_array; + mep_entry _current_transmission; + EB::Buffer_reader<EB::MEP>* _recv_buff; + std::string _m_req; + current_transmission_metadata* _current_transmission_meta; + }; +} // namespace Online +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/Unit.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/Unit.hpp new file mode 100644 index 000000000..137f66820 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/Unit.hpp @@ -0,0 +1,15 @@ +#ifndef UNIT_HPP +#define UNIT_HPP + +namespace Online { + + class Unit { + public: + Unit() = default; + + protected: + int rank; + int worldSize; + }; +} // namespace Online +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/common.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/common.hpp new file mode 100644 index 000000000..48710e027 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/common.hpp @@ -0,0 +1,214 @@ +#ifndef COMMON_HPP +#define COMMON_HPP + +#include <assert.h> +#include <ctime> +#include <malloc.h> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/timerfd.h> +#include <unistd.h> +#include <utility> +#include <sstream> +#include <string> + +/// CONSTANTS + +namespace DISPATCH { + const int BITS_PER_BYTE = 8; + const bool DO_WARMUP = false; + + // init variables + // const size_t M_SIZE = (4 * 1024 * 1024); + // const size_t INIT_AMOUNT = 222220288; + // const size_t INIT_TRANS = 2155872256; + // const size_t FULL_TRANS = INIT_AMOUNT / M_SIZE; + // const size_t REMAINDER = INIT_AMOUNT % M_SIZE; + + const unsigned int BU_RU_DATA_TAG = 10000; + const unsigned int PRINT_TAG = 10001; + const unsigned int BU_RU_SIZE_TAG = 10002; + const unsigned int BU_RU_DATA_REMAINDER_TAG = 10003; + const unsigned int MU_TAG = 10004; + const unsigned int MU_MEPS_TAG = 10005; + const unsigned int OU_FU_WARMUP_TAG = 10006; + const unsigned int MU_FU_ALLOC_TAG = 10008; + // maximal actual number of records of data blobs to be stored in builder units + // (data producers) + // These buffers hold blobs of data must be transmitted to the data consumers + // Typically equals 1 and is cyclically used + const unsigned int MAX_BUFFER_COUNT_BU = 1; + + // BUFFER SIZE + const size_t BUFFER_RECORD_SIZE_MB = 12 * 1024; + + // MPI message size for warmup + const int WARMUP_MPI_SIZE = 512 * 1024 * 1024; + + // sending period in microseconds + const unsigned int PERIOD = 10000; + + // how many times repeat the transmissions + const unsigned int REPEAT_FOR_EVAL = 4096; + + // time lapse in seconds to display BUs / FUs throughput in ms + const unsigned int PROBE_TP_LAPSE = 1000; + + // MAX parallel BU credits + // defines how many data consumers can receive in parallel from a given data + // producer + const int MAX_BU_CREDITS = 1; + + // TODO. Not yet implemented + // For now, FUs receive from a single BU at once + const int MAX_FU_CREDITS = 2; + + // MICROSECONDS IN A SECOND + const long int US_S = 1e6; + + // MILISECONDS IN A SECOND + const long int MS_S = 1000; + + // THRESHOLD BUFFER OCCUPANCY FOR BU + // MAXIMAL NUMBER OF OCCUPIED RECORDS IN A DATA PRODUCER BUFFER + // UPON GENERTAION OF NEW EVENT, IF THIS THRESOLD EXCEEDED, WARNING IS SIGNALLED + // THIS THRESHOLD MUST NOT BE EXCEEDED THROUGHOUT THE WHOLE OPERATION + const int THRESHOLD_BU_QUEUE_BUFFER_OCCUPANCY = 1; + + // once in how many iterations probe time on BU + // tuned if system calls impact performance or event generation interval jitters + const unsigned int PROBE_EVERY_IT = 1000; + + // TIME IN US defining interval how often data producer generates a blob of data + const int64_t TIME_ELAPSED_FOR_GENERATION = 1000000; + + // value used to convert GiB to GB + const double GIB_TO_GB_RATIO = (1024.0 / 1000.0) * (1024.0 / 1000.0) * (1024.0 / 1000.0); + + const unsigned int MB_IN_GRANT = 128; + const size_t PAGE_SIZE = 4096; + const int MAX_MEPS = 518144; + + // meps constants + const int PWORDS_FIELD_OFFSET = 4; + const int BYTES_IN_WORD_32 = 4; + const int MAX_MEPS_IN_ONE_RUN = 1; + + /// PARAMETERS + + // 80 Gbit/s was the value for the 14 BUs and 18 FUs + // How manyEvents + // For 128 MB (1 Gbit) transmisison grants this value also means events + // generation throughput in Gbit/s. + // Throughput is defined as: + // Generated_data = + // Generation_period = TIME_ELAPSED_FOR_GENERATION + // Throughput = Generated_data / Generation_period + extern unsigned int gibit_events_in_one_quantum; + + // Events Manager holds rank 0. THEN THERE ARE BUS - DATA PRODUCERS, THEN THERE + // ARE FUS - DATA CONSUMERS + // How Many Filter Units - DATA CONSUMERS + extern int how_many_fus; + + // How Many Builder Units - DATA PRODUCERS + extern int how_many_ous; + + // Total Number of MPI processes, Including Builder Units, Filter Units and one + // Events Manager + // extern int how_many_processes; + + // Total number of MPI processes + // extern int total_processes_no; + + // transmitting window length + // a single transmission from a data producer to data consumer is implemented by + // multiple MPI_ISends + // WINDOW LENGTH defines a number of parallel MPI_ISends + extern int window_length; + + // total number of MPI_ISends invoked per single BU->FU transmission grant + // ENTRY_SIZE_MB * BUNDLED_TRANSMISSIONS defines the granted BU->FU + // transmission size + // (PER_BUFFER_ENTRIES) / (BUNDLED_TRANSMISSIONS) defines the grant number + // needed for a single generated BU data blob + extern size_t bundled_transmissions; + + // buffer size for single data portion in readout-to-builder units transmission + // 128 MB transmission grant is a reference + extern size_t entry_size_kb; + + extern size_t entry_size_b; + + // defines ratio of amount of generated data in data producer versus amount of + // consumed data in producers + // typically defined by link links speed ratio + extern unsigned int fu_to_ou_buffer_and_throughput_ratio; + + // to set the generation type + extern char distr_type; + + // maximal simulated data consumer capacity for records of a blobs of data + // used to evaluate impact of processing time and consumers blocking on the + // overall transmisisons + extern unsigned int max_simulated_buffer_count_fu; + + extern bool perform_data_check; + + // generate constant or variable size data + extern bool constant_size; + + // use MPI barriers when not running via WinCC + extern bool use_debug_mpi_barriers; + + /// STRUCTURES + + enum fu_status { TRANSMISSION_DONE, FREE_DATA_UPDATE }; + + struct mpi_fu_ready_msg { + int rank; + fu_status status; + }; + + // Message sent from Builder Unit to Event Manager to signal readiness of data + struct mpi_bu_ready_msg { + int rank; + size_t untransmitted_meps_number; + }; + + // Message sent from Event Manager to Builder Unit to signal grant to a Filter + // Unit + struct mpi_bu_transmission_grant_msg { + int send_to_which_fu; + }; + + // Message to exchange data size transmitted from BU to FU + struct mpi_bu_fu_mep_size_msg { + int sender_rank; + size_t size; + }; + + struct current_transmission_metadata { + int full_transmissions_no; + int remainder_size; + }; + + struct fu_processing_entry { + size_t processing_time; + size_t mep_size; + }; + + struct mu_fu_alloc_msg { + bool success; + size_t size; + }; + + // meps structure + typedef std::pair<char*, size_t> mep_entry; + + // get shmem name + std::stringstream get_shmem_name(std::string shmem_name, int rank); +} // namespace DISPATCH + +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api.hpp new file mode 100644 index 000000000..45630e08a --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api.hpp @@ -0,0 +1,32 @@ +#ifndef FBUFF_HPP +#define FBUFF_HPP + +#include <vector> +#include "common.hpp" +#include "buffer_interface.hpp" +#include "EventBuilding/MEP_tools.hpp" + +#include "Dataflow/Incidents.h" +#include "Dataflow/DataflowComponent.h" +#include "buffer_interface.hpp" +#include <sstream> + +namespace FBUFF { + + // Get metadata on all MEP entries (pointer to data and size) given buffer + // tail, head and its size + template<class T> + std::vector<DISPATCH::mep_entry> get_mep(EB::Buffer_reader<T>* _recv_buff); + template<class T> + void sync_data_read(EB::Buffer_reader<T>* _recv_buff); + template<class T> + void sync_data_write(EB::Buffer_writer<T>* _write_buff); + // TODO + // char* get_buffer_data(shmem_buff& buff); + template<class T> + void generate_data(EB::Buffer_writer<T>* _write_buff, int rank, int amount_in_gib); + +} // namespace FBUFF + +#include "fbuff_api_impl.hpp" +#endif diff --git a/Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api_impl.hpp b/Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api_impl.hpp new file mode 100644 index 000000000..c57dc439b --- /dev/null +++ b/Online/EventBuilding/EventBuilding/events_dispatch/fbuff_api_impl.hpp @@ -0,0 +1,101 @@ +#include "../../EventBuilding/events_dispatch/common.hpp" + +using namespace DISPATCH; +template<class T> +std::vector<mep_entry> FBUFF::get_mep(EB::Buffer_reader<T>* _recv_buff) +{ + std::vector<mep_entry> vector_of_entries; + int i; + for (i = 0; i != MAX_MEPS_IN_ONE_RUN; i++) { + EB::MEP* new_elem = _recv_buff->try_get_element(); + if (new_elem == NULL) { + printf("ELEMENT NULL\n"); + break; + } + char* ptr = reinterpret_cast<char*>(new_elem); + // size_t size = new_elem->_size; + size_t size = new_elem->bytes(); + // printf("NONZERO ELEMENT. SIZE %ld. ADDR %ld \n",size,ptr); + vector_of_entries.push_back(mep_entry(ptr, size)); + } + + return vector_of_entries; +} + +// size_t FBUFF::get_buffer_size(shmem_buff& buff) { +// return (buff._local_buffer_status.get_size()); +//}; + +// char* FBUFF::get_buffer_data(shmem_buff& buff) { +// return (buff.get_head()); +//}; + +template<class T> +void FBUFF::sync_data_read(EB::Buffer_reader<T>* _recv_buff) +{ + _recv_buff->read_complete(); +} + +template<class T> +void FBUFF::sync_data_write(EB::Buffer_writer<T>* _write_buff) +{ + _write_buff->write_complete(); +} + +template<class T> +void FBUFF::generate_data(EB::Buffer_writer<T>* _write_buff, int rank, int amount_in_gib) +{ + + if (DISPATCH::constant_size == true) { + size_t gen_size = DISPATCH::MB_IN_GRANT * 1024UL * 1024UL; + size_t total_data_amount = static_cast<size_t>(amount_in_gib) * 1024UL * 1024UL * 1024UL / 8UL; + + unsigned int how_many_to_generate = total_data_amount / gen_size; + // printf("TRYING TO GENERATE %d MEPS \n",how_many_to_generate); + unsigned int i = 0; + for (i = 0; i != how_many_to_generate; i++) { + EB::MEP* new_elem = NULL; + new_elem = _write_buff->try_write_next_element(gen_size); + if (new_elem == NULL) { + printf( + "BUFFER FOR BDU RANK %d NOT ENOUGH SPACE ! GENERATED %d MEPS INSTEAD OF %d\n", rank, i, how_many_to_generate); + break; + } else { + new_elem->set_magic_valid(); + new_elem->header.p_words = gen_size / 4; + _write_buff->write_complete(); + } + } + // printf("BDU rank %d : GENERATED %d MEPS OUT OF OF %d\n", rank, i, how_many_to_generate); + } else { + size_t total_data_amount = + static_cast<size_t>(amount_in_gib) * 1024UL * 1024UL * 1024UL / static_cast<size_t>(BITS_PER_BYTE); + long remaining_data_amount = total_data_amount; + + int all_meps = 0; + while (remaining_data_amount > 0) { + + size_t amount = (rand() % 96 + 32) * 1024 * 1024 * 4; + amount += (4096 * rand()) % (1024 * 1024 * 4); + EB::MEP* new_elem = NULL; + new_elem = _write_buff->try_write_next_element(amount); + if (new_elem == NULL) { + printf( + "BUFFER FOR BDU RANK %d NOT ENOUGH SPACE ! GENERATED %ld B (in %d MEPs) INSTEAD OF %ld\n", + rank, + total_data_amount - remaining_data_amount, + all_meps, + total_data_amount); + break; + } + all_meps++; + new_elem->set_magic_valid(); + new_elem->header.p_words = amount / 4; + remaining_data_amount -= amount; + + _write_buff->write_complete(); + } + } + + return; +} diff --git a/Online/EventBuilding/EventBuilding/generic_block.hpp b/Online/EventBuilding/EventBuilding/generic_block.hpp new file mode 100644 index 000000000..b0a501d1a --- /dev/null +++ b/Online/EventBuilding/EventBuilding/generic_block.hpp @@ -0,0 +1,46 @@ +#ifndef GENERIC_BLOCK_H +#define GENERIC_BLOCK_H 1 + +#include <array> +#include <cerrno> +#include <cstdint> +#include <cstdio> +#include <iostream> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdint.h> +#include <cstring> +#include <unordered_map> +#include <memory> + +namespace EB { + class Generic_block { + private: + protected: + std::shared_ptr<char> _payload; + // void* _payload; + size_t _payload_alloc_size; + // set to true if the payload buffer has been allocate by the object + // bool free_payload; + + // static std::unordered_map<void*, int> ref_counter_map; + + public: + Generic_block(); + Generic_block(std::shared_ptr<char> payload, size_t size); + + virtual ~Generic_block() {} + + std::shared_ptr<char> payload() const; + + void set_payload(std::shared_ptr<char> payload, size_t size); + + bool realloc_payload(size_t size); + + // virtual methods + virtual size_t payload_size() const = 0; + }; +} // namespace EB + +#endif // GENERIC_BLOCK_H \ No newline at end of file diff --git a/Online/EventBuilding/EventBuilding/mdf_tools.hpp b/Online/EventBuilding/EventBuilding/mdf_tools.hpp new file mode 100644 index 000000000..233da6e5b --- /dev/null +++ b/Online/EventBuilding/EventBuilding/mdf_tools.hpp @@ -0,0 +1,97 @@ +#ifndef MDF_TOOLS_H +#define MDF_TOOLS_H 1 + +#include <array> +#include <cerrno> +#include <cstdint> +#include <cstdio> +#include <iostream> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdint.h> +#include "generic_block.hpp" +#include "tools.hpp" + +namespace EB { + struct __attribute__((__packed__)) generic_header { + // MDF generic header field + // size of the data block including the headers repeated 3 times for + // redundancy + uint32_t size[3]; + // base32 checksum 0 if not used + uint32_t checksum; + // compression info 4 bits compression algorithm 4 bits compressio factor + uint8_t compression_information; + // 4 bits header type 4 bit header length in 32 bit words + uint8_t header_information; + // data type + uint8_t data_type; + // spare field + uint8_t spare; + + bool is_valid() const { return (size[0] == size[1]) && (size[0] == size[2]); } + }; + + struct __attribute__((__packed__)) specific_header { + // Trigger mask (if no mask is available, all bytes should be set to 0xFF) + uint32_t trigger_mask[4]; + // Run number + uint32_t run; + // Orbit number + uint32_t orbit; + // Bunch crossing ID + uint32_t bxid; + }; + + struct __attribute__((__packed__)) MDF_header { + generic_header generic; + specific_header specific; + + void print() const; + // MDF_header(int fd, bool skip_payload = false); + }; + + class MDF_block : public Generic_block { + public: + MDF_header header; + + MDF_block(); + MDF_block(std::shared_ptr<char> payload, size_t size); + MDF_block(int fd); + MDF_block(int fd, std::shared_ptr<char> payload, size_t size); + + size_t payload_size() const override; + + // this function reads only the MDF header from the given fd + // returns values + // 0 success + // EOF end of file + // EINVAL truncated file or corrupted header + int read_header(int fd); + + // this function reads the header and the paylod from the given + // fd and saves the payload in an allocated buffer + // if persist is not set the memory will freed by the denstructor + // if persist is set the memory must be hanlded by the user + // returns values + // 0 success + // EOF end of file + // EINVAL truncated file or corrupted header + int read_block(int fd); + + // this function reads the header and the paylod from the given + // fd and saves the payload into the given buffer + // the memory must be hanlded by the user + // returns values + // 0 success + // EOF end of file + // EINVAL truncated file or corrupted header + int read_block(int fd, std::shared_ptr<char> buffer, size_t buffer_size); + + int write_block(int fd) const; + }; + +} // namespace EB + +#endif // MDF_TOOLS_H \ No newline at end of file diff --git a/Online/EventBuilding/EventBuilding/raw_tools.hpp b/Online/EventBuilding/EventBuilding/raw_tools.hpp new file mode 100644 index 000000000..4fa57a501 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/raw_tools.hpp @@ -0,0 +1,178 @@ +#ifndef RAW_TOOLS_H +#define RAW_TOOLS_H 1 + +#include <unistd.h> +#include <stdint.h> +#include <iostream> +#include "generic_block.hpp" +#include <unordered_map> +#include <map> +#include <iostream> + +namespace EB { + // raw block alignment in bytes + constexpr size_t block_alignment = 4; + constexpr uint16_t block_magic = 0xCBCB; + + constexpr uint16_t src_id_det_mask = 0x1; + constexpr uint16_t src_id_fe_mask = 0xCBCB; + + // TODO this should come from LHCb + enum BankType { + L0Calo = 0, // 0 + L0DU, // 1 + PrsE, // 2 + EcalE, // 3 + HcalE, // 4 + PrsTrig, // 5 + EcalTrig, // 6 + HcalTrig, // 7 + Velo, // 8 + Rich, // 9 + TT, // 10 + IT, // 11 + OT, // 12 + Muon, // 13 + L0PU, // 14 + DAQ, // 15 + ODIN, // 16 + HltDecReports, // 17 + VeloFull, // 18 + TTFull, // 19 + ITFull, // 20 + EcalPacked, // 21 + HcalPacked, // 22 + PrsPacked, // 23 + L0Muon, // 24 + ITError, // 25 + TTError, // 26 + ITPedestal, // 27 + TTPedestal, // 28 + VeloError, // 29 + VeloPedestal, // 30 + VeloProcFull, // 31 + OTRaw, // 32 + OTError, // 33 + EcalPackedError, // 34 + HcalPackedError, // 35 + PrsPackedError, // 36 + L0CaloFull, // 37 + L0CaloError, // 38 + L0MuonCtrlAll, // 39 + L0MuonProcCand, // 40 + L0MuonProcData, // 41 + L0MuonRaw, // 42 + L0MuonError, // 43 + GaudiSerialize, // 44 + GaudiHeader, // 45 + TTProcFull, // 46 + ITProcFull, // 47 + TAEHeader, // 48 + MuonFull, // 49 + MuonError, // 50 + TestDet, // 51 + L0DUError, // 52 + HltRoutingBits, // 53 + HltSelReports, // 54 + HltVertexReports, // 55 + HltLumiSummary, // 56 + L0PUFull, // 57 + L0PUError, // 58 + DstBank, // 59 + DstData, // 60 + DstAddress, // 61 + FileID, // 62 + VP, // 63 + FTCluster, // 64 + VL, // 65 + UT, // 66 + UTFull, // 67 + UTError, // 68 + UTPedestal, // 69 + HC, // 70 + HltTrackReports, // 71 + HCError, // 72 + VPRetinaCluster, // 73 + // Add new types here. Don't forget to update also RawBank.cpp + LastType // LOOP Marker; add new bank types ONLY before! + }; + + const std::string ToString(const BankType); + + uint16_t type_to_partition_id(const BankType b_type); + + std::ostream& operator<<(std::ostream& os, const BankType); + + struct __attribute__((__packed__)) raw_header { + uint16_t magic; + uint16_t size; + uint8_t type; + uint8_t version; + uint16_t src_id; + + size_t mem_size() const; + size_t payload_mem_size() const; + size_t payload_size() const; + // this may be dangerous + void* get_payload() { return reinterpret_cast<uint8_t*>(this) + sizeof(this); } + + bool is_valid() const { return (magic == block_magic); } + + int get_sys_src_id() const; + int get_src_id_num() const; + + void set_sys_src_id(uint16_t sys_src_id); + void set_src_id_num(uint16_t src_id_num); + + std::ostream& print(std::ostream& os) const; + friend std::ostream& operator<<(std::ostream& os, const raw_header& header); + }; + + std::ostream& operator<<(std::ostream& os, const raw_header& header); + + class raw_block : public Generic_block { + public: + raw_header header; + + raw_block(); + raw_block(std::shared_ptr<char> payload, size_t size); + + // TODO data may be const void * + int read_block(void* data); + int read_block(void* data, void* buffer, size_t buffer_size); + }; + + typedef std::pair<uint8_t, uint16_t> type_id_pair_type; + + // TODO implement a proper conversion + type_id_pair_type new_src_id_to_old(uint16_t src_id); + + uint16_t old_to_new(EB::type_id_pair_type src_id); + + struct type_src_id_hash { + std::size_t operator()(const type_id_pair_type& p) const { return std::hash<int>{}(p.first << 16 | p.second); } + }; + + template<class F, class S> + struct pair_less { + std::size_t operator()(const std::pair<F, S>& lhs, const std::pair<F, S>& rhs) const + { + + return (lhs.first != rhs.first) ? lhs.first < rhs.first : lhs.second < rhs.second; + } + }; + + // typedef std::unordered_map<type_id_pair_type, raw_header*, type_src_id_hash> source_header_map_type; + template<class value> + class source_header_unordered_map_type : public std::unordered_map<type_id_pair_type, value, type_src_id_hash> { + }; + + template<class value> + class source_header_map_type : public std::map<type_id_pair_type, value, pair_less<uint8_t, uint16_t>> { + public: + typedef type_id_pair_type key_type; + }; + +} // namespace EB + +#endif // RAW_TOOLS_H diff --git a/Online/EventBuilding/EventBuilding/tools.hpp b/Online/EventBuilding/EventBuilding/tools.hpp new file mode 100644 index 000000000..361ea1802 --- /dev/null +++ b/Online/EventBuilding/EventBuilding/tools.hpp @@ -0,0 +1,118 @@ +#ifndef TOOLS_H +#define TOOLS_H 1 +#include <cerrno> +#include <cstdio> +#include <algorithm> +#include <cstdint> +#include <string> +#include <vector> +#include <numeric> + +#define ALLOC_CHECK(ptr) \ + { \ + if (ptr == NULL) { \ + fprintf(stderr, "[%s:%d] ERROR: %s \n", __FILE__, __LINE__, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } + +namespace EB { + inline size_t get_padding(const size_t base_size, const size_t alignment) + { + return (alignment - (base_size % alignment)) % alignment; + } + + template<class Input_it, class T> + inline int get_idx(Input_it first, Input_it last, const T& val) + { + int ret_val = -1; + const Input_it val_it = std::find(first, last, val); + if (val_it != last) { + ret_val = std::distance(first, val_it); + } + return ret_val; + } + + template<class T> + inline size_t aligned_array_size(int len, const size_t alignment) + { + size_t base_size = len * sizeof(T); + return base_size + get_padding(base_size, alignment); + } + + template<class T> + inline size_t aligned_array_end(T* base_ptr, int len, const size_t alignment) + { + size_t base_size = len * sizeof(T); + size_t base_end = reinterpret_cast<uintptr_t>(base_ptr) % alignment + base_size; + return base_size + get_padding(base_end, alignment); + } + + timespec timespec_diff(timespec lhs, timespec rhs); + + timespec timespec_plus(timespec lhs, timespec rhs); + + clock_t timespec_to_ns(const timespec& lhs); + + clock_t timespec_diff_ns(const timespec& lhs, const timespec& rhs); + clock_t timespec_plus_ns(const timespec& lhs, const timespec& rhs); + + int string_icompare(const std::string& lhs, const std::string& rhs); + + int get_idx_UTGID(const std::string& UTGID, const std::string& unit_name); + std::string get_sub_detector_UTGID(const std::string& UTGID, const std::string& unit_name); + int verify_UTGID(const std::string& UTGID, const std::string& unit_name, const std::string& hostname); + + std::vector<std::string> str_split(const std::string& string, const std::string& delim); + + // Finds all repeated elements in a sorted array and stores them in res, the return value is the new end iterator of + // res + template<class InIterator, class OutIterator> + inline OutIterator find_all_rep(InIterator begin, InIterator end, OutIterator res) + { + InIterator it = begin; + while ((it = std::adjacent_find(it, end)) != end) { + *res = *it; + res++; + it++; + } + + return res; + } + + template<class InIterator, class OutIterator, class Predicate> + inline OutIterator find_all_rep(InIterator begin, InIterator end, OutIterator res, Predicate pred) + { + InIterator it = begin; + while ((it = std::adjacent_find(it, end, pred)) != end) { + *res = *it; + res++; + it++; + } + + return res; + } + + template<class T> + std::vector<size_t> sort_indices(const std::vector<T>& v) + { + std::vector<size_t> idx(v.size()); + std::iota(idx.begin(), idx.end(), 0); + + std::stable_sort(idx.begin(), idx.end(), [&v](size_t i1, size_t i2) { return v[i1] < v[i2]; }); + + return idx; + } + + template<class InputIt> + std::vector<InputIt> sort_it(InputIt first, InputIt last) + { + std::vector<InputIt> sorted_it(std::distance(first, last)); + std::generate(sorted_it.begin(), sorted_it.end(), [begin = first]() mutable { return begin++; }); + + std::stable_sort(sorted_it.begin(), sorted_it.end(), [](InputIt i1, InputIt i2) { return *i1 < *i2; }); + + return sorted_it; + } +} // namespace EB +#endif // TOOLS_H \ No newline at end of file diff --git a/Online/EventBuilding/LICENSE b/Online/EventBuilding/LICENSE new file mode 100644 index 000000000..4354d6b29 --- /dev/null +++ b/Online/EventBuilding/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + fakeeb_v2 + Copyright (C) 2020 lhcb-online-eb + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + fakeeb_v2 Copyright (C) 2020 lhcb-online-eb + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/Online/EventBuilding/components/Components.cpp b/Online/EventBuilding/components/Components.cpp new file mode 100644 index 000000000..e26ad54f7 --- /dev/null +++ b/Online/EventBuilding/components/Components.cpp @@ -0,0 +1,35 @@ +//========================================================================== +// LHCb Online software suite +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see OnlineSys/LICENSE. +// +//========================================================================== +// +// Author : M.Frank & R.Krawczyk +// Created : 10/6/2020 +// +//========================================================================== + +// Framework includes +#include "Dataflow/Plugins.h" + +#include "EventBuilding/RU.hpp" +#include "EventBuilding/BU.hpp" +#include "EventBuilding/MFP_generator.hpp" +#include "../EventBuilding/events_dispatch/Builder_dummy_unit.hpp" +#include "../EventBuilding/events_dispatch/Manager_unit.hpp" +#include "../EventBuilding/events_dispatch/Filter_unit.hpp" +#include "../EventBuilding/events_dispatch/Output_unit.hpp" +#include "../EventBuilding/events_dispatch/MBM_reader_dummy_unit.hpp" + +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(EB, EB_RU, RU) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(EB, EB_BU, BU) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(EB, MFP_generator, MFP_generator) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(Online, EB_dummy_builder_unit, Builder_dummy_unit) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(Online, EB_manager_unit, Manager_unit) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(Online, EB_filter_unit, Filter_unit) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(Online, EB_output_unit, Output_unit) +DECLARE_DATAFLOW_NAMED_COMPONENT_NS(Online, EB_MBM_reader_dummy_unit, MBM_reader_dummy_unit) diff --git a/Online/EventBuilding/include/MEP_injector.hpp b/Online/EventBuilding/include/MEP_injector.hpp new file mode 100644 index 000000000..c5a1e117c --- /dev/null +++ b/Online/EventBuilding/include/MEP_injector.hpp @@ -0,0 +1,86 @@ +#ifndef MEP_INJECTOR_H +#define MEP_INJECTOR_H 1 + +#include "buffer_interface.hpp" +#include "dummy_mep_buffer_writer.hpp" +#include "mbm_writer.hpp" +#include "mdf_reader.hpp" +#include "EventBuilding/MEP_tools.hpp" +#include "file_writer.hpp" +#include <vector> +#include <memory> +#include <tuple> +#include <cassert> +#include <cstdint> +#include <memory> +#include <queue> +#include <string> +#include <atomic> +#include <thread> + +namespace EB { + class MEP_injector : public EB::Buffer_writer<EB::MEP> { + public: + // TODO we probably want to delete the default constructor + MEP_injector() = default; + MEP_injector( + const char* MDF_filename, + size_t buffer_size, + int numa_node, + int packing_factor, + int n_meps, + Online::DataflowComponent::Context& context, + const std::string& instance, + const std::string& name, + bool write_to_file = false, + const std::string out_file_name = "out.mep", + int n_meps_to_file = 1); + ~MEP_injector(); + + // TODO src_id conversion + // void set_detector_map(const std::vector<EB::type_id_pair_type>& src_map); + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + EB::MEP* try_write_next_element(size_t size) override; + + void write_complete() override; + void write_discard() override; + // The src id should be set by an external device or in the constructor of the derived class + int get_src_id() const override; + + private: + typedef Mbm_writer<EB::MEP> MBM_buff_type; + + int preload_MEPs(); + // based fragment size used for self buffer allocation + // const size_t frag_size = 256; + std::string _MDF_filename; + Dummy_mep_buffer_writer _internal_buffer_writer; + MBM_buff_type _external_buffer_writer; + File_writer<EB::MEP> _file_writer; + std::vector<std::shared_ptr<EB::MEP>> _MEPs; + + const size_t _frag_size = 1024; + size_t _packing_factor; + size_t _n_MEPs; + std::queue<EB::MEP*> _write_ptrs; + int _curr_mep_idx; + int _numa_node; + bool _write_to_file = false; + std::string _out_file_name; + int _n_meps_to_file; + + std::atomic<int> _copy_status; + bool _thread_exit; + std::thread _t_copy; + void* _t_write_ptr; + EB::MEP* _t_mep_ptr; + + static void thread_copy(bool* exit, std::atomic<int>* status, void** write_ptr, EB::MEP** mep_ptr); + + enum status_t { READY, PTR_READY, COPY_READY }; + }; +} // namespace EB + +#endif // MEP_INJECTOR_H diff --git a/Online/EventBuilding/include/MFP_builder.hpp b/Online/EventBuilding/include/MFP_builder.hpp new file mode 100644 index 000000000..9900cd3e2 --- /dev/null +++ b/Online/EventBuilding/include/MFP_builder.hpp @@ -0,0 +1,63 @@ +#ifndef MFP_BUILDER_H +#define MFP_BUILDER_H 1 + +#include "EventBuilding/raw_tools.hpp" +#include "EventBuilding/mdf_tools.hpp" +#include <vector> +#include <cstring> +#include <cassert> +#include <memory> +#include "EventBuilding/MFP_tools.hpp" + +namespace EB { + + constexpr uint8_t base_MFP_align = 2; + class MFP_builder { + private: + EB::source_header_map_type<std::vector<EB::raw_header*>> _raw_map; + EB::source_header_map_type<uint64_t> _ev_id_map; + + uint64_t _ev_id; + uint64_t _temporary_ev_id; + + public: + MFP_builder(); + // append the raw blocks of the given event to the internal structure + int append_event(const EB::MDF_block& event); + // append the raw blocks of the given events to the internal structure + int append_events(const std::vector<EB::MDF_block>& events); + + // returns the mapping between the various sources and the buffers + std::vector<EB::type_id_pair_type> get_source_mapping(); + // returns the number of sources + size_t get_source_number(); + // generates an MFP with the given packing fraction + int build_MFP(size_t packing_fraction, char* buffer, size_t buffer_size, EB::type_id_pair_type key); + // generates all the MFPs with the given packing fraction + int build_MFPs(size_t packing_fraction, const std::vector<char*>& buffers, const std::vector<size_t>& buffer_sizes); + int build_MFPs( + size_t packing_fraction, + const std::vector<std::shared_ptr<char>>& buffers, + const std::vector<size_t>& buffer_sizes); + // generates multiple MFPs with the given packing fraction the MFPs are generated using the provided source mapping + // a partial mapping of the detector is possible + int build_MFPs( + size_t packing_fraction, + const std::vector<char*>& buffers, + const std::vector<size_t>& buffer_sizes, + const std::vector<EB::type_id_pair_type> source_mapping); + int build_MFPs( + size_t packing_fraction, + const std::vector<std::shared_ptr<char>>& buffers, + const std::vector<size_t>& buffer_sizes, + const std::vector<EB::type_id_pair_type> source_mapping); + // all the events are deleted from the internal structure + void reset_data(); + // resets the ev_id + void reset_ev_id(); + // resets everything + void reset(); + }; +} // namespace EB + +#endif // MFP_BUILDER_H \ No newline at end of file diff --git a/Online/EventBuilding/include/MFP_preloader.hpp b/Online/EventBuilding/include/MFP_preloader.hpp new file mode 100644 index 000000000..1280f1f59 --- /dev/null +++ b/Online/EventBuilding/include/MFP_preloader.hpp @@ -0,0 +1,54 @@ +#ifndef MFP_PRELOADER_H +#define MFP_PRELOADER_H 1 + +#include "MFP_builder.hpp" +#include "mdf_reader.hpp" +#include <vector> +#include <memory> +#include <functional> +#include <tuple> +#include <cassert> +#include <cstdint> + +namespace EB { + class MFP_preloader { + public: + typedef std::shared_ptr<char> buffer_ptr_type; + + MFP_preloader() = default; + + bool set_MDF_filename(const char* filename); + + void set_packing_factor(size_t packing_factor); + size_t get_packing_factor() const; + + void set_n_MFPs(int n_MFPs); + int get_n_MFPs() const; + + int set_buffers(std::vector<buffer_ptr_type>& buffers, std::vector<size_t>& buffer_sizes); + std::tuple<std::vector<buffer_ptr_type>, std::vector<size_t>, std::vector<size_t>> get_buffers(); + + void set_detector_map(const std::vector<EB::type_id_pair_type>& src_map); + + int preload_MFPs(); + + private: + // based fragment size used for self buffer allocation + // const size_t frag_size = 256; + const size_t _frag_size = 1024; + size_t _packing_factor; + size_t _n_MFPs; + + std::vector<buffer_ptr_type> _buffers; + std::vector<size_t> _buffer_sizes; + std::vector<size_t> _buffer_occupancy; + + std::vector<EB::type_id_pair_type> _source_mapping; + + MDF_reader _reader; + + EB::MFP_builder _builder; + }; +} // namespace EB + +#endif // MFP_PRELOADER_H diff --git a/Online/EventBuilding/include/Parallel_Comm.hpp b/Online/EventBuilding/include/Parallel_Comm.hpp new file mode 100644 index 000000000..fab60eed8 --- /dev/null +++ b/Online/EventBuilding/include/Parallel_Comm.hpp @@ -0,0 +1,85 @@ +#ifndef PARALLEL_COMM_H +#define PARALLEL_COMM_H 1 + +#include <vector> +#include <queue> + +#include "timer.hpp" +#include "logger.hpp" +#include "infiniband_net/ib.hpp" +#include "infiniband_net/sock.hpp" +#include "infiniband_net/parser.hpp" +#include "Dataflow/DataflowContext.h" + +namespace EB { + + enum comm_op_status { INIT = 0, PENDING, COMPLETED, ERROR }; + + struct comm_op { + int count; + size_t datatype; + + virtual ~comm_op() = default; + + virtual std::ostream& print(std::ostream& os) const; + friend std::ostream& operator<<(std::ostream& os, const comm_op& op); + }; + + struct comm_send : public comm_op { + const void* snd_buff; + int destination; + + std::ostream& print(std::ostream& os) const override; + friend std::ostream& operator<<(std::ostream& os, const comm_send& send); + }; + + struct comm_recv : public comm_op { + void* recv_buff; + int source; + + std::ostream& print(std::ostream& os) const override; + friend std::ostream& operator<<(std::ostream& os, const comm_recv& recv); + }; + + class Parallel_comm { + public: + Parallel_comm(IB_verbs::Parser* prs, std::string logName, Online::PrintLevel logLevel); + Parallel_comm(const Parallel_comm& src) = delete; + Parallel_comm& operator=(const Parallel_comm& src) = delete; + Parallel_comm(Parallel_comm&& src); + Parallel_comm& operator=(Parallel_comm&& src); + ~Parallel_comm(); + void ibKillBlocking(); + int ibInit(IB_verbs::Parser* ibprs); + int getTotalProcesses(); + int getProcessID(); + int ibDeregMRs(); + int send(const std::vector<comm_send>& sends); + int receive(const std::vector<comm_recv>& recvs); + int addMR( + char* bufPtr, + size_t bufSize, + int access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE); + int ibBarrier(); + int ibScatterV(char* data, size_t n_elem, size_t elem_size, std::vector<int>& dsts); + int ibBroadcastV(char* data, size_t n_elem, size_t elem_size, std::vector<int>& dsts); + int ibGatherBlockV(char* data, int* data_sizes, int* data_idxs, size_t elem_size, std::vector<int>& remotes); + std::vector<uint32_t> + ibGatherV(char* data, int* data_sizes, int* data_idxs, size_t elem_size, std::vector<int>& remotes, int& ret_val); + int ibTestRecvs(std::vector<uint32_t>& recvs); + Log_stream logger; + + private: + IB_verbs::IB _ibObj; + int _ibInit(IB_verbs::Parser* ibprs); + int _ibDestroy(); + int _sendV(const std::vector<comm_send>& sends); + std::vector<uint32_t> _receiveV(const std::vector<comm_recv>& recvs); + int _waitSends(std::vector<uint32_t>& sends); + int _waitRecvs(std::vector<uint32_t>& recvs); + int _syncSend(int dest); + uint32_t _syncRecv(int src); + }; +} // namespace EB + +#endif // PARALLEL_COMM_H diff --git a/Online/EventBuilding/include/buffer_interface.hpp b/Online/EventBuilding/include/buffer_interface.hpp new file mode 100644 index 000000000..079f42acc --- /dev/null +++ b/Online/EventBuilding/include/buffer_interface.hpp @@ -0,0 +1,133 @@ +#ifndef BUFFER_INTERFACE_H +#define BUFFER_INTERFACE_H 1 + +#include <cstdint> +#include <cstddef> +#include <unistd.h> +#include <vector> +#include <tuple> +#include <atomic> + +#include "Dataflow/DataflowContext.h" + +namespace EB { + // DEBUG test + static int BUFFER_STATUS_IGNORE = 0; + + class Buffer_element { + public: + Buffer_element(int payload, size_t size); + Buffer_element(); + ~Buffer_element() {} + + size_t bytes(); + bool is_valid(); + bool is_wrap(); + void set_wrap(); + void init(int payload, size_t size); + + // protected: + int _status; // 0 non init 1 is valid 2 is wrap + + size_t _size; + + int _payload; + }; + + template<class T> + class Buffer_reader { + private: + bool _cancel = false; + + public: + // alignment is expressed as 2^alignment + // Buffer_reader(uint8_t alignment = 12) : Aligned_buffer(alignment) {} + virtual ~Buffer_reader() {} + + virtual std::vector<std::tuple<void*, size_t>> get_full_buffer() = 0; + + // non blocking ask for next data + virtual T* try_get_element() = 0; + // blocking ask for next data + T* get_element(int& status = BUFFER_STATUS_IGNORE) + { + status = Online::DataflowStatus::DF_SUCCESS; + T* ret_val = NULL; + bool cancel_copy; + while ((ret_val == NULL) && !(cancel_copy = _cancel)) { + ret_val = this->try_get_element(); + if (ret_val == NULL) { + usleep(1); + } + } + + if ((ret_val == NULL) && cancel_copy) { + status = Online::DataflowStatus::DF_CANCELLED; + } + + return ret_val; + } + + // cancel all pending operations + void cancel() { _cancel = true; } + // resume normal operation after cancel is issues + void reset_cancel() { _cancel = false; } + // ack all the pending reads + virtual void read_complete() = 0; + // remove any data from the buffer + virtual void flush() = 0; + // The src id should be set by an external device or in the constructor of the derived class + virtual int get_src_id() const = 0; + }; + + template<class T> + class Buffer_writer { + private: + bool _cancel = false; + + public: + virtual ~Buffer_writer() {} + + virtual std::vector<std::tuple<void*, size_t>> get_full_buffer() = 0; + + // non blocking ask for space + virtual T* try_write_next_element(size_t size) = 0; + // blocking ask for space + T* write_next_element(size_t size, int& status = BUFFER_STATUS_IGNORE) + { + status = Online::DataflowStatus::DF_SUCCESS; + T* ret_val = NULL; + bool cancel_copy; + while ((ret_val == NULL) && !(cancel_copy = _cancel)) { + ret_val = this->try_write_next_element(size); + if (ret_val == NULL) { + usleep(1); + } + } + + if ((ret_val == NULL) && cancel_copy) { + status = Online::DataflowStatus::DF_CANCELLED; + } + + return ret_val; + } + + // cancel all pending operations + void cancel() + { + _cancel = true; + write_discard(); + } + // resume normal operation after cancel is issues + void reset_cancel() { _cancel = false; } + // ack all the pending writes + virtual void write_complete() = 0; + // discard all the pending writes + virtual void write_discard() = 0; + // The src id should be set by an external device or in the constructor of the derived class + virtual int get_src_id() const = 0; + }; + +} // namespace EB + +#endif // BUFFER_INTERFACE_H diff --git a/Online/EventBuilding/include/buffer_writer_error.hpp b/Online/EventBuilding/include/buffer_writer_error.hpp new file mode 100644 index 000000000..800d48f2f --- /dev/null +++ b/Online/EventBuilding/include/buffer_writer_error.hpp @@ -0,0 +1,25 @@ +#ifndef BUFFER_WRITER_ERROR_H +#define BUFFER_WRITER_ERROR_H 1 +#include <system_error> +#include <string> + +namespace EB { + enum class Buffer_writer_error { + ALLOC_FAILED = 1, + WRITE_FULL, + BUFFER_OVERFLOW, + NOT_INIT, + }; + + std::error_code make_error_code(Buffer_writer_error ec); + +} // namespace EB + +namespace std { + template<> + struct is_error_code_enum<EB::Buffer_writer_error> : true_type { + }; + +} // namespace std + +#endif // BUFFER_WRITER_ERROR_H diff --git a/Online/EventBuilding/include/bw_mon.hpp b/Online/EventBuilding/include/bw_mon.hpp new file mode 100644 index 000000000..ac1d26915 --- /dev/null +++ b/Online/EventBuilding/include/bw_mon.hpp @@ -0,0 +1,38 @@ +#ifndef BW_MON_H +#define BW_MON_H 1 +#include <ctime> +#include "timer.hpp" + +namespace EB { + class Bw_mon { + public: + Bw_mon(clockid_t clk_id = CLOCK_MONOTONIC); + // resets the bw and the number of bytes sent + void reset(); + // returns the bw in Gb/s since the reset + double get_bw() const; + // returns the bw as in get_bw and resets + double get_bw_and_reset(); + // returns the bytes sent between the reset and the last add_sent_bytes + size_t get_bytes() const; + // returns the bytes sent as in get_bytes and resets + size_t get_bytes_and_reset(); + // adds n_bytes to the counter + void add_sent_bytes(size_t n_bytes); + + // setter and getter for the clockid used the setter resets the time to avoid inconsistency + void set_clock_id(clockid_t clk_id); + clockid_t get_clock_id() const; + + // returns elapsed time since the last reset in seconds + double get_elapsed_time(); + + protected: + size_t _bytes_sent; + + private: + Timer _timer; + }; +} // namespace EB + +#endif // BW_MON_H diff --git a/Online/EventBuilding/include/circular_buffer.hpp b/Online/EventBuilding/include/circular_buffer.hpp new file mode 100644 index 000000000..2d1445906 --- /dev/null +++ b/Online/EventBuilding/include/circular_buffer.hpp @@ -0,0 +1,28 @@ +#ifndef CIRCULAR_BUFFER_H +#define CIRCULAR_BUFFER_H 1 + +#include "buffer_interface.hpp" +#include "circular_buffer_status.hpp" +#include <cstddef> +#include <cstdint> +#include <iostream> +#include <string> +#include <tuple> + +namespace EB { + template<class B> + class Circular_buffer { + public: + virtual ~Circular_buffer() {} + Circular_buffer() {} + Circular_buffer(B&& backend) : _backend(std::move(backend)) {} + + void reset_backend(B&& backend = std::move(B())) { _backend = std::move(backend); } + bool is_set() { return _backend.is_set(); } + + protected: + B _backend; + }; +} // namespace EB + +#endif // CIRCULAR_BUFFER_H \ No newline at end of file diff --git a/Online/EventBuilding/include/circular_buffer_reader.hpp b/Online/EventBuilding/include/circular_buffer_reader.hpp new file mode 100644 index 000000000..6c9dffb26 --- /dev/null +++ b/Online/EventBuilding/include/circular_buffer_reader.hpp @@ -0,0 +1,39 @@ +#ifndef CIRCULAR_BUFFER_READER_H +#define CIRCULAR_BUFFER_READER_H 1 + +#include "buffer_interface.hpp" +#include "circular_buffer.hpp" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> + +namespace EB { + template<class T, class B> + class Circular_buffer_reader : public EB::Buffer_reader<T>, public Circular_buffer<B> { + public: + // alignment is explesser in 2^alignment min value 1 + Circular_buffer_reader(B&& backend) : Circular_buffer<B>(std::move(backend)) {} + Circular_buffer_reader() : Circular_buffer<B>() {} + virtual ~Circular_buffer_reader(); + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + T* try_get_element() override; + + void read_complete() override; + + int get_src_id() const override; + + void flush() override; + + protected: + void update_local_status(); + }; +} // namespace EB + +#include "circular_buffer_reader_impl.hpp" + +#endif // CIRCULAR_BUFFER_READER_H diff --git a/Online/EventBuilding/include/circular_buffer_reader_impl.hpp b/Online/EventBuilding/include/circular_buffer_reader_impl.hpp new file mode 100644 index 000000000..250773ec1 --- /dev/null +++ b/Online/EventBuilding/include/circular_buffer_reader_impl.hpp @@ -0,0 +1,102 @@ +#include "circular_buffer_reader.hpp" +#include <stdexcept> +#include "EventBuilding/tools.hpp" +#include <unistd.h> +#include <sys/stat.h> /* For mode constants */ +#include <fcntl.h> /* For O_* constants */ +#include <sys/mman.h> +#include <cstring> +#include <sstream> +#include <string> +#include <memory> +#include <iostream> +#include <tuple> + +template<class T, class B> +EB::Circular_buffer_reader<T, B>::~Circular_buffer_reader() +{} + +template<class T, class B> +std::vector<std::tuple<void*, size_t>> EB::Circular_buffer_reader<T, B>::get_full_buffer() +{ + std::vector<std::tuple<void*, size_t>> ret_val; + ret_val.emplace_back(this->_backend.get_buffer()); + return ret_val; +} + +template<class T, class B> +void EB::Circular_buffer_reader<T, B>::update_local_status() +{ + if (!this->is_set()) { + std::ostringstream err_mess; + err_mess << __FILE__ << ": " << __FUNCTION__ << " on an invalid buffer"; + throw std::logic_error(err_mess.str()); + } + this->_backend._local_buffer_status.write_stat = this->_backend._remote_buffer_status->write_stat; +} + +template<class T, class B> +T* EB::Circular_buffer_reader<T, B>::try_get_element() +{ + T* ret_val = NULL; + if (!this->is_set()) { + std::ostringstream err_mess; + err_mess << __FILE__ << ": " << __FUNCTION__ << " on an invalid buffer"; + throw std::logic_error(err_mess.str()); + } + + update_local_status(); + + uintptr_t read_ptr = this->_backend._local_buffer_status.read_ptr(); + + if (!this->_backend._local_buffer_status.is_empty()) { + ret_val = reinterpret_cast<T*>(read_ptr + reinterpret_cast<uintptr_t>(this->_backend._buffer)); + if (ret_val->is_wrap()) { + ret_val = reinterpret_cast<T*>(this->_backend._buffer); + this->_backend._local_buffer_status.toggle_read_wrap(); + // std::cout << "reader wrap" << std::endl; + } + + uintptr_t next_elem = reinterpret_cast<uintptr_t>(ret_val) + ret_val->bytes() + + get_padding(ret_val->bytes(), 1 << this->_backend._local_buffer_status.alignment); + + this->_backend._local_buffer_status.set_read_ptr(next_elem - reinterpret_cast<uintptr_t>(this->_backend._buffer)); + } + + return ret_val; +} + +template<class T, class B> +void EB::Circular_buffer_reader<T, B>::flush() +{ + if (!this->is_set()) { + std::ostringstream err_mess; + err_mess << __FILE__ << ": " << __FUNCTION__ << " on an invalid buffer"; + throw std::logic_error(err_mess.str()); + } + + update_local_status(); + + this->_backend._local_buffer_status.read_stat = this->_backend._local_buffer_status.write_stat; + + read_complete(); +} + +template<class T, class B> +void EB::Circular_buffer_reader<T, B>::read_complete() +{ + if (!this->is_set()) { + std::ostringstream err_mess; + err_mess << __FILE__ << ": " << __FUNCTION__ << " on an invalid buffer"; + throw std::logic_error(err_mess.str()); + } + + asm volatile("mfence" ::: "memory"); + this->_backend._remote_buffer_status->read_stat = this->_backend._local_buffer_status.read_stat; +} + +template<class T, class B> +int EB::Circular_buffer_reader<T, B>::get_src_id() const +{ + return this->_backend._local_buffer_status.id; +} diff --git a/Online/EventBuilding/include/circular_buffer_status.hpp b/Online/EventBuilding/include/circular_buffer_status.hpp new file mode 100644 index 000000000..9b826e2ea --- /dev/null +++ b/Online/EventBuilding/include/circular_buffer_status.hpp @@ -0,0 +1,42 @@ +#ifndef CIRCULAR_BUFFER_STATUS_H +#define CIRCULAR_BUFFER_STATUS_H 1 + +#include <cstddef> +#include <cstdint> + +namespace EB { + constexpr uint64_t ptr_mask = 0x7fffffffffffffff; + constexpr uint64_t wrap_mask = ~ptr_mask; + + struct Circular_buffer_status { + Circular_buffer_status() : write_stat(0), read_stat(0), size(0), alignment(0), id(0) {} + Circular_buffer_status(size_t size, size_t alignment, int id) : + write_stat(0), read_stat(0), size(size), alignment(alignment), id(id) + {} + + uint64_t write_stat; + uint64_t read_stat; + + // size of the usable allocated area + size_t size; + size_t alignment; + int id; + + bool is_empty() const; + bool is_full() const; + bool same_page() const; + + size_t tail_free_space() const; + size_t head_free_space() const; + + uintptr_t write_ptr() const; + uintptr_t read_ptr() const; + + void set_write_ptr(uintptr_t write_ptr); + void set_read_ptr(uintptr_t read_ptr); + void toggle_write_wrap(); + void toggle_read_wrap(); + }; +} // namespace EB + +#endif // CIRCULAR_BUFFER_STATUS_H diff --git a/Online/EventBuilding/include/circular_buffer_writer.hpp b/Online/EventBuilding/include/circular_buffer_writer.hpp new file mode 100644 index 000000000..120aa6d87 --- /dev/null +++ b/Online/EventBuilding/include/circular_buffer_writer.hpp @@ -0,0 +1,43 @@ +#ifndef CIRCULAR_BUFFER_WRITER_H +#define CIRCULAR_BUFFER_WRITER_H 1 + +#include "buffer_interface.hpp" +#include "circular_buffer.hpp" +#include "buffer_writer_error.hpp" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> + +namespace EB { + + template<class T, class B> + class Circular_buffer_writer : public EB::Buffer_writer<T>, public Circular_buffer<B> { + public: + // alignment is explesser in 2^alignment min value 1 + Circular_buffer_writer(B&& backend) : Circular_buffer<B>(std::move(backend)) {} + Circular_buffer_writer() : Circular_buffer<B>() {} + virtual ~Circular_buffer_writer(); + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + T* try_write_next_element(size_t size) override; + + void write_complete() override; + + void write_discard() override; + + int get_src_id() const override; + + size_t free_space(); + + protected: + void update_local_status(); + }; +} // namespace EB + +#include "circular_buffer_writer_impl.hpp" + +#endif // CIRCULAR_BUFFER_WRITER_H diff --git a/Online/EventBuilding/include/circular_buffer_writer_impl.hpp b/Online/EventBuilding/include/circular_buffer_writer_impl.hpp new file mode 100644 index 000000000..6106f1a69 --- /dev/null +++ b/Online/EventBuilding/include/circular_buffer_writer_impl.hpp @@ -0,0 +1,113 @@ +#include "circular_buffer_writer.hpp" +#include "EventBuilding/tools.hpp" +#include <unistd.h> +#include <sys/stat.h> /* For mode constants */ +#include <fcntl.h> /* For O_* constants */ +#include <sys/mman.h> +#include <cstring> +#include <sstream> +#include <string> +#include <memory> +#include <iostream> +#include <tuple> +#include <stdexcept> +#include <system_error> + +template<class T, class B> +EB::Circular_buffer_writer<T, B>::~Circular_buffer_writer() +{} + +template<class T, class B> +std::vector<std::tuple<void*, size_t>> EB::Circular_buffer_writer<T, B>::get_full_buffer() +{ + std::vector<std::tuple<void*, size_t>> ret_val; + ret_val.emplace_back(this->_backend.get_buffer()); + return ret_val; +} + +template<class T, class B> +T* EB::Circular_buffer_writer<T, B>::try_write_next_element(size_t size) +{ + if (!this->is_set()) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + T* ret_val = NULL; + + bool fit = false; + + update_local_status(); + + uintptr_t write_ptr = this->_backend._local_buffer_status.write_ptr(); + uintptr_t buffer_ptr = reinterpret_cast<uintptr_t>(this->_backend._buffer); + + size_t padded_size = size + get_padding(size, 1 << this->_backend._local_buffer_status.alignment); + + if ((padded_size + sizeof(T)) <= this->_backend._local_buffer_status.tail_free_space()) { + fit = true; + } else if (padded_size <= this->_backend._local_buffer_status.head_free_space()) { + reinterpret_cast<T*>(write_ptr + buffer_ptr)->set_wrap(); + this->_backend._local_buffer_status.toggle_write_wrap(); + write_ptr = 0; + fit = true; + } + + if (fit) { + ret_val = reinterpret_cast<T*>(write_ptr + buffer_ptr); + + write_ptr += padded_size; + this->_backend._local_buffer_status.set_write_ptr(write_ptr); + ret_val = new (ret_val) T(); + } + + return ret_val; +} + +template<class T, class B> +void EB::Circular_buffer_writer<T, B>::write_complete() +{ + if (!this->is_set()) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + asm volatile("mfence" ::: "memory"); + this->_backend._remote_buffer_status->write_stat = this->_backend._local_buffer_status.write_stat; +} + +template<class T, class B> +void EB::Circular_buffer_writer<T, B>::write_discard() +{ + if (!this->is_set()) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + update_local_status(); +} + +template<class T, class B> +void EB::Circular_buffer_writer<T, B>::update_local_status() +{ + if (!this->is_set()) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + this->_backend._local_buffer_status.read_stat = this->_backend._remote_buffer_status->read_stat; +} + +template<class T, class B> +int EB::Circular_buffer_writer<T, B>::get_src_id() const +{ + return this->_backend._local_buffer_status.id; +} + +template<class T, class B> +size_t EB::Circular_buffer_writer<T, B>::free_space() +{ + if (!this->is_set()) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + update_local_status(); + + return std::max( + this->_backend._local_buffer_status.tail_free_space(), this->_backend._local_buffer_status.head_free_space()); +} diff --git a/Online/EventBuilding/include/dummy_mep_buffer_writer.hpp b/Online/EventBuilding/include/dummy_mep_buffer_writer.hpp new file mode 100644 index 000000000..b6dbb0724 --- /dev/null +++ b/Online/EventBuilding/include/dummy_mep_buffer_writer.hpp @@ -0,0 +1,37 @@ +#ifndef DUMMY_MEP_BUFFER_WRITER_H +#define DUMMY_MEP_BUFFER_WRITER_H 1 +#include "EventBuilding/MEP_tools.hpp" +#include "buffer_interface.hpp" +#include "buffer_writer_error.hpp" +#include <memory> +#include <functional> + +namespace EB { + class Dummy_mep_buffer_writer : public EB::Buffer_writer<EB::MEP> { + public: + Dummy_mep_buffer_writer(); + Dummy_mep_buffer_writer(size_t buffer_size, int numa_node = -1); + virtual ~Dummy_mep_buffer_writer(); + + int reset_buffer(size_t buffer_size, int numa_node); + + EB::MEP* try_write_next_element(size_t size) override; + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + void write_complete() override; + + void write_discard() override; + + int get_src_id() const override { return 0; } + + private: + typedef std::unique_ptr<void, std::function<void(void*)>> buffer_type; + buffer_type _buffer; + size_t _buffer_size; + enum Buff_state { EMPTY, FULL }; + Buff_state _status; + }; +} // namespace EB + +#endif // DUMMY_MEP_BUFFER_WRITER_H \ No newline at end of file diff --git a/Online/EventBuilding/include/dummy_mfp_buffer.hpp b/Online/EventBuilding/include/dummy_mfp_buffer.hpp new file mode 100644 index 000000000..9c9b58158 --- /dev/null +++ b/Online/EventBuilding/include/dummy_mfp_buffer.hpp @@ -0,0 +1,45 @@ +#ifndef DUMMY_MFP_BUFFER_H +#define DUMMY_MFP_BUFFER_H 1 +#include <memory> +#include "EventBuilding/MFP_tools.hpp" +#include <vector> +#include "buffer_interface.hpp" + +namespace EB { + class Dummy_MFP_buffer : public EB::Buffer_reader<EB::MFP> { + private: + std::shared_ptr<char> _buffer; + size_t _buffer_size; + + const char* _read_ptr; + + public: + Dummy_MFP_buffer() = default; + Dummy_MFP_buffer(std::shared_ptr<char>& buffer, size_t buffer_size, int src_id = 0); + + void set_buffer(std::shared_ptr<char>& buffer, size_t buffer_size, int src_id = 0); + + virtual EB::MFP* try_get_element() override; + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + virtual void read_complete() override; + virtual void flush() override; + + virtual ~Dummy_MFP_buffer() = default; + + int get_src_id() const override; + + protected: + size_t get_size_at(int MFP_number = 1); + char* get_ptr_at(int MFP_number = 1); + std::tuple<char*, size_t> get_MFP_at(int MFP_number = 1); + std::tuple<char*, size_t> operator[](int MFP_number); + + void update_read_ptr(int MFP_number = 1); + + int _src_id; + }; +} // namespace EB + +#endif // DUMMY_MFP_BUFFER_H diff --git a/Online/EventBuilding/include/file_writer.hpp b/Online/EventBuilding/include/file_writer.hpp new file mode 100644 index 000000000..c186e9d6a --- /dev/null +++ b/Online/EventBuilding/include/file_writer.hpp @@ -0,0 +1,33 @@ +#ifndef FILE_WRITER_H +#define FILE_WRITER_H 1 + +#include "buffer_interface.hpp" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> +#include <cstdio> +#include <memory> +#include <functional> + +namespace EB { + template<class T> + class File_writer { + public: + File_writer() = default; + File_writer(const std::string& file_name); + + int write(const T* data); + + protected: + typedef std::unique_ptr<FILE, std::function<void(FILE*)>> unique_file_type; + std::string _file_name; + unique_file_type _file; + }; +} // namespace EB + +#include "file_writer_impl.hpp" + +#endif // FILE_WRITER_H diff --git a/Online/EventBuilding/include/file_writer_impl.hpp b/Online/EventBuilding/include/file_writer_impl.hpp new file mode 100644 index 000000000..a5bbcf46b --- /dev/null +++ b/Online/EventBuilding/include/file_writer_impl.hpp @@ -0,0 +1,30 @@ +#include "file_writer.hpp" + +#include <sys/stat.h> +#include <fcntl.h> +#include <sstream> +#include <stdexcept> + +template<class T> +EB::File_writer<T>::File_writer(const std::string& file_name) : + _file_name(file_name), _file(fopen(file_name.c_str(), "wb"), [](FILE* file) { fclose(file); }) +{ + if (_file == NULL) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " " << file_name << ": " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +template<class T> +int EB::File_writer<T>::write(const T* data) +{ + int ret_val = 0; + if (data != NULL) { + ret_val = fwrite(data, 1, data->bytes(), _file.get()); + } + + fflush(_file.get()); + + return ret_val; +} \ No newline at end of file diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson.h b/Online/EventBuilding/include/infiniband_net/ArduinoJson.h new file mode 100644 index 000000000..e5aac0fed --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson.h @@ -0,0 +1,17 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#ifdef __cplusplus + +#include "ArduinoJson.hpp" + +using namespace ArduinoJson; + +#else + +#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp + +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson.hpp new file mode 100644 index 000000000..de4d684c9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson.hpp @@ -0,0 +1,73 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "ArduinoJson/Configuration.hpp" + +#if !ARDUINOJSON_DEBUG +#ifdef __clang__ +#pragma clang system_header +#elif defined __GNUC__ +#pragma GCC system_header +#endif +#endif + +#include "ArduinoJson/Array/ArrayRef.hpp" +#include "ArduinoJson/Object/ObjectRef.hpp" +#include "ArduinoJson/Variant/VariantRef.hpp" + +#include "ArduinoJson/Document/DynamicJsonDocument.hpp" +#include "ArduinoJson/Document/StaticJsonDocument.hpp" + +#include "ArduinoJson/Array/ArrayImpl.hpp" +#include "ArduinoJson/Array/ElementProxy.hpp" +#include "ArduinoJson/Array/Utilities.hpp" +#include "ArduinoJson/Collection/CollectionImpl.hpp" +#include "ArduinoJson/Object/MemberProxy.hpp" +#include "ArduinoJson/Object/ObjectImpl.hpp" +#include "ArduinoJson/Variant/VariantAsImpl.hpp" +#include "ArduinoJson/Variant/VariantCompare.hpp" +#include "ArduinoJson/Variant/VariantImpl.hpp" + +#include "ArduinoJson/Json/JsonDeserializer.hpp" +#include "ArduinoJson/Json/JsonSerializer.hpp" +#include "ArduinoJson/Json/PrettyJsonSerializer.hpp" +#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp" +#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp" + +#include "ArduinoJson/compatibility.hpp" + +namespace ArduinoJson { + typedef ARDUINOJSON_NAMESPACE::ArrayConstRef JsonArrayConst; + typedef ARDUINOJSON_NAMESPACE::ArrayRef JsonArray; + typedef ARDUINOJSON_NAMESPACE::Float JsonFloat; + typedef ARDUINOJSON_NAMESPACE::Integer JsonInteger; + typedef ARDUINOJSON_NAMESPACE::ObjectConstRef JsonObjectConst; + typedef ARDUINOJSON_NAMESPACE::ObjectRef JsonObject; + typedef ARDUINOJSON_NAMESPACE::Pair JsonPair; + typedef ARDUINOJSON_NAMESPACE::PairConst JsonPairConst; + typedef ARDUINOJSON_NAMESPACE::String JsonString; + typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt; + typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst; + typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant; + using ARDUINOJSON_NAMESPACE::BasicJsonDocument; + using ARDUINOJSON_NAMESPACE::copyArray; + using ARDUINOJSON_NAMESPACE::DeserializationError; + using ARDUINOJSON_NAMESPACE::deserializeJson; + using ARDUINOJSON_NAMESPACE::deserializeMsgPack; + using ARDUINOJSON_NAMESPACE::DynamicJsonDocument; + using ARDUINOJSON_NAMESPACE::JsonDocument; + using ARDUINOJSON_NAMESPACE::measureJson; + using ARDUINOJSON_NAMESPACE::serialized; + using ARDUINOJSON_NAMESPACE::serializeJson; + using ARDUINOJSON_NAMESPACE::serializeJsonPretty; + using ARDUINOJSON_NAMESPACE::serializeMsgPack; + using ARDUINOJSON_NAMESPACE::StaticJsonDocument; + + namespace DeserializationOption { + using ARDUINOJSON_NAMESPACE::Filter; + using ARDUINOJSON_NAMESPACE::NestingLimit; + } // namespace DeserializationOption +} // namespace ArduinoJson diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayFunctions.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayFunctions.hpp new file mode 100644 index 000000000..46eb718f4 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayFunctions.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + inline VariantData* arrayAdd(CollectionData* arr, MemoryPool* pool) { return arr ? arr->addElement(pool) : 0; } + + template<typename TVisitor> + inline typename TVisitor::result_type arrayAccept(const CollectionData* arr, TVisitor& visitor) + { + if (arr) + return visitor.visitArray(*arr); + else + return visitor.visitNull(); + } + + inline bool arrayEquals(const CollectionData* lhs, const CollectionData* rhs) + { + if (lhs == rhs) return true; + if (!lhs || !rhs) return false; + return lhs->equalsArray(*rhs); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayImpl.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayImpl.hpp new file mode 100644 index 000000000..378764323 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayImpl.hpp @@ -0,0 +1,30 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TArray> + inline ArrayRef ArrayShortcuts<TArray>::createNestedArray() const + { + return impl()->addElement().template to<ArrayRef>(); + } + + template<typename TArray> + inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const + { + return impl()->addElement().template to<ObjectRef>(); + } + + template<typename TArray> + inline ElementProxy<TArray> ArrayShortcuts<TArray>::operator[](size_t index) const + { + return ElementProxy<TArray>(*impl(), index); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayIterator.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayIterator.hpp new file mode 100644 index 000000000..4dbda8741 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayIterator.hpp @@ -0,0 +1,96 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Variant/SlotFunctions.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class VariantPtr { + public: + VariantPtr(MemoryPool* pool, VariantData* data) : _variant(pool, data) {} + + VariantRef* operator->() { return &_variant; } + + VariantRef& operator*() { return _variant; } + + private: + VariantRef _variant; + }; + + class ArrayIterator { + public: + ArrayIterator() : _slot(0) {} + explicit ArrayIterator(MemoryPool* pool, VariantSlot* slot) : _pool(pool), _slot(slot) {} + + VariantRef operator*() const { return VariantRef(_pool, _slot->data()); } + VariantPtr operator->() { return VariantPtr(_pool, _slot->data()); } + + bool operator==(const ArrayIterator& other) const { return _slot == other._slot; } + + bool operator!=(const ArrayIterator& other) const { return _slot != other._slot; } + + ArrayIterator& operator++() + { + _slot = _slot->next(); + return *this; + } + + ArrayIterator& operator+=(size_t distance) + { + _slot = _slot->next(distance); + return *this; + } + + VariantSlot* internal() { return _slot; } + + private: + MemoryPool* _pool; + VariantSlot* _slot; + }; + + class VariantConstPtr { + public: + VariantConstPtr(const VariantData* data) : _variant(data) {} + + VariantConstRef* operator->() { return &_variant; } + + VariantConstRef& operator*() { return _variant; } + + private: + VariantConstRef _variant; + }; + + class ArrayConstRefIterator { + public: + ArrayConstRefIterator() : _slot(0) {} + explicit ArrayConstRefIterator(const VariantSlot* slot) : _slot(slot) {} + + VariantConstRef operator*() const { return VariantConstRef(_slot->data()); } + VariantConstPtr operator->() { return VariantConstPtr(_slot->data()); } + + bool operator==(const ArrayConstRefIterator& other) const { return _slot == other._slot; } + + bool operator!=(const ArrayConstRefIterator& other) const { return _slot != other._slot; } + + ArrayConstRefIterator& operator++() + { + _slot = _slot->next(); + return *this; + } + + ArrayConstRefIterator& operator+=(size_t distance) + { + _slot = _slot->next(distance); + return *this; + } + + const VariantSlot* internal() { return _slot; } + + private: + const VariantSlot* _slot; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayRef.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayRef.hpp new file mode 100644 index 000000000..3a76f36d0 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayRef.hpp @@ -0,0 +1,144 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayFunctions.hpp> +#include <ArduinoJson/Array/ArrayIterator.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +// Returns the size (in bytes) of an array with n elements. +// Can be very handy to determine the size of a StaticMemoryPool. +#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) + +namespace ARDUINOJSON_NAMESPACE { + + class ObjectRef; + template<typename> + class ElementProxy; + + template<typename TData> + class ArrayRefBase { + public: + operator VariantConstRef() const + { + const void* data = _data; // prevent warning cast-align + return VariantConstRef(reinterpret_cast<const VariantData*>(data)); + } + + template<typename TVisitor> + FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const + { + return arrayAccept(_data, visitor); + } + + FORCE_INLINE bool isNull() const { return _data == 0; } + + FORCE_INLINE operator bool() const { return _data != 0; } + + FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } + + FORCE_INLINE size_t nesting() const { return _data ? _data->nesting() : 0; } + + FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } + + protected: + ArrayRefBase(TData* data) : _data(data) {} + TData* _data; + }; + + class ArrayConstRef : public ArrayRefBase<const CollectionData>, public Visitable { + friend class ArrayRef; + typedef ArrayRefBase<const CollectionData> base_type; + + public: + typedef ArrayConstRefIterator iterator; + + FORCE_INLINE iterator begin() const + { + if (!_data) return iterator(); + return iterator(_data->head()); + } + + FORCE_INLINE iterator end() const { return iterator(); } + + FORCE_INLINE ArrayConstRef() : base_type(0) {} + FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {} + + FORCE_INLINE bool operator==(ArrayConstRef rhs) const { return arrayEquals(_data, rhs._data); } + + FORCE_INLINE VariantConstRef operator[](size_t index) const { return getElement(index); } + + FORCE_INLINE VariantConstRef getElement(size_t index) const + { + return VariantConstRef(_data ? _data->getElement(index) : 0); + } + }; + + class ArrayRef : public ArrayRefBase<CollectionData>, public ArrayShortcuts<ArrayRef>, public Visitable { + typedef ArrayRefBase<CollectionData> base_type; + + public: + typedef ArrayIterator iterator; + + FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {} + FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data) : base_type(data), _pool(pool) {} + + operator VariantRef() + { + void* data = _data; // prevent warning cast-align + return VariantRef(_pool, reinterpret_cast<VariantData*>(data)); + } + + operator ArrayConstRef() const { return ArrayConstRef(_data); } + + VariantRef addElement() const { return VariantRef(_pool, arrayAdd(_data, _pool)); } + + FORCE_INLINE iterator begin() const + { + if (!_data) return iterator(); + return iterator(_pool, _data->head()); + } + + FORCE_INLINE iterator end() const { return iterator(); } + + // Copy a ArrayRef + FORCE_INLINE bool set(ArrayConstRef src) const + { + if (!_data || !src._data) return false; + return _data->copyFrom(*src._data, _pool); + } + + FORCE_INLINE bool operator==(ArrayRef rhs) const { return arrayEquals(_data, rhs._data); } + + // Internal use + FORCE_INLINE VariantRef getOrAddElement(size_t index) const + { + return VariantRef(_pool, _data ? _data->getOrAddElement(index, _pool) : 0); + } + + // Gets the value at the specified index. + FORCE_INLINE VariantRef getElement(size_t index) const + { + return VariantRef(_pool, _data ? _data->getElement(index) : 0); + } + + // Removes element at specified position. + FORCE_INLINE void remove(iterator it) const + { + if (!_data) return; + _data->removeSlot(it.internal()); + } + + // Removes element at specified index. + FORCE_INLINE void remove(size_t index) const + { + if (!_data) return; + _data->removeElement(index); + } + + private: + MemoryPool* _pool; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayShortcuts.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayShortcuts.hpp new file mode 100644 index 000000000..193f3bd40 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ArrayShortcuts.hpp @@ -0,0 +1,47 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + // Forward declarations. + template<typename> + class ElementProxy; + + template<typename TArray> + class ArrayShortcuts { + public: + // Returns the element at specified index if the variant is an array. + FORCE_INLINE ElementProxy<TArray> operator[](size_t index) const; + + FORCE_INLINE ObjectRef createNestedObject() const; + + FORCE_INLINE ArrayRef createNestedArray() const; + + // Adds the specified value at the end of the array. + // + // bool add(TValue); + // TValue = bool, long, int, short, float, double, serialized, VariantRef, + // std::string, String, ObjectRef + template<typename T> + FORCE_INLINE bool add(const T& value) const + { + return impl()->addElement().set(value); + } + // + // bool add(TValue); + // TValue = char*, const char*, const __FlashStringHelper* + template<typename T> + FORCE_INLINE bool add(T* value) const + { + return impl()->addElement().set(value); + } + + private: + const TArray* impl() const { return static_cast<const TArray*>(this); } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ElementProxy.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ElementProxy.hpp new file mode 100644 index 000000000..9629ed737 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/ElementProxy.hpp @@ -0,0 +1,172 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> +#include <ArduinoJson/Variant/VariantTo.hpp> + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TArray> + class ElementProxy : public VariantOperators<ElementProxy<TArray>>, + public VariantShortcuts<ElementProxy<TArray>>, + public Visitable { + typedef ElementProxy<TArray> this_type; + + public: + FORCE_INLINE ElementProxy(TArray array, size_t index) : _array(array), _index(index) {} + + FORCE_INLINE ElementProxy(const ElementProxy& src) : _array(src._array), _index(src._index) {} + + FORCE_INLINE this_type& operator=(const this_type& src) + { + getOrAddUpstreamElement().set(src.as<VariantConstRef>()); + return *this; + } + + // Replaces the value + // + // operator=(const TValue&) + // TValue = bool, long, int, short, float, double, serialized, VariantRef, + // std::string, String, ArrayRef, ObjectRef + template<typename T> + FORCE_INLINE this_type& operator=(const T& src) + { + getOrAddUpstreamElement().set(src); + return *this; + } + // + // operator=(TValue) + // TValue = char*, const char*, const __FlashStringHelper* + template<typename T> + FORCE_INLINE this_type& operator=(T* src) + { + getOrAddUpstreamElement().set(src); + return *this; + } + + FORCE_INLINE void clear() const { getUpstreamElement().clear(); } + + FORCE_INLINE bool isNull() const { return getUpstreamElement().isNull(); } + + template<typename T> + FORCE_INLINE typename VariantAs<T>::type as() const + { + return getUpstreamElement().template as<T>(); + } + + template<typename T> + FORCE_INLINE operator T() const + { + return getUpstreamElement(); + } + + template<typename T> + FORCE_INLINE bool is() const + { + return getUpstreamElement().template is<T>(); + } + + template<typename T> + FORCE_INLINE typename VariantTo<T>::type to() const + { + return getOrAddUpstreamElement().template to<T>(); + } + + // Replaces the value + // + // bool set(const TValue&) + // TValue = bool, long, int, short, float, double, serialized, VariantRef, + // std::string, String, ArrayRef, ObjectRef + template<typename TValue> + FORCE_INLINE bool set(const TValue& value) const + { + return getOrAddUpstreamElement().set(value); + } + // + // bool set(TValue) + // TValue = char*, const char*, const __FlashStringHelper* + template<typename TValue> + FORCE_INLINE bool set(TValue* value) const + { + return getOrAddUpstreamElement().set(value); + } + + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + return getUpstreamElement().accept(visitor); + } + + FORCE_INLINE size_t size() const { return getUpstreamElement().size(); } + + template<typename TNestedKey> + VariantRef getMember(TNestedKey* key) const + { + return getUpstreamElement().getMember(key); + } + + template<typename TNestedKey> + VariantRef getMember(const TNestedKey& key) const + { + return getUpstreamElement().getMember(key); + } + + template<typename TNestedKey> + VariantRef getOrAddMember(TNestedKey* key) const + { + return getOrAddUpstreamElement().getOrAddMember(key); + } + + template<typename TNestedKey> + VariantRef getOrAddMember(const TNestedKey& key) const + { + return getOrAddUpstreamElement().getOrAddMember(key); + } + + VariantRef addElement() const { return getOrAddUpstreamElement().addElement(); } + + VariantRef getElement(size_t index) const { return getOrAddUpstreamElement().getElement(index); } + + VariantRef getOrAddElement(size_t index) const { return getOrAddUpstreamElement().getOrAddElement(index); } + + FORCE_INLINE void remove(size_t index) const { getUpstreamElement().remove(index); } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(TChar* key) const + { + getUpstreamElement().remove(key); + } + // remove(const std::string&) const + // remove(const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(const TString& key) const + { + getUpstreamElement().remove(key); + } + + private: + FORCE_INLINE VariantRef getUpstreamElement() const { return _array.getElement(_index); } + + FORCE_INLINE VariantRef getOrAddUpstreamElement() const { return _array.getOrAddElement(_index); } + + TArray _array; + const size_t _index; + }; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/Utilities.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/Utilities.hpp new file mode 100644 index 000000000..066cd6d9f --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Array/Utilities.hpp @@ -0,0 +1,160 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Document/JsonDocument.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // Copy a 1D array to a JsonArray + template<typename T, size_t N, typename TDestination> + inline typename enable_if<!is_array<T>::value && !is_base_of<JsonDocument, TDestination>::value, bool>::type + copyArray(T (&src)[N], const TDestination& dst) + { + return copyArray(src, N, dst); + } + + // Copy a 1D array to a JsonDocument + template<typename T, size_t N> + inline bool copyArray(T (&src)[N], JsonDocument& dst) + { + return copyArray(src, dst.to<ArrayRef>()); + } + + // Copy a 1D array to a JsonArray + template<typename T, typename TDestination> + inline typename enable_if<!is_array<T>::value && !is_base_of<JsonDocument, TDestination>::value, bool>::type + copyArray(T* src, size_t len, const TDestination& dst) + { + bool ok = true; + for (size_t i = 0; i < len; i++) { + ok &= dst.add(src[i]); + } + return ok; + } + + // Copy a 1D array to a JsonDocument + template<typename T> + inline bool copyArray(T* src, size_t len, JsonDocument& dst) + { + return copyArray(src, len, dst.to<ArrayRef>()); + } + + // Copy a 2D array to a JsonArray + template<typename T, size_t N1, size_t N2, typename TDestination> + inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value, bool>::type copyArray( + T (&src)[N1][N2], + const TDestination& dst) + { + bool ok = true; + for (size_t i = 0; i < N1; i++) { + ArrayRef nestedArray = dst.createNestedArray(); + for (size_t j = 0; j < N2; j++) { + ok &= nestedArray.add(src[i][j]); + } + } + return ok; + } + + // Copy a 2D array to a JsonDocument + template<typename T, size_t N1, size_t N2> + inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) + { + return copyArray(src, dst.to<ArrayRef>()); + } + + template<typename T> + class ArrayCopier1D : public Visitor<size_t> { + public: + ArrayCopier1D(T* destination, size_t capacity) : _destination(destination), _capacity(capacity) {} + + size_t visitArray(const CollectionData& array) + { + size_t size = 0; + VariantSlot* slot = array.head(); + + while (slot != 0 && size < _capacity) { + _destination[size++] = variantAs<T>(slot->data()); + slot = slot->next(); + } + return size; + } + + size_t visitObject(const CollectionData&) { return 0; } + + size_t visitFloat(Float) { return 0; } + + size_t visitString(const char*) { return 0; } + + size_t visitRawJson(const char*, size_t) { return 0; } + + size_t visitNegativeInteger(UInt) { return 0; } + + size_t visitPositiveInteger(UInt) { return 0; } + + size_t visitBoolean(bool) { return 0; } + + size_t visitNull() { return 0; } + + private: + T* _destination; + size_t _capacity; + }; + + template<typename T, size_t N1, size_t N2> + class ArrayCopier2D : public Visitor<void> { + public: + ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {} + + void visitArray(const CollectionData& array) + { + VariantSlot* slot = array.head(); + size_t n = 0; + while (slot != 0 && n < N1) { + ArrayCopier1D<T> copier((*_destination)[n++], N2); + variantAccept(slot->data(), copier); + slot = slot->next(); + } + } + void visitObject(const CollectionData&) {} + void visitFloat(Float) {} + void visitString(const char*) {} + void visitRawJson(const char*, size_t) {} + void visitNegativeInteger(UInt) {} + void visitPositiveInteger(UInt) {} + void visitBoolean(bool) {} + void visitNull() {} + + private: + T (*_destination)[N1][N2]; + size_t _capacity1, _capacity2; + }; + + // Copy a JsonArray to a 1D array + template<typename TSource, typename T, size_t N> + inline typename enable_if<!is_array<T>::value, size_t>::type copyArray(const TSource& src, T (&dst)[N]) + { + return copyArray(src, dst, N); + } + + // Copy a JsonArray to a 1D array + template<typename TSource, typename T> + inline size_t copyArray(const TSource& src, T* dst, size_t len) + { + ArrayCopier1D<T> copier(dst, len); + + return src.accept(copier); + } + + // Copy a JsonArray to a 2D array + template<typename TSource, typename T, size_t N1, size_t N2> + inline void copyArray(const TSource& src, T (&dst)[N1][N2]) + { + ArrayCopier2D<T, N1, N2> copier(&dst); + src.accept(copier); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionData.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionData.hpp new file mode 100644 index 000000000..11a54dd97 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionData.hpp @@ -0,0 +1,87 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> + +#include <stddef.h> // size_t + +namespace ARDUINOJSON_NAMESPACE { + + class MemoryPool; + class VariantData; + class VariantSlot; + + class CollectionData { + VariantSlot* _head; + VariantSlot* _tail; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + + // Array only + + VariantData* addElement(MemoryPool* pool); + + VariantData* getElement(size_t index) const; + + VariantData* getOrAddElement(size_t index, MemoryPool* pool); + + void removeElement(size_t index); + + bool equalsArray(const CollectionData& other) const; + + // Object only + + template<typename TAdaptedString> + VariantData* addMember(TAdaptedString key, MemoryPool* pool); + + template<typename TAdaptedString> + VariantData* getMember(TAdaptedString key) const; + + template<typename TAdaptedString> + VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool); + + template<typename TAdaptedString> + void removeMember(TAdaptedString key) + { + removeSlot(getSlot(key)); + } + + template<typename TAdaptedString> + bool containsKey(const TAdaptedString& key) const; + + bool equalsObject(const CollectionData& other) const; + + // Generic + + void clear(); + size_t memoryUsage() const; + size_t nesting() const; + size_t size() const; + + VariantSlot* addSlot(MemoryPool*); + void removeSlot(VariantSlot* slot); + + bool copyFrom(const CollectionData& src, MemoryPool* pool); + + VariantSlot* head() const { return _head; } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); + + private: + VariantSlot* getSlot(size_t index) const; + + template<typename TAdaptedString> + VariantSlot* getSlot(TAdaptedString key) const; + + VariantSlot* getPreviousSlot(VariantSlot*) const; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionImpl.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionImpl.hpp new file mode 100644 index 000000000..0085ac798 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Collection/CollectionImpl.hpp @@ -0,0 +1,220 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + inline bool variantEquals(const VariantData* a, const VariantData* b) + { + return variantCompare(a, b) == COMPARE_RESULT_EQUAL; + } + + inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) + { + VariantSlot* slot = pool->allocVariant(); + if (!slot) return 0; + + if (_tail) { + _tail->setNextNotNull(slot); + _tail = slot; + } else { + _head = slot; + _tail = slot; + } + + slot->clear(); + return slot; + } + + inline VariantData* CollectionData::addElement(MemoryPool* pool) { return slotData(addSlot(pool)); } + + template<typename TAdaptedString> + inline VariantData* CollectionData::addMember(TAdaptedString key, MemoryPool* pool) + { + VariantSlot* slot = addSlot(pool); + if (!slotSetKey(slot, key, pool)) { + removeSlot(slot); + return 0; + } + return slot->data(); + } + + inline void CollectionData::clear() + { + _head = 0; + _tail = 0; + } + + template<typename TAdaptedString> + inline bool CollectionData::containsKey(const TAdaptedString& key) const + { + return getSlot(key) != 0; + } + + inline bool CollectionData::copyFrom(const CollectionData& src, MemoryPool* pool) + { + clear(); + for (VariantSlot* s = src._head; s; s = s->next()) { + VariantData* var; + if (s->key() != 0) { + if (s->ownsKey()) + var = addMember(RamStringAdapter(s->key()), pool); + else + var = addMember(ConstRamStringAdapter(s->key()), pool); + } else { + var = addElement(pool); + } + if (!var) return false; + if (!var->copyFrom(*s->data(), pool)) return false; + } + return true; + } + + inline bool CollectionData::equalsObject(const CollectionData& other) const + { + size_t count = 0; + for (VariantSlot* slot = _head; slot; slot = slot->next()) { + VariantData* v1 = slot->data(); + VariantData* v2 = other.getMember(adaptString(slot->key())); + if (!variantEquals(v1, v2)) return false; + count++; + } + return count == other.size(); + } + + inline bool CollectionData::equalsArray(const CollectionData& other) const + { + VariantSlot* s1 = _head; + VariantSlot* s2 = other._head; + for (;;) { + if (s1 == s2) return true; + if (!s1 || !s2) return false; + if (!variantEquals(s1->data(), s2->data())) return false; + s1 = s1->next(); + s2 = s2->next(); + } + } + + template<typename TAdaptedString> + inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const + { + VariantSlot* slot = _head; + while (slot) { + if (key.equals(slot->key())) break; + slot = slot->next(); + } + return slot; + } + + inline VariantSlot* CollectionData::getSlot(size_t index) const { return _head->next(index); } + + inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const + { + VariantSlot* current = _head; + while (current) { + VariantSlot* next = current->next(); + if (next == target) return current; + current = next; + } + return 0; + } + + template<typename TAdaptedString> + inline VariantData* CollectionData::getMember(TAdaptedString key) const + { + VariantSlot* slot = getSlot(key); + return slot ? slot->data() : 0; + } + + template<typename TAdaptedString> + inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, MemoryPool* pool) + { + // ignore null key + if (key.isNull()) return 0; + + // search a matching key + VariantSlot* slot = getSlot(key); + if (slot) return slot->data(); + + return addMember(key, pool); + } + + inline VariantData* CollectionData::getElement(size_t index) const + { + VariantSlot* slot = getSlot(index); + return slot ? slot->data() : 0; + } + + inline VariantData* CollectionData::getOrAddElement(size_t index, MemoryPool* pool) + { + VariantSlot* slot = _head; + while (slot && index > 0) { + slot = slot->next(); + index--; + } + if (!slot) index++; + while (index > 0) { + slot = addSlot(pool); + index--; + } + return slotData(slot); + } + + inline void CollectionData::removeSlot(VariantSlot* slot) + { + if (!slot) return; + VariantSlot* prev = getPreviousSlot(slot); + VariantSlot* next = slot->next(); + if (prev) + prev->setNext(next); + else + _head = next; + if (!next) _tail = prev; + } + + inline void CollectionData::removeElement(size_t index) { removeSlot(getSlot(index)); } + + inline size_t CollectionData::memoryUsage() const + { + size_t total = 0; + for (VariantSlot* s = _head; s; s = s->next()) { + total += sizeof(VariantSlot) + s->data()->memoryUsage(); + if (s->ownsKey()) total += strlen(s->key()) + 1; + } + return total; + } + + inline size_t CollectionData::nesting() const + { + size_t maxChildNesting = 0; + for (VariantSlot* s = _head; s; s = s->next()) { + size_t childNesting = s->data()->nesting(); + if (childNesting > maxChildNesting) maxChildNesting = childNesting; + } + return maxChildNesting + 1; + } + + inline size_t CollectionData::size() const { return slotSize(_head); } + + template<typename T> + inline void movePointer(T*& p, ptrdiff_t offset) + { + if (!p) return; + p = reinterpret_cast<T*>(reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset)); + ARDUINOJSON_ASSERT(isAligned(p)); + } + + inline void CollectionData::movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) + { + movePointer(_head, variantDistance); + movePointer(_tail, variantDistance); + for (VariantSlot* slot = _head; slot; slot = slot->next()) + slot->movePointers(stringDistance, variantDistance); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Configuration.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Configuration.hpp new file mode 100644 index 000000000..7ed2ebdb9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Configuration.hpp @@ -0,0 +1,236 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#if __cplusplus >= 201103L +#define ARDUINOJSON_HAS_LONG_LONG 1 +#define ARDUINOJSON_HAS_NULLPTR 1 +#define ARDUINOJSON_HAS_RVALUE_REFERENCES 1 +#else +#define ARDUINOJSON_HAS_LONG_LONG 0 +#define ARDUINOJSON_HAS_NULLPTR 0 +#define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 +#endif + +#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG +#define ARDUINOJSON_HAS_INT64 1 +#else +#define ARDUINOJSON_HAS_INT64 0 +#endif + +// Small or big machine? +#ifndef ARDUINOJSON_EMBEDDED_MODE +#if defined(ARDUINO) /* Arduino*/ \ + || defined(__IAR_SYSTEMS_ICC__) /* IAR Embedded Workbench */ \ + || defined(__XC) /* MPLAB XC compiler */ \ + || defined(__ARMCC_VERSION) /* Keil ARM Compiler */ \ + || defined(__AVR) /* Atmel AVR8/GNU C Compiler */ +#define ARDUINOJSON_EMBEDDED_MODE 1 +#else +#define ARDUINOJSON_EMBEDDED_MODE 0 +#endif +#endif + +// Auto enable std::stream if the right headers are here and no conflicting +// macro is defined +#if !defined(ARDUINOJSON_ENABLE_STD_STREAM) && defined(__has_include) +#if __has_include(<istream>) && \ + __has_include(<ostream>) && \ + !defined(min) && \ + !defined(max) +#define ARDUINOJSON_ENABLE_STD_STREAM 1 +#else +#define ARDUINOJSON_ENABLE_STD_STREAM 0 +#endif +#endif + +// Auto enable std::string if the right header is here and no conflicting +// macro is defined +#if !defined(ARDUINOJSON_ENABLE_STD_STRING) && defined(__has_include) +#if __has_include(<string>) && !defined(min) && !defined(max) +#define ARDUINOJSON_ENABLE_STD_STRING 1 +#else +#define ARDUINOJSON_ENABLE_STD_STRING 0 +#endif +#endif + +#if ARDUINOJSON_EMBEDDED_MODE + +// Store floats by default to reduce the memory usage (issue #134) +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 0 +#endif + +// Store longs by default, because they usually match the size of a float. +#ifndef ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif + +// Embedded systems usually don't have std::string +#ifndef ARDUINOJSON_ENABLE_STD_STRING +#define ARDUINOJSON_ENABLE_STD_STRING 0 +#endif + +// Embedded systems usually don't have std::stream +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 0 +#endif + +// Limit nesting as the stack is likely to be small +#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT +#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 +#endif + +#else // ARDUINOJSON_EMBEDDED_MODE + +// On a computer we have plenty of memory so we can use doubles +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 1 +#endif + +// Use long long when available +#ifndef ARDUINOJSON_USE_LONG_LONG +#if ARDUINOJSON_HAS_LONG_LONG || ARDUINOJSON_HAS_INT64 +#define ARDUINOJSON_USE_LONG_LONG 1 +#else +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#endif + +// On a computer, we can use std::string +#ifndef ARDUINOJSON_ENABLE_STD_STRING +#define ARDUINOJSON_ENABLE_STD_STRING 1 +#endif + +// On a computer, we can assume std::stream +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 1 +#endif + +// On a computer, the stack is large so we can increase nesting limit +#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT +#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 +#endif + +#endif // ARDUINOJSON_EMBEDDED_MODE + +#ifdef ARDUINO + +#include <Arduino.h> + +// Enable support for Arduino's String class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 +#endif + +// Enable support for Arduino's Stream class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM +#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 +#endif + +// Enable support for Arduino's Print class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT +#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 +#endif + +#else // ARDUINO + +// Disable support for Arduino's String class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 +#endif + +// Disable support for Arduino's Stream class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM +#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 +#endif + +// Disable support for Arduino's Print class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT +#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 +#endif + +#endif // ARDUINO + +#ifndef ARDUINOJSON_ENABLE_PROGMEM +#ifdef PROGMEM +#define ARDUINOJSON_ENABLE_PROGMEM 1 +#else +#define ARDUINOJSON_ENABLE_PROGMEM 0 +#endif +#endif + +// Convert unicode escape sequence (\u0123) to UTF-8 +#ifndef ARDUINOJSON_DECODE_UNICODE +#define ARDUINOJSON_DECODE_UNICODE 1 +#endif + +// Ignore comments in input +#ifndef ARDUINOJSON_ENABLE_COMMENTS +#define ARDUINOJSON_ENABLE_COMMENTS 0 +#endif + +// Support NaN in JSON +#ifndef ARDUINOJSON_ENABLE_NAN +#define ARDUINOJSON_ENABLE_NAN 0 +#endif + +// Support Infinity in JSON +#ifndef ARDUINOJSON_ENABLE_INFINITY +#define ARDUINOJSON_ENABLE_INFINITY 0 +#endif + +// Control the exponentiation threshold for big numbers +// CAUTION: cannot be more that 1e9 !!!! +#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD +#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 +#endif + +// Control the exponentiation threshold for small numbers +#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD +#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 +#endif + +#ifndef ARDUINOJSON_LITTLE_ENDIAN +#if defined(_MSC_VER) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ + defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64) +#define ARDUINOJSON_LITTLE_ENDIAN 1 +#else +#define ARDUINOJSON_LITTLE_ENDIAN 0 +#endif +#endif + +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +#if defined(__AVR) +#define ARDUINOJSON_ENABLE_ALIGNMENT 0 +#else +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif +#endif + +#ifndef ARDUINOJSON_TAB +#define ARDUINOJSON_TAB " " +#endif + +#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION +#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 +#endif + +#ifndef ARDUINOJSON_STRING_BUFFER_SIZE +#define ARDUINOJSON_STRING_BUFFER_SIZE 32 +#endif + +#ifndef ARDUINOJSON_DEBUG +#ifdef __PLATFORMIO_BUILD_DEBUG__ +#define ARDUINOJSON_DEBUG 1 +#else +#define ARDUINOJSON_DEBUG 0 +#endif +#endif + +#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) +#error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr +// See https://github.com/bblanchon/ArduinoJson/issues/1355 +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/DeserializationError.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/DeserializationError.hpp new file mode 100644 index 000000000..723ca8ce1 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/DeserializationError.hpp @@ -0,0 +1,95 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/Polyfills/static_array.hpp> + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include <ostream> +#endif + +namespace ARDUINOJSON_NAMESPACE { + + class DeserializationError { + // safe bool idiom + typedef void (DeserializationError::*bool_type)() const; + void safeBoolHelper() const {} + + public: + enum Code { Ok, EmptyInput, IncompleteInput, InvalidInput, NoMemory, NotSupported, TooDeep }; + + DeserializationError() {} + DeserializationError(Code c) : _code(c) {} + + // Compare with DeserializationError + friend bool operator==(const DeserializationError& lhs, const DeserializationError& rhs) + { + return lhs._code == rhs._code; + } + friend bool operator!=(const DeserializationError& lhs, const DeserializationError& rhs) + { + return lhs._code != rhs._code; + } + + // Compare with Code + friend bool operator==(const DeserializationError& lhs, Code rhs) { return lhs._code == rhs; } + friend bool operator==(Code lhs, const DeserializationError& rhs) { return lhs == rhs._code; } + friend bool operator!=(const DeserializationError& lhs, Code rhs) { return lhs._code != rhs; } + friend bool operator!=(Code lhs, const DeserializationError& rhs) { return lhs != rhs._code; } + + // Behaves like a bool + operator bool_type() const { return _code != Ok ? &DeserializationError::safeBoolHelper : 0; } + friend bool operator==(bool value, const DeserializationError& err) { return static_cast<bool>(err) == value; } + friend bool operator==(const DeserializationError& err, bool value) { return static_cast<bool>(err) == value; } + friend bool operator!=(bool value, const DeserializationError& err) { return static_cast<bool>(err) != value; } + friend bool operator!=(const DeserializationError& err, bool value) { return static_cast<bool>(err) != value; } + + // Returns internal enum, useful for switch statement + Code code() const { return _code; } + + const char* c_str() const + { + static const char* messages[] = { + "Ok", "EmptyInput", "IncompleteInput", "InvalidInput", "NoMemory", "NotSupported", "TooDeep"}; + ARDUINOJSON_ASSERT(static_cast<size_t>(_code) < sizeof(messages) / sizeof(messages[0])); + return messages[_code]; + } + +#if ARDUINOJSON_ENABLE_PROGMEM + const __FlashStringHelper* f_str() const + { + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "NotSupported"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s6, "TooDeep"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(const char*, messages, ARDUINOJSON_EXPAND7({s0, s1, s2, s3, s4, s5, s6})); + return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, _code); + } +#endif + + private: + Code _code; + }; + +#if ARDUINOJSON_ENABLE_STD_STREAM + inline std::ostream& operator<<(std::ostream& s, const DeserializationError& e) + { + s << e.c_str(); + return s; + } + + inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) + { + s << DeserializationError(c).c_str(); + return s; + } +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Filter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Filter.hpp new file mode 100644 index 000000000..1d6239264 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Filter.hpp @@ -0,0 +1,52 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class Filter { + public: + explicit Filter(VariantConstRef v) : _variant(v) {} + + bool allow() const { return _variant; } + + bool allowArray() const { return _variant == true || _variant.is<ArrayRef>(); } + + bool allowObject() const { return _variant == true || _variant.is<ObjectRef>(); } + + bool allowValue() const { return _variant == true; } + + template<typename TKey> + Filter operator[](const TKey& key) const + { + if (_variant == true) // "true" means "allow recursively" + return *this; + else + return Filter(_variant[key] | _variant["*"]); + } + + private: + VariantConstRef _variant; + }; + + struct AllowAllFilter { + bool allow() const { return true; } + + bool allowArray() const { return true; } + + bool allowObject() const { return true; } + + bool allowValue() const { return true; } + + template<typename TKey> + AllowAllFilter operator[](const TKey&) const + { + return AllowAllFilter(); + } + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/NestingLimit.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/NestingLimit.hpp new file mode 100644 index 000000000..8bb59c101 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/NestingLimit.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class NestingLimit { + public: + NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} + explicit NestingLimit(uint8_t n) : _value(n) {} + + NestingLimit decrement() const + { + ARDUINOJSON_ASSERT(_value > 0); + return NestingLimit(static_cast<uint8_t>(_value - 1)); + } + + bool reached() const { return _value == 0; } + + private: + uint8_t _value; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Reader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Reader.hpp new file mode 100644 index 000000000..55f5cae1c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Reader.hpp @@ -0,0 +1,52 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stdlib.h> // for size_t + +namespace ARDUINOJSON_NAMESPACE { + + // The default reader is a simple wrapper for Readers that are not copiable + template<typename TSource, typename Enable = void> + struct Reader { + public: + Reader(TSource& source) : _source(&source) {} + + int read() { return _source->read(); } + + size_t readBytes(char* buffer, size_t length) { return _source->readBytes(buffer, length); } + + private: + TSource* _source; + }; + + template<typename TSource, typename Enable = void> + struct BoundedReader { + // no default implementation because we need to pass the size to the + // constructor + }; +} // namespace ARDUINOJSON_NAMESPACE + +#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp> +#include <ArduinoJson/Deserialization/Readers/RamReader.hpp> +#include <ArduinoJson/Deserialization/Readers/VariantReader.hpp> + +#if ARDUINOJSON_ENABLE_ARDUINO_STREAM +#include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp> +#endif + +#if ARDUINOJSON_ENABLE_PROGMEM +#include <ArduinoJson/Deserialization/Readers/FlashReader.hpp> +#endif + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp> +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp new file mode 100644 index 000000000..78758ee7f --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp @@ -0,0 +1,29 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <Arduino.h> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TSource> + struct Reader<TSource, typename enable_if<is_base_of<Stream, TSource>::value>::type> { + public: + explicit Reader(Stream& stream) : _stream(&stream) {} + + int read() + { + // don't use _stream.read() as it ignores the timeout + char c; + return _stream->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1; + } + + size_t readBytes(char* buffer, size_t length) { return _stream->readBytes(buffer, length); } + + private: + Stream* _stream; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp new file mode 100644 index 000000000..fe0e3fe54 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TSource> + struct Reader<TSource, typename enable_if<is_base_of<::String, TSource>::value>::type> : BoundedReader<const char*> { + explicit Reader(const ::String& s) : BoundedReader<const char*>(s.c_str(), s.length()) {} + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/FlashReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/FlashReader.hpp new file mode 100644 index 000000000..aa7d7c0fb --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/FlashReader.hpp @@ -0,0 +1,53 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + + template<> + struct Reader<const __FlashStringHelper*, void> { + const char* _ptr; + + public: + explicit Reader(const __FlashStringHelper* ptr) : _ptr(reinterpret_cast<const char*>(ptr)) {} + + int read() { return pgm_read_byte(_ptr++); } + + size_t readBytes(char* buffer, size_t length) + { + memcpy_P(buffer, _ptr, length); + _ptr += length; + return length; + } + }; + + template<> + struct BoundedReader<const __FlashStringHelper*, void> { + const char* _ptr; + const char* _end; + + public: + explicit BoundedReader(const __FlashStringHelper* ptr, size_t size) : + _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) + {} + + int read() + { + if (_ptr < _end) + return pgm_read_byte(_ptr++); + else + return -1; + } + + size_t readBytes(char* buffer, size_t length) + { + size_t available = static_cast<size_t>(_end - _ptr); + if (available < length) length = available; + memcpy_P(buffer, _ptr, length); + _ptr += length; + return length; + } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/IteratorReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/IteratorReader.hpp new file mode 100644 index 000000000..118b51fb3 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/IteratorReader.hpp @@ -0,0 +1,45 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TIterator> + class IteratorReader { + TIterator _ptr, _end; + + public: + explicit IteratorReader(TIterator begin, TIterator end) : _ptr(begin), _end(end) {} + + int read() + { + if (_ptr < _end) + return static_cast<unsigned char>(*_ptr++); + else + return -1; + } + + size_t readBytes(char* buffer, size_t length) + { + size_t i = 0; + while (i < length && _ptr < _end) + buffer[i++] = *_ptr++; + return i; + } + }; + + template<typename T> + struct void_ { + typedef void type; + }; + + template<typename TSource> + struct Reader<TSource, typename void_<typename TSource::const_iterator>::type> + : IteratorReader<typename TSource::const_iterator> { + explicit Reader(const TSource& source) : + IteratorReader<typename TSource::const_iterator>(source.begin(), source.end()) + {} + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/RamReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/RamReader.hpp new file mode 100644 index 000000000..5e2e4397e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/RamReader.hpp @@ -0,0 +1,47 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct IsCharOrVoid { + static const bool value = is_same<T, void>::value || is_same<T, char>::value || is_same<T, unsigned char>::value || + is_same<T, signed char>::value; + }; + + template<typename T> + struct IsCharOrVoid<const T> : IsCharOrVoid<T> { + }; + + template<typename TSource> + struct Reader<TSource*, typename enable_if<IsCharOrVoid<TSource>::value>::type> { + const char* _ptr; + + public: + explicit Reader(const void* ptr) : _ptr(ptr ? reinterpret_cast<const char*>(ptr) : "") {} + + int read() { return static_cast<unsigned char>(*_ptr++); } + + size_t readBytes(char* buffer, size_t length) + { + for (size_t i = 0; i < length; i++) + buffer[i] = *_ptr++; + return length; + } + }; + + template<typename TSource> + struct BoundedReader<TSource*, typename enable_if<IsCharOrVoid<TSource>::value>::type> + : public IteratorReader<const char*> { + public: + explicit BoundedReader(const void* ptr, size_t len) : + IteratorReader<const char*>(reinterpret_cast<const char*>(ptr), reinterpret_cast<const char*>(ptr) + len) + {} + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp new file mode 100644 index 000000000..bf5d37006 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp @@ -0,0 +1,27 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <istream> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TSource> + struct Reader<TSource, typename enable_if<is_base_of<std::istream, TSource>::value>::type> { + public: + explicit Reader(std::istream& stream) : _stream(&stream) {} + + int read() { return _stream->get(); } + + size_t readBytes(char* buffer, size_t length) + { + _stream->read(buffer, static_cast<std::streamsize>(length)); + return static_cast<size_t>(_stream->gcount()); + } + + private: + std::istream* _stream; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/VariantReader.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/VariantReader.hpp new file mode 100644 index 000000000..544e5b173 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/Readers/VariantReader.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Object/MemberProxy.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TArray> + struct Reader<ElementProxy<TArray>, void> : Reader<char*, void> { + explicit Reader(const ElementProxy<TArray>& x) : Reader<char*, void>(x.template as<const char*>()) {} + }; + + template<typename TObject, typename TStringRef> + struct Reader<MemberProxy<TObject, TStringRef>, void> : Reader<char*, void> { + explicit Reader(const MemberProxy<TObject, TStringRef>& x) : Reader<char*, void>(x.template as<const char*>()) {} + }; + + template<> + struct Reader<VariantRef, void> : Reader<char*, void> { + explicit Reader(VariantRef x) : Reader<char*, void>(x.as<const char*>()) {} + }; + + template<> + struct Reader<VariantConstRef, void> : Reader<char*, void> { + explicit Reader(VariantConstRef x) : Reader<char*, void>(x.as<const char*>()) {} + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/deserialize.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/deserialize.hpp new file mode 100644 index 000000000..267af015c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Deserialization/deserialize.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/DeserializationError.hpp> +#include <ArduinoJson/Deserialization/Filter.hpp> +#include <ArduinoJson/Deserialization/NestingLimit.hpp> +#include <ArduinoJson/Deserialization/Reader.hpp> +#include <ArduinoJson/StringStorage/StringStorage.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<template<typename, typename> class TDeserializer, typename TReader, typename TWriter> + TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool& pool, TReader reader, TWriter writer) + { + return TDeserializer<TReader, TWriter>(pool, reader, writer); + } + + // deserialize(JsonDocument&, const std::string&, NestingLimit, Filter); + // deserialize(JsonDocument&, const String&, NestingLimit, Filter); + // deserialize(JsonDocument&, char*, NestingLimit, Filter); + // deserialize(JsonDocument&, const char*, NestingLimit, Filter); + // deserialize(JsonDocument&, const __FlashStringHelper*, NestingLimit, Filter); + template<template<typename, typename> class TDeserializer, typename TString, typename TFilter> + typename enable_if<!is_array<TString>::value, DeserializationError>::type + deserialize(JsonDocument& doc, const TString& input, NestingLimit nestingLimit, TFilter filter) + { + Reader<TString> reader(input); + doc.clear(); + return makeDeserializer<TDeserializer>(doc.memoryPool(), reader, makeStringStorage(input, doc.memoryPool())) + .parse(doc.data(), filter, nestingLimit); + } + // + // deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter); + // deserialize(JsonDocument&, const char*, size_t, NestingLimit, Filter); + // deserialize(JsonDocument&, const __FlashStringHelper*, size_t, NL, Filter); + template<template<typename, typename> class TDeserializer, typename TChar, typename TFilter> + DeserializationError + deserialize(JsonDocument& doc, TChar* input, size_t inputSize, NestingLimit nestingLimit, TFilter filter) + { + BoundedReader<TChar*> reader(input, inputSize); + doc.clear(); + return makeDeserializer<TDeserializer>(doc.memoryPool(), reader, makeStringStorage(input, doc.memoryPool())) + .parse(doc.data(), filter, nestingLimit); + } + // + // deserialize(JsonDocument&, std::istream&, NestingLimit, Filter); + // deserialize(JsonDocument&, Stream&, NestingLimit, Filter); + template<template<typename, typename> class TDeserializer, typename TStream, typename TFilter> + DeserializationError deserialize(JsonDocument& doc, TStream& input, NestingLimit nestingLimit, TFilter filter) + { + Reader<TStream> reader(input); + doc.clear(); + return makeDeserializer<TDeserializer>(doc.memoryPool(), reader, makeStringStorage(input, doc.memoryPool())) + .parse(doc.data(), filter, nestingLimit); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/BasicJsonDocument.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/BasicJsonDocument.hpp new file mode 100644 index 000000000..530af0a31 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/BasicJsonDocument.hpp @@ -0,0 +1,153 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Document/JsonDocument.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // Helper to implement the "base-from-member" idiom + // (we need to store the allocator before constructing JsonDocument) + template<typename TAllocator> + class AllocatorOwner { + public: + AllocatorOwner() {} + AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} + AllocatorOwner(TAllocator a) : _allocator(a) {} + + void* allocate(size_t size) { return _allocator.allocate(size); } + + void deallocate(void* ptr) + { + if (ptr) _allocator.deallocate(ptr); + } + + void* reallocate(void* ptr, size_t new_size) { return _allocator.reallocate(ptr, new_size); } + + TAllocator& allocator() { return _allocator; } + + private: + TAllocator _allocator; + }; + + template<typename TAllocator> + class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { + public: + explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator()) : + AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) + {} + + // Copy-constructor + BasicJsonDocument(const BasicJsonDocument& src) : AllocatorOwner<TAllocator>(src), JsonDocument() + { + copyAssignFrom(src); + } + + // Move-constructor +#if ARDUINOJSON_HAS_RVALUE_REFERENCES + BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) { moveAssignFrom(src); } +#endif + + BasicJsonDocument(const JsonDocument& src) { copyAssignFrom(src); } + + // Construct from variant, array, or object + template<typename T> + BasicJsonDocument( + const T& src, + typename enable_if< + is_same<T, VariantRef>::value || is_same<T, VariantConstRef>::value || is_same<T, ArrayRef>::value || + is_same<T, ArrayConstRef>::value || is_same<T, ObjectRef>::value || is_same<T, ObjectConstRef>::value>::type* = + 0) : + JsonDocument(allocPool(src.memoryUsage())) + { + set(src); + } + + // disambiguate + BasicJsonDocument(VariantRef src) : JsonDocument(allocPool(src.memoryUsage())) { set(src); } + + ~BasicJsonDocument() { freePool(); } + + BasicJsonDocument& operator=(const BasicJsonDocument& src) + { + copyAssignFrom(src); + return *this; + } + +#if ARDUINOJSON_HAS_RVALUE_REFERENCES + BasicJsonDocument& operator=(BasicJsonDocument&& src) + { + moveAssignFrom(src); + return *this; + } +#endif + + template<typename T> + BasicJsonDocument& operator=(const T& src) + { + reallocPoolIfTooSmall(src.memoryUsage()); + set(src); + return *this; + } + + void shrinkToFit() + { + ptrdiff_t bytes_reclaimed = _pool.squash(); + if (bytes_reclaimed == 0) return; + + void* old_ptr = _pool.buffer(); + void* new_ptr = this->reallocate(old_ptr, _pool.capacity()); + + ptrdiff_t ptr_offset = static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr); + + _pool.movePointers(ptr_offset); + _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); + } + + bool garbageCollect() + { + // make a temporary clone and move assign + BasicJsonDocument tmp(*this); + if (!tmp.capacity()) return false; + tmp.set(*this); + moveAssignFrom(tmp); + return true; + } + + using AllocatorOwner<TAllocator>::allocator; + + private: + MemoryPool allocPool(size_t requiredSize) + { + size_t capa = addPadding(requiredSize); + return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa); + } + + void reallocPoolIfTooSmall(size_t requiredSize) + { + if (requiredSize <= capacity()) return; + freePool(); + replacePool(allocPool(addPadding(requiredSize))); + } + + void freePool() { this->deallocate(memoryPool().buffer()); } + + void copyAssignFrom(const JsonDocument& src) + { + reallocPoolIfTooSmall(src.capacity()); + set(src); + } + + void moveAssignFrom(BasicJsonDocument& src) + { + freePool(); + _data = src._data; + _pool = src._pool; + src._data.setNull(); + src._pool = MemoryPool(0, 0); + } + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/DynamicJsonDocument.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/DynamicJsonDocument.hpp new file mode 100644 index 000000000..7dddb1388 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/DynamicJsonDocument.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Document/BasicJsonDocument.hpp> + +#include <stdlib.h> // malloc, free + +namespace ARDUINOJSON_NAMESPACE { + + struct DefaultAllocator { + void* allocate(size_t size) { return malloc(size); } + + void deallocate(void* ptr) { free(ptr); } + + void* reallocate(void* ptr, size_t new_size) { return realloc(ptr, new_size); } + }; + + typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/JsonDocument.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/JsonDocument.hpp new file mode 100644 index 000000000..e41b214aa --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/JsonDocument.hpp @@ -0,0 +1,301 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ElementProxy.hpp> +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Object/MemberProxy.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantTo.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class JsonDocument : public Visitable { + public: + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + return getVariant().accept(visitor); + } + + template<typename T> + typename VariantAs<T>::type as() + { + return getVariant().template as<T>(); + } + + template<typename T> + typename VariantConstAs<T>::type as() const + { + return getVariant().template as<T>(); + } + + void clear() + { + _pool.clear(); + _data.setNull(); + } + + template<typename T> + bool is() const + { + return getVariant().template is<T>(); + } + + bool isNull() const { return getVariant().isNull(); } + + size_t memoryUsage() const { return _pool.size(); } + + bool overflowed() const { return _pool.overflowed(); } + + size_t nesting() const { return _data.nesting(); } + + size_t capacity() const { return _pool.capacity(); } + + size_t size() const { return _data.size(); } + + bool set(const JsonDocument& src) { return to<VariantRef>().set(src.as<VariantRef>()); } + + template<typename T> + typename enable_if<!is_base_of<JsonDocument, T>::value, bool>::type set(const T& src) + { + return to<VariantRef>().set(src); + } + + template<typename T> + typename VariantTo<T>::type to() + { + clear(); + return getVariant().template to<T>(); + } + + // for internal use only + MemoryPool& memoryPool() { return _pool; } + + // for internal use only + VariantData& data() { return _data; } + + ArrayRef createNestedArray() { return addElement().to<ArrayRef>(); } + + // createNestedArray(char*) + // createNestedArray(const char*) + // createNestedArray(const __FlashStringHelper*) + template<typename TChar> + ArrayRef createNestedArray(TChar* key) + { + return getOrAddMember(key).template to<ArrayRef>(); + } + + // createNestedArray(const std::string&) + // createNestedArray(const String&) + template<typename TString> + ArrayRef createNestedArray(const TString& key) + { + return getOrAddMember(key).template to<ArrayRef>(); + } + + ObjectRef createNestedObject() { return addElement().to<ObjectRef>(); } + + // createNestedObject(char*) + // createNestedObject(const char*) + // createNestedObject(const __FlashStringHelper*) + template<typename TChar> + ObjectRef createNestedObject(TChar* key) + { + return getOrAddMember(key).template to<ObjectRef>(); + } + + // createNestedObject(const std::string&) + // createNestedObject(const String&) + template<typename TString> + ObjectRef createNestedObject(const TString& key) + { + return getOrAddMember(key).template to<ObjectRef>(); + } + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template<typename TChar> + bool containsKey(TChar* key) const + { + return !getMember(key).isUndefined(); + } + + // containsKey(const std::string&) const + // containsKey(const String&) const + template<typename TString> + bool containsKey(const TString& key) const + { + return !getMember(key).isUndefined(); + } + + // operator[](const std::string&) + // operator[](const String&) + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, MemberProxy<JsonDocument&, TString>>::type operator[]( + const TString& key) + { + return MemberProxy<JsonDocument&, TString>(*this, key); + } + + // operator[](char*) + // operator[](const char*) + // operator[](const __FlashStringHelper*) + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, MemberProxy<JsonDocument&, TChar*>>::type operator[]( + TChar* key) + { + return MemberProxy<JsonDocument&, TChar*>(*this, key); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantConstRef>::type operator[]( + const TString& key) const + { + return getMember(key); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, VariantConstRef>::type operator[](TChar* key) const + { + return getMember(key); + } + + FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) + { + return ElementProxy<JsonDocument&>(*this, index); + } + + FORCE_INLINE VariantConstRef operator[](size_t index) const { return getElement(index); } + + FORCE_INLINE VariantRef getElement(size_t index) { return VariantRef(&_pool, _data.getElement(index)); } + + FORCE_INLINE VariantConstRef getElement(size_t index) const { return VariantConstRef(_data.getElement(index)); } + + FORCE_INLINE VariantRef getOrAddElement(size_t index) + { + return VariantRef(&_pool, _data.getOrAddElement(index, &_pool)); + } + + // JsonVariantConst getMember(char*) const + // JsonVariantConst getMember(const char*) const + // JsonVariantConst getMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar* key) const + { + return VariantConstRef(_data.getMember(adaptString(key))); + } + + // JsonVariantConst getMember(const std::string&) const + // JsonVariantConst getMember(const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantConstRef>::type getMember(const TString& key) const + { + return VariantConstRef(_data.getMember(adaptString(key))); + } + + // JsonVariant getMember(char*) + // JsonVariant getMember(const char*) + // JsonVariant getMember(const __FlashStringHelper*) + template<typename TChar> + FORCE_INLINE VariantRef getMember(TChar* key) + { + return VariantRef(&_pool, _data.getMember(adaptString(key))); + } + + // JsonVariant getMember(const std::string&) + // JsonVariant getMember(const String&) + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type getMember(const TString& key) + { + return VariantRef(&_pool, _data.getMember(adaptString(key))); + } + + // getOrAddMember(char*) + // getOrAddMember(const char*) + // getOrAddMember(const __FlashStringHelper*) + template<typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar* key) + { + return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); + } + + // getOrAddMember(const std::string&) + // getOrAddMember(const String&) + template<typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString& key) + { + return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); + } + + FORCE_INLINE VariantRef addElement() { return VariantRef(&_pool, _data.addElement(&_pool)); } + + template<typename TValue> + FORCE_INLINE bool add(const TValue& value) + { + return addElement().set(value); + } + + // add(char*) const + // add(const char*) const + // add(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE bool add(TChar* value) + { + return addElement().set(value); + } + + FORCE_INLINE void remove(size_t index) { _data.remove(index); } + // remove(char*) + // remove(const char*) + // remove(const __FlashStringHelper*) + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(TChar* key) + { + _data.remove(adaptString(key)); + } + // remove(const std::string&) + // remove(const String&) + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(const TString& key) + { + _data.remove(adaptString(key)); + } + + FORCE_INLINE operator VariantConstRef() const { return VariantConstRef(&_data); } + + bool operator==(VariantConstRef rhs) const { return getVariant() == rhs; } + + bool operator!=(VariantConstRef rhs) const { return getVariant() != rhs; } + + protected: + JsonDocument() : _pool(0, 0) { _data.setNull(); } + + JsonDocument(MemoryPool pool) : _pool(pool) { _data.setNull(); } + + JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { _data.setNull(); } + + void replacePool(MemoryPool pool) { _pool = pool; } + + VariantRef getVariant() { return VariantRef(&_pool, &_data); } + + VariantConstRef getVariant() const { return VariantConstRef(&_data); } + + MemoryPool _pool; + VariantData _data; + + private: + JsonDocument(const JsonDocument&); + JsonDocument& operator=(const JsonDocument&); + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/StaticJsonDocument.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/StaticJsonDocument.hpp new file mode 100644 index 000000000..e5121ed2d --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Document/StaticJsonDocument.hpp @@ -0,0 +1,53 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Document/JsonDocument.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<size_t desiredCapacity> + class StaticJsonDocument : public JsonDocument { + static const size_t _capacity = AddPadding<Max<1, desiredCapacity>::value>::value; + + public: + StaticJsonDocument() : JsonDocument(_buffer, _capacity) {} + + StaticJsonDocument(const StaticJsonDocument& src) : JsonDocument(_buffer, _capacity) { set(src); } + + template<typename T> + StaticJsonDocument(const T& src, typename enable_if<IsVisitable<T>::value>::type* = 0) : + JsonDocument(_buffer, _capacity) + { + set(src); + } + + // disambiguate + StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) { set(src); } + + StaticJsonDocument operator=(const StaticJsonDocument& src) + { + set(src); + return *this; + } + + template<typename T> + StaticJsonDocument operator=(const T& src) + { + set(src); + return *this; + } + + void garbageCollect() + { + StaticJsonDocument tmp(*this); + set(tmp); + } + + private: + char _buffer[_capacity]; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/EscapeSequence.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/EscapeSequence.hpp new file mode 100644 index 000000000..371bf9082 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/EscapeSequence.hpp @@ -0,0 +1,37 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class EscapeSequence { + public: + // Optimized for code size on a 8-bit AVR + static char escapeChar(char c) + { + const char* p = escapeTable(true); + while (p[0] && p[1] != c) { + p += 2; + } + return p[0]; + } + + // Optimized for code size on a 8-bit AVR + static char unescapeChar(char c) + { + const char* p = escapeTable(false); + for (;;) { + if (p[0] == '\0') return 0; + if (p[0] == c) return p[1]; + p += 2; + } + } + + private: + static const char* escapeTable(bool excludeSolidus) { return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0]; } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonDeserializer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonDeserializer.hpp new file mode 100644 index 000000000..4ab43fc6c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonDeserializer.hpp @@ -0,0 +1,697 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/deserialize.hpp> +#include <ArduinoJson/Json/EscapeSequence.hpp> +#include <ArduinoJson/Json/Latch.hpp> +#include <ArduinoJson/Json/Utf16.hpp> +#include <ArduinoJson/Json/Utf8.hpp> +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Numbers/parseNumber.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TReader, typename TStringStorage> + class JsonDeserializer { + public: + JsonDeserializer(MemoryPool& pool, TReader reader, TStringStorage stringStorage) : + _stringStorage(stringStorage), _foundSomething(false), _latch(reader), _pool(&pool), + _error(DeserializationError::Ok) + {} + + template<typename TFilter> + DeserializationError parse(VariantData& variant, TFilter filter, NestingLimit nestingLimit) + { + parseVariant(variant, filter, nestingLimit); + + if (!_error && _latch.last() != 0 && !variant.isEnclosed()) { + // We don't detect trailing characters earlier, so we need to check now + return DeserializationError::InvalidInput; + } + + return _error; + } + + private: + JsonDeserializer& operator=(const JsonDeserializer&); // non-copiable + + char current() { return _latch.current(); } + + void move() { _latch.clear(); } + + bool eat(char charToSkip) + { + if (current() != charToSkip) return false; + move(); + return true; + } + + template<typename TFilter> + bool parseVariant(VariantData& variant, TFilter filter, NestingLimit nestingLimit) + { + if (!skipSpacesAndComments()) return false; + + switch (current()) { + case '[': + if (filter.allowArray()) + return parseArray(variant.toArray(), filter, nestingLimit); + else + return skipArray(nestingLimit); + + case '{': + if (filter.allowObject()) + return parseObject(variant.toObject(), filter, nestingLimit); + else + return skipObject(nestingLimit); + + case '\"': + case '\'': + if (filter.allowValue()) + return parseStringValue(variant); + else + return skipString(); + + default: + if (filter.allowValue()) + return parseNumericValue(variant); + else + return skipNumericValue(); + } + } + + bool skipVariant(NestingLimit nestingLimit) + { + if (!skipSpacesAndComments()) return false; + + switch (current()) { + case '[': return skipArray(nestingLimit); + + case '{': return skipObject(nestingLimit); + + case '\"': + case '\'': return skipString(); + + default: return skipNumericValue(); + } + } + + template<typename TFilter> + bool parseArray(CollectionData& array, TFilter filter, NestingLimit nestingLimit) + { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + // Skip opening braket + ARDUINOJSON_ASSERT(current() == '['); + move(); + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // Empty array? + if (eat(']')) return true; + + TFilter memberFilter = filter[0UL]; + + // Read each value + for (;;) { + if (memberFilter.allow()) { + // Allocate slot in array + VariantData* value = array.addElement(_pool); + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } + + // 1 - Parse value + if (!parseVariant(*value, memberFilter, nestingLimit.decrement())) return false; + } else { + if (!skipVariant(nestingLimit.decrement())) return false; + } + + // 2 - Skip spaces + if (!skipSpacesAndComments()) return false; + + // 3 - More values? + if (eat(']')) return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } + } + } + + bool skipArray(NestingLimit nestingLimit) + { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + // Skip opening braket + ARDUINOJSON_ASSERT(current() == '['); + move(); + + // Read each value + for (;;) { + // 1 - Skip value + if (!skipVariant(nestingLimit.decrement())) return false; + + // 2 - Skip spaces + if (!skipSpacesAndComments()) return false; + + // 3 - More values? + if (eat(']')) return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } + } + } + + template<typename TFilter> + bool parseObject(CollectionData& object, TFilter filter, NestingLimit nestingLimit) + { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + // Skip opening brace + ARDUINOJSON_ASSERT(current() == '{'); + move(); + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // Empty object? + if (eat('}')) return true; + + // Read each key value pair + for (;;) { + // Parse key + if (!parseKey()) return false; + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // Colon + if (!eat(':')) { + _error = DeserializationError::InvalidInput; + return false; + } + + const char* key = _stringStorage.c_str(); + + TFilter memberFilter = filter[key]; + + if (memberFilter.allow()) { + VariantData* variant = object.getMember(adaptString(key)); + if (!variant) { + // Save key in memory pool. + // This MUST be done before adding the slot. + key = _stringStorage.save(); + + // Allocate slot in object + VariantSlot* slot = object.addSlot(_pool); + if (!slot) { + _error = DeserializationError::NoMemory; + return false; + } + + slot->setKey(key, typename TStringStorage::storage_policy()); + + variant = slot->data(); + } + + // Parse value + if (!parseVariant(*variant, memberFilter, nestingLimit.decrement())) return false; + } else { + if (!skipVariant(nestingLimit.decrement())) return false; + } + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // More keys/values? + if (eat('}')) return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } + + // Skip spaces + if (!skipSpacesAndComments()) return false; + } + } + + bool skipObject(NestingLimit nestingLimit) + { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + // Skip opening brace + ARDUINOJSON_ASSERT(current() == '{'); + move(); + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // Empty object? + if (eat('}')) return true; + + // Read each key value pair + for (;;) { + // Skip key + if (!skipVariant(nestingLimit.decrement())) return false; + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // Colon + if (!eat(':')) { + _error = DeserializationError::InvalidInput; + return false; + } + + // Skip value + if (!skipVariant(nestingLimit.decrement())) return false; + + // Skip spaces + if (!skipSpacesAndComments()) return false; + + // More keys/values? + if (eat('}')) return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } + } + } + + bool parseKey() + { + _stringStorage.startString(); + if (isQuote(current())) { + return parseQuotedString(); + } else { + return parseNonQuotedString(); + } + } + + bool parseStringValue(VariantData& variant) + { + _stringStorage.startString(); + if (!parseQuotedString()) return false; + const char* value = _stringStorage.save(); + variant.setStringPointer(value, typename TStringStorage::storage_policy()); + return true; + } + + bool parseQuotedString() + { +#if ARDUINOJSON_DECODE_UNICODE + Utf16::Codepoint codepoint; +#endif + const char stopChar = current(); + + move(); + for (;;) { + char c = current(); + move(); + if (c == stopChar) break; + + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } + + if (c == '\\') { + c = current(); + + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } + + if (c == 'u') { +#if ARDUINOJSON_DECODE_UNICODE + move(); + uint16_t codeunit; + if (!parseHex4(codeunit)) return false; + if (codepoint.append(codeunit)) Utf8::encodeCodepoint(codepoint.value(), _stringStorage); + continue; +#else + _error = DeserializationError::NotSupported; + return false; +#endif + } + + // replace char + c = EscapeSequence::unescapeChar(c); + if (c == '\0') { + _error = DeserializationError::InvalidInput; + return false; + } + move(); + } + + _stringStorage.append(c); + } + + _stringStorage.append('\0'); + + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; + } + + bool parseNonQuotedString() + { + char c = current(); + ARDUINOJSON_ASSERT(c); + + if (canBeInNonQuotedString(c)) { // no quotes + do { + move(); + _stringStorage.append(c); + c = current(); + } while (canBeInNonQuotedString(c)); + } else { + _error = DeserializationError::InvalidInput; + return false; + } + + _stringStorage.append('\0'); + + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; + } + + bool skipString() + { + const char stopChar = current(); + + move(); + for (;;) { + char c = current(); + move(); + if (c == stopChar) break; + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } + if (c == '\\') { + if (current() != '\0') move(); + } + } + + return true; + } + + bool parseNumericValue(VariantData& result) + { + uint8_t n = 0; + + char c = current(); + while (canBeInNonQuotedString(c) && n < 63) { + move(); + _buffer[n++] = c; + c = current(); + } + _buffer[n] = 0; + + c = _buffer[0]; + if (c == 't') { // true + result.setBoolean(true); + if (n != 4) { + _error = DeserializationError::IncompleteInput; + return false; + } + return true; + } + if (c == 'f') { // false + result.setBoolean(false); + if (n != 5) { + _error = DeserializationError::IncompleteInput; + return false; + } + return true; + } + if (c == 'n') { // null + // the variant is already null + if (n != 4) { + _error = DeserializationError::IncompleteInput; + return false; + } + return true; + } + + if (!parseNumber(_buffer, result)) { + _error = DeserializationError::InvalidInput; + return false; + } + + return true; + } + + bool skipNumericValue() + { + char c = current(); + while (canBeInNonQuotedString(c)) { + move(); + c = current(); + } + return true; + } + + bool parseHex4(uint16_t& result) + { + result = 0; + for (uint8_t i = 0; i < 4; ++i) { + char digit = current(); + if (!digit) { + _error = DeserializationError::IncompleteInput; + return false; + } + uint8_t value = decodeHex(digit); + if (value > 0x0F) { + _error = DeserializationError::InvalidInput; + return false; + } + result = uint16_t((result << 4) | value); + move(); + } + return true; + } + + static inline bool isBetween(char c, char min, char max) { return min <= c && c <= max; } + + static inline bool canBeInNonQuotedString(char c) + { + return isBetween(c, '0', '9') || isBetween(c, '_', 'z') || isBetween(c, 'A', 'Z') || c == '+' || c == '-' || + c == '.'; + } + + static inline bool isQuote(char c) { return c == '\'' || c == '\"'; } + + static inline uint8_t decodeHex(char c) + { + if (c < 'A') return uint8_t(c - '0'); + c = char(c & ~0x20); // uppercase + return uint8_t(c - 'A' + 10); + } + + bool skipSpacesAndComments() + { + for (;;) { + switch (current()) { + // end of string + case '\0': + _error = _foundSomething ? DeserializationError::IncompleteInput : DeserializationError::EmptyInput; + return false; + + // spaces + case ' ': + case '\t': + case '\r': + case '\n': move(); continue; + +#if ARDUINOJSON_ENABLE_COMMENTS + // comments + case '/': + move(); // skip '/' + switch (current()) { + // block comment + case '*': { + move(); // skip '*' + bool wasStar = false; + for (;;) { + char c = current(); + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } + if (c == '/' && wasStar) { + move(); + break; + } + wasStar = c == '*'; + move(); + } + break; + } + + // trailing comment + case '/': + // no need to skip "//" + for (;;) { + move(); + char c = current(); + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } + if (c == '\n') break; + } + break; + + // not a comment, just a '/' + default: _error = DeserializationError::InvalidInput; return false; + } + break; +#endif + + default: _foundSomething = true; return true; + } + } + } + + TStringStorage _stringStorage; + bool _foundSomething; + Latch<TReader> _latch; + MemoryPool* _pool; + char _buffer[64]; // using a member instead of a local variable because it + // ended in the recursive path after compiler inlined the + // code + DeserializationError _error; + }; + + // + // deserializeJson(JsonDocument&, const std::string&, ...) + // + // ... = NestingLimit + template<typename TString> + DeserializationError + deserializeJson(JsonDocument& doc, const TString& input, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TString> + DeserializationError + deserializeJson(JsonDocument& doc, const TString& input, Filter filter, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TString> + DeserializationError + deserializeJson(JsonDocument& doc, const TString& input, NestingLimit nestingLimit, Filter filter) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); + } + + // + // deserializeJson(JsonDocument&, std::istream&, ...) + // + // ... = NestingLimit + template<typename TStream> + DeserializationError deserializeJson(JsonDocument& doc, TStream& input, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TStream> + DeserializationError + deserializeJson(JsonDocument& doc, TStream& input, Filter filter, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TStream> + DeserializationError deserializeJson(JsonDocument& doc, TStream& input, NestingLimit nestingLimit, Filter filter) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); + } + + // + // deserializeJson(JsonDocument&, char*, ...) + // + // ... = NestingLimit + template<typename TChar> + DeserializationError deserializeJson(JsonDocument& doc, TChar* input, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TChar> + DeserializationError + deserializeJson(JsonDocument& doc, TChar* input, Filter filter, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TChar> + DeserializationError deserializeJson(JsonDocument& doc, TChar* input, NestingLimit nestingLimit, Filter filter) + { + return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); + } + + // + // deserializeJson(JsonDocument&, char*, size_t, ...) + // + // ... = NestingLimit + template<typename TChar> + DeserializationError + deserializeJson(JsonDocument& doc, TChar* input, size_t inputSize, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TChar> + DeserializationError deserializeJson( + JsonDocument& doc, + TChar* input, + size_t inputSize, + Filter filter, + NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TChar> + DeserializationError + deserializeJson(JsonDocument& doc, TChar* input, size_t inputSize, NestingLimit nestingLimit, Filter filter) + { + return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, filter); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonSerializer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonSerializer.hpp new file mode 100644 index 000000000..b71e9fbb3 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/JsonSerializer.hpp @@ -0,0 +1,139 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Json/TextFormatter.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Serialization/measure.hpp> +#include <ArduinoJson/Serialization/serialize.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TWriter> + class JsonSerializer : public Visitor<size_t> { + public: + JsonSerializer(TWriter writer) : _formatter(writer) {} + + FORCE_INLINE size_t visitArray(const CollectionData& array) + { + write('['); + + VariantSlot* slot = array.head(); + + while (slot != 0) { + slot->data()->accept(*this); + + slot = slot->next(); + if (slot == 0) break; + + write(','); + } + + write(']'); + return bytesWritten(); + } + + size_t visitObject(const CollectionData& object) + { + write('{'); + + VariantSlot* slot = object.head(); + + while (slot != 0) { + _formatter.writeString(slot->key()); + write(':'); + slot->data()->accept(*this); + + slot = slot->next(); + if (slot == 0) break; + + write(','); + } + + write('}'); + return bytesWritten(); + } + + size_t visitFloat(Float value) + { + _formatter.writeFloat(value); + return bytesWritten(); + } + + size_t visitString(const char* value) + { + _formatter.writeString(value); + return bytesWritten(); + } + + size_t visitRawJson(const char* data, size_t n) + { + _formatter.writeRaw(data, n); + return bytesWritten(); + } + + size_t visitNegativeInteger(UInt value) + { + _formatter.writeNegativeInteger(value); + return bytesWritten(); + } + + size_t visitPositiveInteger(UInt value) + { + _formatter.writePositiveInteger(value); + return bytesWritten(); + } + + size_t visitBoolean(bool value) + { + _formatter.writeBoolean(value); + return bytesWritten(); + } + + size_t visitNull() + { + _formatter.writeRaw("null"); + return bytesWritten(); + } + + protected: + size_t bytesWritten() const { return _formatter.bytesWritten(); } + + void write(char c) { _formatter.writeRaw(c); } + + void write(const char* s) { _formatter.writeRaw(s); } + + private: + TextFormatter<TWriter> _formatter; + }; + + template<typename TSource, typename TDestination> + size_t serializeJson(const TSource& source, TDestination& destination) + { + return serialize<JsonSerializer>(source, destination); + } + + template<typename TSource> + size_t serializeJson(const TSource& source, void* buffer, size_t bufferSize) + { + return serialize<JsonSerializer>(source, buffer, bufferSize); + } + + template<typename TSource> + size_t measureJson(const TSource& source) + { + return measure<JsonSerializer>(source); + } + +#if ARDUINOJSON_ENABLE_STD_STREAM + template<typename T> + inline typename enable_if<IsVisitable<T>::value, std::ostream&>::type operator<<(std::ostream& os, const T& source) + { + serializeJson(source, os); + return os; + } +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Latch.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Latch.hpp new file mode 100644 index 000000000..7d4f8b2c7 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Latch.hpp @@ -0,0 +1,53 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/assert.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TReader> + class Latch { + public: + Latch(TReader reader) : _reader(reader), _loaded(false) + { +#if ARDUINOJSON_DEBUG + _ended = false; +#endif + } + + void clear() { _loaded = false; } + + int last() const { return _current; } + + FORCE_INLINE char current() + { + if (!_loaded) { + load(); + } + return _current; + } + + private: + void load() + { + ARDUINOJSON_ASSERT(!_ended); + int c = _reader.read(); +#if ARDUINOJSON_DEBUG + if (c <= 0) _ended = true; +#endif + _current = static_cast<char>(c > 0 ? c : 0); + _loaded = true; + } + + TReader _reader; + char _current; + bool _loaded; +#if ARDUINOJSON_DEBUG + bool _ended; +#endif + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/PrettyJsonSerializer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/PrettyJsonSerializer.hpp new file mode 100644 index 000000000..fdbfbc5f4 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/PrettyJsonSerializer.hpp @@ -0,0 +1,95 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Json/JsonSerializer.hpp> +#include <ArduinoJson/Serialization/measure.hpp> +#include <ArduinoJson/Serialization/serialize.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TWriter> + class PrettyJsonSerializer : public JsonSerializer<TWriter> { + typedef JsonSerializer<TWriter> base; + + public: + PrettyJsonSerializer(TWriter& writer) : base(writer), _nesting(0) {} + + size_t visitArray(const CollectionData& array) + { + VariantSlot* slot = array.head(); + if (slot) { + base::write("[\r\n"); + _nesting++; + while (slot != 0) { + indent(); + slot->data()->accept(*this); + + slot = slot->next(); + base::write(slot ? ",\r\n" : "\r\n"); + } + _nesting--; + indent(); + base::write("]"); + } else { + base::write("[]"); + } + return this->bytesWritten(); + } + + size_t visitObject(const CollectionData& object) + { + VariantSlot* slot = object.head(); + if (slot) { + base::write("{\r\n"); + _nesting++; + while (slot != 0) { + indent(); + base::visitString(slot->key()); + base::write(": "); + slot->data()->accept(*this); + + slot = slot->next(); + base::write(slot ? ",\r\n" : "\r\n"); + } + _nesting--; + indent(); + base::write("}"); + } else { + base::write("{}"); + } + return this->bytesWritten(); + } + + private: + void indent() + { + for (uint8_t i = 0; i < _nesting; i++) + base::write(ARDUINOJSON_TAB); + } + + uint8_t _nesting; + }; + + template<typename TSource, typename TDestination> + size_t serializeJsonPretty(const TSource& source, TDestination& destination) + { + return serialize<PrettyJsonSerializer>(source, destination); + } + + template<typename TSource> + size_t serializeJsonPretty(const TSource& source, void* buffer, size_t bufferSize) + { + return serialize<PrettyJsonSerializer>(source, buffer, bufferSize); + } + + template<typename TSource> + size_t measureJsonPretty(const TSource& source) + { + return measure<PrettyJsonSerializer>(source); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/TextFormatter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/TextFormatter.hpp new file mode 100644 index 000000000..bb0acc316 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/TextFormatter.hpp @@ -0,0 +1,156 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stdint.h> +#include <string.h> // for strlen + +#include <ArduinoJson/Json/EscapeSequence.hpp> +#include <ArduinoJson/Numbers/FloatParts.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Serialization/CountingDecorator.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TWriter> + class TextFormatter { + public: + explicit TextFormatter(TWriter writer) : _writer(writer) {} + + // Returns the number of bytes sent to the TWriter implementation. + size_t bytesWritten() const { return _writer.count(); } + + void writeBoolean(bool value) + { + if (value) + writeRaw("true"); + else + writeRaw("false"); + } + + void writeString(const char* value) + { + ARDUINOJSON_ASSERT(value != NULL); + writeRaw('\"'); + while (*value) + writeChar(*value++); + writeRaw('\"'); + } + + void writeChar(char c) + { + char specialChar = EscapeSequence::escapeChar(c); + if (specialChar) { + writeRaw('\\'); + writeRaw(specialChar); + } else { + writeRaw(c); + } + } + + template<typename T> + void writeFloat(T value) + { + if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null"); + +#if ARDUINOJSON_ENABLE_INFINITY + if (value < 0.0) { + writeRaw('-'); + value = -value; + } + + if (isinf(value)) return writeRaw("Infinity"); +#else + if (isinf(value)) return writeRaw("null"); + + if (value < 0.0) { + writeRaw('-'); + value = -value; + } +#endif + + FloatParts<T> parts(value); + + writePositiveInteger(parts.integral); + if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces); + + if (parts.exponent < 0) { + writeRaw("e-"); + writePositiveInteger(-parts.exponent); + } + + if (parts.exponent > 0) { + writeRaw('e'); + writePositiveInteger(parts.exponent); + } + } + + void writeNegativeInteger(UInt value) + { + writeRaw('-'); + writePositiveInteger(value); + } + + template<typename T> + void writePositiveInteger(T value) + { + char buffer[22]; + char* end = buffer + sizeof(buffer); + char* begin = end; + + // write the string in reverse order + do { + *--begin = char(value % 10 + '0'); + value = T(value / 10); + } while (value); + + // and dump it in the right order + writeRaw(begin, end); + } + + void writeDecimals(uint32_t value, int8_t width) + { + // buffer should be big enough for all digits and the dot + char buffer[16]; + char* end = buffer + sizeof(buffer); + char* begin = end; + + // write the string in reverse order + while (width--) { + *--begin = char(value % 10 + '0'); + value /= 10; + } + *--begin = '.'; + + // and dump it in the right order + writeRaw(begin, end); + } + + void writeRaw(const char* s) { _writer.write(reinterpret_cast<const uint8_t*>(s), strlen(s)); } + + void writeRaw(const char* s, size_t n) { _writer.write(reinterpret_cast<const uint8_t*>(s), n); } + + void writeRaw(const char* begin, const char* end) + { + _writer.write(reinterpret_cast<const uint8_t*>(begin), static_cast<size_t>(end - begin)); + } + + template<size_t N> + void writeRaw(const char (&s)[N]) + { + _writer.write(reinterpret_cast<const uint8_t*>(s), N - 1); + } + void writeRaw(char c) { _writer.write(static_cast<uint8_t>(c)); } + + protected: + CountingDecorator<TWriter> _writer; + size_t _length; + + private: + TextFormatter& operator=(const TextFormatter&); // cannot be assigned + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf16.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf16.hpp new file mode 100644 index 000000000..717f1e7fb --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf16.hpp @@ -0,0 +1,61 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stdint.h> // uint16_t, uint32_t + +// The high surrogate may be uninitialized if the pair is invalid, +// we choose to ignore the problem to reduce the size of the code +// Garbage in => Garbage out +#if defined(__GNUC__) +#if __GNUC__ >= 7 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +#endif + +namespace ARDUINOJSON_NAMESPACE { + + namespace Utf16 { + inline bool isHighSurrogate(uint16_t codeunit) { return codeunit >= 0xD800 && codeunit < 0xDC00; } + + inline bool isLowSurrogate(uint16_t codeunit) { return codeunit >= 0xDC00 && codeunit < 0xE000; } + + class Codepoint { + public: + Codepoint() : _highSurrogate(0) {} + + bool append(uint16_t codeunit) + { + if (isHighSurrogate(codeunit)) { + _highSurrogate = codeunit & 0x3FF; + return false; + } + + if (isLowSurrogate(codeunit)) { + _codepoint = uint32_t(0x10000 + ((_highSurrogate << 10) | (codeunit & 0x3FF))); + return true; + } + + _codepoint = codeunit; + return true; + } + + uint32_t value() const { return _codepoint; } + + private: + uint16_t _highSurrogate; + uint32_t _codepoint; + }; + } // namespace Utf16 +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__GNUC__) +#if __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf8.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf8.hpp new file mode 100644 index 000000000..819128564 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Json/Utf8.hpp @@ -0,0 +1,47 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + namespace Utf8 { + template<typename TStringBuilder> + inline void encodeCodepoint(uint32_t codepoint32, TStringBuilder& str) + { + // this function was optimize for code size on AVR + + // a buffer to store the string in reverse + char buf[5]; + char* p = buf; + + *(p++) = 0; + if (codepoint32 < 0x80) { + *(p++) = char((codepoint32)); + } else { + *(p++) = char((codepoint32 | 0x80) & 0xBF); + uint16_t codepoint16 = uint16_t(codepoint32 >> 6); + if (codepoint16 < 0x20) { // 0x800 + *(p++) = char(codepoint16 | 0xC0); + } else { + *(p++) = char((codepoint16 | 0x80) & 0xBF); + codepoint16 = uint16_t(codepoint16 >> 6); + if (codepoint16 < 0x10) { // 0x10000 + *(p++) = char(codepoint16 | 0xE0); + } else { + *(p++) = char((codepoint16 | 0x80) & 0xBF); + codepoint16 = uint16_t(codepoint16 >> 6); + *(p++) = char(codepoint16 | 0xF0); + } + } + } + + while (*(--p)) { + str.append(*p); + } + } + } // namespace Utf8 +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/Alignment.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/Alignment.hpp new file mode 100644 index 000000000..ed2df09cf --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/Alignment.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stddef.h> // size_t + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_ENABLE_ALIGNMENT + + inline bool isAligned(size_t value) + { + const size_t mask = sizeof(void*) - 1; + size_t addr = value; + return (addr & mask) == 0; + } + + inline size_t addPadding(size_t bytes) + { + const size_t mask = sizeof(void*) - 1; + return (bytes + mask) & ~mask; + } + + template<size_t bytes> + struct AddPadding { + static const size_t mask = sizeof(void*) - 1; + static const size_t value = (bytes + mask) & ~mask; + }; + +#else + + inline bool isAligned(size_t) { return true; } + + inline size_t addPadding(size_t bytes) { return bytes; } + + template<size_t bytes> + struct AddPadding { + static const size_t value = bytes; + }; + +#endif + + template<typename T> + inline bool isAligned(T* ptr) + { + return isAligned(reinterpret_cast<size_t>(ptr)); + } + + template<typename T> + inline T* addPadding(T* p) + { + size_t address = addPadding(reinterpret_cast<size_t>(p)); + return reinterpret_cast<T*>(address); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/MemoryPool.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/MemoryPool.hpp new file mode 100644 index 000000000..55fa54b2a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Memory/MemoryPool.hpp @@ -0,0 +1,198 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/Alignment.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/mpl/max.hpp> +#include <ArduinoJson/Variant/VariantSlot.hpp> + +#include <string.h> // memmove + +#define JSON_STRING_SIZE(SIZE) (SIZE + 1) + +namespace ARDUINOJSON_NAMESPACE { + + // _begin _end + // v v + // +-------------+--------------+--------------+ + // | strings... | (free) | ...variants | + // +-------------+--------------+--------------+ + // ^ ^ + // _left _right + + class MemoryPool { + public: + MemoryPool(char* buf, size_t capa) : + _begin(buf), _left(buf), _right(buf ? buf + capa : 0), _end(buf ? buf + capa : 0), _overflowed(false) + { + ARDUINOJSON_ASSERT(isAligned(_begin)); + ARDUINOJSON_ASSERT(isAligned(_right)); + ARDUINOJSON_ASSERT(isAligned(_end)); + } + + void* buffer() { return _begin; } + + // Gets the capacity of the memoryPool in bytes + size_t capacity() const { return size_t(_end - _begin); } + + size_t size() const { return size_t(_left - _begin + _end - _right); } + + bool overflowed() const { return _overflowed; } + + VariantSlot* allocVariant() { return allocRight<VariantSlot>(); } + + template<typename TAdaptedString> + const char* saveString(const TAdaptedString& str) + { + if (str.isNull()) return 0; + +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + const char* existingCopy = findString(str.begin()); + if (existingCopy) return existingCopy; +#endif + + size_t n = str.size(); + + char* newCopy = allocString(n + 1); + if (newCopy) { + str.copyTo(newCopy, n); + newCopy[n] = 0; // force null-terminator + } + return newCopy; + } + + void getFreeZone(char** zoneStart, size_t* zoneSize) const + { + *zoneStart = _left; + *zoneSize = size_t(_right - _left); + } + + const char* saveStringFromFreeZone(size_t len) + { +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + const char* dup = findString(_left); + if (dup) return dup; +#endif + + const char* str = _left; + _left += len; + checkInvariants(); + return str; + } + + void markAsOverflowed() { _overflowed = true; } + + void clear() + { + _left = _begin; + _right = _end; + _overflowed = false; + } + + bool canAlloc(size_t bytes) const { return _left + bytes <= _right; } + + bool owns(void* p) const { return _begin <= p && p < _end; } + + // Workaround for missing placement new + void* operator new(size_t, void* p) { return p; } + + // Squash the free space between strings and variants + // + // _begin _end + // v v + // +-------------+--------------+ + // | strings... | ...variants | + // +-------------+--------------+ + // ^ + // _left _right + // + // This funcion is called before a realloc. + ptrdiff_t squash() + { + char* new_right = addPadding(_left); + if (new_right >= _right) return 0; + + size_t right_size = static_cast<size_t>(_end - _right); + memmove(new_right, _right, right_size); + + ptrdiff_t bytes_reclaimed = _right - new_right; + _right = new_right; + _end = new_right + right_size; + return bytes_reclaimed; + } + + // Move all pointers together + // This funcion is called after a realloc. + void movePointers(ptrdiff_t offset) + { + _begin += offset; + _left += offset; + _right += offset; + _end += offset; + } + + private: + void checkInvariants() + { + ARDUINOJSON_ASSERT(_begin <= _left); + ARDUINOJSON_ASSERT(_left <= _right); + ARDUINOJSON_ASSERT(_right <= _end); + ARDUINOJSON_ASSERT(isAligned(_right)); + } + +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + template<typename TIterator> + const char* findString(TIterator str) + { + for (char* next = _begin; next < _left; ++next) { + char* begin = next; + + // try to match + for (TIterator it = str; *it == *next; ++it) { + if (*next++ == 0) return begin; + } + + // jump to next terminator + while (*next) + ++next; + } + return 0; + } +#endif + + char* allocString(size_t n) + { + if (!canAlloc(n)) { + _overflowed = true; + return 0; + } + char* s = _left; + _left += n; + checkInvariants(); + return s; + } + + template<typename T> + T* allocRight() + { + return reinterpret_cast<T*>(allocRight(sizeof(T))); + } + + void* allocRight(size_t bytes) + { + if (!canAlloc(bytes)) { + _overflowed = true; + return 0; + } + _right -= bytes; + return _right; + } + + char *_begin, *_left, *_right, *_end; + bool _overflowed; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/SerializedValue.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/SerializedValue.hpp new file mode 100644 index 000000000..67b52150f --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/SerializedValue.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/StringAdapters.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // A special type of data that can be used to insert pregenerated JSON portions. + template<typename T> + class SerializedValue { + public: + explicit SerializedValue(T str) : _str(str) {} + operator T() const { return _str; } + + const char* data() const { return _str.c_str(); } + + size_t size() const + { + // CAUTION: the old Arduino String doesn't have size() + return _str.length(); + } + + private: + T _str; + }; + + template<typename TChar> + class SerializedValue<TChar*> { + public: + explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {} + operator TChar*() const { return _data; } + + TChar* data() const { return _data; } + + size_t size() const { return _size; } + + private: + TChar* _data; + size_t _size; + }; + + template<typename T> + inline SerializedValue<T> serialized(T str) + { + return SerializedValue<T>(str); + } + + template<typename TChar> + inline SerializedValue<TChar*> serialized(TChar* p) + { + return SerializedValue<TChar*>(p, adaptString(p).size()); + } + + template<typename TChar> + inline SerializedValue<TChar*> serialized(TChar* p, size_t n) + { + return SerializedValue<TChar*>(p, n); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/Visitable.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/Visitable.hpp new file mode 100644 index 000000000..e1794bf06 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Misc/Visitable.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TResult> + struct Visitor { + typedef TResult result_type; + }; + + struct Visitable { + // template<Visitor> + // void accept(Visitor&) const; + }; + + template<typename T> + struct IsVisitable : is_base_of<Visitable, T> { + }; + + template<typename T> + struct IsVisitable<T&> : IsVisitable<T> { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackDeserializer.hpp new file mode 100644 index 000000000..df89cf451 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -0,0 +1,607 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/deserialize.hpp> +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/MsgPack/endianess.hpp> +#include <ArduinoJson/MsgPack/ieee754.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TReader, typename TStringStorage> + class MsgPackDeserializer { + public: + MsgPackDeserializer(MemoryPool& pool, TReader reader, TStringStorage stringStorage) : + _pool(&pool), _reader(reader), _stringStorage(stringStorage), _error(DeserializationError::Ok), + _foundSomething(false) + {} + + template<typename TFilter> + DeserializationError parse(VariantData& variant, TFilter filter, NestingLimit nestingLimit) + { + parseVariant(variant, filter, nestingLimit); + return _foundSomething ? _error : DeserializationError::EmptyInput; + } + + private: + // Prevent VS warning "assignment operator could not be generated" + MsgPackDeserializer& operator=(const MsgPackDeserializer&); + + bool invalidInput() + { + _error = DeserializationError::InvalidInput; + return false; + } + + bool notSupported() + { + _error = DeserializationError::NotSupported; + return false; + } + + template<typename TFilter> + bool parseVariant(VariantData& variant, TFilter filter, NestingLimit nestingLimit) + { + uint8_t code = 0; // TODO: why do we need to initialize this variable? + if (!readByte(code)) return false; + + _foundSomething = true; + + bool allowValue = filter.allowValue(); + + switch (code) { + case 0xc0: + // already null + return true; + + case 0xc1: return invalidInput(); + + case 0xc2: + if (allowValue) variant.setBoolean(false); + return true; + + case 0xc3: + if (allowValue) variant.setBoolean(true); + return true; + + case 0xc4: // bin 8 + if (allowValue) + return notSupported(); + else + return skipString<uint8_t>(); + + case 0xc5: // bin 16 + if (allowValue) + return notSupported(); + else + return skipString<uint16_t>(); + + case 0xc6: // bin 32 + if (allowValue) + return notSupported(); + else + return skipString<uint32_t>(); + + case 0xc7: // ext 8 + if (allowValue) + return notSupported(); + else + return skipExt<uint8_t>(); + + case 0xc8: // ext 16 + if (allowValue) + return notSupported(); + else + return skipExt<uint16_t>(); + + case 0xc9: // ext 32 + if (allowValue) + return notSupported(); + else + return skipExt<uint32_t>(); + + case 0xca: + if (allowValue) + return readFloat<float>(variant); + else + return skipBytes(4); + + case 0xcb: + if (allowValue) + return readDouble<double>(variant); + else + return skipBytes(8); + + case 0xcc: + if (allowValue) + return readInteger<uint8_t>(variant); + else + return skipBytes(1); + + case 0xcd: + if (allowValue) + return readInteger<uint16_t>(variant); + else + return skipBytes(2); + + case 0xce: + if (allowValue) + return readInteger<uint32_t>(variant); + else + return skipBytes(4); + + case 0xcf: + if (allowValue) +#if ARDUINOJSON_USE_LONG_LONG + return readInteger<uint64_t>(variant); +#else + return notSupported(); +#endif + else + return skipBytes(8); + + case 0xd0: + if (allowValue) + return readInteger<int8_t>(variant); + else + return skipBytes(1); + + case 0xd1: + if (allowValue) + return readInteger<int16_t>(variant); + else + return skipBytes(2); + + case 0xd2: + if (allowValue) + return readInteger<int32_t>(variant); + else + return skipBytes(4); + + case 0xd3: + if (allowValue) +#if ARDUINOJSON_USE_LONG_LONG + return readInteger<int64_t>(variant); +#else + return notSupported(); +#endif + else + return skipBytes(8); + + case 0xd4: // fixext 1 + if (allowValue) + return notSupported(); + else + return skipBytes(2); + + case 0xd5: // fixext 2 + if (allowValue) + return notSupported(); + else + return skipBytes(3); + + case 0xd6: // fixext 4 + if (allowValue) + return notSupported(); + else + return skipBytes(5); + + case 0xd7: // fixext 8 + if (allowValue) + return notSupported(); + else + return skipBytes(9); + + case 0xd8: // fixext 16 + if (allowValue) + return notSupported(); + else + return skipBytes(17); + + case 0xd9: + if (allowValue) + return readString<uint8_t>(variant); + else + return skipString<uint8_t>(); + + case 0xda: + if (allowValue) + return readString<uint16_t>(variant); + else + return skipString<uint16_t>(); + + case 0xdb: + if (allowValue) + return readString<uint32_t>(variant); + else + return skipString<uint32_t>(); + + case 0xdc: return readArray<uint16_t>(variant, filter, nestingLimit); + + case 0xdd: return readArray<uint32_t>(variant, filter, nestingLimit); + + case 0xde: return readObject<uint16_t>(variant, filter, nestingLimit); + + case 0xdf: return readObject<uint32_t>(variant, filter, nestingLimit); + } + + switch (code & 0xf0) { + case 0x80: return readObject(variant, code & 0x0F, filter, nestingLimit); + + case 0x90: return readArray(variant, code & 0x0F, filter, nestingLimit); + } + + if ((code & 0xe0) == 0xa0) { + if (allowValue) + return readString(variant, code & 0x1f); + else + return skipBytes(code & 0x1f); + } + + if (allowValue) variant.setInteger(static_cast<int8_t>(code)); + + return true; + } + + bool readByte(uint8_t& value) + { + int c = _reader.read(); + if (c < 0) { + _error = DeserializationError::IncompleteInput; + return false; + } + value = static_cast<uint8_t>(c); + return true; + } + + bool readBytes(uint8_t* p, size_t n) + { + if (_reader.readBytes(reinterpret_cast<char*>(p), n) == n) return true; + _error = DeserializationError::IncompleteInput; + return false; + } + + template<typename T> + bool readBytes(T& value) + { + return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); + } + + bool skipBytes(size_t n) + { + for (; n; --n) { + if (_reader.read() < 0) { + _error = DeserializationError::IncompleteInput; + return false; + } + } + return true; + } + + template<typename T> + bool readInteger(T& value) + { + if (!readBytes(value)) return false; + fixEndianess(value); + return true; + } + + template<typename T> + bool readInteger(VariantData& variant) + { + T value; + if (!readInteger(value)) return false; + variant.setInteger(value); + return true; + } + + template<typename T> + typename enable_if<sizeof(T) == 4, bool>::type readFloat(VariantData& variant) + { + T value; + if (!readBytes(value)) return false; + fixEndianess(value); + variant.setFloat(value); + return true; + } + + template<typename T> + typename enable_if<sizeof(T) == 8, bool>::type readDouble(VariantData& variant) + { + T value; + if (!readBytes(value)) return false; + fixEndianess(value); + variant.setFloat(value); + return true; + } + + template<typename T> + typename enable_if<sizeof(T) == 4, bool>::type readDouble(VariantData& variant) + { + uint8_t i[8]; // input is 8 bytes + T value; // output is 4 bytes + uint8_t* o = reinterpret_cast<uint8_t*>(&value); + if (!readBytes(i, 8)) return false; + doubleToFloat(i, o); + fixEndianess(value); + variant.setFloat(value); + return true; + } + + template<typename T> + bool readString(VariantData& variant) + { + T size; + if (!readInteger(size)) return false; + return readString(variant, size); + } + + template<typename T> + bool readString() + { + T size; + if (!readInteger(size)) return false; + return readString(size); + } + + template<typename T> + bool skipString() + { + T size; + if (!readInteger(size)) return false; + return skipBytes(size); + } + + bool readString(VariantData& variant, size_t n) + { + if (!readString(n)) return false; + variant.setStringPointer(_stringStorage.save(), typename TStringStorage::storage_policy()); + return true; + } + + bool readString(size_t n) + { + _stringStorage.startString(); + for (; n; --n) { + uint8_t c; + if (!readBytes(c)) return false; + _stringStorage.append(static_cast<char>(c)); + } + _stringStorage.append('\0'); + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; + } + + template<typename TSize, typename TFilter> + bool readArray(VariantData& variant, TFilter filter, NestingLimit nestingLimit) + { + TSize size; + if (!readInteger(size)) return false; + return readArray(variant, size, filter, nestingLimit); + } + + template<typename TFilter> + bool readArray(VariantData& variant, size_t n, TFilter filter, NestingLimit nestingLimit) + { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + bool allowArray = filter.allowArray(); + + CollectionData* array = allowArray ? &variant.toArray() : 0; + + TFilter memberFilter = filter[0U]; + + for (; n; --n) { + VariantData* value; + + if (memberFilter.allow()) { + value = array->addElement(_pool); + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } + } else { + value = 0; + } + + if (!parseVariant(*value, memberFilter, nestingLimit.decrement())) return false; + } + + return true; + } + + template<typename TSize, typename TFilter> + bool readObject(VariantData& variant, TFilter filter, NestingLimit nestingLimit) + { + TSize size; + if (!readInteger(size)) return false; + return readObject(variant, size, filter, nestingLimit); + } + + template<typename TFilter> + bool readObject(VariantData& variant, size_t n, TFilter filter, NestingLimit nestingLimit) + { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + CollectionData* object = filter.allowObject() ? &variant.toObject() : 0; + + for (; n; --n) { + if (!readKey()) return false; + + const char* key = _stringStorage.c_str(); + TFilter memberFilter = filter[key]; + VariantData* member; + + if (memberFilter.allow()) { + // Save key in memory pool. + // This MUST be done before adding the slot. + key = _stringStorage.save(); + + VariantSlot* slot = object->addSlot(_pool); + if (!slot) { + _error = DeserializationError::NoMemory; + return false; + } + + slot->setKey(key, typename TStringStorage::storage_policy()); + + member = slot->data(); + } else { + member = 0; + } + + if (!parseVariant(*member, memberFilter, nestingLimit.decrement())) return false; + } + + return true; + } + + bool readKey() + { + uint8_t code; + if (!readByte(code)) return false; + + if ((code & 0xe0) == 0xa0) return readString(code & 0x1f); + + switch (code) { + case 0xd9: return readString<uint8_t>(); + + case 0xda: return readString<uint16_t>(); + + case 0xdb: return readString<uint32_t>(); + + default: return notSupported(); + } + } + + template<typename T> + bool skipExt() + { + T size; + if (!readInteger(size)) return false; + return skipBytes(size + 1); + } + + MemoryPool* _pool; + TReader _reader; + TStringStorage _stringStorage; + DeserializationError _error; + bool _foundSomething; + }; + + // + // deserializeMsgPack(JsonDocument&, const std::string&, ...) + // + // ... = NestingLimit + template<typename TString> + DeserializationError + deserializeMsgPack(JsonDocument& doc, const TString& input, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TString> + DeserializationError + deserializeMsgPack(JsonDocument& doc, const TString& input, Filter filter, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TString> + DeserializationError + deserializeMsgPack(JsonDocument& doc, const TString& input, NestingLimit nestingLimit, Filter filter) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); + } + + // + // deserializeMsgPack(JsonDocument&, std::istream&, ...) + // + // ... = NestingLimit + template<typename TStream> + DeserializationError deserializeMsgPack(JsonDocument& doc, TStream& input, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TStream> + DeserializationError + deserializeMsgPack(JsonDocument& doc, TStream& input, Filter filter, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TStream> + DeserializationError deserializeMsgPack(JsonDocument& doc, TStream& input, NestingLimit nestingLimit, Filter filter) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); + } + + // + // deserializeMsgPack(JsonDocument&, char*, ...) + // + // ... = NestingLimit + template<typename TChar> + DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TChar> + DeserializationError + deserializeMsgPack(JsonDocument& doc, TChar* input, Filter filter, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TChar> + DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input, NestingLimit nestingLimit, Filter filter) + { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); + } + + // + // deserializeMsgPack(JsonDocument&, char*, size_t, ...) + // + // ... = NestingLimit + template<typename TChar> + DeserializationError + deserializeMsgPack(JsonDocument& doc, TChar* input, size_t inputSize, NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, AllowAllFilter()); + } + // ... = Filter, NestingLimit + template<typename TChar> + DeserializationError deserializeMsgPack( + JsonDocument& doc, + TChar* input, + size_t inputSize, + Filter filter, + NestingLimit nestingLimit = NestingLimit()) + { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, filter); + } + // ... = NestingLimit, Filter + template<typename TChar> + DeserializationError + deserializeMsgPack(JsonDocument& doc, TChar* input, size_t inputSize, NestingLimit nestingLimit, Filter filter) + { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, filter); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackSerializer.hpp new file mode 100644 index 000000000..d37056c82 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -0,0 +1,210 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/MsgPack/endianess.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Serialization/CountingDecorator.hpp> +#include <ArduinoJson/Serialization/measure.hpp> +#include <ArduinoJson/Serialization/serialize.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TWriter> + class MsgPackSerializer : public Visitor<size_t> { + public: + MsgPackSerializer(TWriter writer) : _writer(writer) {} + + template<typename T> + typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) + { + writeByte(0xCA); + writeInteger(value32); + return bytesWritten(); + } + + template<typename T> + ARDUINOJSON_NO_SANITIZE("float-cast-overflow") + typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) + { + float value32 = float(value64); + if (value32 == value64) { + writeByte(0xCA); + writeInteger(value32); + } else { + writeByte(0xCB); + writeInteger(value64); + } + return bytesWritten(); + } + + size_t visitArray(const CollectionData& array) + { + size_t n = array.size(); + if (n < 0x10) { + writeByte(uint8_t(0x90 + array.size())); + } else if (n < 0x10000) { + writeByte(0xDC); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDD); + writeInteger(uint32_t(n)); + } + for (VariantSlot* slot = array.head(); slot; slot = slot->next()) { + slot->data()->accept(*this); + } + return bytesWritten(); + } + + size_t visitObject(const CollectionData& object) + { + size_t n = object.size(); + if (n < 0x10) { + writeByte(uint8_t(0x80 + n)); + } else if (n < 0x10000) { + writeByte(0xDE); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDF); + writeInteger(uint32_t(n)); + } + for (VariantSlot* slot = object.head(); slot; slot = slot->next()) { + visitString(slot->key()); + slot->data()->accept(*this); + } + return bytesWritten(); + } + + size_t visitString(const char* value) + { + ARDUINOJSON_ASSERT(value != NULL); + + size_t n = strlen(value); + + if (n < 0x20) { + writeByte(uint8_t(0xA0 + n)); + } else if (n < 0x100) { + writeByte(0xD9); + writeInteger(uint8_t(n)); + } else if (n < 0x10000) { + writeByte(0xDA); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDB); + writeInteger(uint32_t(n)); + } + writeBytes(reinterpret_cast<const uint8_t*>(value), n); + return bytesWritten(); + } + + size_t visitRawJson(const char* data, size_t size) + { + writeBytes(reinterpret_cast<const uint8_t*>(data), size); + return bytesWritten(); + } + + size_t visitNegativeInteger(UInt value) + { + UInt negated = UInt(~value + 1); + if (value <= 0x20) { + writeInteger(int8_t(negated)); + } else if (value <= 0x80) { + writeByte(0xD0); + writeInteger(int8_t(negated)); + } else if (value <= 0x8000) { + writeByte(0xD1); + writeInteger(int16_t(negated)); + } else if (value <= 0x80000000) { + writeByte(0xD2); + writeInteger(int32_t(negated)); + } +#if ARDUINOJSON_USE_LONG_LONG + else { + writeByte(0xD3); + writeInteger(int64_t(negated)); + } +#endif + return bytesWritten(); + } + + size_t visitPositiveInteger(UInt value) + { + if (value <= 0x7F) { + writeInteger(uint8_t(value)); + } else if (value <= 0xFF) { + writeByte(0xCC); + writeInteger(uint8_t(value)); + } else if (value <= 0xFFFF) { + writeByte(0xCD); + writeInteger(uint16_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else if (value <= 0xFFFFFFFF) +#else + else +#endif + { + writeByte(0xCE); + writeInteger(uint32_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else { + writeByte(0xCF); + writeInteger(uint64_t(value)); + } +#endif + return bytesWritten(); + } + + size_t visitBoolean(bool value) + { + writeByte(value ? 0xC3 : 0xC2); + return bytesWritten(); + } + + size_t visitNull() + { + writeByte(0xC0); + return bytesWritten(); + } + + private: + size_t bytesWritten() const { return _writer.count(); } + + void writeByte(uint8_t c) { _writer.write(c); } + + void writeBytes(const uint8_t* p, size_t n) { _writer.write(p, n); } + + template<typename T> + void writeInteger(T value) + { + fixEndianess(value); + writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); + } + + CountingDecorator<TWriter> _writer; + }; + + template<typename TSource, typename TDestination> + inline size_t serializeMsgPack(const TSource& source, TDestination& output) + { + return serialize<MsgPackSerializer>(source, output); + } + + template<typename TSource> + inline size_t serializeMsgPack(const TSource& source, void* output, size_t size) + { + return serialize<MsgPackSerializer>(source, output, size); + } + + template<typename TSource> + inline size_t measureMsgPack(const TSource& source) + { + return measure<MsgPackSerializer>(source); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/endianess.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/endianess.hpp new file mode 100644 index 000000000..4497ba55d --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/endianess.hpp @@ -0,0 +1,42 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Polyfills/utility.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_LITTLE_ENDIAN + inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) + { + swap(p[0], p[7]); + swap(p[1], p[6]); + swap(p[2], p[5]); + swap(p[3], p[4]); + } + + inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) + { + swap(p[0], p[3]); + swap(p[1], p[2]); + } + + inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) { swap(p[0], p[1]); } + + inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {} + + template<typename T> + inline void fixEndianess(T& value) + { + fixEndianess(reinterpret_cast<uint8_t*>(&value), integral_constant<size_t, sizeof(T)>()); + } +#else + template<typename T> + inline void fixEndianess(T&) + {} +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/ieee754.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/ieee754.hpp new file mode 100644 index 000000000..cb34569a3 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/MsgPack/ieee754.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) + { + f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5)); + f[1] = uint8_t((d[1] << 3) | (d[2] >> 5)); + f[2] = uint8_t((d[2] << 3) | (d[3] >> 5)); + f[3] = uint8_t((d[3] << 3) | (d[4] >> 5)); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Namespace.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Namespace.hpp new file mode 100644 index 000000000..7ca57fa5e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Namespace.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/version.hpp> + +#ifndef ARDUINOJSON_NAMESPACE + +#define ARDUINOJSON_NAMESPACE \ + ARDUINOJSON_CONCAT4( \ + ARDUINOJSON_CONCAT4( \ + ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, ARDUINOJSON_VERSION_REVISION), \ + _, \ + ARDUINOJSON_HEX_DIGIT( \ + ARDUINOJSON_ENABLE_PROGMEM, \ + ARDUINOJSON_USE_LONG_LONG, \ + ARDUINOJSON_USE_DOUBLE, \ + ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ + ARDUINOJSON_HEX_DIGIT( \ + ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) + +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Float.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Float.hpp new file mode 100644 index 000000000..5f203fe15 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Float.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_USE_DOUBLE + typedef double Float; +#else + typedef float Float; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatParts.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatParts.hpp new file mode 100644 index 000000000..784004992 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatParts.hpp @@ -0,0 +1,89 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Polyfills/math.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TFloat> + struct FloatParts { + uint32_t integral; + uint32_t decimal; + int16_t exponent; + int8_t decimalPlaces; + + FloatParts(TFloat value) + { + uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000; + decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6; + + exponent = normalize(value); + + integral = uint32_t(value); + // reduce number of decimal places by the number of integral places + for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { + maxDecimalPart /= 10; + decimalPlaces--; + } + + TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart); + + decimal = uint32_t(remainder); + remainder = remainder - TFloat(decimal); + + // rounding: + // increment by 1 if remainder >= 0.5 + decimal += uint32_t(remainder * 2); + if (decimal >= maxDecimalPart) { + decimal = 0; + integral++; + if (exponent && integral >= 10) { + exponent++; + integral = 1; + } + } + + // remove trailing zeros + while (decimal % 10 == 0 && decimalPlaces > 0) { + decimal /= 10; + decimalPlaces--; + } + } + + static int16_t normalize(TFloat& value) + { + typedef FloatTraits<TFloat> traits; + int16_t powersOf10 = 0; + + int8_t index = sizeof(TFloat) == 8 ? 8 : 5; + int bit = 1 << index; + + if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value >= traits::positiveBinaryPowerOfTen(index)) { + value *= traits::negativeBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 + bit); + } + bit >>= 1; + } + } + + if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) { + value *= traits::positiveBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 - bit); + } + bit >>= 1; + } + } + + return powersOf10; + } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatTraits.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatTraits.hpp new file mode 100644 index 000000000..1f4878947 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/FloatTraits.hpp @@ -0,0 +1,208 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stddef.h> // for size_t +#include <stdint.h> + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/alias_cast.hpp> +#include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/Polyfills/static_array.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T, size_t = sizeof(T)> + struct FloatTraits { + }; + + template<typename T> + struct FloatTraits<T, 8 /*64bits*/> { + typedef uint64_t mantissa_type; + static const short mantissa_bits = 52; + static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; + + typedef int16_t exponent_type; + static const exponent_type exponent_max = 308; + + template<typename TExponent> + static T make_float(T m, TExponent e) + { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = TExponent(-e); + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + + static T positiveBinaryPowerOfTen(int index) + { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, + factors, + ARDUINOJSON_EXPAND18({ + 0x40240000, + 0x00000000, // 1e1 + 0x40590000, + 0x00000000, // 1e2 + 0x40C38800, + 0x00000000, // 1e4 + 0x4197D784, + 0x00000000, // 1e8 + 0x4341C379, + 0x37E08000, // 1e16 + 0x4693B8B5, + 0xB5056E17, // 1e32 + 0x4D384F03, + 0xE93FF9F5, // 1e64 + 0x5A827748, + 0xF9301D32, // 1e128 + 0x75154FDD, + 0x7F73BF3C // 1e256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T negativeBinaryPowerOfTen(int index) + { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, + factors, + ARDUINOJSON_EXPAND18({ + 0x3FB99999, + 0x9999999A, // 1e-1 + 0x3F847AE1, + 0x47AE147B, // 1e-2 + 0x3F1A36E2, + 0xEB1C432D, // 1e-4 + 0x3E45798E, + 0xE2308C3A, // 1e-8 + 0x3C9CD2B2, + 0x97D889BC, // 1e-16 + 0x3949F623, + 0xD5A8A733, // 1e-32 + 0x32A50FFD, + 0x44F4A73D, // 1e-64 + 0x255BBA08, + 0xCF8C979D, // 1e-128 + 0x0AC80628, + 0x64AC6F43 // 1e-256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T negativeBinaryPowerOfTenPlusOne(int index) + { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, + factors, + ARDUINOJSON_EXPAND18({ + 0x3FF00000, + 0x00000000, // 1e0 + 0x3FB99999, + 0x9999999A, // 1e-1 + 0x3F50624D, + 0xD2F1A9FC, // 1e-3 + 0x3E7AD7F2, + 0x9ABCAF48, // 1e-7 + 0x3CD203AF, + 0x9EE75616, // 1e-15 + 0x398039D6, + 0x65896880, // 1e-31 + 0x32DA53FC, + 0x9631D10D, // 1e-63 + 0x25915445, + 0x81B7DEC2, // 1e-127 + 0x0AFE07B2, + 0x7DD78B14 // 1e-255 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T nan() { return forge(0x7ff80000, 0x00000000); } + + static T inf() { return forge(0x7ff00000, 0x00000000); } + + static T highest() { return forge(0x7FEFFFFF, 0xFFFFFFFF); } + + static T lowest() { return forge(0xFFEFFFFF, 0xFFFFFFFF); } + + // constructs a double floating point values from its binary representation + // we use this function to workaround platforms with single precision literals + // (for example, when -fsingle-precision-constant is passed to GCC) + static T forge(uint32_t msb, uint32_t lsb) { return alias_cast<T>((uint64_t(msb) << 32) | lsb); } + }; + + template<typename T> + struct FloatTraits<T, 4 /*32bits*/> { + typedef uint32_t mantissa_type; + static const short mantissa_bits = 23; + static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; + + typedef int8_t exponent_type; + static const exponent_type exponent_max = 38; + + template<typename TExponent> + static T make_float(T m, TExponent e) + { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = -e; + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + + static T positiveBinaryPowerOfTen(int index) + { + ARDUINOJSON_DEFINE_STATIC_ARRAY(T, factors, ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T negativeBinaryPowerOfTen(int index) + { + ARDUINOJSON_DEFINE_STATIC_ARRAY(T, factors, ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T negativeBinaryPowerOfTenPlusOne(int index) + { + ARDUINOJSON_DEFINE_STATIC_ARRAY(T, factors, ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T forge(uint32_t bits) { return alias_cast<T>(bits); } + + static T nan() { return forge(0x7fc00000); } + + static T inf() { return forge(0x7f800000); } + + static T highest() { return forge(0x7f7fffff); } + + static T lowest() { return forge(0xFf7fffff); } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Integer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Integer.hpp new file mode 100644 index 000000000..a5f99357e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/Integer.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> + +#include <stdint.h> // int64_t + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_USE_LONG_LONG + typedef int64_t Integer; + typedef uint64_t UInt; +#else + typedef long Integer; + typedef unsigned long UInt; +#endif + +} // namespace ARDUINOJSON_NAMESPACE + +#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ + static_assert( \ + sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ + "To use 64-bit integers with ArduinoJson, you must set " \ + "ARDUINOJSON_USE_LONG_LONG to 1. See " \ + "https://arduinojson.org/v6/api/config/use_long_long/"); +#else +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/arithmeticCompare.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/arithmeticCompare.hpp new file mode 100644 index 000000000..b9b6c43e9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/arithmeticCompare.hpp @@ -0,0 +1,127 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Numbers/Integer.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + enum CompareResult { + COMPARE_RESULT_DIFFER = 0, + COMPARE_RESULT_EQUAL = 1, + COMPARE_RESULT_GREATER = 2, + COMPARE_RESULT_LESS = 4, + + COMPARE_RESULT_GREATER_OR_EQUAL = 3, + COMPARE_RESULT_LESS_OR_EQUAL = 5 + }; + + template<typename T> + CompareResult arithmeticCompare(const T& lhs, const T& rhs) + { + if (lhs < rhs) + return COMPARE_RESULT_LESS; + else if (lhs > rhs) + return COMPARE_RESULT_GREATER; + else + return COMPARE_RESULT_EQUAL; + } + + template<typename T1, typename T2> + CompareResult arithmeticCompare( + const T1& lhs, + const T2& rhs, + typename enable_if< + is_integral<T1>::value && is_integral<T2>::value && sizeof(T1) < sizeof(T2), + int // Using int instead of void to avoid C2572 on + // Visual Studio 2012, 2013, and 2015 + >::type* = 0) + { + return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); + } + + template<typename T1, typename T2> + CompareResult arithmeticCompare( + const T1& lhs, + const T2& rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && sizeof(T2) < sizeof(T1)>::type* = 0) + { + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); + } + + template<typename T1, typename T2> + CompareResult arithmeticCompare( + const T1& lhs, + const T2& rhs, + typename enable_if< + is_integral<T1>::value && is_integral<T2>::value && is_signed<T1>::value == is_signed<T2>::value && + sizeof(T2) == sizeof(T1)>::type* = 0) + { + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); + } + + template<typename T1, typename T2> + CompareResult arithmeticCompare( + const T1& lhs, + const T2& rhs, + typename enable_if< + is_integral<T1>::value && is_integral<T2>::value && is_unsigned<T1>::value && is_signed<T2>::value && + sizeof(T2) == sizeof(T1)>::type* = 0) + { + if (rhs < 0) return COMPARE_RESULT_GREATER; + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); + } + + template<typename T1, typename T2> + CompareResult arithmeticCompare( + const T1& lhs, + const T2& rhs, + typename enable_if< + is_integral<T1>::value && is_integral<T2>::value && is_signed<T1>::value && is_unsigned<T2>::value && + sizeof(T2) == sizeof(T1)>::type* = 0) + { + if (lhs < 0) return COMPARE_RESULT_LESS; + return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); + } + + template<typename T1, typename T2> + CompareResult arithmeticCompare( + const T1& lhs, + const T2& rhs, + typename enable_if<is_floating_point<T1>::value || is_floating_point<T2>::value>::type* = 0) + { + return arithmeticCompare<double>(static_cast<double>(lhs), static_cast<double>(rhs)); + } + + template<typename T2> + CompareResult arithmeticCompareNegateLeft(UInt, const T2&, typename enable_if<is_unsigned<T2>::value>::type* = 0) + { + return COMPARE_RESULT_LESS; + } + + template<typename T2> + CompareResult + arithmeticCompareNegateLeft(UInt lhs, const T2& rhs, typename enable_if<is_signed<T2>::value>::type* = 0) + { + if (rhs > 0) return COMPARE_RESULT_LESS; + return arithmeticCompare(-rhs, static_cast<T2>(lhs)); + } + + template<typename T1> + CompareResult arithmeticCompareNegateRight(const T1&, UInt, typename enable_if<is_unsigned<T1>::value>::type* = 0) + { + return COMPARE_RESULT_GREATER; + } + + template<typename T1> + CompareResult + arithmeticCompareNegateRight(const T1& lhs, UInt rhs, typename enable_if<is_signed<T1>::value>::type* = 0) + { + if (lhs > 0) return COMPARE_RESULT_GREATER; + return arithmeticCompare(static_cast<T1>(rhs), -lhs); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/convertNumber.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/convertNumber.hpp new file mode 100644 index 000000000..78b206113 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/convertNumber.hpp @@ -0,0 +1,100 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wconversion" +#endif + +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> +#include <ArduinoJson/Polyfills/limits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TOut, typename TIn> + typename enable_if<is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn), bool>::type canStorePositiveInteger( + TIn value) + { + return value <= TIn(numeric_limits<TOut>::highest()); + } + + template<typename TOut, typename TIn> + typename enable_if<is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut), bool>::type canStorePositiveInteger(TIn) + { + return true; + } + + template<typename TOut, typename TIn> + typename enable_if<is_floating_point<TOut>::value, bool>::type canStorePositiveInteger(TIn) + { + return true; + } + + template<typename TOut, typename TIn> + typename enable_if<is_floating_point<TOut>::value, bool>::type canStoreNegativeInteger(TIn) + { + return true; + } + + template<typename TOut, typename TIn> + typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value && sizeof(TOut) <= sizeof(TIn), bool>::type + canStoreNegativeInteger(TIn value) + { + return value <= TIn(numeric_limits<TOut>::highest()) + 1; + } + + template<typename TOut, typename TIn> + typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value && sizeof(TIn) < sizeof(TOut), bool>::type + canStoreNegativeInteger(TIn) + { + return true; + } + + template<typename TOut, typename TIn> + typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value, bool>::type canStoreNegativeInteger(TIn) + { + return false; + } + + template<typename TOut, typename TIn> + TOut convertPositiveInteger(TIn value) + { + return canStorePositiveInteger<TOut>(value) ? TOut(value) : 0; + } + + template<typename TOut, typename TIn> + TOut convertNegativeInteger(TIn value) + { + return canStoreNegativeInteger<TOut>(value) ? TOut(~value + 1) : 0; + } + + template<typename TOut, typename TIn> + typename enable_if<is_floating_point<TOut>::value, TOut>::type convertFloat(TIn value) + { + return TOut(value); + } + + template<typename TOut, typename TIn> + typename enable_if<!is_floating_point<TOut>::value, TOut>::type convertFloat(TIn value) + { + return value >= numeric_limits<TOut>::lowest() && value <= numeric_limits<TOut>::highest() ? TOut(value) : 0; + } +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/parseNumber.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/parseNumber.hpp new file mode 100644 index 000000000..fe8d1b0ac --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Numbers/parseNumber.hpp @@ -0,0 +1,142 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/ctype.hpp> +#include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantAs.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename A, typename B> + struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> { + }; + + inline bool parseNumber(const char* s, VariantData& result) + { + typedef FloatTraits<Float> traits; + typedef choose_largest<traits::mantissa_type, UInt>::type mantissa_t; + typedef traits::exponent_type exponent_t; + + ARDUINOJSON_ASSERT(s != 0); + + bool is_negative = false; + switch (*s) { + case '-': + is_negative = true; + s++; + break; + case '+': s++; break; + } + +#if ARDUINOJSON_ENABLE_NAN + if (*s == 'n' || *s == 'N') { + result.setFloat(traits::nan()); + return true; + } +#endif + +#if ARDUINOJSON_ENABLE_INFINITY + if (*s == 'i' || *s == 'I') { + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } +#endif + + if (!isdigit(*s) && *s != '.') return false; + + mantissa_t mantissa = 0; + exponent_t exponent_offset = 0; + const mantissa_t maxUint = UInt(-1); + + while (isdigit(*s)) { + uint8_t digit = uint8_t(*s - '0'); + if (mantissa > maxUint / 10) break; + mantissa *= 10; + if (mantissa > maxUint - digit) break; + mantissa += digit; + s++; + } + + if (*s == '\0') { + if (is_negative) + result.setNegativeInteger(UInt(mantissa)); + else + result.setPositiveInteger(UInt(mantissa)); + return true; + } + + // avoid mantissa overflow + while (mantissa > traits::mantissa_max) { + mantissa /= 10; + exponent_offset++; + } + + // remaing digits can't fit in the mantissa + while (isdigit(*s)) { + exponent_offset++; + s++; + } + + if (*s == '.') { + s++; + while (isdigit(*s)) { + if (mantissa < traits::mantissa_max / 10) { + mantissa = mantissa * 10 + uint8_t(*s - '0'); + exponent_offset--; + } + s++; + } + } + + int exponent = 0; + if (*s == 'e' || *s == 'E') { + s++; + bool negative_exponent = false; + if (*s == '-') { + negative_exponent = true; + s++; + } else if (*s == '+') { + s++; + } + + while (isdigit(*s)) { + exponent = exponent * 10 + (*s - '0'); + if (exponent + exponent_offset > traits::exponent_max) { + if (negative_exponent) + result.setFloat(is_negative ? -0.0f : 0.0f); + else + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } + s++; + } + if (negative_exponent) exponent = -exponent; + } + exponent += exponent_offset; + + // we should be at the end of the string, otherwise it's an error + if (*s != '\0') return false; + + Float final_result = traits::make_float(static_cast<Float>(mantissa), exponent); + + result.setFloat(is_negative ? -final_result : final_result); + return true; + } + + template<typename T> + inline T parseNumber(const char* s) + { + VariantData value; + value.init(); // VariantData is a POD, so it has no constructor + parseNumber(s, value); + return variantAs<T>(&value); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/MemberProxy.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/MemberProxy.hpp new file mode 100644 index 000000000..550755ec0 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/MemberProxy.hpp @@ -0,0 +1,181 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> +#include <ArduinoJson/Variant/VariantTo.hpp> + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TObject, typename TStringRef> + class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef>>, + public VariantShortcuts<MemberProxy<TObject, TStringRef>>, + public Visitable { + typedef MemberProxy<TObject, TStringRef> this_type; + + public: + FORCE_INLINE MemberProxy(TObject variant, TStringRef key) : _object(variant), _key(key) {} + + FORCE_INLINE MemberProxy(const MemberProxy& src) : _object(src._object), _key(src._key) {} + + FORCE_INLINE operator VariantConstRef() const { return getUpstreamMember(); } + + FORCE_INLINE this_type& operator=(const this_type& src) + { + getOrAddUpstreamMember().set(src); + return *this; + } + + template<typename TValue> + FORCE_INLINE typename enable_if<!is_array<TValue>::value, this_type&>::type operator=(const TValue& src) + { + getOrAddUpstreamMember().set(src); + return *this; + } + + // operator=(char*) + // operator=(const char*) + // operator=(const __FlashStringHelper*) + template<typename TChar> + FORCE_INLINE this_type& operator=(TChar* src) + { + getOrAddUpstreamMember().set(src); + return *this; + } + + FORCE_INLINE void clear() const { getUpstreamMember().clear(); } + + FORCE_INLINE bool isNull() const { return getUpstreamMember().isNull(); } + + template<typename TValue> + FORCE_INLINE typename VariantAs<TValue>::type as() const + { + return getUpstreamMember().template as<TValue>(); + } + + template<typename T> + FORCE_INLINE operator T() const + { + return getUpstreamMember(); + } + + template<typename TValue> + FORCE_INLINE bool is() const + { + return getUpstreamMember().template is<TValue>(); + } + + FORCE_INLINE size_t size() const { return getUpstreamMember().size(); } + + FORCE_INLINE void remove(size_t index) const { getUpstreamMember().remove(index); } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(TChar* key) const + { + getUpstreamMember().remove(key); + } + // remove(const std::string&) const + // remove(const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(const TString& key) const + { + getUpstreamMember().remove(key); + } + + template<typename TValue> + FORCE_INLINE typename VariantTo<TValue>::type to() + { + return getOrAddUpstreamMember().template to<TValue>(); + } + + template<typename TValue> + FORCE_INLINE bool set(const TValue& value) + { + return getOrAddUpstreamMember().set(value); + } + + // set(char*) const + // set(const char*) const + // set(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE bool set(TChar* value) + { + return getOrAddUpstreamMember().set(value); + } + + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + return getUpstreamMember().accept(visitor); + } + + FORCE_INLINE VariantRef addElement() const { return getOrAddUpstreamMember().addElement(); } + + FORCE_INLINE VariantRef getElement(size_t index) const { return getUpstreamMember().getElement(index); } + + FORCE_INLINE VariantRef getOrAddElement(size_t index) const + { + return getOrAddUpstreamMember().getOrAddElement(index); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantRef getMember(TChar* key) const + { + return getUpstreamMember().getMember(key); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template<typename TString> + FORCE_INLINE VariantRef getMember(const TString& key) const + { + return getUpstreamMember().getMember(key); + } + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar* key) const + { + return getOrAddUpstreamMember().getOrAddMember(key); + } + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template<typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString& key) const + { + return getOrAddUpstreamMember().getOrAddMember(key); + } + + private: + FORCE_INLINE VariantRef getUpstreamMember() const { return _object.getMember(_key); } + + FORCE_INLINE VariantRef getOrAddUpstreamMember() const { return _object.getOrAddMember(_key); } + + TObject _object; + TStringRef _key; + }; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectFunctions.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectFunctions.hpp new file mode 100644 index 000000000..1ebff912d --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectFunctions.hpp @@ -0,0 +1,48 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TVisitor> + typename TVisitor::result_type objectAccept(const CollectionData* obj, TVisitor& visitor) + { + if (obj) + return visitor.visitObject(*obj); + else + return visitor.visitNull(); + } + + inline bool objectEquals(const CollectionData* lhs, const CollectionData* rhs) + { + if (lhs == rhs) return true; + if (!lhs || !rhs) return false; + return lhs->equalsObject(*rhs); + } + + template<typename TAdaptedString> + inline VariantData* objectGetMember(const CollectionData* obj, TAdaptedString key) + { + if (!obj) return 0; + return obj->getMember(key); + } + + template<typename TAdaptedString> + void objectRemove(CollectionData* obj, TAdaptedString key) + { + if (!obj) return; + obj->removeMember(key); + } + + template<typename TAdaptedString> + inline VariantData* objectGetOrAddMember(CollectionData* obj, TAdaptedString key, MemoryPool* pool) + { + if (!obj) return 0; + + return obj->getOrAddMember(key, pool); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectImpl.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectImpl.hpp new file mode 100644 index 000000000..5a00eabaa --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectImpl.hpp @@ -0,0 +1,71 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TObject> + template<typename TString> + inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(const TString& key) const + { + return impl()->getOrAddMember(key).template to<ArrayRef>(); + } + + template<typename TObject> + template<typename TChar> + inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(TChar* key) const + { + return impl()->getOrAddMember(key).template to<ArrayRef>(); + } + + template<typename TObject> + template<typename TString> + inline ObjectRef ObjectShortcuts<TObject>::createNestedObject(const TString& key) const + { + return impl()->getOrAddMember(key).template to<ObjectRef>(); + } + + template<typename TObject> + template<typename TChar> + inline ObjectRef ObjectShortcuts<TObject>::createNestedObject(TChar* key) const + { + return impl()->getOrAddMember(key).template to<ObjectRef>(); + } + + template<typename TObject> + template<typename TString> + inline typename enable_if<IsString<TString>::value, bool>::type ObjectShortcuts<TObject>::containsKey( + const TString& key) const + { + return !impl()->getMember(key).isUndefined(); + } + + template<typename TObject> + template<typename TChar> + inline typename enable_if<IsString<TChar*>::value, bool>::type ObjectShortcuts<TObject>::containsKey(TChar* key) const + { + return !impl()->getMember(key).isUndefined(); + } + + template<typename TObject> + template<typename TString> + inline typename enable_if<IsString<TString*>::value, MemberProxy<TObject, TString*>>::type + ObjectShortcuts<TObject>::operator[](TString* key) const + { + return MemberProxy<TObject, TString*>(*impl(), key); + } + + template<typename TObject> + template<typename TString> + inline typename enable_if<IsString<TString>::value, MemberProxy<TObject, TString>>::type + ObjectShortcuts<TObject>::operator[](const TString& key) const + { + return MemberProxy<TObject, TString>(*impl(), key); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectIterator.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectIterator.hpp new file mode 100644 index 000000000..09f581703 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectIterator.hpp @@ -0,0 +1,98 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Object/Pair.hpp> +#include <ArduinoJson/Variant/SlotFunctions.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class PairPtr { + public: + PairPtr(MemoryPool* pool, VariantSlot* slot) : _pair(pool, slot) {} + + const Pair* operator->() const { return &_pair; } + + const Pair& operator*() const { return _pair; } + + private: + Pair _pair; + }; + + class ObjectIterator { + public: + ObjectIterator() : _slot(0) {} + + explicit ObjectIterator(MemoryPool* pool, VariantSlot* slot) : _pool(pool), _slot(slot) {} + + Pair operator*() const { return Pair(_pool, _slot); } + PairPtr operator->() { return PairPtr(_pool, _slot); } + + bool operator==(const ObjectIterator& other) const { return _slot == other._slot; } + + bool operator!=(const ObjectIterator& other) const { return _slot != other._slot; } + + ObjectIterator& operator++() + { + _slot = _slot->next(); + return *this; + } + + ObjectIterator& operator+=(size_t distance) + { + _slot = _slot->next(distance); + return *this; + } + + VariantSlot* internal() { return _slot; } + + private: + MemoryPool* _pool; + VariantSlot* _slot; + }; + + class PairConstPtr { + public: + PairConstPtr(const VariantSlot* slot) : _pair(slot) {} + + const PairConst* operator->() const { return &_pair; } + + const PairConst& operator*() const { return _pair; } + + private: + PairConst _pair; + }; + + class ObjectConstIterator { + public: + ObjectConstIterator() : _slot(0) {} + + explicit ObjectConstIterator(const VariantSlot* slot) : _slot(slot) {} + + PairConst operator*() const { return PairConst(_slot); } + PairConstPtr operator->() { return PairConstPtr(_slot); } + + bool operator==(const ObjectConstIterator& other) const { return _slot == other._slot; } + + bool operator!=(const ObjectConstIterator& other) const { return _slot != other._slot; } + + ObjectConstIterator& operator++() + { + _slot = _slot->next(); + return *this; + } + + ObjectConstIterator& operator+=(size_t distance) + { + _slot = _slot->next(distance); + return *this; + } + + const VariantSlot* internal() { return _slot; } + + private: + const VariantSlot* _slot; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectRef.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectRef.hpp new file mode 100644 index 000000000..b4613947b --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectRef.hpp @@ -0,0 +1,225 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Object/ObjectFunctions.hpp> +#include <ArduinoJson/Object/ObjectIterator.hpp> + +// Returns the size (in bytes) of an object with n elements. +// Can be very handy to determine the size of a StaticMemoryPool. +#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TData> + class ObjectRefBase { + public: + operator VariantConstRef() const + { + const void* data = _data; // prevent warning cast-align + return VariantConstRef(reinterpret_cast<const VariantData*>(data)); + } + + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + return objectAccept(_data, visitor); + } + + FORCE_INLINE bool isNull() const { return _data == 0; } + + FORCE_INLINE operator bool() const { return _data != 0; } + + FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } + + FORCE_INLINE size_t nesting() const { return _data ? _data->nesting() : 0; } + + FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } + + protected: + ObjectRefBase(TData* data) : _data(data) {} + TData* _data; + }; + + class ObjectConstRef : public ObjectRefBase<const CollectionData>, public Visitable { + friend class ObjectRef; + typedef ObjectRefBase<const CollectionData> base_type; + + public: + typedef ObjectConstIterator iterator; + + ObjectConstRef() : base_type(0) {} + ObjectConstRef(const CollectionData* data) : base_type(data) {} + + FORCE_INLINE iterator begin() const + { + if (!_data) return iterator(); + return iterator(_data->head()); + } + + FORCE_INLINE iterator end() const { return iterator(); } + + // containsKey(const std::string&) const + // containsKey(const String&) const + template<typename TString> + FORCE_INLINE bool containsKey(const TString& key) const + { + return !getMember(key).isUndefined(); + } + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE bool containsKey(TChar* key) const + { + return !getMember(key).isUndefined(); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template<typename TString> + FORCE_INLINE VariantConstRef getMember(const TString& key) const + { + return get_impl(adaptString(key)); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar* key) const + { + return get_impl(adaptString(key)); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantConstRef>::type operator[]( + const TString& key) const + { + return get_impl(adaptString(key)); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, VariantConstRef>::type operator[](TChar* key) const + { + return get_impl(adaptString(key)); + } + + FORCE_INLINE bool operator==(ObjectConstRef rhs) const { return objectEquals(_data, rhs._data); } + + private: + template<typename TAdaptedString> + FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const + { + return VariantConstRef(objectGetMember(_data, key)); + } + }; + + class ObjectRef : public ObjectRefBase<CollectionData>, public ObjectShortcuts<ObjectRef>, public Visitable { + typedef ObjectRefBase<CollectionData> base_type; + + public: + typedef ObjectIterator iterator; + + FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {} + FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data) : base_type(data), _pool(buf) {} + + operator VariantRef() const + { + void* data = _data; // prevent warning cast-align + return VariantRef(_pool, reinterpret_cast<VariantData*>(data)); + } + + operator ObjectConstRef() const { return ObjectConstRef(_data); } + + FORCE_INLINE iterator begin() const + { + if (!_data) return iterator(); + return iterator(_pool, _data->head()); + } + + FORCE_INLINE iterator end() const { return iterator(); } + + void clear() const + { + if (!_data) return; + _data->clear(); + } + + FORCE_INLINE bool set(ObjectConstRef src) + { + if (!_data || !src._data) return false; + return _data->copyFrom(*src._data, _pool); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template<typename TString> + FORCE_INLINE VariantRef getMember(const TString& key) const + { + return VariantRef(_pool, objectGetMember(_data, adaptString(key))); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantRef getMember(TChar* key) const + { + return VariantRef(_pool, objectGetMember(_data, adaptString(key))); + } + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template<typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString& key) const + { + return VariantRef(_pool, objectGetOrAddMember(_data, adaptString(key), _pool)); + } + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar* key) const + { + return VariantRef(_pool, objectGetOrAddMember(_data, adaptString(key), _pool)); + } + + FORCE_INLINE bool operator==(ObjectRef rhs) const { return objectEquals(_data, rhs._data); } + + FORCE_INLINE void remove(iterator it) const + { + if (!_data) return; + _data->removeSlot(it.internal()); + } + + // remove(const std::string&) const + // remove(const String&) const + template<typename TString> + FORCE_INLINE void remove(const TString& key) const + { + objectRemove(_data, adaptString(key)); + } + + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE void remove(TChar* key) const + { + objectRemove(_data, adaptString(key)); + } + + private: + MemoryPool* _pool; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectShortcuts.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectShortcuts.hpp new file mode 100644 index 000000000..f11f5a560 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/ObjectShortcuts.hpp @@ -0,0 +1,67 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StringAdapters.hpp> + +namespace ARDUINOJSON_NAMESPACE { + template<typename TParent, typename TStringRef> + class MemberProxy; + + template<typename TObject> + class ObjectShortcuts { + public: + // containsKey(const std::string&) const + // containsKey(const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type containsKey(const TString& key) const; + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, bool>::type containsKey(TChar* key) const; + + // operator[](const std::string&) const + // operator[](const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, MemberProxy<TObject, TString>>::type operator[]( + const TString& key) const; + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, MemberProxy<TObject, TChar*>>::type operator[]( + TChar* key) const; + + // createNestedArray(const std::string&) const + // createNestedArray(const String&) const + template<typename TString> + FORCE_INLINE ArrayRef createNestedArray(const TString& key) const; + + // createNestedArray(char*) const + // createNestedArray(const char*) const + // createNestedArray(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE ArrayRef createNestedArray(TChar* key) const; + + // createNestedObject(const std::string&) const + // createNestedObject(const String&) const + template<typename TString> + ObjectRef createNestedObject(const TString& key) const; + + // createNestedObject(char*) const + // createNestedObject(const char*) const + // createNestedObject(const __FlashStringHelper*) const + template<typename TChar> + ObjectRef createNestedObject(TChar* key) const; + + private: + const TObject* impl() const { return static_cast<const TObject*>(this); } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/Pair.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/Pair.hpp new file mode 100644 index 000000000..41346001a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Object/Pair.hpp @@ -0,0 +1,49 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/String.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + // A key value pair for CollectionData. + class Pair { + public: + Pair(MemoryPool* pool, VariantSlot* slot) + { + if (slot) { + _key = String(slot->key(), !slot->ownsKey()); + _value = VariantRef(pool, slot->data()); + } + } + + String key() const { return _key; } + + VariantRef value() const { return _value; } + + private: + String _key; + VariantRef _value; + }; + + class PairConst { + public: + PairConst(const VariantSlot* slot) + { + if (slot) { + _key = String(slot->key(), !slot->ownsKey()); + _value = VariantConstRef(slot->data()); + } + } + + String key() const { return _key; } + + VariantConstRef value() const { return _value; } + + private: + String _key; + VariantConstRef _value; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/alias_cast.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/alias_cast.hpp new file mode 100644 index 000000000..bcc8ac6af --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/alias_cast.hpp @@ -0,0 +1,30 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stdint.h> +#include <stdlib.h> // for size_t + +#include <ArduinoJson/Configuration.hpp> +#include "math.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T, typename F> + struct alias_cast_t { + union { + F raw; + T data; + }; + }; + + template<typename T, typename F> + T alias_cast(F raw_data) + { + alias_cast_t<T, F> ac; + ac.raw = raw_data; + return ac.data; + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/assert.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/assert.hpp new file mode 100644 index 000000000..3e160eaee --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/assert.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> + +#if ARDUINOJSON_DEBUG +#include <assert.h> +#define ARDUINOJSON_ASSERT(X) assert(X) +#else +#define ARDUINOJSON_ASSERT(X) ((void) 0) +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/attributes.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/attributes.hpp new file mode 100644 index 000000000..0db028d4b --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/attributes.hpp @@ -0,0 +1,45 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#ifdef _MSC_VER // Visual Studio + +#define FORCE_INLINE // __forceinline causes C4714 when returning std::string +#define NO_INLINE __declspec(noinline) +#define DEPRECATED(msg) __declspec(deprecated(msg)) + +#elif defined(__GNUC__) // GCC or Clang + +#define FORCE_INLINE __attribute__((always_inline)) +#define NO_INLINE __attribute__((noinline)) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#define DEPRECATED(msg) __attribute__((deprecated(msg))) +#else +#define DEPRECATED(msg) __attribute__((deprecated)) +#endif + +#else // Other compilers + +#define FORCE_INLINE +#define NO_INLINE +#define DEPRECATED(msg) + +#endif + +#if __cplusplus >= 201103L +#define NOEXCEPT noexcept +#else +#define NOEXCEPT throw() +#endif + +#if defined(__has_attribute) +#if __has_attribute(no_sanitize) +#define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) +#else +#define ARDUINOJSON_NO_SANITIZE(check) +#endif +#else +#define ARDUINOJSON_NO_SANITIZE(check) +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/ctype.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/ctype.hpp new file mode 100644 index 000000000..303812294 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/ctype.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + inline bool isdigit(char c) { return '0' <= c && c <= '9'; } + + inline bool issign(char c) { return '-' == c || c == '+'; } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/limits.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/limits.hpp new file mode 100644 index 000000000..b040541e9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/limits.hpp @@ -0,0 +1,36 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "type_traits.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4310) +#endif + +namespace ARDUINOJSON_NAMESPACE { + + // Differs from standard because we can't use the symbols "min" and "max" + template<typename T, typename Enable = void> + struct numeric_limits; + + template<typename T> + struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> { + static T lowest() { return 0; } + static T highest() { return T(-1); } + }; + + template<typename T> + struct numeric_limits<T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> { + static T lowest() { return T(T(1) << (sizeof(T) * 8 - 1)); } + static T highest() { return T(~lowest()); } + }; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/math.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/math.hpp new file mode 100644 index 000000000..b9e6c746a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/math.hpp @@ -0,0 +1,29 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // Some libraries #define isnan() and isinf() so we need to check before + // using this name + +#ifndef isnan + template<typename T> + bool isnan(T x) + { + return x != x; + } +#endif + +#ifndef isinf + template<typename T> + bool isinf(T x) + { + return x != 0.0 && x * 2 == x; + } +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/mpl/max.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/mpl/max.hpp new file mode 100644 index 000000000..7c9f7f2a8 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/mpl/max.hpp @@ -0,0 +1,27 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stddef.h> // for size_t + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that returns the highest value + template<size_t X, size_t Y, bool MaxIsX = (X > Y)> + struct Max { + }; + + template<size_t X, size_t Y> + struct Max<X, Y, true> { + static const size_t value = X; + }; + + template<size_t X, size_t Y> + struct Max<X, Y, false> { + static const size_t value = Y; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace.hpp new file mode 100644 index 000000000..931e7a57d --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace.hpp @@ -0,0 +1,78 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> + +namespace ARDUINOJSON_NAMESPACE { + // Wraps a const char* so that the our functions are picked only if the + // originals are missing + struct pgm_p { + pgm_p(const char* p) : address(p) {} + const char* address; + }; +} // namespace ARDUINOJSON_NAMESPACE + +#ifndef strlen_P +inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) +{ + const char* p = s.address; + ARDUINOJSON_ASSERT(p != NULL); + while (pgm_read_byte(p)) + p++; + return size_t(p - s.address); +} +#endif + +#ifndef strncmp_P +inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) +{ + const char* s1 = a; + const char* s2 = b.address; + ARDUINOJSON_ASSERT(s1 != NULL); + ARDUINOJSON_ASSERT(s2 != NULL); + while (n-- > 0) { + char c1 = *s1++; + char c2 = static_cast<char>(pgm_read_byte(s2++)); + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0 /* and c2 as well */) return 0; + } + return 0; +} +#endif + +#ifndef strcmp_P +inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) +{ + const char* s1 = a; + const char* s2 = b.address; + ARDUINOJSON_ASSERT(s1 != NULL); + ARDUINOJSON_ASSERT(s2 != NULL); + for (;;) { + char c1 = *s1++; + char c2 = static_cast<char>(pgm_read_byte(s2++)); + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0 /* and c2 as well */) return 0; + } +} +#endif + +#ifndef memcpy_P +inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) +{ + uint8_t* d = reinterpret_cast<uint8_t*>(dst); + const char* s = src.address; + ARDUINOJSON_ASSERT(d != NULL); + ARDUINOJSON_ASSERT(s != NULL); + while (n-- > 0) { + *d++ = pgm_read_byte(s++); + } + return dst; +} +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace_generic.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace_generic.hpp new file mode 100644 index 000000000..74c577ebf --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/pgmspace_generic.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + typename enable_if<is_pointer<T>::value, T>::type pgm_read(const void* p) + { + return reinterpret_cast<T>(pgm_read_ptr(p)); + } + + template<typename T> + typename enable_if< + is_floating_point<T>::value && sizeof(T) == sizeof(float), // on AVR sizeof(double) == + // sizeof(float) + T>::type + pgm_read(const void* p) + { + return pgm_read_float(p); + } + + template<typename T> + typename enable_if<is_same<T, uint32_t>::value, T>::type pgm_read(const void* p) + { + return pgm_read_dword(p); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/preprocessor.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/preprocessor.hpp new file mode 100644 index 000000000..e32d8857a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/preprocessor.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f +#define ARDUINOJSON_EXPAND7(a, b, c, d, e, f, g) a, b, c, d, e, f, g +#define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i +#define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) \ + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r + +#define ARDUINOJSON_CONCAT_(A, B) A##B +#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) +#define ARDUINOJSON_CONCAT4(A, B, C, D) ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) + +#define ARDUINOJSON_HEX_DIGIT_0000() 0 +#define ARDUINOJSON_HEX_DIGIT_0001() 1 +#define ARDUINOJSON_HEX_DIGIT_0010() 2 +#define ARDUINOJSON_HEX_DIGIT_0011() 3 +#define ARDUINOJSON_HEX_DIGIT_0100() 4 +#define ARDUINOJSON_HEX_DIGIT_0101() 5 +#define ARDUINOJSON_HEX_DIGIT_0110() 6 +#define ARDUINOJSON_HEX_DIGIT_0111() 7 +#define ARDUINOJSON_HEX_DIGIT_1000() 8 +#define ARDUINOJSON_HEX_DIGIT_1001() 9 +#define ARDUINOJSON_HEX_DIGIT_1010() A +#define ARDUINOJSON_HEX_DIGIT_1011() B +#define ARDUINOJSON_HEX_DIGIT_1100() C +#define ARDUINOJSON_HEX_DIGIT_1101() D +#define ARDUINOJSON_HEX_DIGIT_1110() E +#define ARDUINOJSON_HEX_DIGIT_1111() F +#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() +#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/safe_strcmp.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/safe_strcmp.hpp new file mode 100644 index 000000000..4000e7889 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/safe_strcmp.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stdint.h> // int8_t + +namespace ARDUINOJSON_NAMESPACE { + + inline int safe_strcmp(const char* a, const char* b) + { + if (a == b) return 0; + if (!a) return -1; + if (!b) return 1; + return strcmp(a, b); + } + + inline int safe_strncmp(const char* a, const char* b, size_t n) + { + if (a == b) return 0; + if (!a) return -1; + if (!b) return 1; + return strncmp(a, b, n); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/static_array.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/static_array.hpp new file mode 100644 index 000000000..5348758c6 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/static_array.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> + +#if ARDUINOJSON_ENABLE_PROGMEM + +#include <ArduinoJson/Polyfills/pgmspace_generic.hpp> + +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) static type const name[] PROGMEM = value; +#endif + +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) pgm_read<type>(name + index) +#endif + +#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 + +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) static type const name[] = value; +#endif + +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] +#endif + +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits.hpp new file mode 100644 index 000000000..43dc4e01c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits.hpp @@ -0,0 +1,24 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "type_traits/conditional.hpp" +#include "type_traits/enable_if.hpp" +#include "type_traits/integral_constant.hpp" +#include "type_traits/is_array.hpp" +#include "type_traits/is_base_of.hpp" +#include "type_traits/is_class.hpp" +#include "type_traits/is_const.hpp" +#include "type_traits/is_convertible.hpp" +#include "type_traits/is_enum.hpp" +#include "type_traits/is_floating_point.hpp" +#include "type_traits/is_integral.hpp" +#include "type_traits/is_pointer.hpp" +#include "type_traits/is_same.hpp" +#include "type_traits/is_signed.hpp" +#include "type_traits/is_unsigned.hpp" +#include "type_traits/make_unsigned.hpp" +#include "type_traits/remove_const.hpp" +#include "type_traits/remove_reference.hpp" diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/conditional.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/conditional.hpp new file mode 100644 index 000000000..745381bef --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/conditional.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<bool Condition, class TrueType, class FalseType> + struct conditional { + typedef TrueType type; + }; + + template<class TrueType, class FalseType> + struct conditional<false, TrueType, FalseType> { + typedef FalseType type; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/declval.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/declval.hpp new file mode 100644 index 000000000..b87b862cf --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/declval.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + T declval(); + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/enable_if.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/enable_if.hpp new file mode 100644 index 000000000..245e8907a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/enable_if.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that return the type T if Condition is true. + template<bool Condition, typename T = void> + struct enable_if { + }; + + template<typename T> + struct enable_if<true, T> { + typedef T type; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/integral_constant.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/integral_constant.hpp new file mode 100644 index 000000000..d1da093eb --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/integral_constant.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T, T v> + struct integral_constant { + static const T value = v; + }; + + typedef integral_constant<bool, true> true_type; + typedef integral_constant<bool, false> false_type; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_array.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_array.hpp new file mode 100644 index 000000000..1f420cd6c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_array.hpp @@ -0,0 +1,24 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stddef.h> // size_t + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct is_array : false_type { + }; + + template<typename T> + struct is_array<T[]> : true_type { + }; + + template<typename T, size_t N> + struct is_array<T[N]> : true_type { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_base_of.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_base_of.hpp new file mode 100644 index 000000000..6dd5e7902 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_base_of.hpp @@ -0,0 +1,25 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that returns true if Derived inherits from TBase is an + // integral type. + template<typename TBase, typename TDerived> + class is_base_of { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + static Yes& probe(const TBase*); + static No& probe(...); + + public: + static const bool value = sizeof(probe(reinterpret_cast<TDerived*>(0))) == sizeof(Yes); + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_class.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_class.hpp new file mode 100644 index 000000000..ec15afde9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_class.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "declval.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct is_class { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + template<typename U> + static Yes& probe(void (U::*)(void)); + template<typename> + static No& probe(...); + + public: + static const bool value = sizeof(probe<T>(0)) == sizeof(Yes); + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_const.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_const.hpp new file mode 100644 index 000000000..edbb88086 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_const.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that return the type T without the const modifier + template<typename T> + struct is_const : false_type { + }; + + template<typename T> + struct is_const<const T> : true_type { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_convertible.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_convertible.hpp new file mode 100644 index 000000000..651ca3e9a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_convertible.hpp @@ -0,0 +1,43 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "declval.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +// conversion from 'T' to 'To', possible loss of data +#pragma warning(disable : 4244) +#endif + +#ifdef __ICCARM__ +// Suppress IAR Compiler Warning[Pa093]: implicit conversion from floating point to integer +#pragma diag_suppress = Pa093 +#endif + +namespace ARDUINOJSON_NAMESPACE { + + template<typename From, typename To> + struct is_convertible { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + static Yes& probe(To); + static No& probe(...); + + public: + static const bool value = sizeof(probe(declval<From>())) == sizeof(Yes); + }; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __ICCARM__ +#pragma diag_default = Pa093 +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_enum.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_enum.hpp new file mode 100644 index 000000000..a4536af86 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_enum.hpp @@ -0,0 +1,21 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "is_class.hpp" +#include "is_convertible.hpp" +#include "is_floating_point.hpp" +#include "is_integral.hpp" +#include "is_same.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct is_enum { + static const bool value = + is_convertible<T, int>::value && !is_class<T>::value && !is_integral<T>::value && !is_floating_point<T>::value; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp new file mode 100644 index 000000000..ddc82eca5 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + template<typename> + struct is_floating_point : false_type { + }; + + template<> + struct is_floating_point<float> : true_type { + }; + + template<> + struct is_floating_point<double> : true_type { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_integral.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_integral.hpp new file mode 100644 index 000000000..d8bd259a9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_integral.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include "is_same.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that returns true if T is an integral type. + template<typename T> + struct is_integral { + static const bool value = is_same<T, signed char>::value || is_same<T, unsigned char>::value || + is_same<T, signed short>::value || is_same<T, unsigned short>::value || + is_same<T, signed int>::value || is_same<T, unsigned int>::value || + is_same<T, signed long>::value || is_same<T, unsigned long>::value || +#if ARDUINOJSON_HAS_LONG_LONG + is_same<T, signed long long>::value || is_same<T, unsigned long long>::value || +#endif +#if ARDUINOJSON_HAS_INT64 + is_same<T, signed __int64>::value || is_same<T, unsigned __int64>::value || +#endif + is_same<T, char>::value || is_same<T, bool>::value; + }; + + template<typename T> + struct is_integral<const T> : is_integral<T> { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_pointer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_pointer.hpp new file mode 100644 index 000000000..a27e2935e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_pointer.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct is_pointer : false_type { + }; + + template<typename T> + struct is_pointer<T*> : true_type { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_same.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_same.hpp new file mode 100644 index 000000000..9469ff1e6 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_same.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that returns true if types T and U are the same. + template<typename T, typename U> + struct is_same : false_type { + }; + + template<typename T> + struct is_same<T, T> : true_type { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_signed.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_signed.hpp new file mode 100644 index 000000000..fa347e385 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_signed.hpp @@ -0,0 +1,53 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" +namespace ARDUINOJSON_NAMESPACE { + + template<typename> + struct is_signed : false_type { + }; + + template<> + struct is_signed<char> : true_type { + }; + + template<> + struct is_signed<signed char> : true_type { + }; + + template<> + struct is_signed<signed short> : true_type { + }; + + template<> + struct is_signed<signed int> : true_type { + }; + + template<> + struct is_signed<signed long> : true_type { + }; + + template<> + struct is_signed<float> : true_type { + }; + + template<> + struct is_signed<double> : true_type { + }; + +#if ARDUINOJSON_HAS_LONG_LONG + template<> + struct is_signed<signed long long> : true_type { + }; +#endif + +#if ARDUINOJSON_HAS_INT64 + template<> + struct is_signed<signed __int64> : true_type { + }; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp new file mode 100644 index 000000000..70f825ac7 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp @@ -0,0 +1,45 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" +namespace ARDUINOJSON_NAMESPACE { + + template<typename> + struct is_unsigned : false_type { + }; + + template<> + struct is_unsigned<bool> : true_type { + }; + + template<> + struct is_unsigned<unsigned char> : true_type { + }; + + template<> + struct is_unsigned<unsigned short> : true_type { + }; + + template<> + struct is_unsigned<unsigned int> : true_type { + }; + + template<> + struct is_unsigned<unsigned long> : true_type { + }; + +#if ARDUINOJSON_HAS_INT64 + template<> + struct is_unsigned<unsigned __int64> : true_type { + }; +#endif + +#if ARDUINOJSON_HAS_LONG_LONG + template<> + struct is_unsigned<unsigned long long> : true_type { + }; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp new file mode 100644 index 000000000..05aa8f62d --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "type_identity.hpp" +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct make_unsigned; + + template<> + struct make_unsigned<char> : type_identity<unsigned char> { + }; + + template<> + struct make_unsigned<signed char> : type_identity<unsigned char> { + }; + template<> + struct make_unsigned<unsigned char> : type_identity<unsigned char> { + }; + + template<> + struct make_unsigned<signed short> : type_identity<unsigned short> { + }; + template<> + struct make_unsigned<unsigned short> : type_identity<unsigned short> { + }; + + template<> + struct make_unsigned<signed int> : type_identity<unsigned int> { + }; + template<> + struct make_unsigned<unsigned int> : type_identity<unsigned int> { + }; + + template<> + struct make_unsigned<signed long> : type_identity<unsigned long> { + }; + template<> + struct make_unsigned<unsigned long> : type_identity<unsigned long> { + }; + +#if ARDUINOJSON_HAS_LONG_LONG + template<> + struct make_unsigned<signed long long> : type_identity<unsigned long long> { + }; + template<> + struct make_unsigned<unsigned long long> : type_identity<unsigned long long> { + }; +#endif + +#if ARDUINOJSON_HAS_INT64 + template<> + struct make_unsigned<signed __int64> : type_identity<unsigned __int64> { + }; + template<> + struct make_unsigned<unsigned __int64> : type_identity<unsigned __int64> { + }; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_const.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_const.hpp new file mode 100644 index 000000000..d53003f47 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_const.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that return the type T without the const modifier + template<typename T> + struct remove_const { + typedef T type; + }; + template<typename T> + struct remove_const<const T> { + typedef T type; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_reference.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_reference.hpp new file mode 100644 index 000000000..8c43ee91a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/remove_reference.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // A meta-function that return the type T without the reference modifier. + template<typename T> + struct remove_reference { + typedef T type; + }; + template<typename T> + struct remove_reference<T&> { + typedef T type; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/type_identity.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/type_identity.hpp new file mode 100644 index 000000000..0b7f43b51 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/type_traits/type_identity.hpp @@ -0,0 +1,15 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + struct type_identity { + typedef T type; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/utility.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/utility.hpp new file mode 100644 index 000000000..608f6104c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Polyfills/utility.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "type_traits.hpp" + +namespace ARDUINOJSON_NAMESPACE { + template<typename T> + inline void swap(T& a, T& b) + { + T t(a); + a = b; + b = t; + } + +#if ARDUINOJSON_HAS_RVALUE_REFERENCES + template<typename T> + typename remove_reference<T>::type&& move(T&& t) + { + return static_cast<typename remove_reference<T>::type&&>(t); + } +#else + template<typename T> + T& move(T& t) + { + return t; + } +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/CountingDecorator.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/CountingDecorator.hpp new file mode 100644 index 000000000..a35ece1d9 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/CountingDecorator.hpp @@ -0,0 +1,27 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TWriter> + class CountingDecorator { + public: + explicit CountingDecorator(TWriter& writer) : _writer(writer), _count(0) {} + + void write(uint8_t c) { _count += _writer.write(c); } + + void write(const uint8_t* s, size_t n) { _count += _writer.write(s, n); } + + size_t count() const { return _count; } + + private: + TWriter _writer; + size_t _count; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writer.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writer.hpp new file mode 100644 index 000000000..700ee1d09 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writer.hpp @@ -0,0 +1,43 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // The default writer is a simple wrapper for Writers that are not copiable + template<typename TDestination, typename Enable = void> + class Writer { + public: + explicit Writer(TDestination& dest) : _dest(&dest) {} + + size_t write(uint8_t c) { return _dest->write(c); } + + size_t write(const uint8_t* s, size_t n) { return _dest->write(s, n); } + + private: + TDestination* _dest; + }; + +} // namespace ARDUINOJSON_NAMESPACE + +#include <ArduinoJson/Serialization/Writers/StaticStringWriter.hpp> + +#if ARDUINOJSON_ENABLE_STD_STRING +#include <ArduinoJson/Serialization/Writers/StdStringWriter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include <ArduinoJson/Serialization/Writers/StdStreamWriter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_PRINT +#include <ArduinoJson/Serialization/Writers/PrintWriter.hpp> +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp new file mode 100644 index 000000000..0bb317d5c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp @@ -0,0 +1,50 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <Arduino.h> + +namespace ARDUINOJSON_NAMESPACE { + + template<> + class Writer<::String, void> { + static const size_t bufferCapacity = ARDUINOJSON_STRING_BUFFER_SIZE; + + public: + explicit Writer(::String& str) : _destination(&str) { _size = 0; } + + ~Writer() { flush(); } + + size_t write(uint8_t c) + { + ARDUINOJSON_ASSERT(_size < bufferCapacity); + _buffer[_size++] = static_cast<char>(c); + if (_size + 1 >= bufferCapacity) flush(); + return 1; + } + + size_t write(const uint8_t* s, size_t n) + { + for (size_t i = 0; i < n; i++) { + write(s[i]); + } + return n; + } + + private: + void flush() + { + ARDUINOJSON_ASSERT(_size < bufferCapacity); + _buffer[_size] = 0; + *_destination += _buffer; + _size = 0; + } + + ::String* _destination; + char _buffer[bufferCapacity]; + size_t _size; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/DummyWriter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/DummyWriter.hpp new file mode 100644 index 000000000..9d2da503e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/DummyWriter.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class DummyWriter { + public: + size_t write(uint8_t) { return 1; } + + size_t write(const uint8_t*, size_t n) { return n; } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/PrintWriter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/PrintWriter.hpp new file mode 100644 index 000000000..1caa8a66a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/PrintWriter.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TDestination> + class Writer<TDestination, typename enable_if<is_base_of<::Print, TDestination>::value>::type> { + public: + explicit Writer(::Print& print) : _print(&print) {} + + size_t write(uint8_t c) { return _print->write(c); } + + size_t write(const uint8_t* s, size_t n) { return _print->write(s, n); } + + private: + ::Print* _print; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp new file mode 100644 index 000000000..d38d0b32f --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp @@ -0,0 +1,39 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // A Print implementation that allows to write in a char[] + class StaticStringWriter { + public: + StaticStringWriter(char* buf, size_t size) : end(buf + size - 1), p(buf) { *p = '\0'; } + + size_t write(uint8_t c) + { + if (p >= end) return 0; + *p++ = static_cast<char>(c); + *p = '\0'; + return 1; + } + + size_t write(const uint8_t* s, size_t n) + { + char* begin = p; + while (p < end && n > 0) { + *p++ = static_cast<char>(*s++); + n--; + } + *p = '\0'; + return size_t(p - begin); + } + + private: + char* end; + char* p; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp new file mode 100644 index 000000000..060e9807c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ostream> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TDestination> + class Writer<TDestination, typename enable_if<is_base_of<std::ostream, TDestination>::value>::type> { + public: + explicit Writer(std::ostream& os) : _os(&os) {} + + size_t write(uint8_t c) + { + _os->put(static_cast<char>(c)); + return 1; + } + + size_t write(const uint8_t* s, size_t n) + { + _os->write(reinterpret_cast<const char*>(s), static_cast<std::streamsize>(n)); + return n; + } + + private: + std::ostream* _os; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStringWriter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStringWriter.hpp new file mode 100644 index 000000000..0d61c8e07 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/Writers/StdStringWriter.hpp @@ -0,0 +1,42 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +#include <string> + +namespace ARDUINOJSON_NAMESPACE { + + template<class T> + struct is_std_string : false_type { + }; + + template<class TCharTraits, class TAllocator> + struct is_std_string<std::basic_string<char, TCharTraits, TAllocator>> : true_type { + }; + + template<typename TDestination> + class Writer<TDestination, typename enable_if<is_std_string<TDestination>::value>::type> { + public: + Writer(TDestination& str) : _str(&str) {} + + size_t write(uint8_t c) + { + _str->operator+=(static_cast<char>(c)); + return 1; + } + + size_t write(const uint8_t* s, size_t n) + { + _str->append(reinterpret_cast<const char*>(s), n); + return n; + } + + private: + TDestination* _str; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/measure.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/measure.hpp new file mode 100644 index 000000000..c40afbb6e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/measure.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Serialization/Writers/DummyWriter.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<template<typename> class TSerializer, typename TSource> + size_t measure(const TSource& source) + { + DummyWriter dp; + TSerializer<DummyWriter> serializer(dp); + return source.accept(serializer); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/serialize.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/serialize.hpp new file mode 100644 index 000000000..2a9d2eb2b --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Serialization/serialize.hpp @@ -0,0 +1,44 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Serialization/Writer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<template<typename> class TSerializer, typename TSource, typename TWriter> + size_t doSerialize(const TSource& source, TWriter writer) + { + TSerializer<TWriter> serializer(writer); + return source.accept(serializer); + } + + template<template<typename> class TSerializer, typename TSource, typename TDestination> + size_t serialize(const TSource& source, TDestination& destination) + { + Writer<TDestination> writer(destination); + return doSerialize<TSerializer>(source, writer); + } + + template<template<typename> class TSerializer, typename TSource> + size_t serialize(const TSource& source, void* buffer, size_t bufferSize) + { + StaticStringWriter writer(reinterpret_cast<char*>(buffer), bufferSize); + return doSerialize<TSerializer>(source, writer); + } + + template<template<typename> class TSerializer, typename TSource, typename TChar, size_t N> +#if defined _MSC_VER && _MSC_VER < 1900 + typename enable_if<sizeof(remove_reference<TChar>::type) == 1, size_t>::type +#else + typename enable_if<sizeof(TChar) == 1, size_t>::type +#endif + serialize(const TSource& source, TChar (&buffer)[N]) + { + StaticStringWriter writer(reinterpret_cast<char*>(buffer), N); + return doSerialize<TSerializer>(source, writer); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringCopier.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringCopier.hpp new file mode 100644 index 000000000..57c88994b --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringCopier.hpp @@ -0,0 +1,64 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/MemoryPool.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class StringCopier { + public: + StringCopier(MemoryPool& pool) : _pool(&pool) {} + + void startString() + { + _pool->getFreeZone(&_ptr, &_capacity); + _size = 0; + } + + const char* save() + { + ARDUINOJSON_ASSERT(_ptr); + return _pool->saveStringFromFreeZone(_size); + } + + void append(const char* s) + { + while (*s) + append(*s++); + } + + void append(const char* s, size_t n) + { + while (n-- > 0) + append(*s++); + } + + void append(char c) + { + if (!_ptr) return; + + if (_size >= _capacity) { + _ptr = 0; + _pool->markAsOverflowed(); + return; + } + + _ptr[_size++] = c; + } + + bool isValid() { return _ptr != 0; } + + const char* c_str() { return _ptr; } + + typedef storage_policies::store_by_copy storage_policy; + + private: + MemoryPool* _pool; + char* _ptr; + size_t _size; + size_t _capacity; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringMover.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringMover.hpp new file mode 100644 index 000000000..10eab596f --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringMover.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class StringMover { + public: + StringMover(char* ptr) : _writePtr(ptr) {} + + void startString() { _startPtr = _writePtr; } + + const char* save() const { return _startPtr; } + + void append(char c) { *_writePtr++ = c; } + + bool isValid() const { return true; } + + const char* c_str() const { return _startPtr; } + + typedef storage_policies::store_by_address storage_policy; + + private: + char* _writePtr; + char* _startPtr; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringStorage.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringStorage.hpp new file mode 100644 index 000000000..e21ea8a5a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/StringStorage/StringStorage.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/StringStorage/StringCopier.hpp> +#include <ArduinoJson/StringStorage/StringMover.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TInput> + StringCopier makeStringStorage(TInput&, MemoryPool& pool) + { + return StringCopier(pool); + } + + template<typename TChar> + StringMover makeStringStorage(TChar* input, MemoryPool&, typename enable_if<!is_const<TChar>::value>::type* = 0) + { + return StringMover(reinterpret_cast<char*>(input)); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ArduinoStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ArduinoStringAdapter.hpp new file mode 100644 index 000000000..89e5d06ff --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ArduinoStringAdapter.hpp @@ -0,0 +1,56 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <Arduino.h> + +#include <ArduinoJson/Polyfills/safe_strcmp.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class ArduinoStringAdapter { + public: + ArduinoStringAdapter(const ::String& str) : _str(&str) {} + + void copyTo(char* p, size_t n) const { memcpy(p, _str->c_str(), n); } + + bool isNull() const + { + // Arduino's String::c_str() can return NULL + return !_str->c_str(); + } + + int compare(const char* other) const + { + // Arduino's String::c_str() can return NULL + const char* me = _str->c_str(); + return safe_strcmp(me, other); + } + + bool equals(const char* expected) const { return compare(expected) == 0; } + + size_t size() const { return _str->length(); } + + const char* begin() const { return _str->c_str(); } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const ::String* _str; + }; + + template<> + struct IsString<::String> : true_type { + }; + + template<> + struct IsString<::StringSumHelper> : true_type { + }; + + inline ArduinoStringAdapter adaptString(const ::String& str) { return ArduinoStringAdapter(str); } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ConstRamStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ConstRamStringAdapter.hpp new file mode 100644 index 000000000..acc83df86 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/ConstRamStringAdapter.hpp @@ -0,0 +1,52 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stddef.h> // size_t +#include <string.h> // strcmp + +#include <ArduinoJson/Polyfills/safe_strcmp.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class ConstRamStringAdapter { + public: + ConstRamStringAdapter(const char* str = 0) : _str(str) {} + + int compare(const char* other) const { return safe_strcmp(_str, other); } + + bool equals(const char* expected) const { return compare(expected) == 0; } + + bool isNull() const { return !_str; } + + size_t size() const + { + if (!_str) return 0; + return strlen(_str); + } + + const char* data() const { return _str; } + + const char* begin() const { return _str; } + + typedef storage_policies::store_by_address storage_policy; + + protected: + const char* _str; + }; + + template<> + struct IsString<const char*> : true_type { + }; + + template<int N> + struct IsString<const char[N]> : true_type { + }; + + inline ConstRamStringAdapter adaptString(const char* str) { return ConstRamStringAdapter(str); } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringAdapter.hpp new file mode 100644 index 000000000..e588b96cc --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringAdapter.hpp @@ -0,0 +1,51 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/pgmspace.hpp> +#include <ArduinoJson/Strings/FlashStringIterator.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class FlashStringAdapter { + public: + FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {} + + int compare(const char* other) const + { + if (!other && !_str) return 0; + if (!_str) return -1; + if (!other) return 1; + return -strcmp_P(other, reinterpret_cast<const char*>(_str)); + } + + bool equals(const char* expected) const { return compare(expected) == 0; } + + bool isNull() const { return !_str; } + + void copyTo(char* p, size_t n) const { memcpy_P(p, reinterpret_cast<const char*>(_str), n); } + + size_t size() const + { + if (!_str) return 0; + return strlen_P(reinterpret_cast<const char*>(_str)); + } + + FlashStringIterator begin() const { return FlashStringIterator(_str); } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const __FlashStringHelper* _str; + }; + + inline FlashStringAdapter adaptString(const __FlashStringHelper* str) { return FlashStringAdapter(str); } + + template<> + struct IsString<const __FlashStringHelper*> : true_type { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringIterator.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringIterator.hpp new file mode 100644 index 000000000..cf3b30ca1 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/FlashStringIterator.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + + class FlashStringIterator { + public: + explicit FlashStringIterator(const __FlashStringHelper* ptr) : _ptr(reinterpret_cast<const char*>(ptr)) {} + + explicit FlashStringIterator(const char* ptr) : _ptr(ptr) {} + + FlashStringIterator operator+(ptrdiff_t d) const { return FlashStringIterator(_ptr + d); } + + ptrdiff_t operator-(FlashStringIterator other) const { return _ptr - other._ptr; } + + FlashStringIterator operator++(int) { return FlashStringIterator(_ptr++); } + + FlashStringIterator operator++() { return FlashStringIterator(++_ptr); } + + bool operator!=(FlashStringIterator other) const { return _ptr != other._ptr; } + + char operator*() const { return char(pgm_read_byte(_ptr)); } + + private: + const char* _ptr; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsString.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsString.hpp new file mode 100644 index 000000000..4de83a719 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsString.hpp @@ -0,0 +1,21 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + template<typename> + struct IsString : false_type { + }; + + template<typename T> + struct IsString<const T> : IsString<T> { + }; + + template<typename T> + struct IsString<T&> : IsString<T> { + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsWriteableString.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsWriteableString.hpp new file mode 100644 index 000000000..ae193c146 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/IsWriteableString.hpp @@ -0,0 +1,39 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <Arduino.h> +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING +#include <string> +#endif + +namespace ARDUINOJSON_NAMESPACE { + + template<typename> + struct IsWriteableString : false_type { + }; + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING + + template<> + struct IsWriteableString<::String> : true_type { + }; + +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING + + template<typename TCharTraits, typename TAllocator> + struct IsWriteableString<std::basic_string<char, TCharTraits, TAllocator>> : true_type { + }; + +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/RamStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/RamStringAdapter.hpp new file mode 100644 index 000000000..da09009be --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/RamStringAdapter.hpp @@ -0,0 +1,40 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class RamStringAdapter : public ConstRamStringAdapter { + public: + RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} + + void copyTo(char* p, size_t n) const { memcpy(p, _str, n); } + + typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy; + }; + + template<typename TChar> + inline RamStringAdapter adaptString(const TChar* str) + { + return RamStringAdapter(reinterpret_cast<const char*>(str)); + } + + inline RamStringAdapter adaptString(char* str) { return RamStringAdapter(str); } + + template<typename TChar> + struct IsString<TChar*> { + static const bool value = sizeof(TChar) == 1; + }; + + template<> + struct IsString<void*> { + static const bool value = false; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedFlashStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedFlashStringAdapter.hpp new file mode 100644 index 000000000..08544f044 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedFlashStringAdapter.hpp @@ -0,0 +1,47 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/FlashStringIterator.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class SizedFlashStringAdapter { + public: + SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) : _str(str), _size(sz) {} + + int compare(const char* other) const + { + if (!other && !_str) return 0; + if (!_str) return -1; + if (!other) return 1; + return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size); + } + + bool equals(const char* expected) const { return compare(expected) == 0; } + + bool isNull() const { return !_str; } + + void copyTo(char* p, size_t n) const { memcpy_P(p, reinterpret_cast<const char*>(_str), n); } + + size_t size() const { return _size; } + + FlashStringIterator begin() const { return FlashStringIterator(_str); } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const __FlashStringHelper* _str; + size_t _size; + }; + + inline SizedFlashStringAdapter adaptString(const __FlashStringHelper* str, size_t sz) + { + return SizedFlashStringAdapter(str, sz); + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedRamStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedRamStringAdapter.hpp new file mode 100644 index 000000000..8a528e911 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/SizedRamStringAdapter.hpp @@ -0,0 +1,44 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +#include <string.h> // strcmp + +namespace ARDUINOJSON_NAMESPACE { + + class SizedRamStringAdapter { + public: + SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} + + int compare(const char* other) const { return safe_strncmp(_str, other, _size); } + + bool equals(const char* expected) const { return compare(expected) == 0; } + + bool isNull() const { return !_str; } + + void copyTo(char* p, size_t n) const { memcpy(p, _str, n); } + + size_t size() const { return _size; } + + const char* begin() const { return _str; } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const char* _str; + size_t _size; + }; + + template<typename TChar> + inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) + { + return SizedRamStringAdapter(reinterpret_cast<const char*>(str), size); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StdStringAdapter.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StdStringAdapter.hpp new file mode 100644 index 000000000..38e963b43 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StdStringAdapter.hpp @@ -0,0 +1,57 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +#include <string> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TString> + class StdStringAdapter { + public: + StdStringAdapter(const TString& str) : _str(&str) {} + + void copyTo(char* p, size_t n) const { memcpy(p, _str->c_str(), n); } + + bool isNull() const { return false; } + + int compare(const char* other) const + { + if (!other) return 1; + return _str->compare(other); + } + + bool equals(const char* expected) const + { + if (!expected) return false; + return *_str == expected; + } + + size_t size() const { return _str->size(); } + + const char* begin() const { return _str->c_str(); } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const TString* _str; + }; + + template<typename TCharTraits, typename TAllocator> + struct IsString<std::basic_string<char, TCharTraits, TAllocator>> : true_type { + }; + + template<typename TCharTraits, typename TAllocator> + inline StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator>> adaptString( + const std::basic_string<char, TCharTraits, TAllocator>& str) + { + return StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator>>(str); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StoragePolicy.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StoragePolicy.hpp new file mode 100644 index 000000000..137bbb6f2 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StoragePolicy.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + + namespace storage_policies { + struct store_by_address { + }; + struct store_by_copy { + }; + struct decide_at_runtime { + }; + } // namespace storage_policies + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/String.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/String.hpp new file mode 100644 index 000000000..e15a43a6c --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/String.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class String { + public: + String() : _data(0), _isStatic(true) {} + String(const char* data, bool isStaticData = true) : _data(data), _isStatic(isStaticData) {} + + const char* c_str() const { return _data; } + + bool isNull() const { return !_data; } + + bool isStatic() const { return _isStatic; } + + friend bool operator==(String lhs, String rhs) + { + if (lhs._data == rhs._data) return true; + if (!lhs._data) return false; + if (!rhs._data) return false; + return strcmp(lhs._data, rhs._data) == 0; + } + + friend bool operator!=(String lhs, String rhs) + { + if (lhs._data == rhs._data) return false; + if (!lhs._data) return true; + if (!rhs._data) return true; + return strcmp(lhs._data, rhs._data) != 0; + } + + private: + const char* _data; + bool _isStatic; + }; + + class StringAdapter : public RamStringAdapter { + public: + StringAdapter(const String& str) : RamStringAdapter(str.c_str()), _isStatic(str.isStatic()) {} + + bool isStatic() const { return _isStatic; } + + typedef storage_policies::decide_at_runtime storage_policy; + + private: + bool _isStatic; + }; + + template<> + struct IsString<String> : true_type { + }; + + inline StringAdapter adaptString(const String& str) { return StringAdapter(str); } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StringAdapters.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StringAdapters.hpp new file mode 100644 index 000000000..986f30523 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Strings/StringAdapters.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> +#include <ArduinoJson/Strings/RamStringAdapter.hpp> +#include <ArduinoJson/Strings/SizedRamStringAdapter.hpp> + +#if ARDUINOJSON_ENABLE_STD_STRING +#include <ArduinoJson/Strings/StdStringAdapter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <ArduinoJson/Strings/ArduinoStringAdapter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_PROGMEM +#include <ArduinoJson/Strings/FlashStringAdapter.hpp> +#include <ArduinoJson/Strings/SizedFlashStringAdapter.hpp> +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/SlotFunctions.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/SlotFunctions.hpp new file mode 100644 index 000000000..ca6e9ca7b --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/SlotFunctions.hpp @@ -0,0 +1,58 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TAdaptedString> + inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) + { + if (!var) return false; + return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy()); + } + + template<typename TAdaptedString> + inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, storage_policies::decide_at_runtime) + { + if (key.isStatic()) { + return slotSetKey(var, key, pool, storage_policies::store_by_address()); + } else { + return slotSetKey(var, key, pool, storage_policies::store_by_copy()); + } + } + + template<typename TAdaptedString> + inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, storage_policies::store_by_address) + { + ARDUINOJSON_ASSERT(var); + var->setKey(key.data(), storage_policies::store_by_address()); + return true; + } + + template<typename TAdaptedString> + inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, storage_policies::store_by_copy) + { + const char* dup = pool->saveString(key); + if (!dup) return false; + ARDUINOJSON_ASSERT(var); + var->setKey(dup, storage_policies::store_by_copy()); + return true; + } + + inline size_t slotSize(const VariantSlot* var) + { + size_t n = 0; + while (var) { + n++; + var = var->next(); + } + return n; + } + + inline VariantData* slotData(VariantSlot* slot) { return reinterpret_cast<VariantData*>(slot); } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAs.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAs.hpp new file mode 100644 index 000000000..dae5f478e --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAs.hpp @@ -0,0 +1,109 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/IsWriteableString.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class ArrayRef; + class ArrayConstRef; + class ObjectRef; + class ObjectConstRef; + class VariantRef; + class VariantConstRef; + + // A metafunction that returns the type of the value returned by + // VariantRef::as<T>() + template<typename T> + struct VariantAs { + typedef T type; + }; + + template<> + struct VariantAs<char*> { + typedef const char* type; + }; + + // A metafunction that returns the type of the value returned by + // VariantRef::as<T>() + template<typename T> + struct VariantConstAs { + typedef typename VariantAs<T>::type type; + }; + + template<> + struct VariantConstAs<VariantRef> { + typedef VariantConstRef type; + }; + + template<> + struct VariantConstAs<ObjectRef> { + typedef ObjectConstRef type; + }; + + template<> + struct VariantConstAs<ArrayRef> { + typedef ArrayConstRef type; + }; + + // --- + + template<typename T> + inline typename enable_if<is_integral<T>::value && !is_same<bool, T>::value, T>::type variantAs( + const VariantData* data) + { + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); + return data != 0 ? data->asIntegral<T>() : T(0); + } + + template<typename T> + inline typename enable_if<is_enum<T>::value, T>::type variantAs(const VariantData* data) + { + return data != 0 ? static_cast<T>(data->asIntegral<int>()) : T(); + } + + template<typename T> + inline typename enable_if<is_same<T, bool>::value, T>::type variantAs(const VariantData* data) + { + return data != 0 ? data->asBoolean() : false; + } + + template<typename T> + inline typename enable_if<is_floating_point<T>::value, T>::type variantAs(const VariantData* data) + { + return data != 0 ? data->asFloat<T>() : T(0); + } + + template<typename T> + inline typename enable_if<is_same<T, const char*>::value || is_same<T, char*>::value, const char*>::type variantAs( + const VariantData* data) + { + return data != 0 ? data->asString() : 0; + } + + template<typename T> + T variantAs(VariantData* data, MemoryPool*) + { + // By default use the read-only conversion. + // There are specializations for + // - ArrayRef + return variantAs<T>(data); + } + + template<typename T> + inline typename enable_if<is_same<ArrayConstRef, T>::value, T>::type variantAs(const VariantData* data); + + template<typename T> + inline typename enable_if<is_same<ObjectConstRef, T>::value, T>::type variantAs(const VariantData* data); + + template<typename T> + inline typename enable_if<is_same<VariantConstRef, T>::value, T>::type variantAs(const VariantData* data); + + template<typename T> + inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(const VariantData* data); + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAsImpl.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAsImpl.hpp new file mode 100644 index 000000000..102a9b538 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantAsImpl.hpp @@ -0,0 +1,59 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/IsWriteableString.hpp> +#include <ArduinoJson/Variant/VariantFunctions.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + inline typename enable_if<is_same<ArrayConstRef, T>::value, T>::type variantAs(const VariantData* _data) + { + return ArrayConstRef(variantAsArray(_data)); + } + + template<typename T> + inline typename enable_if<is_same<ObjectConstRef, T>::value, T>::type variantAs(const VariantData* _data) + { + return ObjectConstRef(variantAsObject(_data)); + } + + template<typename T> + inline typename enable_if<is_same<VariantConstRef, T>::value, T>::type variantAs(const VariantData* _data) + { + return VariantConstRef(_data); + } + + template<typename T> + inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(const VariantData* _data) + { + const char* cstr = _data != 0 ? _data->asString() : 0; + if (cstr) return T(cstr); + T s; + serializeJson(VariantConstRef(_data), s); + return s; + } + + template<> + inline ArrayRef variantAs<ArrayRef>(VariantData* data, MemoryPool* pool) + { + return ArrayRef(pool, data != 0 ? data->asArray() : 0); + } + + template<> + inline ObjectRef variantAs<ObjectRef>(VariantData* data, MemoryPool* pool) + { + return ObjectRef(pool, data != 0 ? data->asObject() : 0); + } + + template<> + inline VariantRef variantAs<VariantRef>(VariantData* data, MemoryPool* pool) + { + return VariantRef(pool, data); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantCompare.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantCompare.hpp new file mode 100644 index 000000000..30577e5d3 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantCompare.hpp @@ -0,0 +1,230 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Numbers/arithmeticCompare.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/IsString.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + class CollectionData; + + struct ComparerBase : Visitor<CompareResult> { + CompareResult visitArray(const CollectionData&) { return COMPARE_RESULT_DIFFER; } + CompareResult visitBoolean(bool) { return COMPARE_RESULT_DIFFER; } + CompareResult visitFloat(Float) { return COMPARE_RESULT_DIFFER; } + CompareResult visitNegativeInteger(UInt) { return COMPARE_RESULT_DIFFER; } + CompareResult visitNull() { return COMPARE_RESULT_DIFFER; } + CompareResult visitObject(const CollectionData&) { return COMPARE_RESULT_DIFFER; } + CompareResult visitPositiveInteger(UInt) { return COMPARE_RESULT_DIFFER; } + CompareResult visitRawJson(const char*, size_t) { return COMPARE_RESULT_DIFFER; } + CompareResult visitString(const char*) { return COMPARE_RESULT_DIFFER; } + }; + + template<typename T, typename Enable = void> + struct Comparer; + + template<typename T> + struct Comparer<T, typename enable_if<IsString<T>::value>::type> : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitString(const char* lhs) + { + int i = adaptString(rhs).compare(lhs); + if (i < 0) + return COMPARE_RESULT_GREATER; + else if (i > 0) + return COMPARE_RESULT_LESS; + else + return COMPARE_RESULT_EQUAL; + } + + CompareResult visitNull() + { + if (adaptString(rhs).isNull()) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } + }; + + template<typename T> + struct Comparer<T, typename enable_if<is_integral<T>::value || is_floating_point<T>::value>::type> : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitFloat(Float lhs) { return arithmeticCompare(lhs, rhs); } + + CompareResult visitNegativeInteger(UInt lhs) { return arithmeticCompareNegateLeft(lhs, rhs); } + + CompareResult visitPositiveInteger(UInt lhs) { return arithmeticCompare(lhs, rhs); } + + CompareResult visitBoolean(bool lhs) { return visitPositiveInteger(static_cast<UInt>(lhs)); } + }; + + struct NullComparer : ComparerBase { + CompareResult visitNull() { return COMPARE_RESULT_EQUAL; } + }; + +#if ARDUINOJSON_HAS_NULLPTR + template<> + struct Comparer<decltype(nullptr), void> : NullComparer { + explicit Comparer(decltype(nullptr)) : NullComparer() {} + }; +#endif + + struct ArrayComparer : ComparerBase { + const CollectionData* _rhs; + + explicit ArrayComparer(const CollectionData& rhs) : _rhs(&rhs) {} + + CompareResult visitArray(const CollectionData& lhs) + { + if (lhs.equalsArray(*_rhs)) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } + }; + + struct NegativeIntegerComparer : ComparerBase { + UInt _rhs; + + explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {} + + CompareResult visitFloat(Float lhs) { return arithmeticCompareNegateRight(lhs, _rhs); } + + CompareResult visitNegativeInteger(UInt lhs) { return arithmeticCompare(_rhs, lhs); } + + CompareResult visitPositiveInteger(UInt) { return COMPARE_RESULT_GREATER; } + + CompareResult visitBoolean(bool) { return COMPARE_RESULT_GREATER; } + }; + + struct ObjectComparer : ComparerBase { + const CollectionData* _rhs; + + explicit ObjectComparer(const CollectionData& rhs) : _rhs(&rhs) {} + + CompareResult visitObject(const CollectionData& lhs) + { + if (lhs.equalsObject(*_rhs)) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } + }; + + struct RawComparer : ComparerBase { + const char* _rhsData; + size_t _rhsSize; + + explicit RawComparer(const char* rhsData, size_t rhsSize) : _rhsData(rhsData), _rhsSize(rhsSize) {} + + CompareResult visitRawJson(const char* lhsData, size_t lhsSize) + { + size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; + int n = memcmp(lhsData, _rhsData, size); + if (n < 0) + return COMPARE_RESULT_LESS; + else if (n > 0) + return COMPARE_RESULT_GREATER; + else + return COMPARE_RESULT_EQUAL; + } + }; + + template<typename T> + struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type> : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitArray(const CollectionData& lhs) + { + ArrayComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitObject(const CollectionData& lhs) + { + ObjectComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitFloat(Float lhs) + { + Comparer<Float> comparer(lhs); + return accept(comparer); + } + + CompareResult visitString(const char* lhs) + { + Comparer<const char*> comparer(lhs); + return accept(comparer); + } + + CompareResult visitRawJson(const char* lhsData, size_t lhsSize) + { + RawComparer comparer(lhsData, lhsSize); + return accept(comparer); + } + + CompareResult visitNegativeInteger(UInt lhs) + { + NegativeIntegerComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitPositiveInteger(UInt lhs) + { + Comparer<UInt> comparer(lhs); + return accept(comparer); + } + + CompareResult visitBoolean(bool lhs) + { + Comparer<bool> comparer(lhs); + return accept(comparer); + } + + CompareResult visitNull() + { + NullComparer comparer; + return accept(comparer); + } + + private: + template<typename TComparer> + CompareResult accept(TComparer& comparer) + { + CompareResult reversedResult = rhs.accept(comparer); + switch (reversedResult) { + case COMPARE_RESULT_GREATER: return COMPARE_RESULT_LESS; + case COMPARE_RESULT_LESS: return COMPARE_RESULT_GREATER; + default: return reversedResult; + } + } + }; + + template<typename T1, typename T2> + CompareResult compare(const T1& lhs, const T2& rhs) + { + Comparer<T2> comparer(rhs); + return lhs.accept(comparer); + } + + inline int variantCompare(const VariantData* a, const VariantData* b) + { + return compare(VariantConstRef(a), VariantConstRef(b)); + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantContent.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantContent.hpp new file mode 100644 index 000000000..98f9d6b33 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantContent.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stddef.h> // size_t + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // + enum { + VALUE_MASK = 0x7F, + + VALUE_IS_OWNED = 0x01, + VALUE_IS_NULL = 0, + VALUE_IS_LINKED_RAW = 0x02, + VALUE_IS_OWNED_RAW = 0x03, + VALUE_IS_LINKED_STRING = 0x04, + VALUE_IS_OWNED_STRING = 0x05, + + // CAUTION: no VALUE_IS_OWNED below + VALUE_IS_BOOLEAN = 0x06, + VALUE_IS_POSITIVE_INTEGER = 0x08, + VALUE_IS_NEGATIVE_INTEGER = 0x0A, + VALUE_IS_FLOAT = 0x0C, + + COLLECTION_MASK = 0x60, + VALUE_IS_OBJECT = 0x20, + VALUE_IS_ARRAY = 0x40, + + KEY_IS_OWNED = 0x80 + }; + + struct RawData { + const char* data; + size_t size; + }; + + union VariantContent { + Float asFloat; + UInt asInteger; + CollectionData asCollection; + const char* asString; + struct { + const char* data; + size_t size; + } asRaw; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantData.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantData.hpp new file mode 100644 index 000000000..574a9a665 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantData.hpp @@ -0,0 +1,351 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Misc/SerializedValue.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Strings/RamStringAdapter.hpp> +#include <ArduinoJson/Variant/VariantContent.hpp> + +// VariantData can't have a constructor (to be a POD), so we have no way to fix +// this warning +#if defined(__GNUC__) +#if __GNUC__ >= 7 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif +#endif + +namespace ARDUINOJSON_NAMESPACE { + + class VariantData { + VariantContent _content; // must be first to allow cast from array to variant + uint8_t _flags; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + void init() { _flags = 0; } + + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + switch (type()) { + case VALUE_IS_FLOAT: return visitor.visitFloat(_content.asFloat); + + case VALUE_IS_ARRAY: return visitor.visitArray(_content.asCollection); + + case VALUE_IS_OBJECT: return visitor.visitObject(_content.asCollection); + + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: return visitor.visitString(_content.asString); + + case VALUE_IS_OWNED_RAW: + case VALUE_IS_LINKED_RAW: return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size); + + case VALUE_IS_NEGATIVE_INTEGER: return visitor.visitNegativeInteger(_content.asInteger); + + case VALUE_IS_POSITIVE_INTEGER: return visitor.visitPositiveInteger(_content.asInteger); + + case VALUE_IS_BOOLEAN: return visitor.visitBoolean(_content.asInteger != 0); + + default: return visitor.visitNull(); + } + } + + template<typename T> + T asIntegral() const; + + template<typename T> + T asFloat() const; + + const char* asString() const; + + bool asBoolean() const; + + CollectionData* asArray() { return isArray() ? &_content.asCollection : 0; } + + const CollectionData* asArray() const { return const_cast<VariantData*>(this)->asArray(); } + + CollectionData* asObject() { return isObject() ? &_content.asCollection : 0; } + + const CollectionData* asObject() const { return const_cast<VariantData*>(this)->asObject(); } + + bool copyFrom(const VariantData& src, MemoryPool* pool) + { + switch (src.type()) { + case VALUE_IS_ARRAY: return toArray().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OBJECT: return toObject().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OWNED_STRING: return setString(RamStringAdapter(src._content.asString), pool); + case VALUE_IS_OWNED_RAW: return setOwnedRaw(serialized(src._content.asRaw.data, src._content.asRaw.size), pool); + default: + setType(src.type()); + _content = src._content; + return true; + } + } + + bool isArray() const { return (_flags & VALUE_IS_ARRAY) != 0; } + + bool isBoolean() const { return type() == VALUE_IS_BOOLEAN; } + + bool isCollection() const { return (_flags & COLLECTION_MASK) != 0; } + + template<typename T> + bool isInteger() const + { + switch (type()) { + case VALUE_IS_POSITIVE_INTEGER: return canStorePositiveInteger<T>(_content.asInteger); + + case VALUE_IS_NEGATIVE_INTEGER: return canStoreNegativeInteger<T>(_content.asInteger); + + default: return false; + } + } + + bool isFloat() const + { + return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER || type() == VALUE_IS_NEGATIVE_INTEGER; + } + + bool isString() const { return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; } + + bool isObject() const { return (_flags & VALUE_IS_OBJECT) != 0; } + + bool isNull() const { return type() == VALUE_IS_NULL; } + + bool isEnclosed() const { return !isFloat(); } + + void remove(size_t index) + { + if (isArray()) _content.asCollection.removeElement(index); + } + + template<typename TAdaptedString> + void remove(TAdaptedString key) + { + if (isObject()) _content.asCollection.removeMember(key); + } + + void setBoolean(bool value) + { + setType(VALUE_IS_BOOLEAN); + _content.asInteger = static_cast<UInt>(value); + } + + void setFloat(Float value) + { + setType(VALUE_IS_FLOAT); + _content.asFloat = value; + } + + void setLinkedRaw(SerializedValue<const char*> value) + { + if (value.data()) { + setType(VALUE_IS_LINKED_RAW); + _content.asRaw.data = value.data(); + _content.asRaw.size = value.size(); + } else { + setType(VALUE_IS_NULL); + } + } + + template<typename T> + bool setOwnedRaw(SerializedValue<T> value, MemoryPool* pool) + { + const char* dup = pool->saveString(adaptString(value.data(), value.size())); + if (dup) { + setType(VALUE_IS_OWNED_RAW); + _content.asRaw.data = dup; + _content.asRaw.size = value.size(); + return true; + } else { + setType(VALUE_IS_NULL); + return false; + } + } + + template<typename T> + typename enable_if<is_unsigned<T>::value>::type setInteger(T value) + { + setUnsignedInteger(value); + } + + template<typename T> + typename enable_if<is_signed<T>::value>::type setInteger(T value) + { + setSignedInteger(value); + } + + template<typename T> + void setSignedInteger(T value) + { + if (value >= 0) { + setPositiveInteger(static_cast<UInt>(value)); + } else { + setNegativeInteger(~static_cast<UInt>(value) + 1); + } + } + + void setUnsignedInteger(UInt value) + { + setType(VALUE_IS_POSITIVE_INTEGER); + _content.asInteger = static_cast<UInt>(value); + } + + void setPositiveInteger(UInt value) + { + setType(VALUE_IS_POSITIVE_INTEGER); + _content.asInteger = value; + } + + void setNegativeInteger(UInt value) + { + setType(VALUE_IS_NEGATIVE_INTEGER); + _content.asInteger = value; + } + + void setNull() { setType(VALUE_IS_NULL); } + + void setStringPointer(const char* s, storage_policies::store_by_copy) + { + setType(VALUE_IS_OWNED_STRING); + _content.asString = s; + } + + void setStringPointer(const char* s, storage_policies::store_by_address) + { + setType(VALUE_IS_LINKED_STRING); + _content.asString = s; + } + + template<typename TAdaptedString> + bool setString(TAdaptedString value, MemoryPool* pool) + { + return setString(value, pool, typename TAdaptedString::storage_policy()); + } + + template<typename TAdaptedString> + inline bool setString(TAdaptedString value, MemoryPool* pool, storage_policies::decide_at_runtime) + { + if (value.isStatic()) + return setString(value, pool, storage_policies::store_by_address()); + else + return setString(value, pool, storage_policies::store_by_copy()); + } + + template<typename TAdaptedString> + inline bool setString(TAdaptedString value, MemoryPool*, storage_policies::store_by_address) + { + if (value.isNull()) + setNull(); + else + setStringPointer(value.data(), storage_policies::store_by_address()); + return true; + } + + template<typename TAdaptedString> + inline bool setString(TAdaptedString value, MemoryPool* pool, storage_policies::store_by_copy) + { + if (value.isNull()) { + setNull(); + return true; + } + const char* copy = pool->saveString(value); + if (!copy) { + setNull(); + return false; + } + setStringPointer(copy, storage_policies::store_by_copy()); + return true; + } + + CollectionData& toArray() + { + setType(VALUE_IS_ARRAY); + _content.asCollection.clear(); + return _content.asCollection; + } + + CollectionData& toObject() + { + setType(VALUE_IS_OBJECT); + _content.asCollection.clear(); + return _content.asCollection; + } + + size_t memoryUsage() const + { + switch (type()) { + case VALUE_IS_OWNED_STRING: return strlen(_content.asString) + 1; + case VALUE_IS_OWNED_RAW: return _content.asRaw.size; + case VALUE_IS_OBJECT: + case VALUE_IS_ARRAY: return _content.asCollection.memoryUsage(); + default: return 0; + } + } + + size_t nesting() const { return isCollection() ? _content.asCollection.nesting() : 0; } + + size_t size() const { return isCollection() ? _content.asCollection.size() : 0; } + + VariantData* addElement(MemoryPool* pool) + { + if (isNull()) toArray(); + if (!isArray()) return 0; + return _content.asCollection.addElement(pool); + } + + VariantData* getElement(size_t index) const { return isArray() ? _content.asCollection.getElement(index) : 0; } + + VariantData* getOrAddElement(size_t index, MemoryPool* pool) + { + if (isNull()) toArray(); + if (!isArray()) return 0; + return _content.asCollection.getOrAddElement(index, pool); + } + + template<typename TAdaptedString> + VariantData* getMember(TAdaptedString key) const + { + return isObject() ? _content.asCollection.getMember(key) : 0; + } + + template<typename TAdaptedString> + VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool) + { + if (isNull()) toObject(); + if (!isObject()) return 0; + return _content.asCollection.getOrAddMember(key, pool); + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) + { + if (_flags & VALUE_IS_OWNED) _content.asString += stringDistance; + if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); + } + + uint8_t type() const { return _flags & VALUE_MASK; } + + private: + void setType(uint8_t t) + { + _flags &= KEY_IS_OWNED; + _flags |= t; + } + }; + +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__GNUC__) +#if __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantFunctions.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantFunctions.hpp new file mode 100644 index 000000000..d9cf3d3a5 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantFunctions.hpp @@ -0,0 +1,142 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TVisitor> + inline typename TVisitor::result_type variantAccept(const VariantData* var, TVisitor& visitor) + { + if (var != 0) + return var->accept(visitor); + else + return visitor.visitNull(); + } + + inline const CollectionData* variantAsArray(const VariantData* var) { return var != 0 ? var->asArray() : 0; } + + inline const CollectionData* variantAsObject(const VariantData* var) { return var != 0 ? var->asObject() : 0; } + + inline CollectionData* variantAsObject(VariantData* var) { return var != 0 ? var->asObject() : 0; } + + inline bool variantCopyFrom(VariantData* dst, const VariantData* src, MemoryPool* pool) + { + if (!dst) return false; + if (!src) { + dst->setNull(); + return true; + } + return dst->copyFrom(*src, pool); + } + + inline int variantCompare(const VariantData* a, const VariantData* b); + + inline bool variantIsArray(const VariantData* var) { return var && var->isArray(); } + + inline bool variantIsBoolean(const VariantData* var) { return var && var->isBoolean(); } + + template<typename T> + inline bool variantIsInteger(const VariantData* var) + { + return var && var->isInteger<T>(); + } + + inline bool variantIsFloat(const VariantData* var) { return var && var->isFloat(); } + + inline bool variantIsString(const VariantData* var) { return var && var->isString(); } + + inline bool variantIsObject(const VariantData* var) { return var && var->isObject(); } + + inline bool variantIsNull(const VariantData* var) { return var == 0 || var->isNull(); } + + inline bool variantSetBoolean(VariantData* var, bool value) + { + if (!var) return false; + var->setBoolean(value); + return true; + } + + inline bool variantSetFloat(VariantData* var, Float value) + { + if (!var) return false; + var->setFloat(value); + return true; + } + + inline bool variantSetLinkedRaw(VariantData* var, SerializedValue<const char*> value) + { + if (!var) return false; + var->setLinkedRaw(value); + return true; + } + + template<typename T> + inline bool variantSetOwnedRaw(VariantData* var, SerializedValue<T> value, MemoryPool* pool) + { + return var != 0 && var->setOwnedRaw(value, pool); + } + + inline void variantSetNull(VariantData* var) + { + if (!var) return; + var->setNull(); + } + + template<typename TAdaptedString> + inline bool variantSetString(VariantData* var, TAdaptedString value, MemoryPool* pool) + { + if (!var) return false; + return var->setString(value, pool); + } + + template<typename T> + inline bool variantSetInteger(VariantData* var, T value) + { + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); + if (!var) return false; + var->setInteger(value); + return true; + } + + inline size_t variantSize(const VariantData* var) { return var != 0 ? var->size() : 0; } + + inline CollectionData* variantToArray(VariantData* var) + { + if (!var) return 0; + return &var->toArray(); + } + + inline CollectionData* variantToObject(VariantData* var) + { + if (!var) return 0; + return &var->toObject(); + } + + inline NO_INLINE VariantData* variantAddElement(VariantData* var, MemoryPool* pool) + { + return var != 0 ? var->addElement(pool) : 0; + } + + inline NO_INLINE VariantData* variantGetOrAddElement(VariantData* var, size_t index, MemoryPool* pool) + { + return var != 0 ? var->getOrAddElement(index, pool) : 0; + } + + template<typename TChar> + NO_INLINE VariantData* variantGetOrAddMember(VariantData* var, TChar* key, MemoryPool* pool) + { + return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; + } + + template<typename TString> + NO_INLINE VariantData* variantGetOrAddMember(VariantData* var, const TString& key, MemoryPool* pool) + { + return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; + } + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantImpl.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantImpl.hpp new file mode 100644 index 000000000..5f6d8fd0a --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantImpl.hpp @@ -0,0 +1,139 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Numbers/parseNumber.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +#include <string.h> // for strcmp + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T> + inline T VariantData::asIntegral() const + { + switch (type()) { + case VALUE_IS_POSITIVE_INTEGER: + case VALUE_IS_BOOLEAN: return convertPositiveInteger<T>(_content.asInteger); + case VALUE_IS_NEGATIVE_INTEGER: return convertNegativeInteger<T>(_content.asInteger); + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: return parseNumber<T>(_content.asString); + case VALUE_IS_FLOAT: return convertFloat<T>(_content.asFloat); + default: return 0; + } + } + + inline bool VariantData::asBoolean() const + { + switch (type()) { + case VALUE_IS_POSITIVE_INTEGER: + case VALUE_IS_BOOLEAN: + case VALUE_IS_NEGATIVE_INTEGER: return _content.asInteger != 0; + case VALUE_IS_FLOAT: return _content.asFloat != 0; + case VALUE_IS_NULL: return false; + default: return true; + } + } + + // T = float/double + template<typename T> + inline T VariantData::asFloat() const + { + switch (type()) { + case VALUE_IS_POSITIVE_INTEGER: + case VALUE_IS_BOOLEAN: return static_cast<T>(_content.asInteger); + case VALUE_IS_NEGATIVE_INTEGER: return -static_cast<T>(_content.asInteger); + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: return parseNumber<T>(_content.asString); + case VALUE_IS_FLOAT: return static_cast<T>(_content.asFloat); + default: return 0; + } + } + + inline const char* VariantData::asString() const + { + switch (type()) { + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: return _content.asString; + default: return 0; + } + } + + template<typename TVariant> + typename enable_if<IsVisitable<TVariant>::value, bool>::type VariantRef::set(const TVariant& value) const + { + VariantConstRef v = value; + return variantCopyFrom(_data, v._data, _pool); + } + + template<typename T> + inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type VariantRef::to() const + { + return ArrayRef(_pool, variantToArray(_data)); + } + + template<typename T> + typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type VariantRef::to() const + { + return ObjectRef(_pool, variantToObject(_data)); + } + + template<typename T> + typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type VariantRef::to() const + { + variantSetNull(_data); + return *this; + } + + inline VariantConstRef VariantConstRef::getElement(size_t index) const + { + return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; + } + + inline VariantRef VariantRef::addElement() const { return VariantRef(_pool, variantAddElement(_data, _pool)); } + + inline VariantRef VariantRef::getElement(size_t index) const + { + return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0); + } + + inline VariantRef VariantRef::getOrAddElement(size_t index) const + { + return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool)); + } + + template<typename TChar> + inline VariantRef VariantRef::getMember(TChar* key) const + { + return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); + } + + template<typename TString> + inline typename enable_if<IsString<TString>::value, VariantRef>::type VariantRef::getMember(const TString& key) const + { + return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); + } + + template<typename TChar> + inline VariantRef VariantRef::getOrAddMember(TChar* key) const + { + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); + } + + template<typename TString> + inline VariantRef VariantRef::getOrAddMember(const TString& key) const + { + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); + } + + inline VariantConstRef operator|(VariantConstRef preferedValue, VariantConstRef defaultValue) + { + return preferedValue ? preferedValue : defaultValue; + } +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantOperators.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantOperators.hpp new file mode 100644 index 000000000..e0bad1dfe --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantOperators.hpp @@ -0,0 +1,185 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Numbers/arithmeticCompare.hpp> +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantAs.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename T1, typename T2> + CompareResult compare(const T1& lhs, const T2& rhs); // VariantCompare.cpp + + template<typename TVariant> + struct VariantOperators { + // Returns the default value if the VariantRef is undefined of incompatible + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, T>::type operator|(const TVariant& variant, const T& defaultValue) + { + if (variant.template is<T>()) + return variant.template as<T>(); + else + return defaultValue; + } + + // Returns the default value if the VariantRef is undefined of incompatible + // Special case for string: null is treated as undefined + template<typename T> + friend typename enable_if<is_same<T, const char*>::value, T>::type operator|( + const TVariant& variant, + T defaultValue) + { + const char* value = variant.template as<const char*>(); + return value ? value : defaultValue; + } + + // value == TVariant + template<typename T> + friend bool operator==(T* lhs, TVariant rhs) + { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; + } + template<typename T> + friend bool operator==(const T& lhs, TVariant rhs) + { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; + } + + // TVariant == value + template<typename T> + friend bool operator==(TVariant lhs, T* rhs) + { + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; + } + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(TVariant lhs, const T& rhs) + { + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; + } + + // value != TVariant + template<typename T> + friend bool operator!=(T* lhs, TVariant rhs) + { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; + } + template<typename T> + friend bool operator!=(const T& lhs, TVariant rhs) + { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; + } + + // TVariant != value + template<typename T> + friend bool operator!=(TVariant lhs, T* rhs) + { + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; + } + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(TVariant lhs, const T& rhs) + { + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; + } + + // value < TVariant + template<typename T> + friend bool operator<(T* lhs, TVariant rhs) + { + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; + } + template<typename T> + friend bool operator<(const T& lhs, TVariant rhs) + { + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; + } + + // TVariant < value + template<typename T> + friend bool operator<(TVariant lhs, T* rhs) + { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; + } + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<(TVariant lhs, const T& rhs) + { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; + } + + // value <= TVariant + template<typename T> + friend bool operator<=(T* lhs, TVariant rhs) + { + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + template<typename T> + friend bool operator<=(const T& lhs, TVariant rhs) + { + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + + // TVariant <= value + template<typename T> + friend bool operator<=(TVariant lhs, T* rhs) + { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=(TVariant lhs, const T& rhs) + { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + + // value > TVariant + template<typename T> + friend bool operator>(T* lhs, TVariant rhs) + { + return compare(rhs, lhs) == COMPARE_RESULT_LESS; + } + template<typename T> + friend bool operator>(const T& lhs, TVariant rhs) + { + return compare(rhs, lhs) == COMPARE_RESULT_LESS; + } + + // TVariant > value + template<typename T> + friend bool operator>(TVariant lhs, T* rhs) + { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; + } + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>(TVariant lhs, const T& rhs) + { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; + } + + // value >= TVariant + template<typename T> + friend bool operator>=(T* lhs, TVariant rhs) + { + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + template<typename T> + friend bool operator>=(const T& lhs, TVariant rhs) + { + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + + // TVariant >= value + template<typename T> + friend bool operator>=(TVariant lhs, T* rhs) + { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + template<typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=(TVariant lhs, const T& rhs) + { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantRef.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantRef.hpp new file mode 100644 index 000000000..3d77bf275 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantRef.hpp @@ -0,0 +1,386 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stddef.h> +#include <stdint.h> // for uint8_t + +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StringAdapters.hpp> +#include <ArduinoJson/Variant/VariantAs.hpp> +#include <ArduinoJson/Variant/VariantFunctions.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + // Forward declarations. + class ArrayRef; + class ObjectRef; + + template<typename, typename> + class MemberProxy; + + // Contains the methods shared by VariantRef and VariantConstRef + template<typename TData> + class VariantRefBase { + public: + // Tells wether the variant has the specified type. + // Returns true if the variant has type type T, false otherwise. + // + // bool is<char>() const; + // bool is<signed char>() const; + // bool is<signed short>() const; + // bool is<signed int>() const; + // bool is<signed long>() const; + // bool is<unsigned char>() const; + // bool is<unsigned short>() const; + // bool is<unsigned int>() const; + // bool is<unsigned long>() const; + template<typename T> + FORCE_INLINE typename enable_if<is_integral<T>::value && !is_same<bool, T>::value, bool>::type is() const + { + return variantIsInteger<T>(_data); + } + // + // bool is<double>() const; + // bool is<float>() const; + template<typename T> + FORCE_INLINE typename enable_if<is_floating_point<T>::value, bool>::type is() const + { + return variantIsFloat(_data); + } + // + // bool is<bool>() const + template<typename T> + FORCE_INLINE typename enable_if<is_same<T, bool>::value, bool>::type is() const + { + return variantIsBoolean(_data); + } + // + // bool is<const char*>() const; + // bool is<char*>() const; + // bool is<std::string>() const; + // bool is<String>() const; + template<typename T> + FORCE_INLINE typename enable_if< + is_same<T, const char*>::value || is_same<T, char*>::value || IsWriteableString<T>::value, + bool>::type + is() const + { + return variantIsString(_data); + } + // + // bool is<ArrayRef> const; + // bool is<const ArrayRef> const; + template<typename T> + FORCE_INLINE typename enable_if<is_same<typename remove_const<T>::type, ArrayRef>::value, bool>::type is() const + { + return variantIsArray(_data); + } + // + // bool is<ObjectRef> const; + // bool is<const ObjectRef> const; + template<typename T> + FORCE_INLINE typename enable_if<is_same<typename remove_const<T>::type, ObjectRef>::value, bool>::type is() const + { + return variantIsObject(_data); + } +#if ARDUINOJSON_HAS_NULLPTR + // + // bool is<nullptr_t> const; + template<typename T> + FORCE_INLINE typename enable_if<is_same<T, decltype(nullptr)>::value, bool>::type is() const + { + return variantIsNull(_data); + } +#endif + // bool is<enum>() const; + template<typename T> + FORCE_INLINE typename enable_if<is_enum<T>::value, bool>::type is() const + { + return variantIsInteger<int>(_data); + } + + FORCE_INLINE bool isNull() const { return variantIsNull(_data); } + + FORCE_INLINE bool isUndefined() const { return !_data; } + + FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } + + FORCE_INLINE size_t nesting() const { return _data ? _data->nesting() : 0; } + + size_t size() const { return variantSize(_data); } + + protected: + VariantRefBase(TData* data) : _data(data) {} + TData* _data; + }; + + // A variant that can be a any value serializable to a JSON value. + // + // It can be set to: + // - a boolean + // - a char, short, int or a long (signed or unsigned) + // - a string (const char*) + // - a reference to a ArrayRef or ObjectRef + class VariantRef : public VariantRefBase<VariantData>, + public VariantOperators<VariantRef>, + public VariantShortcuts<VariantRef>, + public Visitable { + typedef VariantRefBase<VariantData> base_type; + friend class VariantConstRef; + + public: + // Intenal use only + FORCE_INLINE VariantRef(MemoryPool* pool, VariantData* data) : base_type(data), _pool(pool) {} + + // Creates an uninitialized VariantRef + FORCE_INLINE VariantRef() : base_type(0), _pool(0) {} + + FORCE_INLINE void clear() const { return variantSetNull(_data); } + + // set(bool value) + template<typename T> + FORCE_INLINE bool set(T value, typename enable_if<is_same<T, bool>::value>::type* = 0) const + { + return variantSetBoolean(_data, value); + } + + // set(double value); + // set(float value); + template<typename T> + FORCE_INLINE bool set(T value, typename enable_if<is_floating_point<T>::value>::type* = 0) const + { + return variantSetFloat(_data, static_cast<Float>(value)); + } + + // set(char) + // set(signed short) + // set(signed int) + // set(signed long) + // set(signed char) + // set(unsigned short) + // set(unsigned int) + // set(unsigned long) + template<typename T> + FORCE_INLINE bool set(T value, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value>::type* = 0) + const + { + return variantSetInteger<T>(_data, value); + } + + // set(SerializedValue<const char *>) + FORCE_INLINE bool set(SerializedValue<const char*> value) const { return variantSetLinkedRaw(_data, value); } + + // set(SerializedValue<std::string>) + // set(SerializedValue<String>) + // set(SerializedValue<const __FlashStringHelper*>) + template<typename T> + FORCE_INLINE bool set(SerializedValue<T> value, typename enable_if<!is_same<const char*, T>::value>::type* = 0) + const + { + return variantSetOwnedRaw(_data, value, _pool); + } + + // set(const std::string&) + // set(const String&) + template<typename T> + FORCE_INLINE bool set(const T& value, typename enable_if<IsString<T>::value>::type* = 0) const + { + return variantSetString(_data, adaptString(value), _pool); + } + // set(char*) + // set(const __FlashStringHelper*) + // set(const char*) + template<typename T> + FORCE_INLINE bool set(T* value, typename enable_if<IsString<T*>::value>::type* = 0) const + { + return variantSetString(_data, adaptString(value), _pool); + } + + // set(VariantRef) + // set(VariantConstRef) + // set(ArrayRef) + // set(ArrayConstRef) + // set(ObjectRef) + // set(ObjecConstRef) + // set(const JsonDocument&) + template<typename TVariant> + typename enable_if<IsVisitable<TVariant>::value, bool>::type set(const TVariant& value) const; + + // set(enum value) + template<typename T> + FORCE_INLINE bool set(T value, typename enable_if<is_enum<T>::value>::type* = 0) const + { + return variantSetInteger(_data, static_cast<Integer>(value)); + } + +#if ARDUINOJSON_HAS_NULLPTR + // set(nullptr_t) + FORCE_INLINE bool set(decltype(nullptr)) const + { + variantSetNull(_data); + return true; + } +#endif + + template<typename T> + FORCE_INLINE typename VariantAs<T>::type as() const + { + return variantAs<typename VariantAs<T>::type>(_data, _pool); + } + + template<typename T> + FORCE_INLINE operator T() const + { + return variantAs<T>(_data, _pool); + } + + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + return variantAccept(_data, visitor); + } + + // Change the type of the variant + // + // ArrayRef to<ArrayRef>() + template<typename T> + typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type to() const; + // + // ObjectRef to<ObjectRef>() + template<typename T> + typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type to() const; + // + // ObjectRef to<VariantRef>() + template<typename T> + typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type to() const; + + VariantRef addElement() const; + + FORCE_INLINE VariantRef getElement(size_t) const; + + FORCE_INLINE VariantRef getOrAddElement(size_t) const; + + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantRef getMember(TChar*) const; + + // getMember(const std::string&) const + // getMember(const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type getMember(const TString&) const; + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar*) const; + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template<typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString&) const; + + FORCE_INLINE void remove(size_t index) const + { + if (_data) _data->remove(index); + } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(TChar* key) const + { + if (_data) _data->remove(adaptString(key)); + } + // remove(const std::string&) const + // remove(const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(const TString& key) const + { + if (_data) _data->remove(adaptString(key)); + } + + private: + MemoryPool* _pool; + }; // namespace ARDUINOJSON_NAMESPACE + + class VariantConstRef : public VariantRefBase<const VariantData>, + public VariantOperators<VariantConstRef>, + public VariantShortcuts<VariantConstRef>, + public Visitable { + typedef VariantRefBase<const VariantData> base_type; + friend class VariantRef; + + public: + VariantConstRef() : base_type(0) {} + VariantConstRef(const VariantData* data) : base_type(data) {} + VariantConstRef(VariantRef var) : base_type(var._data) {} + + template<typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const + { + return variantAccept(_data, visitor); + } + + template<typename T> + FORCE_INLINE typename VariantConstAs<T>::type as() const + { + return variantAs<typename VariantConstAs<T>::type>(_data); + } + + template<typename T> + FORCE_INLINE operator T() const + { + return variantAs<T>(_data); + } + + FORCE_INLINE VariantConstRef getElement(size_t) const; + + FORCE_INLINE VariantConstRef operator[](size_t index) const { return getElement(index); } + + // getMember(const std::string&) const + // getMember(const String&) const + template<typename TString> + FORCE_INLINE VariantConstRef getMember(const TString& key) const + { + return VariantConstRef(objectGetMember(variantAsObject(_data), adaptString(key))); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar* key) const + { + const CollectionData* obj = variantAsObject(_data); + return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template<typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantConstRef>::type operator[]( + const TString& key) const + { + return getMember(key); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template<typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, VariantConstRef>::type operator[](TChar* key) const + { + return getMember(key); + } + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantShortcuts.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantShortcuts.hpp new file mode 100644 index 000000000..b4c204811 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantShortcuts.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayShortcuts.hpp> +#include <ArduinoJson/Object/ObjectShortcuts.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + template<typename TVariant> + class VariantShortcuts : public ObjectShortcuts<TVariant>, public ArrayShortcuts<TVariant> { + public: + using ArrayShortcuts<TVariant>::createNestedArray; + using ArrayShortcuts<TVariant>::createNestedObject; + using ArrayShortcuts<TVariant>::operator[]; + using ObjectShortcuts<TVariant>::createNestedArray; + using ObjectShortcuts<TVariant>::createNestedObject; + using ObjectShortcuts<TVariant>::operator[]; + }; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantSlot.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantSlot.hpp new file mode 100644 index 000000000..8631a2a98 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantSlot.hpp @@ -0,0 +1,94 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <stdint.h> // int8_t, int16_t + +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> +#include <ArduinoJson/Variant/VariantContent.hpp> + +namespace ARDUINOJSON_NAMESPACE { + + typedef conditional<sizeof(void*) <= 2, int8_t, int16_t>::type VariantSlotDiff; + + class VariantSlot { + // CAUTION: same layout as VariantData + // we cannot use composition because it adds padding + // (+20% on ESP8266 for example) + VariantContent _content; + uint8_t _flags; + VariantSlotDiff _next; + const char* _key; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + + VariantData* data() { return reinterpret_cast<VariantData*>(&_content); } + + const VariantData* data() const { return reinterpret_cast<const VariantData*>(&_content); } + + VariantSlot* next() { return _next ? this + _next : 0; } + + const VariantSlot* next() const { return const_cast<VariantSlot*>(this)->next(); } + + VariantSlot* next(size_t distance) + { + VariantSlot* slot = this; + while (distance--) { + if (!slot->_next) return 0; + slot += slot->_next; + } + return slot; + } + + const VariantSlot* next(size_t distance) const { return const_cast<VariantSlot*>(this)->next(distance); } + + void setNext(VariantSlot* slot) { _next = VariantSlotDiff(slot ? slot - this : 0); } + + void setNextNotNull(VariantSlot* slot) + { + ARDUINOJSON_ASSERT(slot != 0); + _next = VariantSlotDiff(slot - this); + } + + void setKey(const char* k, storage_policies::store_by_copy) + { + ARDUINOJSON_ASSERT(k != NULL); + _flags |= KEY_IS_OWNED; + _key = k; + } + + void setKey(const char* k, storage_policies::store_by_address) + { + ARDUINOJSON_ASSERT(k != NULL); + _flags &= VALUE_MASK; + _key = k; + } + + const char* key() const { return _key; } + + bool ownsKey() const { return (_flags & KEY_IS_OWNED) != 0; } + + void clear() + { + _next = 0; + _flags = 0; + _key = 0; + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) + { + if (_flags & KEY_IS_OWNED) _key += stringDistance; + if (_flags & VALUE_IS_OWNED) _content.asString += stringDistance; + if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); + } + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantTo.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantTo.hpp new file mode 100644 index 000000000..7bf44c7a0 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/Variant/VariantTo.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + class ArrayRef; + class ObjectRef; + class VariantRef; + + // A metafunction that returns the type of the value returned by + // VariantRef::to<T>() + template<typename T> + struct VariantTo { + }; + + template<> + struct VariantTo<ArrayRef> { + typedef ArrayRef type; + }; + template<> + struct VariantTo<ObjectRef> { + typedef ObjectRef type; + }; + template<> + struct VariantTo<VariantRef> { + typedef VariantRef type; + }; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/compatibility.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/compatibility.hpp new file mode 100644 index 000000000..eadaca901 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/compatibility.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License +// +// clang-format off + +#ifdef __GNUC__ + +#define ARDUINOJSON_PRAGMA(x) _Pragma(#x) + +#define ARDUINOJSON_COMPILE_ERROR(msg) ARDUINOJSON_PRAGMA(GCC error msg) + +#define ARDUINOJSON_STRINGIFY(S) #S + +#define ARDUINOJSON_DEPRECATION_ERROR(X, Y) \ + ARDUINOJSON_COMPILE_ERROR(ARDUINOJSON_STRINGIFY(X is a Y from ArduinoJson 5. Please see arduinojson.org/upgrade to learn how to upgrade your program to ArduinoJson version 6)) + +#define StaticJsonBuffer ARDUINOJSON_DEPRECATION_ERROR(StaticJsonBuffer, class) +#define DynamicJsonBuffer ARDUINOJSON_DEPRECATION_ERROR(DynamicJsonBuffer, class) +#define JsonBuffer ARDUINOJSON_DEPRECATION_ERROR(JsonBuffer, class) +#define RawJson ARDUINOJSON_DEPRECATION_ERROR(RawJson, function) + +#endif diff --git a/Online/EventBuilding/include/infiniband_net/ArduinoJson/version.hpp b/Online/EventBuilding/include/infiniband_net/ArduinoJson/version.hpp new file mode 100644 index 000000000..03479c390 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ArduinoJson/version.hpp @@ -0,0 +1,10 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#define ARDUINOJSON_VERSION "6.16.1" +#define ARDUINOJSON_VERSION_MAJOR 6 +#define ARDUINOJSON_VERSION_MINOR 16 +#define ARDUINOJSON_VERSION_REVISION 1 diff --git a/Online/EventBuilding/include/infiniband_net/ib.hpp b/Online/EventBuilding/include/infiniband_net/ib.hpp new file mode 100644 index 000000000..45d4b5fb5 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/ib.hpp @@ -0,0 +1,586 @@ +/** + * @file ib.hpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ + +#ifndef IB_H +#define IB_H + +constexpr int PARALLEL_WRS = 10; + +#define VERSION "0.1.7" +#include <infiniband/verbs.h> +#include <vector> +#include <array> +#include <netinet/in.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/ip.h> +#include <sys/time.h> +#include <arpa/inet.h> +#include "sock.hpp" +#include "parser.hpp" +#include <thread> +#include <mutex> +#include <atomic> +#include <unordered_map> +#include <future> +#include <stdexcept> +#include <errno.h> + +// #define IB_DUMP_FILE 1 + +/** + * @class ib ib.hpp + * @brief InfiniBand Communication Library + * + * This library implements an high-level API to + * enable InfiniBand communication between machines. + * It is written in InfiniBand verbs in order to + * have maximum customization and achieve best performance. + * + * @author Alberto Perro (alberto.perro@cern.ch) + * @date 24/03/2021 + */ + +namespace IB_verbs { + class IB { + public: + /** + * @brief Construct a new empty ib object + * + */ + IB(); + /** + * @brief Default move constructor + * + * @param src The ib object to move + */ + IB(IB&& src); + /** + * @brief Construct a new ib object with host file and process number + * Construct a new ib object and call ibParseHosts method in + * order to configure the object. + * @param filename Host file formatted in JSON. + * @param nProc Number of the global process, start from 0. + */ + IB(const char* filename, const int nProc); + /** + * @brief Construct a new ib object with host file + * Construct a new ib object and call ibParseHosts method in + * order to configure the object. + * Host id is determined by reading the environment variable UTGID. + * @param filename Host file formatted in JSON. + */ + IB(const char* filename); + /** + * @brief Host file parser + * Parse a Host file formatted in JSON where the hostname, TCP port + * and IB device are assigned to every process. + * + * @param filename Host file formatted in JSON. + * @param nProc Number of the global process, start from 0. + * @return int + */ + int ibParseHosts(const char* filename, const int nProc); + /** + * @brief Host file parser + * Parse a Host file formatted in JSON where the hostname, TCP port + * and IB device are assigned to every process. + * Localhost is determined by reading the environment variable UTGID + * @param filename Host file formatted in JSON. + * @return int + */ + int ibParseHosts(const char* filename); + /** + * @brief Initialization of the ib object + * Open IB device, set protection domain, set completion queues, + * set TCP server for receiving queue pairs on a separate thread. + * Send QP information to all the hosts, wait to receive all QP info, + * set the QPs to Ready-To-Send, initialize sync requests, start sync thread, + * compute barrier host LUT. + */ + void ibInit(); + /** + * @brief Register a Memory Region + * Register a Memory Region to the IB device. + * The MR is defined by a pointer and a size. + * MRs are saved in a list, so this method + * has to be called only once. + * The memory must be aligned in sizes of 4096 B. + * @param bufPtr Pointer to the memory. + * @param bufSize Size of the memory. + * @param access_flags optional IBV access flags + * @return ibv_mr* Pointer to the MR object. NULL if error. + */ + ibv_mr* ibAddMR( + char* bufPtr, + size_t bufSize, + int access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE); + /** + * @brief Deregister a Memory Region + * Deregister a Memory Region from the IB device. + * To indentify the MR, the pointer and size must be passed. + * It also removes the MR from the list. + * ibAddMr must be called in order to use this memory again. + * @param bufPtr Pointer to the memory. + * @param bufSize Size of the memory. + * @return int 0 for success, -1 for error. + */ + int ibRemoveMR(char* bufPtr, size_t bufSize); + /** + * @brief Receive data from a remote source + * Post a Receive Request (RR) and retreive a Work ID associated + * to this request. + * Polling of the Receive Completion Queue must be done in + * order to know the status of the request. + * This method is non-blocking. + * @param bufPtr Pointer to the buffer where incoming data will be written. + * @param bufSize Size of the buffer for the incoming data. + * @param sender Source ID, corresponds to the position in the host file. + * @return uint32_t Work ID associated with this RR. + */ + uint32_t ibRecv(char* bufPtr, uint32_t bufSize, uint32_t sender); + /** + * @brief Send data to a remote destination + * Post a Send Request (SR) and retreive a Work ID associated + * to this request. + * Polling of the Send Completion Queue must be done in + * order to know the status of the request. + * This method is non-blocking. + * @param bufPtr Pointer to the buffer to be sent. + * @param bufSize Size of the buffer. + * @param dest Desitination ID, corresponds to the position in the host file. + * @return uint32_t Work ID associated with this SR. + */ + uint32_t ibSend(char* bufPtr, uint32_t bufSize, uint32_t dest); + /** + * @brief Receive data from a remote source (blocking) + * Post a Receive Request (RR), poll the Receive Completion Queue + * order to retreive the status of the request. + * This method is blocking. + * @param bufPtr Pointer to the buffer where incoming data will be written. + * @param bufSize Size of the buffer for the incoming data. + * @param sender Source ID, corresponds to the position in the host file. + * @return int 0 for success, -1 for error. + */ + int ibBlockRecv(char* bufPtr, uint32_t bufSize, uint32_t sender); + /** + * @brief Send data to a remote destination (blocking) + * Post a Send Request (SR), poll the Send Completion Queue + * order to retreive the status of the request. + * This method is blocking. + * @param bufPtr Pointer to the buffer to be sent. + * @param bufSize Size of the buffer. + * @param dest Desitination ID, corresponds to the position in the host file. + * @return int 0 for success, -1 for error. + */ + int ibBlockSend(char* bufPtr, uint32_t bufSize, uint32_t dest); + /** + * @brief Blocking write to a remote destitation via RDMA + * Write to a remote destination memory region via RDMA opcode. + * Prior to this, mr info must be exchanged using the appropriate method. + * The transfer completion can be signaled by a SR by setting the sendComplete to true. + * Transfer completion will be transmitted using the sync QP, to retrieve the result + * use ibWaitSyncRecv(RDMA_OP_COMPLETE, src). + * @param bufPtr pointer to the send buffer. + * @param bufSize size of the region. + * @param dest Destination ID. + * @param sendComplete true if completion must be signaled to the remote, false otherwise. + * @return int 0 for success, -1 for error. + */ + int ibBlockRDMAWrite(char* bufPtr, uint32_t bufSize, uint32_t dest, bool sendComplete); + /** + * @brief Write to a remote destitation via RDMA + * Write to a remote destination memory region via RDMA opcode. + * Prior to this, mr info must be exchanged using the appropriate method. + * @param bufPtr pointer to the send buffer. + * @param bufSize size of the region. + * @param dest Destination ID. + * @return uint32_t RDMA operation wrId. + */ + uint32_t ibRDMAWrite(char* bufPtr, uint32_t bufSize, uint32_t dest); + /** + * @brief Blocking read from a remote destitation via RDMA + * Read from a remote destination memory region via RDMA opcode. + * Prior to this, mr info must be exchanged using the appropriate method. + * The transfer completion can be signaled by a SR by setting the sendComplete to true. + * Transfer completion will be transmitted using the sync QP, to retrieve the result + * use ibWaitSyncRecv(RDMA_OP_COMPLETE, src). + * @param bufPtr pointer to the region where incoming data is written to. + * @param bufSize size of the region. + * @param dest Destination ID. + * @param sendComplete true if completion must be signaled to the remote, false otherwise. + * @return int 0 for success, -1 for error. + */ + int ibBlockRDMARead(char* bufPtr, uint32_t bufSize, uint32_t dest, bool sendComplete); + /** + * @brief Read to a remote destitation via RDMA + * Read from a remote destination memory region via RDMA opcode. + * Prior to this, mr info must be exchanged using the appropriate method. + * @param bufPtr pointer to the region where incoming data is written to. + * @param bufSize size of the region. + * @param dest Destination ID. + * @return uint32_t RDMA operation wrId. + */ + uint32_t ibRDMARead(char* bufPtr, uint32_t bufSize, uint32_t dest); + /** + * @brief Receive RDMA MR info + * Exchange Memory Region address and key with a remote source + * to initialize the RDMA transfer. + * @param bufPtr pointer to the region where RDMA is executed. + * @param bufSize size of the region where RDMA is executed. + * @param src Source ID + * @return int 0 for success, -1 for error. + */ + int ibRecvRDMAInfo(char* bufPtr, uint32_t bufSize, uint32_t src); + /** + * @brief Send RDMA MR info + * Exchange Memory Region address and key with a remote source + * to initialize the RDMA transfer. + * @param bufPtr pointer to the region where RDMA is executed. + * @param bufSize size of the region where RDMA is executed. + * @param src Source ID + * @return int 0 for success, -1 for error. + */ + + int ibSendRDMAInfo(char* bufPtr, uint32_t bufSize, uint32_t dest); + /** + * @brief Check the status of a Send Request (blocking) + * Poll the Send Completion Queue and wait + * the completion of the SR. + * This method is blocking. + * @param wrId The work ID of the Send Request. + * @return int 0 for success, -1 for error. + */ + int ibWaitSendCQ(uint32_t wrId); + /** + * @brief Check the status of a Receive Request (blocking) + * Poll the Receive Completion Queue and wait + * the completion of the RR. + * This method is blocking. + * @param wrId The work ID of the Receive Request. + * @return int 0 for success, -1 for error. + */ + int ibWaitRecvCQ(uint32_t wrId); + /** + * @brief Check the status of a Send Request + * Poll the Send Completion Queue and check if + * the SR has been completed with success. + * This method is non blocking. + * @param wrId The work ID of the Send Request. + * @return int 1 for not found, 0 for success, -1 for error. + */ + int ibTestSendCQ(uint32_t wrId); + /** + * @brief Check the status of a Receive Request + * Poll the Receive Completion Queue and check if + * the RR has been completed with success. + * This method is non blocking. + * @param wrId The work ID of the Receive Request. + * @return int 1 for not found, 0 for success, -1 for error. + */ + int ibTestRecvCQ(uint32_t wrId); + /** + * @brief Wait a vector of send requests to be completed + * Poll the Send Completion Queue until all the SR in wrs + * have been completed. + * @param wrs vector of work ids. + * @return int 0 for success, -1 for error. + */ + int ibWaitAllSends(std::vector<uint32_t>& wrs); + /** + * @brief Wait a vector of receive requests to be completed + * Poll the Receive Completion Queue until all the RR in wrs + * have been completed. + * @param wrs vector of work ids. + * @return int 0 for success, -1 for error. + */ + int ibWaitAllRecvs(std::vector<uint32_t>& wrs); + /** + * @brief Test a vector of Send Requests for completion + * Poll the Send Completion Queue and returns a vector reporting + * the status of the SRs present in wrs. + * @param wrs vector of work ids. + * @return std::vector<int> vector reporting the status of + * SRs, 1 for not found, 0 for success, -1 for error. + */ + std::vector<int> ibTestAnySends(std::vector<uint32_t>& wrs); + /** + * @brief Test a vector of Receive Requests for completion + * Poll the Receive Completion Queue and returns a vector reporting + * the status of the RRs present in wrs. + * @param wrs vector of work ids. + * @return std::vector<int> vector reporting the status of + * RRs, 1 for not found, 0 for success, -1 for error. + */ + std::vector<int> ibTestAnyRecvs(std::vector<uint32_t>& wrs); + /** + * @brief Test a vector of receive requests to be completed + * Poll the Receive Completion Queue until all the RR in wrs + * have been completed. It deletes completed WRs from the + * given vector. + * @param wrs vector of work ids. + * @return int 1 for not found, 0 for success, -1 for error. + */ + int ibTestAllRecvs(std::vector<uint32_t>& wrs); + /** + * @brief Test a vector of Send Requests for completion (at least one) + * Poll the Send Completion Queue and returns a vector reporting + * the status of the SRs present in wrs. + * This method wait for at least one requesto to be successful. + * @param wrs vector of work ids. + * @return std::vector<int> vector reporting the status of + * SRs, 1 for not found, 0 for success, -1 for error. + */ + std::vector<int> ibWaitAnySends(std::vector<uint32_t>& wrs); + /** + * @brief Test a vector of Receive Requests for completion (at least one) + * Poll the Receive Completion Queue and returns a vector reporting + * the status of the RRs present in wrs. + * This method wait for at least one requesto to be successful. + * @param wrs vector of work ids. + * @return std::vector<int> vector reporting the status of + * RRs, 1 for not found, 0 for success, -1 for error. + */ + std::vector<int> ibWaitAnyRecvs(std::vector<uint32_t>& wrs); + /** + * @brief Immediate codes for synchronization + * + */ + enum immediate_t : uint32_t { NO_IMM_DATA, BARRIER, ONE_TO_ONE, RDMA_OP_COMPLETE }; + /** + * @brief Send a sync message + * Post a zero-byte with immediate SR to the sync QP. + * Used to synchronize between processes. + * @param imm_code immediate code to send (immediate_t) + * @param dest remote host process id. + * @return uint32_t work id associated with this SR. + */ + uint32_t ibSendSync(immediate_t imm_code, uint32_t dest); + /** + * @brief Retrieve the status of a Sync SR + * Poll the sync send CQ to retrieve the status + * of a specified SR. + * @param wrId The work id of the SR to test. + * @return int 1 for not found, 0 for success, -1 for error. + */ + int ibTestSyncSend(uint32_t wrId); + /** + * @brief Wait the completion of a Sync SR + * Poll the sync send CQ and wait the specified SR to be + * completed. + * @param wrId The work id of the SR to check. + * @return int 0 for success, -1 for error. + */ + int ibWaitSyncSend(uint32_t wrId); + /** + * @brief Wait the completion of a vector of Sync SRs + * Poll the sync send CQ and wait the specified SRs to be + * completed. + * @param wrs The work ids vector of the SR to check. + * @return int 0 for success, -1 for error. + */ + int ibWaitAllSyncSends(std::vector<uint32_t>& wrs); + /** + * @brief Post a RR for a sync message + * Post a zero-byte with immediate RR to the sync QP. + * Used to synchronize between processes. + * @param src remote host process id. + * @return uint32_t work id associated with this SR. + */ + uint32_t ibRecvSync(uint32_t src); + /** + * @brief Check for a sync message + * Check if a sync message from src has arrived and + * the immediate code corresponds. + * @param imm_code immediate_t code to check. + * @param src remote host process id. + * @return int 1 for not found, 0 for success, -1 for error. + */ + int ibTestSyncRecv(immediate_t imm_code, uint32_t src); + /** + * @brief Wait for a sync message + * Wait a sync message from src with the immediate code specified. + * @param imm_code immediate_t code to check. + * @param src remote host process id. + * @return int 0 for success, -1 for error. + */ + int ibWaitSyncRecv(immediate_t imm_code, uint32_t src); + /** + * @brief Wait a sync message vector to be completed + * Wait until all the sync messages in the vector are completed. + * @param wrs vector of a 2 uint32_t array. + * [0] is immediate code, [1] is remote host id. + * @return int 0 for success, -1 for error. + */ + int ibWaitAllSyncRecvs(std::vector<std::array<uint32_t, 2>>& wrs); + /** + * @brief types of barriers + * TOURNAMENT barrier is an highly parallel implementation + * for high scalability. + * CENTRAL barrier is a simple All-to-One, One-to-All implementation. + * does not scale well, useful for debugging. + */ + enum barrier_t : int { TOURNAMENT, CENTRAL }; + /** + * @brief Synchronize all processes. + * The barrier waits for all processes to synchronize. + * Every process must call the barrier in order to synchronize. + * @param type Default is TOURNAMENT, CENTRAL is also available. (barrier_t) + * @return int 0 for success, -1 for error. + */ + int ibBarrier(barrier_t type = TOURNAMENT); + /** + * @brief Deregisters the allocated Memory Regions + * deregisters the memory regions from the device and erase the LUT. + * @return int 0 for success, -1 for error. + */ + int ibDeregMRs(); + /** + * @brief Destroys the ib object + * Join open threads, eallocate MRs, destroy Queue Pairs, Protection Domain, Completion Queues. + * Close the IB device. + */ + void ibDestroy(); + /** + * @brief Get the Process ID + * Return the process ID, determined by the position in the host file. + * @return int process ID. + */ + int getProcessID() const; + /** + * @brief Get the total number of processes + * Correspond to the host file array size. + * @return int total number of processes. + */ + int getTotalProcesses() const; + /** + * @brief Returns the InfiniBand device number + * Get the infiniBand device number which correspond to the system name (e.g. 0 -> ib0, mlx5_0.) + * @return int device number. + */ + int ibGetDevNum() const; + /** + * @brief Returns the NUMA node associated with the device + * Get the NUMA node associate with the InfiniBand device. + * @return int NUMA node. + */ + int ibGetNumaNode() const; + /** + * @brief Destroy the ib object + * Join open threads, eallocate MRs, destroy Queue Pairs, Protection Domain, Completion Queues. + * Close the IB device. + */ + ~IB() noexcept; + /** + * @brief Kill all blocking methods + * This command will signal all the blocking calls to die. + */ + void ibKillBlocking(); + IB& operator=(IB&& src) noexcept; + // delete copy constructor and copy assignment + IB(const IB& src) = delete; + IB& operator=(const IB& src) = delete; // copy assignment + int ibSetHostList(Parser& hostParser); + + private: + int _ibSetQP(Proc& host); + int _getDevInfo(); + void _destroyQP(ibv_qp* qp); + uint32_t _ibGetNextWrId(); + std::thread _QPrecv; + std::promise<int> _ret; + std::future<int> _rtf; + // data methods + uint32_t _ibRecv(ibv_mr* mr, char* bufPtr, uint32_t bufSize, uint32_t sender); + uint32_t _ibSend(ibv_mr* mr, char* bufPtr, uint32_t bufSize, uint32_t dest); + int _ibSendCQ(uint32_t wrId); + int _ibRecvCQ(immediate_t imm_code, uint32_t wrId); + int _pollSCQ(); + int _pollRCQ(); + // sync methods + int _pollSyncRCQ(); + int _ibSync(uint64_t key); + void _syncFunc(std::atomic<bool>& run); + int _syncInit(); + // barrier methods + int _runCentral(); + int _initTournament(); + int _runTournament(); + // for tournament barrier + std::vector<uint32_t> _tournament_hlist; + std::vector<std::array<uint32_t, 2>> _tournament_lut; + bool _tournament_lonely = false; + int _tournament_dst = -1; + // global stuff + int _devNum; + std::string _devName = ""; + int _numaNode; + uint8_t _portNum = 1; + size_t _procNum; + std::atomic<uint32_t> _wrId = 0; + int _totalProcs; + ibv_context* _ctx = NULL; + ibv_pd* _pd = NULL; + ibv_port_attr _port_attr; + ibv_device_attr _dev_attr; + ibv_device** _dev_list = NULL; + std::vector<Proc> _hosts; + std::atomic<bool> _kill_blocking{false}; + // DATA CQ objects + ibv_cq* _sendcq = NULL; + ibv_cq* _recvcq = NULL; + std::unordered_map<uint32_t, ibv_wc> _wcsend; + std::unordered_map<uint32_t, ibv_wc> _wcrecv; + // SYNC CQ objects + ibv_cq* _syncRcq = NULL; + ibv_cq* _syncScq = NULL; + std::unordered_map<uint64_t, ibv_wc> _wcsyncr; + std::unordered_map<uint32_t, ibv_wc> _wcsyncs; + std::unordered_map<uint32_t, size_t> _reverse_hosts; + std::thread _syncThread; + std::atomic<bool> _runsync{true}; + // Out-of-Band comms + Sock _sockObj; + // mutexes for inter-thread synchronization + std::mutex _mtx_poll_r; + std::mutex _mtx_poll_s; + std::mutex _mtx_host; + std::mutex _mtx_mr; + std::mutex _mtx_sync; + // memory region registers + struct memreg { + ibv_mr* _mr = NULL; + char* _bufPtr = NULL; + size_t _bufSize = 0; + }; + std::vector<memreg> _memMap; + // rdma operations + uint32_t _RDMAop(char* bufPtr, uint32_t bufSize, uint32_t dest, bool opType /*true read, false write*/); + +#ifdef IB_DUMP_FILE + std::string _dump_file_path = "/scratch/eb_testing"; + std::ofstream _wc_dump_file; + std::mutex _wc_dump_file_mutex; + void _dump_wc(const struct ibv_wc& wc); + std::ofstream _wr_dump_file; + std::mutex _wr_dump_file_mutex; + struct ib_wr { + uint32_t qp_num; + uint32_t src_qp; + ibv_wr_opcode opcode; + bool receive; + }; + void _dump_wr(const ib_wr& wr); +#endif + }; +} // namespace IB_verbs + +#endif // !IB_H \ No newline at end of file diff --git a/Online/EventBuilding/include/infiniband_net/parser.hpp b/Online/EventBuilding/include/infiniband_net/parser.hpp new file mode 100644 index 000000000..40e05f2c1 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/parser.hpp @@ -0,0 +1,67 @@ +/** + * @file parser.hpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief Parser for InfiniBand Library + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#pragma once +#if !defined(PARSER_H) +#define PARSER_H +#include <fstream> +#include <vector> +#include <string> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <infiniband/verbs.h> +#include <iostream> +#include "proc.hpp" +#include "ArduinoJson.h" +#include <future> +#include <stdexcept> + +namespace IB_verbs { + class Parser { + private: + int _globalProc = 0; + int _ipPort = 0; + int _totalProcs = 0; + int _ibNumaNode = -1; + int _ibDevNum = -1; + std::string _ibDevString = ""; + std::vector<sockaddr_in> _hostvec; + std::string _myHostName = ""; + std::string _myIP = ""; + int _getMyNetInfo(); + std::string _getIpByHostname(std::string hostname); + void _readHostFile(const char* filename, const int nProc); + void _readHostFile(const char* filename); + void _getMyIbDevInfo(); + + public: + Parser(); + Parser(const char* filename); + Parser(const char* filename, const int rankid); + ~Parser(); + std::string getMyHostname() const; + std::string getMyIp() const; + int getTotalProcesses() const; + int getIpPort() const; + std::string getIbDevString() const; + // TODO getters should be const + int getIbNumaNode() const; + int getIbDevNum() const; + int getProcessId() const; + std::vector<sockaddr_in> getHostList(); + }; +} // namespace IB_verbs + +#endif // PARSER_H diff --git a/Online/EventBuilding/include/infiniband_net/proc.hpp b/Online/EventBuilding/include/infiniband_net/proc.hpp new file mode 100644 index 000000000..c848c8475 --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/proc.hpp @@ -0,0 +1,71 @@ +/** + * @file proc.hpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief Process Class + * @version 0.1.1 + * @date 16/11/2020 + * + * @copyright Copyright (c) 2020 + * + */ + +#pragma once +#if !defined(PROC_H) +#define PROC_H +#include <fstream> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <unistd.h> +#include <infiniband/verbs.h> +#include <iostream> +#include <memory> +#include <string> + +namespace IB_verbs { + class Proc { + private: + /* data */ + public: + struct MRInfo { + uint32_t rkey; + uintptr_t addr; + }; + int sockFd; + std::string ibDevString; + sockaddr_in sockAddr; + int ibDev; + uint16_t local_lid; + uint16_t remote_lid; + uint32_t remote_qp_num; // must be 32 bit + uint32_t remote_sync_qp_num; // must be 32 bit + uint8_t qp_rdma; + uint8_t next_qp; + ibv_qp* qp; + ibv_qp* sync_qp; + MRInfo rdma; + Proc(/* args */); + Proc(Proc&&) = default; + Proc& operator=(Proc&&) = default; + Proc(const Proc&) = delete; + Proc& operator=(const Proc&) = delete; + ~Proc(); + }; + + inline Proc::Proc(/* args */) + { + this->sockFd = 0; + memset(&this->sockAddr, 0, sizeof(sockaddr_in)); + this->ibDevString = ""; + this->ibDev = 0; + this->local_lid = 0; + this->remote_lid = 0; + this->next_qp = 0; + this->qp = NULL; + this->sync_qp = NULL; + } + + inline Proc::~Proc() {} +} // namespace IB_verbs +#endif // PROC_H diff --git a/Online/EventBuilding/include/infiniband_net/sock.hpp b/Online/EventBuilding/include/infiniband_net/sock.hpp new file mode 100644 index 000000000..5945d27af --- /dev/null +++ b/Online/EventBuilding/include/infiniband_net/sock.hpp @@ -0,0 +1,44 @@ +/** + * @file sock.hpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief Socket Communication for InfiniBand Library + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#pragma once +#if !defined(SOCK_H) +#define SOCK_H +#include <vector> +#include <string> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <infiniband/verbs.h> +#include <iostream> +#include "proc.hpp" +#include <atomic> +#include <stdexcept> + +namespace IB_verbs { + class Sock { + public: + Sock(); + ~Sock(); + struct QPInfo { + uint16_t lid; + uint32_t qp_num; + uint32_t sync_qp_num; + uint32_t procNum; + }; + int sendQP(const int rankid, Proc& rem); + void recvQPs(const int rankid, const std::vector<Proc>& k, std::atomic<int>& ret); + }; +} // namespace IB_verbs +#endif // SOCK_H diff --git a/Online/EventBuilding/include/logger.hpp b/Online/EventBuilding/include/logger.hpp new file mode 100644 index 000000000..f461d0416 --- /dev/null +++ b/Online/EventBuilding/include/logger.hpp @@ -0,0 +1,170 @@ +#ifndef EB_LOGGER_H_ +#define EB_LOGGER_H_ 1 +#include <streambuf> +#include <syslog.h> +#include <cstring> +#include <ostream> +#include <iostream> +#include <memory> +#include "DD4hep/Printout.h" +#include "RTL/rtl.h" + +namespace EB { + enum class Log_priority { + kLogEmerg = LOG_EMERG, // system is unusable + kLogAlert = LOG_ALERT, // action must be taken immediately + kLogCrit = LOG_CRIT, // critical conditions + kLogErr = LOG_ERR, // error conditions + kLogWarning = LOG_WARNING, // warning conditions + kLogNotice = LOG_NOTICE, // normal, but significant, condition + kLogInfo = LOG_INFO, // informational message + kLogDebug = LOG_DEBUG, // debug-level message + kLogNoLog, // unprinted message + }; + + std::string log_priority_to_string(const Log_priority& elem); + Log_priority online_print_level_to_log_priority(const Online::PrintLevel& elem); + Online::PrintLevel log_priority_to_online_print_level(const Log_priority& elem); + + // TODO convert Online debug levels to Log_priority + + constexpr Log_priority default_log = Log_priority::kLogInfo; + + constexpr char default_ident[] = "dataflow"; + constexpr int default_facility = LOG_LOCAL0; + + // Meyers Singleton that guarantees single initialization of the syslog infrastructure + class Log_initializer { + public: + static void init_log() { static Log_initializer instance; } + + Log_initializer(const Log_initializer&) = delete; + Log_initializer& operator=(const Log_initializer&) = delete; + Log_initializer(const Log_initializer&&) = delete; + Log_initializer& operator=(const Log_initializer&&) = delete; + + private: + Log_initializer() : _ident(default_ident) { openlog(_ident.c_str(), LOG_PID, default_facility); } + + ~Log_initializer() { closelog(); } + + std::string _ident; + }; + + class Log : public std::stringbuf { + public: + explicit Log( + std::string name = "", + Log_priority log_level = default_log, + bool enable_syslog = true, + bool enable_online = true, + int facility = 0); + + void set_log_level(const Log_priority& log_level); + Log_priority get_log_level() const; + + void set_name(const std::string& name); + std::string get_name() const; + + void set_facility(int facility); + int get_facility() const; + + void enable_syslog(bool flag = true); + void enable_online(bool flag = true); + bool syslog_enabled() const; + bool online_enabled() const; + + protected: + int sync(); + int overflow(int c); + + private: + // friend Log_stream& operator<<(Log_stream& os, const Log_priority& log_priority); + std::string _buffer; + int _facility; + Log_priority _log_level; + std::string _name; + bool _syslog_ena; + bool _online_ena; + std::string _UTGID; + }; + + class Log_stream : public std::ostream { + public: + Log_stream( + std::string name = "", + Log_priority out_level = default_log, + bool enable_syslog = true, + bool enable_online = true, + int facility = 0); + + Log_stream(Log_stream&&); + Log_stream& operator=(Log_stream&&); + + Log_stream(Log_stream&) = delete; + Log_stream& operator=(Log_stream&) = delete; + + virtual ~Log_stream() = default; + + void set_output_level(const Log_priority& output_level); + void set_output_level(const Online::PrintLevel& output_level); + Log_priority get_output_level() const; + + Log_stream& set_log_level(const Log_priority& log_level); + Log_stream& set_log_level(const Online::PrintLevel& log_level); + Log_priority get_log_level() const; + + bool is_active(const Log_priority& priority) const; + bool is_active(const Online::PrintLevel& priority) const; + + void set_name(const std::string& name); + std::string get_name() const; + + void enable_syslog(bool flag = true); + void enable_online(bool flag = true); + bool syslog_enabled() const; + bool online_enabled() const; + + // always is there for backwasrds compatibility + Log_stream& always() { return set_log_level(Log_priority::kLogEmerg); } + Log_stream& emergency() { return set_log_level(Log_priority::kLogEmerg); } + Log_stream& alert() { return set_log_level(Log_priority::kLogAlert); } + Log_stream& critical() { return set_log_level(Log_priority::kLogCrit); } + Log_stream& error() { return set_log_level(Log_priority::kLogErr); } + Log_stream& warning() { return set_log_level(Log_priority::kLogWarning); } + Log_stream& notice() { return set_log_level(Log_priority::kLogNotice); } + Log_stream& info() { return set_log_level(Log_priority::kLogInfo); } + Log_stream& debug() { return set_log_level(Log_priority::kLogDebug); } + Log_stream& nolog() { return set_log_level(Log_priority::kLogNoLog); } + + Log_stream& operator<<(std::ostream& (*pf)(std::ostream&) ) + { + auto priority = static_cast<Log*>(rdbuf())->get_log_level(); + if (priority <= _output_level) { + pf(*(dynamic_cast<std::ostream*>(this))); + } + return *this; + } + + template<typename T> + Log_stream& operator<<(const T& data) + { + auto priority = static_cast<Log*>(rdbuf())->get_log_level(); + if (priority <= _output_level) { + *(dynamic_cast<std::ostream*>(this)) << data; + } + + return *this; + } + + private: + Log_priority _output_level; + std::unique_ptr<std::streambuf> _buff; + }; + +} // namespace EB + +std::ostream& operator<<(std::ostream& os, EB::Log_priority const& log_priority); +EB::Log_stream& operator<<(EB::Log_stream& os, EB::Log_priority const& log_priority); + +#endif // EB_LOGGER_H_ \ No newline at end of file diff --git a/Online/EventBuilding/include/mbm_reader.hpp b/Online/EventBuilding/include/mbm_reader.hpp new file mode 100644 index 000000000..c97be317c --- /dev/null +++ b/Online/EventBuilding/include/mbm_reader.hpp @@ -0,0 +1,51 @@ +#ifndef MBM_READER_H +#define MBM_READER_H 1 + +#include "buffer_interface.hpp" +#include "Dataflow/MBMClient.h" +#include "Dataflow/DataflowComponent.h" +#include "MBM/Producer.h" +#include "MBM/Consumer.h" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> + +#include "MBM/Requirement.h" + +namespace EB { + template<class T> + class Mbm_reader : public EB::Buffer_reader<T> { + public: + // alignment is explesser in 2^alignment min value 1 + Mbm_reader() : EB::Buffer_reader<T>() {} + // Mbm_writer(MBM::Producer* producer, int facility = 0); + Mbm_reader( + Online::DataflowComponent::Context& context, + const std::string& instance, + const std::string& name, + const std::string& req); + virtual ~Mbm_reader(); + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + T* try_get_element() override; + void read_complete() override; + void flush() override; + void cancel(); + + int get_src_id() const override { return 0; } + + protected: + Online::DataflowComponent::Context* _context; + std::unique_ptr<MBM::Consumer> _consumer; + int _total_size = 0; + std::string _m_req; + MBM::Requirement _m_requirement; + bool _ack_pending = false; + }; +} // namespace EB + +#include "mbm_reader_impl.hpp" + +#endif // MBM_WRITER_H diff --git a/Online/EventBuilding/include/mbm_reader_impl.hpp b/Online/EventBuilding/include/mbm_reader_impl.hpp new file mode 100644 index 000000000..99bc824bc --- /dev/null +++ b/Online/EventBuilding/include/mbm_reader_impl.hpp @@ -0,0 +1,85 @@ +#include "mbm_writer.hpp" +#include "RTL/rtl.h" +#include <stdexcept> +#include "EventBuilding/tools.hpp" +#include <unistd.h> +#include <sys/stat.h> /* For mode constants */ +#include <fcntl.h> /* For O_* constants */ +#include <sys/mman.h> +#include <cstring> +#include <sstream> +#include <string> +#include <memory> +#include <iostream> +#include <tuple> + +template<class T> +EB::Mbm_reader<T>::Mbm_reader( + Online::DataflowComponent::Context& context, + const std::string& instance, + const std::string& name, + const std::string& req) : + EB::Buffer_reader<T>(), + _context(&context), _consumer(context.mbm->createConsumer(name, instance)), _m_req(req), _ack_pending(false) +{ + _m_requirement.parse(req); + _consumer->addRequest(_m_requirement); +} + +template<class T> +EB::Mbm_reader<T>::~Mbm_reader() +{} + +template<class T> +T* EB::Mbm_reader<T>::try_get_element() +{ + T* data = NULL; + int status = _consumer->getEvent(); + if (status == MBM_NORMAL) { + const MBM::EventDesc& dsc = _consumer->event(); + data = (T*) dsc.data; + // size_t size = dsc.len; + // info("Got MEP size %ld\n", size); + _ack_pending = true; + } + return data; +} + +template<class T> +void EB::Mbm_reader<T>::read_complete() +{ + if (_ack_pending) { + _consumer->freeEvent(); + _ack_pending = false; + } +} + +template<class T> +void EB::Mbm_reader<T>::flush() +{ + // TODO check if there is a way of removing all the events from the buffer + if (_ack_pending) { + _consumer->freeEvent(); + _ack_pending = false; + } +} + +template<class T> +std::vector<std::tuple<void*, size_t>> EB::Mbm_reader<T>::get_full_buffer() +{ + // TODO verify + void* mbm_data = (void*) mbm_buffer_address(_consumer->id()); + size_t mbm_size; + mbm_buffer_size(_consumer->id(), &mbm_size); + std::vector<std::tuple<void*, size_t>> ret_val; + ret_val.emplace_back(std::tuple<void*, size_t>(mbm_data, mbm_size)); + return ret_val; +} + +template<class T> +void EB::Mbm_reader<T>::cancel() +{ + EB::Buffer_reader<T>::cancel(); + _consumer->cancel(); + _ack_pending = false; +} diff --git a/Online/EventBuilding/include/mbm_writer.hpp b/Online/EventBuilding/include/mbm_writer.hpp new file mode 100644 index 000000000..b480cf3bb --- /dev/null +++ b/Online/EventBuilding/include/mbm_writer.hpp @@ -0,0 +1,54 @@ +#ifndef MBM_WRITER_H +#define MBM_WRITER_H 1 + +#include "buffer_interface.hpp" +#include "Dataflow/MBMClient.h" +#include "Dataflow/DataflowComponent.h" +#include "MBM/Producer.h" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> +#include <memory> + +namespace EB { + template<class T> + class Mbm_writer : public EB::Buffer_writer<T> { + public: + // alignment is explesser in 2^alignment min value 1 + Mbm_writer() : EB::Buffer_writer<T>() {} + // Mbm_writer(MBM::Producer* producer, int facility = 0); + Mbm_writer(Online::DataflowComponent::Context& context, const std::string& instance, const std::string& name); + virtual ~Mbm_writer(); + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + T* try_write_next_element(size_t size) override; + + void write_complete() override; + void write_discard() override; + + void cancel(); + + size_t free_space(); + + bool is_set(); + + void reset(MBM::Producer* producer = NULL); + + int get_src_id() const override { return 0; } + + protected: + Online::DataflowComponent::Context* _context; + std::unique_ptr<MBM::Producer> _producer; + // bool _ack_pending = false; + enum Status { IDLE, ACK_PENDING }; + Status _status; + }; +} // namespace EB + +#include "mbm_writer_impl.hpp" + +#endif // MBM_WRITER_H diff --git a/Online/EventBuilding/include/mbm_writer_impl.hpp b/Online/EventBuilding/include/mbm_writer_impl.hpp new file mode 100644 index 000000000..a6f9584f8 --- /dev/null +++ b/Online/EventBuilding/include/mbm_writer_impl.hpp @@ -0,0 +1,154 @@ +#include "mbm_writer.hpp" +#include "RTL/rtl.h" +#include <stdexcept> +#include "EventBuilding/tools.hpp" +#include <unistd.h> +#include <sys/stat.h> /* For mode constants */ +#include <fcntl.h> /* For O_* constants */ +#include <sys/mman.h> +#include <cstring> +#include <sstream> +#include <string> +#include <memory> +#include <iostream> +#include <tuple> + +template<class T> +EB::Mbm_writer<T>::Mbm_writer( + Online::DataflowComponent::Context& context, + const std::string& instance, + const std::string& name) : + EB::Buffer_writer<T>(), + _context(&context), _producer(context.mbm->createProducer(name, instance)), _status(IDLE) +{} + +template<class T> +EB::Mbm_writer<T>::~Mbm_writer() +{ + if (this->is_set()) { + _context->mbm->cancelBuffers(); + } +} + +template<class T> +std::vector<std::tuple<void*, size_t>> EB::Mbm_writer<T>::get_full_buffer() +{ + // TODO check for errors + void* mbm_data = (void*) mbm_buffer_address(_producer->id()); + size_t mbm_size; + mbm_buffer_size(_producer->id(), &mbm_size); + + std::vector<std::tuple<void*, size_t>> ret_val; + ret_val.emplace_back(std::tuple<void*, size_t>(mbm_data, mbm_size)); + return ret_val; +} + +template<class T> +T* EB::Mbm_writer<T>::try_write_next_element(size_t size) +{ + T* ret_val = NULL; + int status; + + if (!this->is_set()) { + std::ostringstream err_mess; + err_mess << __FILE__ << ": " << __FUNCTION__ << " on an invalid buffer"; + throw std::logic_error(err_mess.str()); + } + + if (_status != IDLE) { + std::ostringstream err_mess; + err_mess << __FILE__ << ": " << __FUNCTION__ << " used buffer use write_complete, write_discard or cancel."; + throw std::logic_error(err_mess.str()); + } + + status = _producer->getSpaceTry(size); + + if (status == MBM_NORMAL) { + MBM::EventDesc& dsc = _producer->event(); + ret_val = reinterpret_cast<T*>(dsc.data); + dsc.len = size; + dsc.type = EVENT_TYPE_MEP; + // If MEP, we emulate a trigger mask with the partition ID + // TODO check what should be put in here + dsc.mask[0] = _producer->partitionID(); + dsc.mask[1] = ~0x0; + dsc.mask[2] = ~0x0; + dsc.mask[3] = ~0x0; + _status = ACK_PENDING; + } else if (status == MBM_NO_ROOM) { + ret_val = NULL; + } else { + std::ostringstream err_mess; + err_mess << "Mbm_writer: try_write_next_element getSpaceTry error " << status; + throw std::runtime_error(err_mess.str()); + } + + return ret_val; +} + +template<class T> +void EB::Mbm_writer<T>::write_discard() +{ + _status = IDLE; +} + +template<class T> +void EB::Mbm_writer<T>::write_complete() +{ + // TODO status and ret_Val should consistent + int status; + if (!this->is_set()) { + std::ostringstream err_mess; + err_mess << "Mbm_writer: write_complete on an invalid buffer"; + throw std::logic_error(err_mess.str()); + } + + if (_status == ACK_PENDING) { + + status = _producer->declareEvent(); + if (status != MBM_NORMAL) { + // TODO add proper error handling, like cancelling pending requests + std::ostringstream err_mess; + err_mess << "Mbm_writer: write_complete declareEvent error " << status; + throw std::runtime_error(err_mess.str()); + } + + status = _producer->sendSpace(); + if (status != MBM_NORMAL) { + // TODO add proper error handling, like cancelli pending requests + std::ostringstream err_mess; + err_mess << "Mbm_writer: write_complete sendSpace error " << status; + throw std::runtime_error(err_mess.str()); + } + _status = IDLE; + } +} + +template<class T> +void EB::Mbm_writer<T>::cancel() +{ + EB::Buffer_writer<T>::cancel(); + + _producer->cancel(); + _status = IDLE; +} + +template<class T> +size_t EB::Mbm_writer<T>::free_space() +{ + return 0; +} + +template<class T> +bool EB::Mbm_writer<T>::is_set() +{ + return (_producer.get() != nullptr); +} + +template<class T> +void EB::Mbm_writer<T>::reset(MBM::Producer* producer) +{ + _producer.reset(producer); + // if the instance is different we assume non pending acks + _status = IDLE; +} diff --git a/Online/EventBuilding/include/mdf_reader.hpp b/Online/EventBuilding/include/mdf_reader.hpp new file mode 100644 index 000000000..33a93bb7b --- /dev/null +++ b/Online/EventBuilding/include/mdf_reader.hpp @@ -0,0 +1,36 @@ +#ifndef MDF_READER_H +#define MDF_READER_H 1 + +#include "EventBuilding/mdf_tools.hpp" +#include <cstdio> +#include <cstring> +#include <fcntl.h> +#include <fstream> +#include <iostream> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <vector> +#include <exception> +#include <unordered_map> +#include "EventBuilding/raw_tools.hpp" + +namespace EB { + class MDF_reader { + private: + int _input_fd; + + public: + MDF_reader() {} + MDF_reader(const char* file_name); + bool set_file(const char* file_name); + int extract_event(EB::MDF_block& block); + int extract_event(EB::MDF_block& block, void* buffer, size_t size); + int extract_events(std::vector<EB::MDF_block>& blocks, int n_events); + int extract_events(std::vector<EB::MDF_block>& blocks, int n_events, void* buffer, size_t size); + int extract_events(std::vector<EB::MDF_block>& blocks); + int extract_events(std::vector<EB::MDF_block>& blocks, void* buffer, size_t size); + }; +} // namespace EB + +#endif // MDF_READER_H \ No newline at end of file diff --git a/Online/EventBuilding/include/options.hpp b/Online/EventBuilding/include/options.hpp new file mode 100644 index 000000000..78d83c41f --- /dev/null +++ b/Online/EventBuilding/include/options.hpp @@ -0,0 +1,55 @@ +#ifndef OPTIONS_H +#define OPTIONS_H 1 + +#include <vector> +#include <string> +#include <functional> +#include <getopt.h> +#include <tuple> + +namespace EB { + class Options { + public: + Options(int argc, char** argv); + + ~Options(); + + void add_option( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + std::function<void(const char*)> user_funct, + bool has_args = false); + + template<class T> + void + add_option(const std::string& long_name, char short_name, const std::string& help, bool is_required, T& out_var); + + void + add_flag(const std::string& long_name, char short_name, const std::string& help, bool is_required, bool& out_flag); + + void + add_counter(const std::string& long_name, char short_name, const std::string& help, bool is_required, int& counter); + + bool parse_args(); + + void print_usage() const; + + private: + int _argc; + char** _argv; + std::vector<option> _options; + std::vector<std::function<void(const char*)>> _lambdas; + std::vector<char> _short_names; + std::vector<bool> _required; + std::vector<std::string> _help; + size_t _max_text_aling = 0; + + std::string build_short_options(); + void apply_lambda(int idx); + void print_option(int idx) const; + }; +} // namespace EB + +#endif // OPTIONS_H \ No newline at end of file diff --git a/Online/EventBuilding/include/pcie40_reader.hpp b/Online/EventBuilding/include/pcie40_reader.hpp new file mode 100644 index 000000000..d62e4c65a --- /dev/null +++ b/Online/EventBuilding/include/pcie40_reader.hpp @@ -0,0 +1,178 @@ +#ifndef PCIE40_READER_H +#define PCIE40_READER_H 1 +#include <memory> +#include <vector> +#include <exception> +#include <deque> +#include <lhcb/pcie40/id.h> +#include <lhcb/pcie40/daq.h> +#include <lhcb/pcie40/pcie40.hpp> +#include "EventBuilding/MFP_tools.hpp" +#include "buffer_interface.hpp" +#include "circular_buffer_reader.hpp" +#include "circular_buffer_writer.hpp" +#include "shared_ptr_buffer_backend.hpp" +#include "file_writer.hpp" +#include "pcie40_reader_error.hpp" + +namespace EB { + // alignments are expressed as a power of 2 + constexpr int default_PCIe40_alignment = 12; // 4096 B + constexpr int default_PCIe40_frag_alignment = 5; // 32 B + + class PCIe40_reader { + public: + PCIe40_reader(); + PCIe40_reader( + int id, + int stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN, + bool enable_MFP = true, + int packing_factor = 3000); + + PCIe40_reader( + const std::string& name, + int stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN, + bool enable_MFP = true, + int packing_factor = 3000); + + PCIe40_reader(const PCIe40_reader& other) = delete; + PCIe40_reader(PCIe40_reader&& other); + virtual ~PCIe40_reader(); + + PCIe40_reader& operator=(const PCIe40_reader& other) = delete; + PCIe40_reader& operator=(PCIe40_reader&& other); + + std::error_code open(int id); + std::error_code open(const std::string& name); + + std::error_code set_packing_factor(int packing_factor); + + std::error_code enable_MFP_stream(); + std::error_code disable_MFP_stream(); + + // Resets the the cards and flush the buffer + std::error_code reset(); + + bool is_open(); + + void close(); + + template<class T> + T* extract_element(); + void ack_read(); + void update_usage(); + void cancel_pending(); + + const std::string get_name() const; + + uint16_t _src_id; + uint8_t _block_version; + + protected: + static constexpr int src_version_mask = 0xFF0000; + static constexpr int src_version_shift = 16; + static constexpr int src_subsystem_mask = 0xF800; + static constexpr int src_subsystem_shift = 11; + static constexpr int src_num_mask = 0x7FF; + static constexpr int src_num_shift = 0; + + void* _buffer; + ssize_t _buffer_size; + + ssize_t _internal_read_off; + ssize_t _device_read_off; + ssize_t _available_data; + size_t _requested_size; + + int _stream; + int _id_fd; + int _stream_fd; + int _ctrl_fd; + int _meta_fd; + + std::string _name; + + // TODO this hould be controlled by the ECS + // alignment between MFPs into the PCIe40 buffer as a power of 2 + int PCIe40_alignment = default_PCIe40_alignment; + + std::error_code update_device_ptr(); + + virtual void init_internal_status(); + + int update_read_off(size_t size); + }; + + class PCIe40_MFP_reader : public PCIe40_reader, public EB::Buffer_reader<EB::MFP> { + public: + PCIe40_MFP_reader(); + PCIe40_MFP_reader(int id, int stream, int packing_factor); + PCIe40_MFP_reader(const std::string& name, int stream, int packing_factor); + + EB::MFP* try_get_element() override; + void read_complete() override; + void flush() override; + + int get_src_id() const override; + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + }; + + class PCIe40_frag_reader : public EB::Buffer_reader<EB::MFP> { + public: + PCIe40_frag_reader(); + PCIe40_frag_reader( + int id, + size_t buffer_size, + int packing_factor = 1, + size_t buffer_alignment = default_PCIe40_alignment, + int stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN); + PCIe40_frag_reader( + const std::string& name, + size_t buffer_size, + int packing_factor = 1, + size_t buffer_alignment = default_PCIe40_alignment, + int stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN); + + EB::MFP* try_get_element() override; + void read_complete() override; + void flush() override; + + int get_src_id() const override; + + void set_n_frags(int n_MFPs); + int get_n_frags() const; + + void set_align(int n_MFPs); + int get_align() const; + + std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + + protected: + PCIe40_reader _pcie40_reader; + Circular_buffer_reader<EB::MFP, Shared_ptr_buffer_backend> _internal_buffer_reader; + Circular_buffer_writer<EB::MFP, Shared_ptr_buffer_backend> _internal_buffer_writer; + + uint16_t _packing_factor; + // TODO we may want to modify this + uint8_t _align = default_PCIe40_frag_alignment; + // add more vectors for sizes and offsets + // add a function that builds all the MFPs in the buffer + std::vector<void*> _frag_list; + std::vector<uint8_t> _type_list; + std::vector<uint16_t> _size_list; + uint64_t _ev_id; + uint8_t _version; + uint32_t _total_size = 0; + + // Set to true when a flush is received, deasserted when the consecutive sequenque of flushes ends + bool _flush = false; + // Set to true if a flush MFP is pending because the internal buffer is full, deasserted when the flush MFP is sent + bool _flush_pending = false; + + void scan_frag_list(); + std::error_code build_MFP(); + }; +} // namespace EB + +#endif // PCIE40_READER_H diff --git a/Online/EventBuilding/include/pcie40_reader_error.hpp b/Online/EventBuilding/include/pcie40_reader_error.hpp new file mode 100644 index 000000000..e41efe6a9 --- /dev/null +++ b/Online/EventBuilding/include/pcie40_reader_error.hpp @@ -0,0 +1,45 @@ +#ifndef PCIE40_READER_ERROR_H +#define PCIE40_READER_ERROR_H 1 +#include <system_error> +#include <string> + +namespace EB { + enum class PCIe40_errors { + ID_OPEN = 1, + ID_FIND, + STREAM_OPEN, + META_STREAM_OPEN, + META_STREAM_ENABLE, + META_STREAM_DISABLE, + CTRL_STREAM_OPEN, + STREAM_GET_ENABLED, + STREAM_ENABLED, + STREAM_LOCK, + STREAM_SIZE, + STREAM_MAP, + HOST_READ_OFF, + HOST_FREE_BUFF, + GET_NAME, + DEVICE_NOT_OPEN, + SET_META_PACKING, + LOGIC_RESET, + CORRUPTED_DATA, + INVALID_PACKING_FACTOR, + INTERNAL_BUFFER_FULL, + INTERNAL_BUFFER_FULL_FLUSH, + }; + + std::error_code make_error_code(PCIe40_errors ec); + + // enum class + +} // namespace EB + +namespace std { + template<> + struct is_error_code_enum<EB::PCIe40_errors> : true_type { + }; + +} // namespace std + +#endif // PCIE40_READER_ERROR_H diff --git a/Online/EventBuilding/include/shared_mem_buffer_backend.hpp b/Online/EventBuilding/include/shared_mem_buffer_backend.hpp new file mode 100644 index 000000000..4aeeb3890 --- /dev/null +++ b/Online/EventBuilding/include/shared_mem_buffer_backend.hpp @@ -0,0 +1,82 @@ +#ifndef SHARED_MEM_BUFFER_BACKEND_H +#define SHARED_MEM_BUFFER_BACKEND_H 1 + +#include "circular_buffer_status.hpp" +#include <cstddef> +#include <cstdint> +#include <iostream> +#include <string> +#include <tuple> +#include <memory> +#include <functional> +#include <sys/stat.h> /* For mode constants */ +#include <numa.h> + +namespace EB { + class Shared_mem_buffer_backend { + public: + virtual ~Shared_mem_buffer_backend(); + Shared_mem_buffer_backend(); + Shared_mem_buffer_backend( + const std::string& name, + bool is_writer, + bool allow_reconnect, + bool allow_unlink, + size_t size = 0, + size_t alignment = 12, + int id = 0, + int numa_node = -1); + Shared_mem_buffer_backend(Shared_mem_buffer_backend&& other); + Shared_mem_buffer_backend& operator=(Shared_mem_buffer_backend&& other); + + std::tuple<void*, size_t> get_buffer(); + + bool is_set(); + + // protected: + uintptr_t _buffer; + + Circular_buffer_status* _remote_buffer_status; + + Circular_buffer_status _local_buffer_status; + + private: + static constexpr mode_t permission_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH | S_IROTH; + + std::string _shmem_name; + int _shmem_fd; + + bool _is_writer; + bool _allow_unlink; + + // Unique ptrs to the shmem region + typedef std::unique_ptr<void, std::function<void(void*)>> shmem_ptr_type; + shmem_ptr_type _shm_area; + + std::string _reader_lock_name; + int _reader_lock_fd; + std::string _writer_lock_name; + int _writer_lock_fd; + + void open_shmem(); + void create_shmem(); + void create_locks(); + void init_buffer(size_t size, size_t alignment, int id); + void shm_map(int numa_node = -1); + void close_shmem(); + void destroy_shmem(); + + bool is_open(); + + void try_lock_reader(); + void release_reader(); + + void try_lock_writer(); + void release_writer(); + + void close_fd(int& fd); + + void clean_up(); + }; +} // namespace EB +#endif // SHARED_MEM_BUFFER_BACKEND_H \ No newline at end of file diff --git a/Online/EventBuilding/include/shared_ptr_buffer_backend.hpp b/Online/EventBuilding/include/shared_ptr_buffer_backend.hpp new file mode 100644 index 000000000..1cc98f321 --- /dev/null +++ b/Online/EventBuilding/include/shared_ptr_buffer_backend.hpp @@ -0,0 +1,33 @@ +#ifndef SHARED_PTR_BUFFER_BACKEND_H +#define SHARED_PTR_BUFFER_BACKEND_H 1 + +#include "circular_buffer_status.hpp" +#include <cstddef> +#include <cstdint> +#include <iostream> +#include <string> +#include <tuple> +#include <memory> +#include <numa.h> + +namespace EB { + class Shared_ptr_buffer_backend { + public: + virtual ~Shared_ptr_buffer_backend(); + Shared_ptr_buffer_backend(){}; + Shared_ptr_buffer_backend(size_t size, size_t alignment = 12, int id = 0, int numa_node = -1); + + std::tuple<void*, size_t> get_buffer(); + bool is_set(); + + uintptr_t _buffer; + + std::shared_ptr<Circular_buffer_status> _remote_buffer_status; + + Circular_buffer_status _local_buffer_status; + + private: + std::shared_ptr<void> _buffer_ptr; + }; +} // namespace EB +#endif // SHARED_PTR_BUFFER_BACKEND_H \ No newline at end of file diff --git a/Online/EventBuilding/include/shmem_buffer_reader.hpp b/Online/EventBuilding/include/shmem_buffer_reader.hpp new file mode 100644 index 000000000..04e5d106f --- /dev/null +++ b/Online/EventBuilding/include/shmem_buffer_reader.hpp @@ -0,0 +1,27 @@ +#ifndef SHMEM_BUFFER_READER_H +#define SHMEM_BUFFER_READER_H 1 + +#include "circular_buffer_reader.hpp" +#include "shared_mem_buffer_backend.hpp" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> + +namespace EB { + template<class T> + class Shmem_buffer_reader : public Circular_buffer_reader<T, Shared_mem_buffer_backend> { + public: + // alignment is explesser in 2^alignment min value 1 + Shmem_buffer_reader() {} + Shmem_buffer_reader(const std::string& shm_name) : + Circular_buffer_reader<T, Shared_mem_buffer_backend>( + std::move(Shared_mem_buffer_backend(shm_name, false, false, false))) + {} + + virtual ~Shmem_buffer_reader() {} + }; +} // namespace EB +#endif // SHMEM_BUFFER_READER_H diff --git a/Online/EventBuilding/include/shmem_buffer_writer.hpp b/Online/EventBuilding/include/shmem_buffer_writer.hpp new file mode 100644 index 000000000..6c9b2c5ab --- /dev/null +++ b/Online/EventBuilding/include/shmem_buffer_writer.hpp @@ -0,0 +1,28 @@ +#ifndef SHMEM_BUFFER_WRITER_H +#define SHMEM_BUFFER_WRITER_H 1 + +#include "circular_buffer_writer.hpp" +#include "shared_mem_buffer_backend.hpp" +#include <cstddef> +#include <cstdint> +#include <deque> +#include <iostream> +#include <string> +#include <tuple> + +namespace EB { + template<class T> + class Shmem_buffer_writer : public Circular_buffer_writer<T, Shared_mem_buffer_backend> { + public: + // alignment is explesser in 2^alignment min value 1 + Shmem_buffer_writer() {} + // Options for unlinking and reconnection are available via the full API of Shared_mem_buffer_backend + Shmem_buffer_writer(const std::string& shm_name, size_t size, uint8_t alignment = 12, int id = 0) : + Circular_buffer_writer<T, Shared_mem_buffer_backend>( + std::move(Shared_mem_buffer_backend(shm_name, true, true, true, size, alignment, id))) + {} + + virtual ~Shmem_buffer_writer() {} + }; +} // namespace EB +#endif // SHMEM_BUFFER_WRITER_H diff --git a/Online/EventBuilding/include/timer.hpp b/Online/EventBuilding/include/timer.hpp new file mode 100644 index 000000000..df9f07956 --- /dev/null +++ b/Online/EventBuilding/include/timer.hpp @@ -0,0 +1,35 @@ +#ifndef TIMER_H +#define TIMER_H 1 +#include <ctime> + +namespace EB { + class Timer { + public: + Timer(clockid_t clk_id = CLOCK_MONOTONIC); + + // start stop and reset of a stop watch timer reset does not stop the timer it clears only the elasped time + void start(); + void stop(); + void reset(); + + // get elasped time is seconds or nano seconds without stopping the timer + double get_elapsed_time_s() const; + clock_t get_elapsed_time_ns() const; + + // setter and getter for the clockid used the setter resets the time to avoid inconsistency + clockid_t get_clk_id() const; + void set_clk_id(clockid_t clk_id); + + void disable(); + void enable(); + bool is_enabled(); + + private: + bool _is_running; + timespec _start_time; + clock_t _elapsed_time; + clockid_t _clock_id; + bool _is_enabled; + }; +} // namespace EB +#endif // TIMER_H \ No newline at end of file diff --git a/Online/EventBuilding/include/transport_unit.hpp b/Online/EventBuilding/include/transport_unit.hpp new file mode 100644 index 000000000..67fa1ec94 --- /dev/null +++ b/Online/EventBuilding/include/transport_unit.hpp @@ -0,0 +1,98 @@ +#ifndef TRANSPORT_UNIT_H +#define TRANSPORT_UNIT_H 1 + +#include <memory> +#include <vector> +#include <cassert> +#include <exception> +#include <string> +#include "logger.hpp" +#include "Parallel_Comm.hpp" +#include "EventBuilding/MEP_tools.hpp" +#include "Dataflow/DataflowComponent.h" + +namespace EB { + using namespace Online; + // static configuration + bool is_bu(int rank, const std::vector<int>& n_rus_nic); + bool is_ru(int rank, const std::vector<int>& n_rus_nic); + + class Transport_unit : public DataflowComponent { + public: + Transport_unit(const std::string& name, Context& framework); + virtual ~Transport_unit(); + + // FOR DEBUG ONLY + void set_rank(int rank); + + virtual int initialize() override; + virtual int finalize() override; + virtual int cancel() override; + virtual int start() override; + virtual int stop() override; + + protected: + int _my_rank; + int _world_size; + int _numa_node; + // Properties + std::vector<int> _n_rus_per_nic; + int _n_par_mess; + std::vector<int> _n_sources_per_ru; + // _ru_ranks and _bu_ranks can either be self assigned or set via an opts file + std::vector<int> _ru_ranks; + std::vector<int> _bu_ranks; + // simmetric shift pattern used when running with the same number of RUs and BUs + std::vector<int> _shift_pattern; + // shift pattern used to send to the RUs + std::vector<int> _RU_shift_pattern; + // shift pattern used to send to the BUs + std::vector<int> _BU_shift_pattern; + bool _MPI_errors_return; + int _profiling_update_interval; + bool _enable_profiling; + + // DEBUG counters + uint32_t _barrier_count; + uint32_t _pre_barrier_count; + // profiling counters + double _sync_time_counter; + double _total_time_counter; + + // Profiling timers + Timer _total_timer; + Timer _sync_timer; + + // prefix sum of the number of sources up to the give idx, the last element is the total number of sources + std::vector<int> _prefix_n_sources_per_ru; + + Log_stream logger; + std::unique_ptr<IB_verbs::Parser> _ibParser; + std::unique_ptr<Parallel_comm> _ibComm; + std::string _ib_config_file = ""; + int sync(); + static std::vector<int> init_shift_pattern(const std::vector<int>& ranks); + int check_shift_pattern(const std::vector<int>& ranks, const std::vector<int>& pattern); + int init_pattern(); + int init_ranks(); + int check_ranks(); + int init_n_sources(); + virtual void reset_counters(); + virtual void update_profiling(); + virtual void init_profiling(); + + // class Shift_pattern_exception : public exception { + // public: + // Shift_pattern_exception(int err_code, const std::vector<int>& pattern, int rank_size, int num_ghost); + // virtual const char what() const throw() { return mess.c_str(); } + // const int err_code; + // const std::vector<int> pattern; + // const int rank_size; + // const int num_ghost; + // private: + // std::string mess; + // } + }; +} // namespace EB + +#endif // TRANSPORT_UNIT_H diff --git a/Online/EventBuilding/options/BU_0.opts b/Online/EventBuilding/options/BU_0.opts new file mode 100644 index 000000000..fc05a9c5c --- /dev/null +++ b/Online/EventBuilding/options/BU_0.opts @@ -0,0 +1,4 @@ +#pragma print off +#include "$EVENTBUILDINGROOT/options/EB_BU.opts" +MEPManager.Buffers = { "Events_0" }; +BU.MBM_name = { "Events_0" }; diff --git a/Online/EventBuilding/options/BU_1.opts b/Online/EventBuilding/options/BU_1.opts new file mode 100644 index 000000000..33f12dc5b --- /dev/null +++ b/Online/EventBuilding/options/BU_1.opts @@ -0,0 +1,4 @@ +#pragma print off +#include "$EVENTBUILDINGROOT/options/EB_BU.opts" +MEPManager.Buffers = { "Events_1" }; +BU.MBM_name = { "Events_1" }; diff --git a/Online/EventBuilding/options/EB_BU.opts b/Online/EventBuilding/options/EB_BU.opts new file mode 100755 index 000000000..cf04af7b2 --- /dev/null +++ b/Online/EventBuilding/options/EB_BU.opts @@ -0,0 +1,33 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIG_OPTIONS/Logging.opts" +#include "$FARMCONFIG_OPTIONS/Monitoring.opts" +#include "$EVENTBUILDINGROOT/options/EB_transport.opts" + +Manager.Services = { + "Dataflow_MBMClient/MEPManager", + "EB_BU/BU", + "Dataflow_RunableWrapper/Wrap" + }; + +Manager.Runable = "Wrap"; +Wrap.Callable = "BU"; +// algorithm properties +#include "$DYNAMIC_OPTS/EB/EB_BU_algo.opts" + +// properties of the Transport_unit class set them from the EB_transport.opts file +BU.RUs_per_nic = @EB_transport.RUs_per_nic; +BU.n_par_mess = @EB_transport.n_par_mess; +BU.n_sources_per_ru = @EB_transport.n_sources_per_ru; +BU.MPI_errors_return = @EB_transport.MPI_errors_return; +BU.OutputLevel = @EB_transport.OutputLevel; +BU.RU_ranks = @EB_transport.RU_ranks; +BU.BU_ranks = @EB_transport.BU_ranks; +BU.shift_pattern = @EB_transport.shift_pattern; +BU.ib_config_file = @EB_transport.ib_config_file; + +MEPManager.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.PartitionID = @OnlineEnv.PartitionID; +MEPManager.Buffers = @OnlineEnv.Data_Buffers; diff --git a/Online/EventBuilding/options/EB_RU.opts b/Online/EventBuilding/options/EB_RU.opts new file mode 100755 index 000000000..0682fdc44 --- /dev/null +++ b/Online/EventBuilding/options/EB_RU.opts @@ -0,0 +1,24 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$EVENTBUILDINGROOT/options/EB_transport.opts" +#include "$FARMCONFIG_OPTIONS/Monitoring.opts" +#include "$FARMCONFIG_OPTIONS/Logging.opts" + +Manager.Services = {"EB_RU/RU", + "Dataflow_RunableWrapper/Wrap" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "RU"; +// algorithm properties +#include "$DYNAMIC_OPTS/EB/EB_RU_algo.opts" + +// properties of the Transport_unit class set them from the EB_transport.opts file +RU.RUs_per_nic = @EB_transport.RUs_per_nic; +RU.n_par_mess = @EB_transport.n_par_mess; +RU.n_sources_per_ru = @EB_transport.n_sources_per_ru; +RU.MPI_errors_return = @EB_transport.MPI_errors_return; +RU.OutputLevel = @EB_transport.OutputLevel; +RU.RU_ranks = @EB_transport.RU_ranks; +RU.BU_ranks = @EB_transport.BU_ranks; +RU.shift_pattern = @EB_transport.shift_pattern; +RU.ib_config_file = @EB_transport.ib_config_file; diff --git a/Online/EventBuilding/options/EB_RU_algo.opts b/Online/EventBuilding/options/EB_RU_algo.opts new file mode 100644 index 000000000..91ff2aab5 --- /dev/null +++ b/Online/EventBuilding/options/EB_RU_algo.opts @@ -0,0 +1,9 @@ +RU.MDF_filename = "/home/fpisani/mc_data/biger_file.mdf"; +RU.PCIe40_ids = {}; +RU.PCIe40_names = { 'tdtel051_1', 'tdtel052_0', 'tdtel052_1', 'tdtel053_0', 'tdtel053_1' }; +RU.buffer_sizes = {}; +RU.buffer_type = { 1 }; +RU.n_MFPs = 100; +RU.n_fragment = 3000; +RU.shmem_prefix = "RU"; +RU.stop_timeout = 60; diff --git a/Online/EventBuilding/options/EB_transport.opts b/Online/EventBuilding/options/EB_transport.opts new file mode 100644 index 000000000..e0120531c --- /dev/null +++ b/Online/EventBuilding/options/EB_transport.opts @@ -0,0 +1,10 @@ +EB_transport.MPI_errors_return = true; +EB_transport.OutputLevel = 3; +// an empty array will trigger the default value in the code +EB_transport.RU_ranks = {}; +EB_transport.BU_ranks = {}; +EB_transport.shift_pattern = {}; +//EB_transport.ib_config_file = "$EVENTBUILDINGROOT/options/hosts_example.json"; + +// EB transport_unit properties +#include "$DYNAMIC_OPTS/EB/EB_Transport_properties.opts" diff --git a/Online/EventBuilding/options/MFPGen.opts b/Online/EventBuilding/options/MFPGen.opts new file mode 100755 index 000000000..d783949f9 --- /dev/null +++ b/Online/EventBuilding/options/MFPGen.opts @@ -0,0 +1,11 @@ +#pragma print on +#include "$INFO_OPTIONS" +#include "$EVENTBUILDINGROOT/options/EB_transport.opts" +#include "$FARMCONFIG_OPTIONS/Logging.opts" + +Manager.Services = {"MFP_generator/MFP_generator", + "Dataflow_RunableWrapper/Wrap" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "MFP_generator"; +#include "$DYNAMIC_OPTS/EB/MFP_generator_params.opts" diff --git a/Online/EventBuilding/scripts/example_debug_config.json b/Online/EventBuilding/scripts/example_debug_config.json new file mode 100644 index 000000000..3b0b91d83 --- /dev/null +++ b/Online/EventBuilding/scripts/example_debug_config.json @@ -0,0 +1,33 @@ +{ + "gdb_runfile": "Online/EventBuilding/scripts/run.gdb", + "mbm": { + "debug": [ + "host list python regex are supported" + ], + "xterm": [ + "host list python regex are supported" + ] + }, + "mfp": { + "debug": [ + "host list python regex are supported" + ], + "xterm": [ + "host list python regex are supported" + ] + }, + "eb": { + "ru_debug": [ + "host list python regex are supported" + ], + "ru_xterm": [ + "host list python regex are supported" + ], + "bu_debug": [ + "host list python regex are supported" + ], + "bu_xterm": [ + "host list python regex are supported" + ] + } +} \ No newline at end of file diff --git a/Online/EventBuilding/scripts/gen_config.py b/Online/EventBuilding/scripts/gen_config.py new file mode 100755 index 000000000..494117522 --- /dev/null +++ b/Online/EventBuilding/scripts/gen_config.py @@ -0,0 +1,211 @@ +import json +import argparse +import numpy as np +import re +import itertools +import shlex + +hca_conversion_map = { + 'HCA-1': 0, + 'HCA-2': 1, + 'mlx5_0': 0, + 'mlx5_1': 1, +} + +dev_name_conversion = ['mlx5_0', 'mlx5_1'] + + +def consecutive(data, stepsize=1): + return np.split(data, np.where(np.diff(data) != stepsize)[0] + 1) + + +def parse_sequence(sec): + ret_val = sum( + ((list(range( + *[int(b) + c + for c, b in enumerate(a.split('-'))])) if '-' in a else [int(a)]) + for a in sec.split(',')), []) + return ret_val + + +def parse_line(line): + fields = line.split() + if (len(fields) == 2) and (fields[1] == "DUMMY"): + # DUMMY node + ret_val = (-1, -1) + elif (len(fields) == 3): + ret_val = (fields[1], hca_conversion_map[fields[2]]) + else: + ret_val = (-2, -2) + + return ret_val + + +def parse_file_hosts(file_name, hosts): + reg_expr = [re.compile(host) for host in hosts] + + ret_val = [] + with open(file_name, 'r') as input_file: + for line in input_file.readlines(): + if (any( + [expr.search(line.split()[1]) != None for expr in reg_expr])): + ret_val.append(parse_line(line)) + else: + ret_val.append((-1, -1)) + + return ret_val + + +def parse_file_lines(file_name, lines): + unique_lines = np.unique(np.array(lines)) + + ret_val = [] + with open(file_name, 'r') as input_file: + for line_num, line in enumerate(input_file.readlines()): + if (line_num in unique_lines): + ret_val.append(parse_line(line)) + else: + ret_val.append((-1, -1)) + + return ret_val + + +def generate_host_json(hostname, dev, rank_id): + return [{ + 'hostname': hostname, + 'ibdev': dev_name_conversion[dev], + 'rankid': rank_id, + 'utgid': f'EB_{hostname.upper()}_RU_{dev}' + }, { + 'hostname': hostname, + 'ibdev': dev_name_conversion[dev], + 'rankid': rank_id + 1, + 'utgid': f'EB_{hostname.upper()}_BU_{dev}' + }] + + +def generate_json(host_list): + ret_val = {"hosts": []} + node_idx = 0 + rankid = 0 + sorted_hosts_ids = sorted(range(len(host_list)), + key=lambda k: host_list[k] + if host_list[k][1] >= 0 else ('', -1)) + + for host, dev in [ + host_list[k] for k in sorted_hosts_ids if host_list[k][1] >= 0 + ]: + ret_val['hosts'].extend(generate_host_json(host, dev, rankid)) + rankid += 2 + + return ret_val + + +def generate_hostfile(host_list): + return [ + f'{host}' + for host, dev in sorted(host_list, + key=lambda k: k if k[1] >= 0 else ('', -1)) + if dev >= 0 + ] + + +def generate_shift(host_list, switch_radix): + valid_hosts = [(host, dev) for host, dev in sorted( + host_list, key=lambda k: k if k[1] >= 0 else ('', -1)) if dev >= 0] + hosts_dict = {key: idx for idx, key in enumerate(valid_hosts)} + shift_pattern = np.array([hosts_dict.get(key, -1) for key in host_list]) + + shift_pattern = shift_pattern.reshape( + (len(shift_pattern) // switch_radix, switch_radix)) + + mask = shift_pattern == np.full_like(shift_pattern, -1) + # shift_pattern = np.delete(shift_pattern, np.all(mask, axis=1), axis=0) + shift_pattern = np.delete(shift_pattern, + np.nonzero(np.all(mask, axis=1)), + axis=0) + + mask = shift_pattern == np.full_like(shift_pattern, -1) + #shift_pattern = np.delete(shift_pattern, np.all(mask, axis=0), axis=1) + shift_pattern = np.delete(shift_pattern, + np.nonzero(np.all(mask, axis=0)), + axis=1) + + return shift_pattern + + +def main(): + parser = argparse.ArgumentParser( + description='EB configuration script', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + parser.add_argument("-f", + "--fat_tree_file", + help='Optimal shift patter generated by opensm.', + type=str, + required=True) + + parser.add_argument("-j", + "--json", + help='Ouput json config file name.', + type=str, + default='config.json', + required=False) + + parser.add_argument("-H", + "--hostfile", + help='Ouput host file.', + type=str, + default='host.txt', + required=False) + + parser.add_argument("-l", + "--lines", + help='List of line ranges e.g. 0,1,2,3-10.', + type=str, + default='', + required=False) + + parser.add_argument( + "-n", + "--nodes", + help= + "List of regular expressions used to include nodes e.g. 'tdeb0[0-9],uaeb.*'", + type=str, + default='.*', + required=False) + + parser.add_argument( + "-r", + "--radix", + help='switch radix (number of ports connected to the nodes).', + type=int, + default=20, + required=False) + + args = parser.parse_args() + + if (args.lines != ''): + lines = parse_sequence(args.lines) + + hosts = parse_file_lines(args.fat_tree_file, lines) + else: + host_match = args.nodes.split(',') + hosts = parse_file_hosts(args.fat_tree_file, host_match) + + with open(args.json, 'w') as outfile: + json.dump(generate_json(hosts), outfile, indent=2) + + with open(args.hostfile, 'w') as outfile: + outfile.write('\n'.join(generate_hostfile(hosts))) + + shift_pattern = np.concatenate(generate_shift(hosts, args.radix)) + n_nodes = np.count_nonzero(shift_pattern != -1) + n_dummy = len(shift_pattern) - n_nodes + print('EB_transport.shift_pattern = {', ','.join(map(str, shift_pattern)), + '};') + print(f'// n_nodes {n_nodes} n_dummy {n_dummy} active fraction {n_nodes/(n_nodes+n_dummy)}') + + +if __name__ == "__main__": + main() diff --git a/Online/EventBuilding/scripts/monitor_couters.py b/Online/EventBuilding/scripts/monitor_couters.py new file mode 100644 index 000000000..5bc252c38 --- /dev/null +++ b/Online/EventBuilding/scripts/monitor_couters.py @@ -0,0 +1,145 @@ +import argparse +import os +import re +import time +import pydim + +def monitor_counters(bu_metrics, ru_metrics, hosts, partition, time_interval, rate): + services = [] + for host in hosts: + host_metrics = [] + for metric in ru_metrics: + for idx in range(2): + host_metrics.append(f'{host.upper()}_RU_{idx}/RU/{metric}') + if rate: + host_metrics.append(f'{host.upper()}_RU_{idx}/R_RU/{metric}') + + for metric in bu_metrics: + for idx in range(2): + host_metrics.append(f'{host.upper()}_BU_{idx}/BU/{metric}') + if rate: + host_metrics.append(f'{host.upper()}_BU_{idx}/R_BU/{metric}') + + services.append(host_metrics) + + print('host\t' + '\t'.join([service[(service.find('/'))+1:] for service in services[0]])) + + + while True: + for host, host_services in zip(hosts,services): + results = [monitor_counter(service, partition) for service in host_services] + print(f'{host}\t\t' + '\t\t'.join([f'{result[0]:.5f}' if len(result)>=1 else '-' for result in results])) + + + time.sleep(time_interval) + print('host\t' + '\t'.join([service[(service.find('/'))+1:] for service in services[0]])) + + +def monitor_counter(service, partition): + service_name = f'{partition}_{service}' + return pydim.dic_sync_info_service(service_name) + + +def main(): + parser = argparse.ArgumentParser( + description='EB counters reader script', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + host_group = parser.add_mutually_exclusive_group(required=True) + + host_group.add_argument( + "-H", + "--hosts", + help= + 'Comma separated list of hosts to monitor.', + type=str) + + host_group.add_argument( + "-f", + "--host_file", + help= + 'Host file, one hostname per row. # comment', + type=str) + + parser.add_argument("-D", + "--dim_dns", + help='Override the DIM_DNS_NODE env variable value.', + default=None, + type=str) + + parser.add_argument( + "-p", + "--partition", + help= + 'Partition to monitor.', + type=str, + default='LHCb', + required=False) + + parser.add_argument( + "-R", + "--rate", + help= + 'Enable rate counter reading.', + action='store_true', + required=False) + + parser.add_argument( + "-b", + "--bu_counters", + help= + 'Comma separated list of BU counters to monitor.', + type=str, + default='snd_bytes,rcv_bytes,event_counter,discarted_MEP_counter', + required=False) + + parser.add_argument( + "-r", + "--ru_counters", + help= + 'Comma separated list of BU counters to monitor.', + type=str, + default='Events/OUT', + required=False) + + parser.add_argument( + "-t", + "--time", + help= 'Time interval in seconds between prints.', + type=float, + required=False, + default=1) + + args = parser.parse_args() + + env = os.environ.copy() + + if (args.dim_dns): + env['DIM_DNS_NODE'] = args.dim_dns + pydim.dic_set_dns_node(args.dim_dns) + + if (args.hosts): + host_list = args.hosts.split(',') + else : + with open(args.host_file, 'r') as host_file: + no_comment_match = re.compile('([^#]*)(?:#)?.*') + host_list = [match.group(1) for match in + [no_comment_match.match(line.strip()) for line in host_file.readlines()] + if match.group(1) != ''] + + host_list = list(set(host_list)) + + bu_metrics = list(set(args.bu_counters.split(','))) + ru_metrics = list(set(args.ru_counters.split(','))) + + bu_metrics.sort() + ru_metrics.sort() + host_list.sort() + + monitor_counters(bu_metrics, ru_metrics, host_list, args.partition, args.time, args.rate) + + + + +if __name__ == "__main__": + main() diff --git a/Online/EventBuilding/scripts/pcie_checker.py b/Online/EventBuilding/scripts/pcie_checker.py new file mode 100644 index 000000000..13e29f755 --- /dev/null +++ b/Online/EventBuilding/scripts/pcie_checker.py @@ -0,0 +1,118 @@ +import os +import pwd +import sys +import signal +import subprocess +import shlex +import argparse +import time +import re +import distutils.core +import itertools +import json +import multiprocessing +import functools + + +def get_pcie_ids(device_grep, host): + device_id_cmd = f'ssh {host} /usr/sbin/lspci | grep -i {device_grep}' + pipe = subprocess.Popen(shlex.split(device_id_cmd), stdout=subprocess.PIPE) + output = pipe.communicate()[0].decode("utf-8") + pcie_ids = [ + line.split(' ')[0] for line in output.split('\n') if len(line) > 0 + ] + return pcie_ids + + +def get_pcie_status(device_grep, host): + pcie_ids = get_pcie_ids(device_grep, host) + device_status_cmds = [ + f'ssh {host} sudo /usr/sbin/lspci -s {dev_id} -vvv' + for dev_id in pcie_ids + ] + outs = [ + subprocess.Popen( + shlex.split(cmd), + stdout=subprocess.PIPE).communicate()[0].decode("utf-8") + for cmd in device_status_cmds + ] + + match = re.compile( + 'LnkSta:\s+Speed\s+(?P<link_speed>[0-9]+)GT/s,\s+Width\s+x(?P<link_width>[0-9]+)' + ) + + matches = [(dev_id, match.search(out)) + for dev_id, out in zip(pcie_ids, outs)] + + speed_widths = [(dev_id, int(out_match.group('link_speed')), + int(out_match.group('link_width'))) + for dev_id, out_match in matches if out_match != None] + + return speed_widths + + +def check_pcie_status(curr_width, curr_speed, target_width, target_speed): + return (curr_width == target_width) and (curr_speed == target_speed) + + +def main(): + parser = argparse.ArgumentParser( + description='EB startup script', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + parser.add_argument("-H", + "--hostfile", + help='Host/device file.' + 'Every line must contain an hostname.', + type=str, + required=True) + + parser.add_argument("-p", + "--parallel", + help='Number of parallel ssh connections', + type=int, + default=16, + required=False) + + parser.add_argument("-s", + "--speed", + help='Link speed in GT/s', + type=int, + default=16, + required=False) + + parser.add_argument("-w", + "--width", + help='Link width', + type=int, + default=16, + required=False) + + parser.add_argument( + "-v", + "--vendor", + help='Device vendor string to parse (case insensitive)', + type=str, + default='mellanox', + required=False) + + args = parser.parse_args() + + with open(args.hostfile, 'r') as host_file: + hosts = set( + [line.strip().split(' ')[0] for line in host_file.readlines()]) + + pool = multiprocessing.Pool(processes=args.parallel) + + status_funct = functools.partial(get_pcie_status, args.vendor) + + pcie_statuses = pool.map(status_funct, hosts) + + for host, devs in zip(hosts, pcie_statuses): + for dev_id, speed, width in devs: + if (not check_pcie_status(width, speed, args.width, args.speed)): + print(host, dev_id, f'{speed} GT/s x{width}') + + +if __name__ == "__main__": + main() diff --git a/Online/EventBuilding/scripts/read_eb_counters.py b/Online/EventBuilding/scripts/read_eb_counters.py new file mode 100644 index 000000000..086493471 --- /dev/null +++ b/Online/EventBuilding/scripts/read_eb_counters.py @@ -0,0 +1,138 @@ +import run_eb_scan +import argparse +import os +import re +import pydim +import csv + +def main(): + parser = argparse.ArgumentParser( + description='EB counters reader script', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + host_group = parser.add_mutually_exclusive_group(required=True) + + host_group.add_argument( + "-H", + "--hosts", + help= + 'Comma separated list of hosts to monitor.', + type=str) + + host_group.add_argument( + "-f", + "--host_file", + help= + 'Host file, one hostname per row. # comment', + type=str) + + parser.add_argument( + "-o", + "--out", + help= + 'Output file.', + default='eb_counters.csv', + type=str) + + parser.add_argument("-D", + "--dim_dns", + help='Override the DIM_DNS_NODE env variable value.', + default=None, + type=str) + + parser.add_argument( + "-p", + "--partition", + help= + 'Partition to monitor.', + type=str, + default='LHCb', + required=False) + + parser.add_argument( + "-R", + "--rate", + help= + 'Enable rate counter reading.', + type=bool, + default=False, + required=False) + + parser.add_argument( + "-b", + "--bu_counters", + help= + 'Comma separated list of BU counters to monitor.', + type=str, + default='snd_bytes,rcv_bytes,event_counter,discarted_MEP_counter', + required=False) + + parser.add_argument( + "-r", + "--ru_counters", + help= + 'Comma separated list of BU counters to monitor.', + type=str, + default='Events/OUT', + required=False) + + parser.add_argument( + "-t", + "--time", + help= 'Time interval in seconds.', + type=float, + required=True) + + args = parser.parse_args() + + env = os.environ.copy() + + if (args.dim_dns): + env['DIM_DNS_NODE'] = args.dim_dns + pydim.dic_set_dns_node(args.dim_dns) + + if (args.hosts): + host_list = args.hosts.split(',') + else : + with open(args.host_file, 'r') as host_file: + no_comment_match = re.compile('([^#]*)(?:#)?.*') + host_list = [match.group(1) for match in + [no_comment_match.match(line.strip()) for line in host_file.readlines()] + if match.group(1) != ''] + + bu_metrics = list(set(args.bu_counters.split(','))) + ru_metrics = list(set(args.ru_counters.split(','))) + + services = [] + for metric in ru_metrics: + for host in host_list: + for idx in range(2): + services.append(f'{host.upper()}_RU_{idx}/RU/{metric}') + if(args.rate): + services.append(f'{host.upper()}_RU_{idx}/R_RU/{metric}') + + for metric in bu_metrics: + for host in host_list: + for idx in range(2): + services.append(f'{host.upper()}_BU_{idx}/BU/{metric}') + if(args.rate): + services.append(f'{host.upper()}_BU_{idx}/R_BU/{metric}') + + res = run_eb_scan.check_data_df(services, args.time, args.partition) + + # transpose_res = [dict()]*len(list(res.values())[0]) + transpose_res = [dict() for k in range(len(list(res.values())[0]))] + for key, values in res.items(): + for k, value in enumerate(values): + transpose_res[k][key] = value + + with open(args.out, 'w') as out_file: + writer = csv.DictWriter(out_file, fieldnames=res.keys()) + writer.writeheader() + for data in transpose_res: + writer.writerow(data) + + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Online/EventBuilding/scripts/run.gdb b/Online/EventBuilding/scripts/run.gdb new file mode 100644 index 000000000..0af8e376f --- /dev/null +++ b/Online/EventBuilding/scripts/run.gdb @@ -0,0 +1,9 @@ +set breakpoint pending on + +break BU.cpp:498 +# break BU.cpp:119 +# break mbm_writer_impl.hpp:31 +# break Producer.cpp:219 + + +run \ No newline at end of file diff --git a/Online/EventBuilding/scripts/run_eb.py b/Online/EventBuilding/scripts/run_eb.py new file mode 100755 index 000000000..3ab6949f0 --- /dev/null +++ b/Online/EventBuilding/scripts/run_eb.py @@ -0,0 +1,473 @@ +import os +import pwd +import sys +import signal +import subprocess +import shlex +import argparse +import time +import re +import random +import distutils.core +import itertools +import json +import tempfile + +mpi_base_options = shlex.split('-bind-to none') +gdb_base_command = shlex.split('gdb') +mpi_base_command = shlex.split('mpirun -oversubscribe') +mpi_ib_options = shlex.split('') +dataflow_task = shlex.split( + 'gentest.exe libDataflow.so dataflow_run_task -msg=Dataflow_OutputLogger -mon=Dataflow_DIMMonitoring' +) + + +def split_lst(lst, n): + """Yield successive n-sized chunks from lst.""" + for i in range(0, len(lst), n): + yield lst[i:i + n] + + +def signal_handler(sig, frame): + print('Caught SIGINT. Exiting...') + + processes = [ + frame.f_locals['mfp_gen_proc'], frame.f_locals['eb_proc'], + frame.f_locals['mbm_proc'] + ] + + for process in processes: + if process: + process.kill() + + kill_exit = 0 + if (frame.f_locals['args'].kill): + kill_exit += kill_gentest(frame.f_locals['hosts'], 32) + else: + kill_exit = 0 + + sys.exit(kill_exit) + + +def kill_gentest(hosts, n_proc): + kill_exit = 0 + hosts = list(set(hosts)) + for host_split in split_lst(hosts, n_proc): + kills = [ + subprocess.Popen(shlex.split(f'ssh {host} killall gentest.exe')) + for host in host_split + ] + + kill_exit += sum([proc.wait() for proc in kills]) + + return kill_exit + + +def shell_source(script): + """Sometime you want to emulate the action of "source" in bash, + settings some environment variables. Here is a way to do it.""" + pipe = subprocess.Popen(f'source {os.path.abspath(script)} ; env -0', + stdout=subprocess.PIPE, + shell=True) + output = pipe.communicate()[0].decode("utf-8") + env = os.environ.copy() + env.update(dict(line.partition('=')[::2] for line in output.split('\0'))) + return env + + +def gen_env_file(env, tmp_dir=None): + # remove empty keys and macros the MPI parser does't like macros + def clean_funct(x): + return (x != '') and ('()' not in x) + + env_list = (f'-x {var}\n' for var in filter(clean_funct, env.keys())) + temp_file = tempfile.NamedTemporaryFile(mode='w', + prefix='eb_env_', + dir=tmp_dir) + + temp_file.writelines(env_list) + temp_file.flush() + + return temp_file + + +def start_mbm(env, env_file_name, host_list, auto, debug_config): + mpi_command = mpi_base_command.copy() + # mpi gets env from a file + mpi_command.extend(shlex.split(f'-tune {env_file_name}')) + + df_task_full = dataflow_task + \ + shlex.split( + f'-class=Class0 -opts={env["EVENTBUILDINGROOT"]}/options/MBM_server.opts') + if (auto): + df_task_full.append('-auto') + + if (debug_config): + gdb_runfile = debug_config['gdb_runfile'] + debug_list = [ + re.compile(item) for item in debug_config['mbm']['debug'] + ] + xterm_list = [ + re.compile(item) for item in debug_config['mbm']['xterm'] + ] + + rank = 0 + xterm_ranks = [] + local_id = {host: 0 for host in host_list} + for k, host in enumerate(host_list): + mpi_command.extend(shlex.split(f'-H {host}')) + mpi_command.extend(mpi_base_options) + mpi_command.extend( + shlex.split( + f'-x DIM_HOST_NODE={host} -x UTGID=EB_{host.upper()}_MBM_{local_id[host]}' + )) + + if (debug_config): + debug_commands(host, rank, debug_list, xterm_list, gdb_runfile, + mpi_command, xterm_ranks) + + mpi_command.extend(df_task_full) + mpi_command.append(':') + rank += 1 + local_id[host] += 1 + + if (xterm_ranks): + mpi_command[1:1] = shlex.split('-xterm ' + + ','.join(str(x) for x in xterm_ranks)) + + return subprocess.Popen(mpi_command, env=env, cwd=env['PWD'], shell=False) + + +def start_mfp_gen(env, env_file_name, host_list, n_rus_per_nic, + n_sources_per_ru, auto, debug_config): + mpi_command = mpi_base_command.copy() + # mpi gets env from a file + mpi_command.extend(shlex.split(f'-tune {env_file_name}')) + + df_task_full = dataflow_task + \ + shlex.split( + f'-class=Class1 -opts={env["EVENTBUILDINGROOT"]}/options/MFP_generator.opts') + if (auto): + df_task_full.append('-auto') + + if (debug_config): + gdb_runfile = debug_config['gdb_runfile'] + debug_list = [ + re.compile(item) for item in debug_config['mfp']['debug'] + ] + xterm_list = [ + re.compile(item) for item in debug_config['mfp']['xterm'] + ] + + rank = 0 + ru_idx = 0 + xterm_ranks = [] + local_id = {host: 0 for host in host_list} + for k, host in enumerate(host_list): + for count in range(n_rus_per_nic[k]): + for src_idx in range(n_sources_per_ru[ru_idx]): + seed = int(4096 * random.random()) + mpi_command.extend(shlex.split(f'-H {host}')) + mpi_command.extend(mpi_base_options) + mpi_command.extend( + shlex.split( + f' -x DIM_HOST_NODE={host} -x UTGID=EB_{host.upper()}_MFPGen_{local_id[host]} -x RAND_SEED={seed} -x MFP_SRC_ID={20*(k+1) - local_id[host]}' + )) + if (debug_config): + debug_commands(host, rank, debug_list, xterm_list, + gdb_runfile, mpi_command, xterm_ranks) + + mpi_command.extend(df_task_full) + mpi_command.append(':') + rank += 1 + local_id[host] += 1 + ru_idx += 1 + + if (xterm_ranks): + mpi_command[1:1] = shlex.split('-xterm ' + + ','.join(str(x) for x in xterm_ranks)) + + return subprocess.Popen(mpi_command, env=env, cwd=env['PWD'], shell=False) + + +def start_eb(env, env_file_name, host_list, n_rus_per_nic, auto, debug_config): + mpi_command = mpi_base_command.copy() + # mpi gets env from a file + mpi_command.extend(shlex.split(f'-tune {env_file_name}')) + + df_task_full = dataflow_task + \ + shlex.split( + f'-class=Class1') + if (auto): + df_task_full.append('-auto') + + if (debug_config): + gdb_runfile = debug_config['gdb_runfile'] + ru_debug_list = [ + re.compile(item) for item in debug_config['eb']['ru_debug'] + ] + bu_debug_list = [ + re.compile(item) for item in debug_config['eb']['bu_debug'] + ] + ru_xterm_list = [ + re.compile(item) for item in debug_config['eb']['ru_xterm'] + ] + bu_xterm_list = [ + re.compile(item) for item in debug_config['eb']['bu_xterm'] + ] + + bu_local_id = {host: 0 for host in host_list} + ru_local_id = {host: 0 for host in host_list} + rank = 0 + xterm_ranks = [] + for k, host in enumerate(host_list): + for count in range(n_rus_per_nic[k]): + # RUs + mpi_command.extend(shlex.split(f'-H {host}')) + mpi_command.extend(mpi_base_options) + mpi_command.extend( + shlex.split( + f'-x DIM_HOST_NODE={host} -x UTGID=EB_{host.upper()}_RU_{ru_local_id[host]}' + )) + + if (debug_config): + debug_commands(host, rank, ru_debug_list, ru_xterm_list, + gdb_runfile, mpi_command, xterm_ranks) + + mpi_command.extend(df_task_full) + mpi_command.append( + f'-opts={env["EVENTBUILDINGROOT"]}/options/EB_RU.opts') + mpi_command.append(':') + + ru_local_id[host] += 1 + rank += 1 + # BUs + mpi_command.extend(shlex.split(f'-H {host}')) + mpi_command.extend(mpi_base_options) + mpi_command.extend( + shlex.split( + f'-x DIM_HOST_NODE={host} -x UTGID=EB_{host.upper()}_BU_{bu_local_id[host]}' + )) + + if (debug_config): + debug_commands(host, rank, bu_debug_list, bu_xterm_list, + gdb_runfile, mpi_command, xterm_ranks) + + mpi_command.extend(df_task_full) + mpi_command.append( + f'-opts={env["EVENTBUILDINGROOT"]}/options/EB_BU.opts') + mpi_command.append(':') + bu_local_id[host] += 1 + rank += 1 + + if (xterm_ranks): + mpi_command[1:1] = shlex.split('-xterm ' + + ','.join(str(x) for x in xterm_ranks)) + + return subprocess.Popen(mpi_command, env=env, cwd=env['PWD'], shell=False) + + +def debug_commands(host, rank, debug_list, xterm_list, gdb_runfile, + mpi_command, xterm_ranks_list): + if (any((match.fullmatch(host) for match in debug_list))): + mpi_command.extend(shlex.split(f'gdb -x {gdb_runfile} -args')) + xterm_ranks_list.append(rank) + elif (any((match.fullmatch(host) for match in xterm_list))): + xterm_ranks_list.append(rank) + + +def set_env(vars_script): + env = os.environ.copy() + env.update(shell_source(vars_script)) + env['INFO_OPTIONS'] = f'{env["EVENTBUILDINGROOT"]}/options/OnlineEnv.opts' + env['MBM_SETUP_OPTIONS'] = f'{env["EVENTBUILDINGROOT"]}/options/MBMSetup.opts' + return env + + +def parse_DF_opts(opt_file_name): + match = re.compile( + '(?P<prop_name>[a-zA-Z0-9._]+)\s*=\s*{?(?P<prop_value>[a-zA-Z0-9_,$ \t"]+)}?\s*;\s*(?:[^/]{2})?' + ) + with open(opt_file_name, 'r') as opt_file: + properties = { + match_line.group('prop_name'): match_line.group('prop_value') + for line in opt_file.readlines() + for match_line in [match.match(line)] if match_line != None + } + + return properties + + +def parse_DF_opts_list(properties, prop_name, default, list_len): + prop = properties.get(prop_name, '') + val_type = type(default) + if (prop != ''): + ret_val = list(map(val_type, re.split('(?:\s+)?,(?:\s+)?', prop))) + else: + # default value + ret_val = [default] * list_len + + if (len(ret_val) == 1): + ret_val = [ret_val[0]] * list_len + + return ret_val + + +def parse_hostfile(hostfile_name): + with open(hostfile_name, 'r') as hostfile: + comment_match = re.compile('([^#]*)') + matches = map(comment_match.search, hostfile.readlines()) + hosts = [match.group(0).strip() for match in matches if match != None] + + return hosts + + +def main(): + parser = argparse.ArgumentParser( + description='EB startup script', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + parser.add_argument( + "-H", + "--hostfile", + help='Host file.' + 'Every line must contain an hostname. To run multiple units on the same host enter the host name multiple times.' + ' Lines starting with # are threaded as comments.', + type=str, + required=True) + + parser.add_argument( + "-s", + "--setup", + help= + 'Setup file generated by cmsetup (like setup.x86_64-centos7-gcc9-do0.vars).', + type=str, + required=True) + + parser.add_argument( + "-u", + "--user", + help= + 'Prepend the user name to the shmem prefix user by the MFP generator and the RU.', + action='store_true') + + parser.add_argument( + "-d", + "--debug", + help= + 'Debug json config file. Check the example file provided.\n Xterm running processes are not killed by MPI.', + default=None, + type=str) + + parser.add_argument( + "-p", + "--prefix", + help='Shmem prefix user by the MFP generator and the RU.', + type=str, + default='RU') + + parser.add_argument( + "-e", + "--eb", + help="Enable/Disable EB processes, select auto for automatic startup.", + type=lambda x: x.lower() + if x.lower() == 'auto' else bool(distutils.util.strtobool(x)), + default='auto') + + parser.add_argument( + "-m", + "--mfp", + help= + "Enable/Disable MFP generator processes, select auto for automatic startup.", + type=lambda x: x.lower() + if x.lower() == 'auto' else bool(distutils.util.strtobool(x)), + default='auto') + + parser.add_argument( + "-b", + "--mbm", + help="Enable/Disable MBM processes, select auto for automatic startup.", + type=lambda x: x.lower() + if x.lower() == 'auto' else bool(distutils.util.strtobool(x)), + default='auto') + + parser.add_argument("-k", + "--kill", + help="Force killing of gentest.exe on all the hosts.", + action='store_true') + + parser.add_argument("-D", + "--dim_dns", + help='Override the DIM_DNS_NODE env variable value.', + default=None, + type=str) + + parser.add_argument( + "-t", + "--tmp", + help= + 'Shared tmp directory. This directory needs to be writable by the machine running this script and readable by all the machines.', + default=os.getcwd(), + type=str) + + args = parser.parse_args() + + env = set_env(args.setup) + + if (args.dim_dns): + env['DIM_DNS_NODE'] = args.dim_dns + + # configures the shmem_prefix env variable according to the user specified options + + hosts = parse_hostfile(args.hostfile) + + if (args.debug): + with open(args.debug, 'r') as debug_config_file: + debug_config = json.load(debug_config_file) + else: + debug_config = None + + EB_transport_props = parse_DF_opts( + f'{env["EVENTBUILDINGROOT"]}/options/EB_transport.opts') + + n_rus_per_nic = parse_DF_opts_list(EB_transport_props, + 'EB_transport.RUs_per_nic', 1, + len(hosts)) + + n_sources_per_ru = parse_DF_opts_list(EB_transport_props, + 'EB_transport.n_sources_per_ru', 1, + sum(n_rus_per_nic)) + + # write env setup file for mpi + env_file = gen_env_file(env, args.tmp) + + if (args.mbm): + mbm_proc = start_mbm(env, env_file.name, hosts, args.mbm == 'auto', + debug_config) + else: + mbm_proc = None + + time.sleep(2) + + if (args.mfp): + mfp_gen_proc = start_mfp_gen(env, env_file.name, hosts, n_rus_per_nic, + n_sources_per_ru, args.mfp == 'auto', + debug_config) + else: + mfp_gen_proc = None + + time.sleep(2) + + if (args.eb): + eb_proc = start_eb(env, env_file.name, hosts, n_rus_per_nic, + args.eb == 'auto', debug_config) + else: + eb_proc = None + + signal.signal(signal.SIGINT, signal_handler) + print("Press Ctrl+C to exit.") + signal.pause() + + +if __name__ == "__main__": + main() diff --git a/Online/EventBuilding/scripts/run_eb_scan.py b/Online/EventBuilding/scripts/run_eb_scan.py new file mode 100755 index 000000000..ef7da5a7a --- /dev/null +++ b/Online/EventBuilding/scripts/run_eb_scan.py @@ -0,0 +1,465 @@ +import os +import pwd +import sys +import signal +import subprocess +import shlex +import argparse +import time +import re +import random +import distutils.core +import itertools +import json +import tempfile +import datetime +import pydim +import numpy as np +import statistics +import run_eb +import gen_config + + +def scan_config(lines, tmp_folder, out_folder, fat_tree_file, hostfile_name, + json_name, scan_idx, switch_radix, shift_pattern_file): + hosts = gen_config.parse_file_lines(fat_tree_file, lines) + + host_list = gen_config.generate_hostfile(hosts) + + shift_pattern = [] + + if (len(host_list) > 0): + + with open(f'{out_folder}/scan_{scan_idx}_{hostfile_name}', + 'w') as outfile: + outfile.write('\n'.join(host_list)) + + # TODO hack to keep the json files + json_config = gen_config.generate_json(hosts) + + with open(json_name, 'w') as outfile: + json.dump(json_config, outfile, indent=2) + + with open(f'{out_folder}/scan_{scan_idx}.json', 'w') as outfile: + json.dump(json_config, outfile, indent=2) + + shift_pattern = np.concatenate( + gen_config.generate_shift(hosts, switch_radix)) + + shift_pattern_property = 'EB_transport.shift_pattern = {' + ','.join( + map(str, shift_pattern)) + '};\n' + + # TODO hack to keep the shift pattern files + with open(shift_pattern_file, 'w') as outfile: + outfile.write(shift_pattern_property) + + with open(f'{out_folder}/scan_{scan_idx}_shift_pattern.opts', + 'w') as outfile: + outfile.write(shift_pattern_property) + else: + print('This step has 0 valid nodes, skipping.') + + return host_list, shift_pattern + + +def scan_step(hostfile, env, tmp_folder, debug_config): + hosts = run_eb.parse_hostfile(hostfile) + + EB_transport_props = run_eb.parse_DF_opts( + f'{env["EVENTBUILDINGROOT"]}/options/EB_transport.opts') + + n_rus_per_nic = run_eb.parse_DF_opts_list(EB_transport_props, + 'EB_transport.RUs_per_nic', 1, + len(hosts)) + + n_sources_per_ru = run_eb.parse_DF_opts_list( + EB_transport_props, 'EB_transport.n_sources_per_ru', 1, + sum(n_rus_per_nic)) + + # write env setup file for mpi + env_file = run_eb.gen_env_file(env, tmp_folder) + + mfp_gen_proc = run_eb.start_mfp_gen(env, env_file.name, hosts, + n_rus_per_nic, n_sources_per_ru, True, + debug_config) + + time.sleep(2) + + eb_proc = run_eb.start_eb(env, env_file.name, hosts, n_rus_per_nic, True, + debug_config) + + time.sleep(2) + + return (mfp_gen_proc, eb_proc) + + +def check_warm_up(host, timeout=120): + res = [] + + service_name = f'EB_{host.upper()}_BU_0/R_BU/rcv_bytes' + srv_id = pydim.dic_info_service(service_name, + lambda x: res.append(x / 1e9 * 8)) + + timeout_delta = datetime.timedelta(seconds=timeout) + + start_time = datetime.datetime.now() + + stable_val = lambda vec: (abs(vec[-1] - vec[-2]) < 10) and (vec[ + -1] > 20) if len(vec) >= 2 else False + + while ((not stable_val(res)) + and ((datetime.datetime.now() - start_time) < timeout_delta)): + time.sleep(10) + + pydim.dic_release_service(srv_id) + + if (stable_val(res)): + print('warmup done') + else: + print('WARNING warmup timed out') + +def check_data_df(services, total_time, partition='EB'): + unique_services_list = list(set(services)) + # unique_host_list = [host_list[0]] + + res = {} + ids = [] + + print("services " , unique_services_list) + for service in unique_services_list: + # TODO change this to measure BW + service_name = f'{partition.upper()}_{service}' + service_fields = service_name.split('/') + service_key = service_fields[0] + '/' + '/'.join(service_fields[2:]) + if 'R_' in service_fields[1]: + service_key += '/rate' + try: + data_list = res[service_key] + except KeyError: + data_list = list() + res[service_key] = data_list + ids.append( + pydim.dic_info_service( + service_name, + lambda x, data=data_list: data.append(x))) + + time.sleep(total_time) + # for _ in range(total_time): + # time.sleep(1) + + list(map(lambda idx: pydim.dic_release_service(idx), ids)) + + return res + +def check_data(host_list, total_time, counter_names, partition='EB', unit='BU'): + unique_host_list = list(set(host_list)) + # unique_host_list = [host_list[0]] + + res = { + key: [list() for k in range(len(unique_host_list) * 2)] + for key in counter_names + } + ids = [] + + k = 0 + for host in unique_host_list: + for idx in range(2): + # TODO change this to measure BW + for counter in counter_names: + service_name = f'{partition}_{host.upper()}_{unit}_{idx}/R_{unit}/{counter}' + ids.append( + pydim.dic_info_service( + service_name, + lambda x, res=res[counter], k=k: res[k].append(x))) + + k += 1 + + time.sleep(total_time) + # for _ in range(total_time): + # time.sleep(1) + + list(map(lambda idx: pydim.dic_release_service(idx), ids)) + + return res + + +def window_scan(win_size, env, tmp, out_folder, fat_tree_file, host_file, + json_file_name, switch_radix, pattern_file, selected_steps, duration): + # get line count + with open(fat_tree_file) as f: + line_count = sum(1 for _ in f) + + with open(f'{out_folder}/scan_summary.dat', 'w') as summary_file: + summary_file.write(f'# window step run win size {win_size}\n') + + lines = [ + list(range(n, n + win_size)) + for n in range(0, line_count - win_size + 1, 2) + ] + + run_scan(lines, env, tmp, out_folder, fat_tree_file, host_file, + json_file_name, switch_radix, pattern_file, selected_steps, duration) + + +def switch_window_scan(min_port, max_port, increment, env, tmp, out_folder, + fat_tree_file, host_file, json_file_name, switch_radix, + pattern_file, selected_steps, duration): + # get line count + with open(fat_tree_file) as f: + line_count = sum(1 for _ in f) + + if ((line_count % switch_radix) != 0): + print(f"WARNING number of entries in {fat_tree_file} are not multiple of the switch radix.\n"\ + f"N entries {line_count} switch radix {switch_radix}") + + with open(f'{out_folder}/scan_summary.dat', 'w') as summary_file: + summary_file.write( + f'# switch window step run with range {min_port} {max_port} {increment}\n' + ) + + # TODO this is quite unreadable + steps = range(min_port, max_port, increment) + lines = [None] * len(steps) + n_switches = line_count // switch_radix + for idx, n in enumerate(steps): + lines[idx] = [ + port for sw in range(0, n_switches) + for port in range(sw * switch_radix + min_port, sw * switch_radix + + n + increment) + ] + + run_scan(lines, env, tmp, out_folder, fat_tree_file, host_file, + json_file_name, switch_radix, pattern_file, selected_steps, duration) + + +def run_scan(lines, env, tmp, out_folder, fat_tree_file, host_file, + json_file_name, switch_radix, pattern_file, steps, duration): + + metrics = ['rcv_bytes', 'event_counter'] + + with open(f'{out_folder}/scan_summary.dat', 'a') as summary_file: + summary_file.write('# step, Nu nodes | n dummy |' + '|'.join([ + f' avg {metric} | std {metric} | total {metric} ' + for metric in metrics + ]) + '\n') + + if (steps == None): + steps = list(range(len(lines))) + + for step_num, step_lines in [(idx, val) + for idx, val in enumerate(lines) + if idx in steps]: + host_list, shift_pattern = scan_config(step_lines, tmp, out_folder, + fat_tree_file, host_file, + json_file_name, step_num, + switch_radix, pattern_file) + + if (len(host_list) > 0): + n_dummy = np.count_nonzero(shift_pattern == -1) + n_nodes = len(shift_pattern) - n_dummy + + summary_file.write(f'{step_num} {n_nodes} {n_dummy} ') + run_eb.kill_gentest(host_list, 32) + + processes = scan_step( + f'{out_folder}/scan_{step_num}_{host_file}', env, tmp, + None) + + check_warm_up(host_list[0], 180) + res = check_data(host_list, duration, metrics) + + for process in processes: + if process: + process.kill() + + run_eb.kill_gentest(host_list, 32) + + for metric in metrics: + with open( + f'{out_folder}/scan_{step_num}_{metric}_rate_raw.dat', + 'w') as outfile: + outfile.write(f'# raw scan step {step_num}\n') + outfile.write(f'# {"|".join(host_list)}\n') + for line in [ + ' '.join(map(str, elem)) + for elem in (zip(*res[metric])) + ]: + outfile.write(line + '\n') + data = np.concatenate(res[metric]) + mean = data.mean() + std = data.std() + sum = data.sum() + summary_file.write(f'{mean} {std} {sum} ') + + summary_file.write('\n') + summary_file.flush() + + +def main(): + parser = argparse.ArgumentParser( + description='EB run scanner script', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + parser.add_argument( + "-s", + "--setup", + help= + 'Setup file generated by cmsetup (like setup.x86_64-centos7-gcc9-do0.vars).', + type=str, + required=True) + + parser.add_argument( + "-d", + "--debug", + help= + 'Debug json config file. Check the example file provided.\n Xterm running processes are not killed by MPI.', + default=None, + type=str) + + parser.add_argument("-D", + "--dim_dns", + help='Override the DIM_DNS_NODE env variable value.', + default=None, + type=str) + + parser.add_argument( + "-p", + "--pattern", + help= + 'Shift pattern file name. This must match the file included in the transport unit options file', + default='EB_transport_shift.opts', + type=str) + + parser.add_argument( + "-t", + "--tmp", + help= + 'Shared tmp directory. This directory needs to be writable by the machine running this script and readable by all the machines.', + default=os.getcwd(), + type=str) + + parser.add_argument( + "-T", + "--time", + help= + 'Duration of a single step of the scan in seconds.', + default=120, + type=int) + + parser.add_argument( + "-o", + "--out", + help= + 'Shared output directory. This directory needs to be writable by the machine running this script and readable by all the machines.', + default=os.getcwd(), + type=str) + + parser.add_argument("-f", + "--fat_tree_file", + help='Optimal shift patter generated by opensm.', + type=str, + required=True) + + parser.add_argument( + "-r", + "--radix", + help='switch radix (number of ports connected to the nodes).', + type=int, + default=20, + required=False) + + parser.add_argument("-j", + "--json", + help='Ouput json config file name.', + type=str, + default='config.json', + required=False) + + parser.add_argument("-H", + "--hostfile", + help='Ouput host file.', + type=str, + default='host.txt', + required=False) + + parser.add_argument( + "-e", + "--step", + help= + 'Selects a subset of steps in the selected configuration e.g. 0,1,2,5-10', + type=str, + required=False, + default=None) + + scan = parser.add_mutually_exclusive_group(required=True) + + scan.add_argument( + "-S", + "--switch", + help= + 'Scan pattern adds switches with a specific port pattern e.g. 0,1,2,5-10', + type=str) + + scan.add_argument( + "-N", + "--node", + nargs=3, + metavar=('MIN', 'MAX', 'INCREMENT'), + help= + 'Node pattern adds nodes from a specific range (indices from the ftree config file)', + type=int) + + scan.add_argument( + "-W", + "--window", + help= + 'Node pattern scans the full network with window of size WINDOW (indices from the ftree config file)', + type=int) + + scan.add_argument( + "-w", + "--switch_window", + nargs=3, + metavar=('MIN', 'MAX', 'INCREMENT'), + help= + 'Scan pattern adds switches with a specific port range (indices from 0 to radix-1)', + type=int) + + args = parser.parse_args() + + env = run_eb.set_env(args.setup) + + if (args.dim_dns): + env['DIM_DNS_NODE'] = args.dim_dns + pydim.dic_set_dns_node(args.dim_dns) + + if (args.step != None): + steps = gen_config.parse_sequence(args.step) + else: + steps = None + + if (args.window != None): + window_scan(args.window, env, args.tmp, args.out, args.fat_tree_file, + args.hostfile, args.json, args.radix, args.pattern, steps, args.time) + elif (args.switch_window != None): + print(args.switch_window) + switch_window_scan(args.switch_window[0], args.switch_window[1], + args.switch_window[2], env, args.tmp, args.out, + args.fat_tree_file, args.hostfile, args.json, + args.radix, args.pattern, steps, args.time) + + return 0 + + host_list = scan_config([0, 1], args.tmp, args.out, args.fat_tree_file, + args.hostfile, args.json, 0, args.radix, + args.pattern) + + if (len(host_list) > 0): + scan_step(f'{args.out}/scan_{0}_{args.hostfile}', env, args.tmp, None) + + check_warm_up(host_list[0]) + check_data(host_list, 30) + + +if __name__ == "__main__": + main() diff --git a/Online/EventBuilding/src/BU.cpp b/Online/EventBuilding/src/BU.cpp new file mode 100644 index 000000000..01dbc9306 --- /dev/null +++ b/Online/EventBuilding/src/BU.cpp @@ -0,0 +1,959 @@ +#include "EventBuilding/BU.hpp" +#include "shmem_buffer_writer.hpp" +#include "MEP_injector.hpp" +#include "dummy_mep_buffer_writer.hpp" +#include "RTL/rtl.h" +#include <sstream> +#include <algorithm> +#include <numeric> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <chrono> + +const std::string EB::BU_buffer_type_to_string(BU_buffer_types type) +{ + switch (type) { + case dummy_MEP_buffer: return "dummy_MEP_buffer"; + case shmem_MEP_buffer: return "shmem_MEP_buffer"; + case MBM_MEP_buffer: return "MBM_MEP_buffer"; + case MEP_injector_buffer: return "MEP_injector_buffer"; + default: return "Error unkown buffer type"; + } +} + +std::ostream& EB::operator<<(std::ostream& os, BU_buffer_types type) { return os << BU_buffer_type_to_string(type); } + +EB::BU::BU(const std::string& nam, DataflowContext& ctxt) : Transport_unit(nam, ctxt) +{ + // Property declaration + declareProperty("buffer_type", _buffer_type); + declareProperty("shmem_prefix", _shmem_prefix = "BU"); + declareProperty("buffer_size", _prop_buffer_sizes); + declareProperty("discard_buffer_size", _prop_discard_buffer_size = 5); + declareProperty("MBM_name", _mbm_name); + declareProperty("MDF_filename", _MDF_filename); + declareProperty("packing_factor", _packing_factor = 10); + declareProperty("n_meps", _n_meps = 1); + + declareProperty("write_to_file", _write_to_file); + declareProperty("out_file_prefix", _out_file_prefix = "BU"); + declareProperty("n_meps_to_file", _n_meps_to_file = 1); + declareProperty("stop_timeout", _stop_timeout = 10); + declareProperty("sort_src_ids", _sort_src_ids = true); + + // MOnitoring counters declaration + declareMonitor("MEP_counter", _MEP_count, "Number of build MEPs in the RUN"); + declareMonitor("discarted_MEP_counter", _discarted_MEP_count, "Number of discarted MEPs in the RUN"); + declareMonitor("incomplete_MEP_counter", _incomplete_MEP_count, "Number of incomplete MEPs in the RUN"); + declareMonitor("corrupted_MEP_counter", _corrupted_MEP_count, "Number of corrupted MEPs in the RUN"); + declareMonitor("rcv_bytes", _rcv_bytes, "Number of received bytes in the RUN"); + declareMonitor("snd_bytes", _snd_bytes, "Number of bytes sent to HLT1 in the RUN"); + + // DF monitoring counters + declareMonitor("Events/IN", _DF_events_in, "Number events received in the RUN"); + declareMonitor("Events/OUT", _DF_events_out, "Number events processed and sent in RUN"); + declareMonitor("Events/ERROR", _DF_events_err, "Number events with errors in the RUN"); + // DEBUG counters + declareMonitor("run_loop_iteration", _run_loop_iteration, "Iteration fo the run loop in the RUN"); + // profiling counters + declareMonitor("receive_size_time_counter", _receive_size_time_counter); + declareMonitor("calc_offsets_time_counter", _calc_offsets_time_counter); + declareMonitor("build_header_time_counter", _build_header_time_counter); + declareMonitor("linear_shift_time_counter", _linear_shift_time_counter); + declareMonitor("receive_MFPs_time_counter", _receive_MFPs_time_counter); + + logger.set_name(name); +} + +EB::BU::~BU() {} + +int EB::BU::initialize() +{ + logger.info() << "initialize" << std::flush; + int sc = Transport_unit::initialize(); + if (sc != DF_SUCCESS) { + return error("Failed to initialize Transport_unit base class."); + } + + _my_idx = get_idx(_bu_ranks.begin(), _bu_ranks.end(), _my_rank); + if (_my_idx < 0) { + logger.error() << __FUNCTION__ << " this node should not be a BU." << std::flush; + return DF_ERROR; + } + + sc = init_shift(); + if (sc != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " init shift failed" << std::flush; + return DF_ERROR; + } + + // Addding unit index information to the log name + std::stringstream logger_name; + logger_name << logger.get_name() << " idx " << _my_idx; + logger.set_name(logger_name.str()); + + _sizes.resize(_prefix_n_sources_per_ru.back()); + std::fill(_sizes.begin(), _sizes.end(), 0); + + _data_offset_words.resize(_prefix_n_sources_per_ru[_ru_ranks.size()], 0); + std::fill(_data_offset_words.begin(), _data_offset_words.end(), 0); + + _dummy.resize(_n_sources_per_ru.back()); + std::fill(_dummy.begin(), _dummy.end(), 0); + + sc = config_buffer(); + if (sc != DF_SUCCESS) { + return sc; + } + + // TODO check how error handling should be done here + // returning DF_ERROR may not be enough + return DF_SUCCESS; +} + +int EB::BU::start() +{ + auto buflist = _recv_buff->get_full_buffer(); + int ret_val = DF_SUCCESS; + logger.info() << "start" << std::flush; + // start verbs + int sc = Transport_unit::start(); + if (sc != DF_SUCCESS) { + return error("Failed to start Transport_unit base class."); + } + // exchange srcids + ret_val = receive_src_ids(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + _ibComm->ibDeregMRs(); // clear memory regions + + ret_val = sort_src_ids(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + // recv data mr + for (auto& list_it : buflist) { + ret_val = _ibComm->addMR((char*) std::get<0>(list_it), std::get<1>(list_it)); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + } + logger.debug() << "data MRs allocated" << std::flush; + + // recv sizes mr + ret_val = _ibComm->addMR((char*) &_sizes, _sizes.size() * sizeof(uint32_t)); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + logger.debug() << "sync MRs allocated" << std::flush; + + std::lock_guard<decltype(_start_lock)> guard(_start_lock); + _receive_MEPs = true; + reset_counters(); + _end_of_run = true; + return DF_SUCCESS; +} + +int EB::BU::stop() +{ + int ret_val = DF_SUCCESS; + logger.info() << "stop" << std::flush; + std::unique_lock<std::timed_mutex> guard(_loop_lock, std::chrono::duration<int>(_stop_timeout)); + if (guard) { + logger.info() << "stop executed properly" << std::flush; + } else { + logger.error() << "Unable to execute a clean stop. Aborting" << std::flush; + ret_val = DF_ERROR; + } + + _recv_buff->reset_cancel(); + _discard_buff->reset_cancel(); + + int sc = Transport_unit::stop(); + if (sc != DF_SUCCESS) { + return error("Failed to stop Transport_unit base class."); + } + if (ret_val != DF_SUCCESS) { + return ret_val; + } + return ret_val; +} + +int EB::BU::cancel() +{ + // TODO check race condition between start and cancel + std::lock_guard<decltype(_start_lock)> guard(_start_lock); + _receive_MEPs = false; + Transport_unit::cancel(); + _recv_buff->cancel(); + _discard_buff->cancel(); + + return DF_SUCCESS; +} + +int EB::BU::pause() +{ + // TODO implement this + logger.info() << "BU pause" << std::flush; + // the EB does not go into pause + // _receive_MEPs = false; + return DF_SUCCESS; +} + +int EB::BU::finalize() +{ + logger.info() << "BU finalize" << std::flush; + delete _recv_buff; + return Transport_unit::finalize(); +} + +void EB::BU::handle(const DataflowIncident& inc) +{ + logger.info() << "BU incident" << std::flush; + // TODO implement this +} + +int EB::BU::check_buffer() +{ + int ret_val = DF_SUCCESS; + + _buffer_sizes.resize(_prop_buffer_sizes.size()); + std::transform(_prop_buffer_sizes.begin(), _prop_buffer_sizes.end(), _buffer_sizes.begin(), [](auto val) { + return val * 1024 * 1024 * 1024UL; + }); + + if (_buffer_type.size() == 0) { + _buffer_type.resize(_bu_ranks.size(), default_BU_buffer_type); + logger.warning() << __FUNCTION__ << " no buffer types provided setting to default value " + << EB::default_BU_buffer_type << std::flush; + } else if (_buffer_type.size() == 1) { + _buffer_type.resize(_bu_ranks.size(), _buffer_type[0]); + logger.warning() << __FUNCTION__ << " Single buffer type provided: " << _buffer_type[0] << std::flush; + } + + if (_buffer_type.size() != _bu_ranks.size()) { + logger.error() << __FUNCTION__ << " Configuration error: not enough buffer types provided " << _buffer_type.size() + << "/" << _bu_ranks.size() << std::flush; + + ret_val = DF_ERROR; + } + + if (_buffer_sizes.size() == 0) { + _buffer_sizes.resize(_bu_ranks.size(), default_BU_buffer_size); + logger.warning() << __FUNCTION__ << " no buffer sizes provided setting to default value " + << EB::default_BU_buffer_size << std::flush; + } else if (_buffer_sizes.size() == 1) { + _buffer_sizes.resize(_bu_ranks.size(), _buffer_sizes[0]); + logger.warning() << __FUNCTION__ << " Single buffer size provided: " << _buffer_sizes[0] << std::flush; + } + + if (_buffer_sizes.size() != _bu_ranks.size()) { + logger.error() << __FUNCTION__ << " Configuration error: not enough buffer sizes provided " << _buffer_sizes.size() + << "/" << _bu_ranks.size() << std::flush; + + ret_val = DF_ERROR; + } + + if (_write_to_file.size() == 0) { + _write_to_file.resize(_bu_ranks.size(), false); + logger.warning() << __FUNCTION__ << " write to file was not set, setting it to the default value " << false + << std::flush; + } else if (_write_to_file.size() == 1) { + _write_to_file.resize(_bu_ranks.size(), _write_to_file[0]); + logger.warning() << __FUNCTION__ << " Single write to file provided: " << _write_to_file[0] << std::flush; + } + + if (_write_to_file.size() != _bu_ranks.size()) { + logger.error() << __FUNCTION__ << " Configuration error: not enough write to file provided " + << _write_to_file.size() << "/" << _bu_ranks.size() << std::flush; + + ret_val = DF_ERROR; + } + + if (_mbm_name.size() == 0) { + _mbm_name.resize(_bu_ranks.size(), EB::default_MBM_name); + logger.warning() << __FUNCTION__ << " no MBM names provided setting to default value " << EB::default_MBM_name + << std::flush; + } else if (_mbm_name.size() == 1) { + _mbm_name.resize(_bu_ranks.size(), _mbm_name[0]); + logger.warning() << __FUNCTION__ << " single MBM name provided: " << _mbm_name[0] << std::flush; + } + + if (_mbm_name.size() != _bu_ranks.size()) { + logger.error() << __FUNCTION__ << " Configuration error: not enough MBM names provided " << _mbm_name.size() << "/" + << _bu_ranks.size() << std::flush; + + ret_val = DF_ERROR; + } + + return ret_val; +} + +int EB::BU::sort_src_ids() +{ + int ret_val = DF_SUCCESS; + + // TODO we can probably use the sorted array. It looks like the unsorted one is never used. + _sorted_src_ids = _src_ids; + _src_id_idx_to_ru_src_idx.resize(_src_ids.size()); + _ru_src_idx_to_src_id_idx.resize(_src_ids.size()); + std::sort(_sorted_src_ids.begin(), _sorted_src_ids.end()); + + std::vector<src_id_type> duplicated_src_ids(_src_ids.size(), -1); + auto duplicated_src_ids_end = + find_all_rep(_sorted_src_ids.begin(), _sorted_src_ids.end(), duplicated_src_ids.begin()); + + if (duplicated_src_ids.begin() != duplicated_src_ids_end) { + logger.error() << "Duplicated src ids: "; + for (auto it = duplicated_src_ids.begin(); it != duplicated_src_ids_end; it++) { + logger.error() << *it << " "; + } + logger.error() << std::flush; + + ret_val = DF_ERROR; + } + + // TODO we need the sorted list to get the repeated values + if (!_sort_src_ids) { + _sorted_src_ids = _src_ids; + } + + std::transform( + _sorted_src_ids.begin(), + _sorted_src_ids.end(), + _src_id_idx_to_ru_src_idx.begin(), + [&vec = _src_ids](src_id_type elem) { return get_idx(vec.begin(), vec.end(), elem); }); + + std::transform( + _src_ids.begin(), _src_ids.end(), _ru_src_idx_to_src_id_idx.begin(), [&vec = _sorted_src_ids](src_id_type elem) { + return get_idx(vec.begin(), vec.end(), elem); + }); + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "Source id ordering: "; + for (const auto& elem : _sorted_src_ids) { + logger.debug() << elem << ", "; + } + logger.debug() << std::flush; + } + + return ret_val; +} + +int EB::BU::config_buffer() +{ + int ret_val = DF_SUCCESS; + + ret_val = check_buffer(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + try { + if (_buffer_type[_my_idx] == dummy_MEP_buffer) { + config_dummy(); + } else if (_buffer_type[_my_idx] == shmem_MEP_buffer) { + config_shmem(); + } else if (_buffer_type[_my_idx] == MBM_MEP_buffer) { + if (!context.mbm) { + ret_val = error("Failed to access MBM client."); + } else { + config_mbm(); + } + } else if (_buffer_type[_my_idx] == MEP_injector_buffer) { + // if (!context.mbm) { + // ret_val = error("Failed to access MBM client."); + // } else { + config_MEP_injector(); + // } + } else { + logger.error() << __FUNCTION__ << " unsupported buffer type " << _buffer_type[_my_idx] << std::flush; + ret_val = DF_ERROR; + } + + _discard_buff = new Dummy_mep_buffer_writer(_prop_discard_buffer_size * 1024 * 1024 * 1024UL); + + if (_write_to_file[_my_idx]) { + std::stringstream file_name; + file_name << _out_file_prefix << "_" << _my_idx << ".mep"; + _file_writer = std::move(File_writer<EB::MEP>(file_name.str())); + } + } catch (const std::system_error& e) { + logger.error() << __FUNCTION__ << " unable to configure buffer type" << BU_buffer_types(_buffer_type[_my_idx]) + << ". " << e.what() << ": " << strerror(errno) << ". Error code: " << e.code() << std::flush; + ret_val = DF_ERROR; + return ret_val; + } catch (const std::exception& e) { + logger.error() << __FUNCTION__ << " unable to configure buffer type " << BU_buffer_types(_buffer_type[_my_idx]) + << ". " << e.what() << ": " << strerror(errno) << std::flush; + ret_val = DF_ERROR; + return ret_val; + } catch (...) { + logger.error() << __FUNCTION__ << " unexpected exception buffer type " << BU_buffer_types(_buffer_type[_my_idx]) + << std::flush; + ret_val = DF_ERROR; + return ret_val; + } + + return ret_val; +} + +void EB::BU::config_dummy() { _recv_buff = new Dummy_mep_buffer_writer(_buffer_sizes[_my_idx]); } + +void EB::BU::config_shmem() +{ + std::stringstream buff_name; + buff_name << _shmem_prefix << "_" << _my_idx; + _recv_buff = new Shmem_buffer_writer<EB::MEP>(buff_name.str(), _buffer_sizes[_my_idx]); +} + +void EB::BU::config_mbm() { _recv_buff = new Mbm_writer<EB::MEP>(context, RTL::processName(), _mbm_name[_my_idx]); } + +void EB::BU::config_MEP_injector() +{ + std::stringstream file_name; + file_name << _out_file_prefix << "_" << _my_idx << "_injector" + << ".mep"; + _recv_buff = new MEP_injector( + _MDF_filename.c_str(), + _buffer_sizes[_my_idx], + _numa_node, + _packing_factor, + _n_meps, + context, + RTL::processName(), + _mbm_name[_my_idx], + _write_to_file[_my_idx], + file_name.str(), + _n_meps_to_file); +} + +int EB::BU::init_shift() +{ + // There is at least on RU for every BU + + int id = 0; + // this is the shift phase of the current unit i.e. the unit index plus the number of ghost before the unit itself + + int ru_block_idx = _RU_shift_pattern.back(); + std::vector<std::vector<int>> ru_blocks(_n_rus_per_nic.size()); + + std::transform(_n_rus_per_nic.begin(), _n_rus_per_nic.end(), ru_blocks.begin(), [&id](int val) { + std::vector<int> ret_val(val); + std::iota(ret_val.begin(), ret_val.end(), id); + id += val; + return ret_val; + }); + + _shift_offset.resize(_RU_shift_pattern.size()); + std::transform(_RU_shift_pattern.rbegin(), _RU_shift_pattern.rend(), _shift_offset.begin(), [&ru_blocks](int val) { + return (val >= 0) ? ru_blocks[val] : std::vector<int>(1, -1); + }); + + int shift_idx = get_idx(_BU_shift_pattern.begin(), _BU_shift_pattern.end(), _my_idx); + + logger.debug() << "shift idx " << shift_idx << std::flush; + + std::rotate(_shift_offset.begin(), _shift_offset.end() - shift_idx - 1, _shift_offset.end()); + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "shift vector "; + for (auto block : _shift_offset) { + for (auto elem : block) { + logger.debug() << elem << " "; + } + logger.debug() << ", "; + } + + logger.debug() << std::flush; + } + + return DF_SUCCESS; +} + +int EB::BU::run() +{ + // reset the number of MEPs written to file + _n_meps_written_to_file = 0; + int ret_val = DF_SUCCESS; + logger.info() << "BU run" << std::flush; + // Transport_unit::run(); + init_profiling(); + while (_receive_MEPs) { + // This lock is released when a full iteration is completed, and it used to detect stuck functions + std::lock_guard<decltype(_loop_lock)> guard(_loop_lock); + + // additional sync barrier + ret_val = sync(); + if (ret_val != DF_SUCCESS) { + break; + } + + logger.debug() << "recv sizes" << std::flush; + ret_val = receive_sizes(); + + // DF_CANCELLED means that the STOP signal has been received + _build_header_timer.start(); + if (ret_val == DF_CANCELLED) { + break; + } else if (ret_val != DF_SUCCESS) { + break; + } + + if (!_end_of_run) { + ret_val = get_next_MEP_space(); + if (ret_val != DF_SUCCESS) { + break; + } + ret_val = build_MEP_header(); + if (ret_val != DF_SUCCESS) { + break; + } + } else { + _curr_MEP = NULL; + } + _build_header_timer.stop(); + + logger.debug() << "shift" << std::flush; + ret_val = linear_shift(); + if (ret_val != DF_SUCCESS) { + break; + } + + // At the end of the run there is no MEP to check + if (!_end_of_run) { + int n_events = (_curr_MEP->at(0))->header.n_banks; + _DF_events_in += n_events; + if (_curr_MEP->is_valid()) { + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "active MEP\n"; + if (logger.is_active(Online::PrintLevel::VERBOSE)) { + logger.debug() << _curr_MEP->print(false); + logger.debug() << std::flush; + } else { + logger.debug() << _curr_MEP->print(false); + } + logger.debug() << std::flush; + } + + if (_write_to_file[_my_idx] && (_n_meps_written_to_file < _n_meps_to_file)) { + // TODO add error checking + _file_writer.write(_curr_MEP); + _n_meps_written_to_file++; + } + + if (_discarted) { + // TODO check what to do with discarted _DF counters + _discarted_MEP_count++; + } else if (_incomplete) { + _incomplete_MEP_count++; + _DF_events_err += n_events; + _recv_buff->write_discard(); + _curr_MEP = NULL; + } else { + _DF_events_out += n_events; + _MEP_count++; + _snd_bytes += _curr_MEP->bytes(); + } + } else { + // TODO check what to do, should this be fatal? Do we discard the data (how?) + logger.error() << "CORRUPTED MEP received: "; + if (!_curr_MEP->is_magic_valid()) { + logger.error() << " corrupted header" << std::flush; + } else { + // logger.error() << _curr_MEP->print() << std::flush; + logger.error() << "Inconsistent EV ids " << std::flush; + int k = 0; + for (auto it = _curr_MEP->begin(); it != _curr_MEP->end(); it++) { + logger.error() << "fragnum " << k << " magic: " << it->is_header_valid() << " source: " << it->header.src_id + << " ev ID: " << it->header.ev_id << std::flush; + k++; + } + logger.error() << std::flush; + } + + _recv_buff->write_discard(); + _curr_MEP = NULL; + + _corrupted_MEP_count++; + _DF_events_err += n_events; + // TODO check if this is the correct behaviour + // fireIncident("DAQ_ERROR"); + } + // Ack all the buffers + // after write complete _curr_MEP is not valid + _discard_buff->write_complete(); + _recv_buff->write_complete(); + // _DF_events_out += n_events; + _curr_MEP = NULL; + } + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "sleep" << std::flush; + sleep(1); + } + + update_profiling(); + + _run_loop_iteration++; + } + + // this will trigger the transition of the FSM into error + if (ret_val == DF_ERROR) { + fireIncident("DAQ_ERROR"); + } + + return ret_val; +} + +// TODO this function does too many things +int EB::BU::receive_sizes() +{ + _receive_size_timer.start(); + int ret_val = DF_SUCCESS; + std::vector<uint32_t> wrids = _ibComm->ibGatherV( + reinterpret_cast<char*>(_sizes.data()), + _n_sources_per_ru.data(), + _prefix_n_sources_per_ru.data(), + sizeof(uint32_t), + _ru_ranks, + ret_val); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + int test_recv_status; + do { + test_recv_status = _ibComm->ibTestRecvs(wrids); + + if (test_recv_status == -1) { + logger.error() << __FUNCTION__ << " ibTestRecvs " << test_recv_status << std::flush; + return DF_ERROR; + } + } while ((test_recv_status == 1) && (_receive_MEPs)); + + if (!_receive_MEPs) { + logger.info() << "STOP received cancelling pending IO" << std::flush; + // TODO check if an IO canc is needed + return DF_CANCELLED; + } + + _receive_size_timer.stop(); + // TODO this may be a good spot to split this function + _calc_offsets_timer.start(); + + // TODO end of run detection may go into a different function + bool old_end_run = _end_of_run; + _end_of_run = false; + + std::vector<int> no_data_src_ids; + no_data_src_ids.reserve(_data_offset_words.size()); + // first offset is the header size + // TODO mem size should already include padding + _data_offset_words[0] = (EB::mep_header_mem_size(_data_offset_words.size()) + + get_padding(EB::mep_header_mem_size(_data_offset_words.size()), 4096)) / + EB::MEP_WORD_SIZE; + for (int k = 1; k < _src_ids.size(); k++) { + const auto ru_idx = _src_id_idx_to_ru_src_idx[k - 1]; + const auto src_id = _sorted_src_ids[k - 1]; + + if (_sizes[ru_idx] == 0) { + _end_of_run = true; + no_data_src_ids.push_back(src_id); + } + + // Every MFP should be page aligned + size_t padded_size = (_sizes[ru_idx] + get_padding(_sizes[ru_idx], 4096)) / EB::MEP_WORD_SIZE; + _data_offset_words[k] = _data_offset_words[k - 1] + padded_size; + } + + const auto last_src_id = _sorted_src_ids[_data_offset_words.size() - 1]; + const auto last_ru_idx = _src_id_idx_to_ru_src_idx[_data_offset_words.size() - 1]; + + // check the last valid element, the last element of sizes is set to 0 and is needed by the MPI_Gater call + if (_sizes[last_ru_idx] == 0) { + _end_of_run = true; + no_data_src_ids.push_back(last_src_id); + } + + _full_size_words = _data_offset_words[_data_offset_words.size() - 1] + _sizes[last_ru_idx] / EB::MEP_WORD_SIZE; + + _incomplete = false; + + if (_end_of_run) { + if (_full_size_words == _data_offset_words[0]) { + _full_size_words = 0; + std::fill(_data_offset_words.begin(), _data_offset_words.end(), 0); + logger.warning() << "end of run" << std::flush; + } else { + // If only a subset of the MFPs are 0-sized the MEP is incomplete the src ids are reported and the BU goes into + // ERROR + _incomplete = true; + logger.error() << "Incomplete event! No data received from the following sources: "; + for (const auto& src : no_data_src_ids) { + logger.error() << src << " "; + _incomplete_MEP_srcs[src]++; + } + + logger.error() << std::flush; + + _end_of_run = false; + } + } + + if (!_end_of_run && old_end_run) { + // reset counters on the start of the new run + reset_counters(); + } + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "sizes "; + for (const auto& size : _sizes) { + logger.debug() << size << " "; + } + logger.debug() << std::flush; + + logger.debug() << "offsets "; + for (const auto& elem : _data_offset_words) { + logger.debug() << elem << " "; + } + logger.debug() << std::flush; + logger.debug() << "full MEP size " << _full_size_words * EB::MEP_WORD_SIZE << std::flush; + } + + _calc_offsets_timer.stop(); + + return DF_SUCCESS; +} + +int EB::BU::receive_src_ids() +{ + _src_ids.resize(_prefix_n_sources_per_ru.back()); + _ibComm->addMR((char*) &_src_ids, _src_ids.size() * sizeof(EB::src_id_type)); + int ret_val = _ibComm->ibGatherBlockV( + reinterpret_cast<char*>(_src_ids.data()), + _n_sources_per_ru.data(), + _prefix_n_sources_per_ru.data(), + sizeof(EB::src_id_type), + _ru_ranks); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " size ibGatherBlockV failed " << ret_val << std::flush; + return ret_val; + } + + logger.debug() << "src ids written " << _src_ids.size() << ": " << std::flush; + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + for (const auto& id : _src_ids) { + logger.debug() << id << " "; + } + logger.debug() << std::flush; + } + return ret_val; +} + +int EB::BU::linear_shift() +{ + _linear_shift_timer.start(); + int ret_val = DF_SUCCESS; + for (const auto& shift_vec : _shift_offset) { + logger.debug() << "sync" << std::flush; + _sync_timer.start(); + ret_val = sync(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + _sync_timer.stop(); + _receive_MFPs_timer.start(); + logger.debug() << "recv MFPs" << std::flush; + // we skip the ghost nodes + if (shift_vec[0] != -1) { + ret_val = receive_MFPs(shift_vec); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + } + + _receive_MFPs_timer.stop(); + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "on shift "; + for (const auto& elem : shift_vec) { + logger.debug() << elem << " "; + } + logger.debug() << std::flush; + } + } + + _linear_shift_timer.stop(); + return ret_val; +} + +int EB::BU::receive_MFPs(const std::vector<int>& shift_vec) +{ + int comm_err = 0; + std::vector<comm_recv> recv_vect; + // TODO find a better value for this + recv_vect.reserve(_n_sources_per_ru[0] * shift_vec.size()); + size_t total_size = 0; + uintptr_t payload_revc_buff = reinterpret_cast<uintptr_t>(_curr_MEP); + int src = 0; + for (const auto& ru_idx : shift_vec) { + src = _ru_ranks[ru_idx]; + for (int k = 0; k < _n_sources_per_ru[ru_idx]; k++) { + int idx = _prefix_n_sources_per_ru[ru_idx] + k; + auto src_id_idx = _ru_src_idx_to_src_id_idx[idx]; + const auto& size = _sizes[idx]; + // Inplace construction with a proper initializer is more elegant than this + recv_vect.emplace_back(); + auto& recv = recv_vect.back(); + if (_curr_MEP != NULL) { + recv.recv_buff = reinterpret_cast<void*>(_curr_MEP->at(src_id_idx)); + } else { + recv.recv_buff = NULL; + } + recv.datatype = sizeof(char); + recv.source = src; + recv.count = size; + total_size += size; + } + } + comm_err = _ibComm->receive(recv_vect); + if (comm_err != DF_SUCCESS) { + // TODO this happens if CANCELL is issued + logger.error() << __FUNCTION__ << " receive " << comm_err << std::flush; + return comm_err; + } + _rcv_bytes += total_size; + return DF_SUCCESS; +} + +int EB::BU::get_next_MEP_space() +{ + int ret_val = DF_SUCCESS; + _curr_MEP = _recv_buff->try_write_next_element(_full_size_words * EB::MEP_WORD_SIZE); + + if (_curr_MEP == NULL) { + logger.info() << "Receive buffer full discarding the MEP" << std::flush; + + // TODO add error handling + _curr_MEP = _discard_buff->write_next_element(_full_size_words * EB::MEP_WORD_SIZE, ret_val); + _discarted = true; + } else { + _discarted = false; + } + + if (_curr_MEP == NULL) { + logger.error() << "CURR MEP NULL ret val " << ret_val << std::flush; + } + + return ret_val; +} + +int EB::BU::build_MEP_header() +{ + // set magic + _curr_MEP->set_magic_valid(); + _curr_MEP->header.n_MFPs = _data_offset_words.size(); + _curr_MEP->header.p_words = _full_size_words; + ::memcpy(_curr_MEP->header.offsets(), _data_offset_words.data(), _data_offset_words.size() * sizeof(EB::offset_type)); + // TODO this list should be checked against the data in the MFP headers + ::memcpy(_curr_MEP->header.src_ids(), _sorted_src_ids.data(), _sorted_src_ids.size() * sizeof(EB::src_id_type)); + + return DF_SUCCESS; +} + +void EB::BU::reset_counters() +{ + // reset counters of the base class + Transport_unit::reset_counters(); + logger.info() << "resetting counters" << std::flush; + _MEP_count = 0; + _discarted_MEP_count = 0; + _corrupted_MEP_count = 0; + _incomplete_MEP_count = 0; + _rcv_bytes = 0; + _snd_bytes = 0; + _DF_events_out = 0; + _DF_events_in = 0; + _DF_events_err = 0; + _run_loop_iteration = 0; + _incomplete_MEP_srcs.clear(); + _receive_size_time_counter = 0; + _calc_offsets_time_counter = 0; + _build_header_time_counter = 0; + _linear_shift_time_counter = 0; + _receive_MFPs_time_counter = 0; +} + +void EB::BU::update_profiling() +{ + if (_enable_profiling) { + double total_time = _total_timer.get_elapsed_time_s(); + if (total_time > _profiling_update_interval) { + // This is here to prevent double evaluation of the total_timer + EB::Transport_unit::update_profiling(); + double MEP_rate = _MEP_count / _total_time_counter; + double event_rate = _DF_events_out / _total_time_counter; + double bw = (_rcv_bytes * 8 * 1e-9) / _total_time_counter; + + double receive_size_total_time = _receive_size_timer.get_elapsed_time_s(); + double calc_offsets_time = _calc_offsets_timer.get_elapsed_time_s(); + double receive_size_time = receive_size_total_time - calc_offsets_time; + double build_header_time = _build_header_timer.get_elapsed_time_s(); + double linear_shift_time = _linear_shift_timer.get_elapsed_time_s(); + double receive_MFPs_time = _receive_MFPs_timer.get_elapsed_time_s(); + + _receive_size_time_counter += receive_size_time; + _calc_offsets_time_counter += calc_offsets_time; + _build_header_time_counter += build_header_time; + _linear_shift_time_counter += linear_shift_time; + _receive_MFPs_time_counter += receive_MFPs_time; + + if (logger.is_active(Online::PrintLevel::INFO)) { + logger.info() << "receive sizes " << receive_size_time << " s " << receive_size_time / total_time * 100 << " %" + << std::flush; + logger.info() << "calculate offsets " << calc_offsets_time << " s " << calc_offsets_time / total_time * 100 + << " %" << std::flush; + logger.info() << "build header " << build_header_time << " s " << build_header_time / total_time * 100 << " %" + << std::flush; + logger.info() << "linear shift " << linear_shift_time << " s " << linear_shift_time / total_time * 100 << " %" + << std::flush; + logger.info() << "receive data " << receive_MFPs_time << " s " << receive_MFPs_time / total_time * 100 << " %" + << std::flush; + + logger.info() << "MEP rate " << MEP_rate << " MEPS/s" << std::flush; + logger.info() << "event rate " << event_rate << " Hz" << std::flush; + logger.info() << "BW " << bw << " Gb/s" << std::flush; + } + + _receive_size_timer.reset(); + _calc_offsets_timer.reset(); + _linear_shift_timer.reset(); + _receive_MFPs_timer.reset(); + } + } +} + +void EB::BU::init_profiling() +{ + EB::Transport_unit::init_profiling(); + + if (_enable_profiling) { + _receive_size_timer.stop(); + _receive_size_timer.reset(); + _calc_offsets_timer.stop(); + _calc_offsets_timer.reset(); + _linear_shift_timer.stop(); + _linear_shift_timer.reset(); + _receive_MFPs_timer.stop(); + _receive_MFPs_timer.reset(); + } else { + _receive_size_timer.disable(); + _calc_offsets_timer.disable(); + _linear_shift_timer.disable(); + _receive_MFPs_timer.disable(); + } +} \ No newline at end of file diff --git a/Online/EventBuilding/src/MEP_injector.cpp b/Online/EventBuilding/src/MEP_injector.cpp new file mode 100644 index 000000000..21855f6b4 --- /dev/null +++ b/Online/EventBuilding/src/MEP_injector.cpp @@ -0,0 +1,228 @@ +#include "MEP_injector.hpp" +#include "MFP_builder.hpp" +#include "mdf_reader.hpp" +#include "EventBuilding/tools.hpp" +#include "EventBuilding/tools.hpp" +#include <numa.h> +#include <stdexcept> +#include <sstream> +#include <algorithm> +#include <utility> +#include <unistd.h> + +EB::MEP_injector::MEP_injector( + const char* MDF_filename, + size_t buffer_size, + int numa_node, + int packing_factor, + int n_meps, + Online::DataflowComponent::Context& context, + const std::string& instance, + const std::string& name, + bool write_to_file, + const std::string out_file_name, + int n_meps_to_file) : + _MDF_filename(MDF_filename), + _internal_buffer_writer(buffer_size, numa_node), _external_buffer_writer(context, instance, name), + _packing_factor(packing_factor), _n_MEPs(n_meps), _numa_node(numa_node), _copy_status(status_t::READY), + _thread_exit(false) +{ + if (write_to_file) { + _file_writer = std::move(File_writer<EB::MEP>(out_file_name)); + _n_meps_to_file = n_meps_to_file; + } else { + _n_meps_to_file = 0; + } + + int err_check; + err_check = preload_MEPs(); + if (err_check != 0) { + std::stringstream err_mess; + err_mess << "Unable to preload MEPs error code: " << err_check; + throw std::runtime_error(err_mess.str()); + } + _t_copy = std::thread(thread_copy, &_thread_exit, &_copy_status, &_t_write_ptr, &_t_mep_ptr); +} + +EB::MEP_injector::~MEP_injector() +{ + _thread_exit = true; + if (_t_copy.joinable()) { + _t_copy.join(); + } +} + +std::vector<std::tuple<void*, size_t>> EB::MEP_injector::get_full_buffer() +{ + return _internal_buffer_writer.get_full_buffer(); +} + +EB::MEP* EB::MEP_injector::try_write_next_element(size_t size) +{ + EB::MEP* ret_val = NULL; + // this should be always re to READY at this point extra safety + if (_copy_status.load() == status_t::READY) { + ret_val = _external_buffer_writer.try_write_next_element(_MEPs[_curr_mep_idx]->bytes()); + if (ret_val != NULL) { + + _t_write_ptr = ret_val; + _t_mep_ptr = _MEPs[_curr_mep_idx].get(); + _copy_status.store(status_t::PTR_READY, std::memory_order_release); + + if (_n_meps_to_file > 0) { + _file_writer.write(_MEPs[_curr_mep_idx].get()); + _n_meps_to_file--; + } + + _curr_mep_idx = (_curr_mep_idx + 1) % _MEPs.size(); + // The dummy buffer should always have space + ret_val = _internal_buffer_writer.try_write_next_element(size); + } + } + return ret_val; +} + +void EB::MEP_injector::thread_copy(bool* exit, std::atomic<int>* status, void** write_ptr, EB::MEP** mep_ptr) +{ + while (!*exit) { + while (status->load(std::memory_order_acquire) != status_t::PTR_READY) { + // we try not to block + if (*exit) { + return; + } + } + memcpy(*write_ptr, *mep_ptr, (*mep_ptr)->bytes()); + status->store(status_t::COPY_READY, std::memory_order_release); + } +} + +void EB::MEP_injector::write_complete() +{ + // If we are in ready the thread is not doing anything + if (_copy_status.load() != status_t::READY) { + while (_copy_status.load(std::memory_order_acquire) != status_t::COPY_READY) { + // If the copy joins we try not to block + // This is in principle not necessary with the current implementation + if (_thread_exit) { + return; + } + } + _external_buffer_writer.write_complete(); + _copy_status.store(status_t::READY, std::memory_order_release); + } + _internal_buffer_writer.write_complete(); +} + +void EB::MEP_injector::write_discard() +{ + if (_copy_status.load() != status_t::READY) { + while (_copy_status.load(std::memory_order_acquire) != status_t::COPY_READY) { + // If the copy joins we try not to block + // This is in principle not necessary with the current implementation + if (_thread_exit) { + return; + } + } + _external_buffer_writer.write_discard(); + _copy_status.store(status_t::READY, std::memory_order_release); + } + _internal_buffer_writer.write_discard(); +} + +// no src id +int EB::MEP_injector::get_src_id() const { return 0; } + +int EB::MEP_injector::preload_MEPs() +{ + int ret_val = 0; + std::vector<EB::MDF_block> blocks; + std::vector<std::shared_ptr<char>> MFPs; + std::vector<size_t> buffer_sizes; + + std::vector<EB::offset_type> offsets; + std::vector<EB::src_id_type> src_ids; + size_t MFP_size = 300 * 1024 * _packing_factor; + MDF_reader reader(_MDF_filename.c_str()); + EB::MFP_builder builder; + + while (!_write_ptrs.empty()) { + _write_ptrs.pop(); + } + _curr_mep_idx = 0; + + _MEPs.clear(); + _MEPs.reserve(_n_MEPs); + for (size_t k = 0; k < _n_MEPs; k++) { + blocks.clear(); + ret_val = reader.extract_events(blocks, _packing_factor); + if (ret_val != 0) { + break; + } + + ret_val = builder.append_events(blocks); + if (ret_val != 0) { + break; + } + + size_t n_sources = builder.get_source_number(); + buffer_sizes.resize(n_sources, MFP_size); + // resize the temporary MFP buffers + if (MFPs.size() != n_sources) { + int old_size = MFPs.size(); + MFPs.resize(n_sources); + for (size_t k = old_size; k < MFPs.size(); k++) { + MFPs[k] = std::shared_ptr<char>(new char[MFP_size]); + } + } + offsets.resize(n_sources, 0); + src_ids.resize(n_sources, 0); + + ret_val = builder.build_MFPs(_packing_factor, MFPs, buffer_sizes); + if (ret_val != 0) { + break; + } + + std::sort(MFPs.begin(), MFPs.end(), [](const auto a, const auto b) { + return reinterpret_cast<EB::MFP*>(a.get())->header.src_id < reinterpret_cast<EB::MFP*>(b.get())->header.src_id; + }); + + auto current_mfp = reinterpret_cast<EB::MFP*>(MFPs[0].get()); + size_t header_size = EB::mep_header_mem_size(n_sources); + size_t padded_size = current_mfp->bytes() + get_padding(current_mfp->bytes(), 4096); + size_t total_size = EB::mep_header_mem_size(n_sources) + padded_size; + offsets[0] = header_size / EB::MEP_WORD_SIZE; + src_ids[0] = current_mfp->header.src_id; + for (int k = 1; k < n_sources; k++) { + current_mfp = reinterpret_cast<EB::MFP*>(MFPs[k].get()); + // For the offset calculation we use the size of the previous MFP + offsets[k] = offsets[k - 1] + padded_size / EB::MEP_WORD_SIZE; + src_ids[k] = current_mfp->header.src_id; + padded_size = current_mfp->bytes() + get_padding(current_mfp->bytes(), 4096); + total_size += padded_size; + } + + _MEPs.emplace_back(std::shared_ptr<EB::MEP>(reinterpret_cast<EB::MEP*>(new char[total_size]))); + EB::MEP* curr_mep = _MEPs.back().get(); + if (curr_mep == NULL) { + ret_val = ENOMEM; + break; + } + + if (_numa_node != -1) { + numa_tonode_memory(_MEPs.back().get(), total_size, _numa_node); + } + + curr_mep->set_magic_valid(); + curr_mep->header.n_MFPs = n_sources; + curr_mep->header.p_words = total_size / EB::MEP_WORD_SIZE; + memcpy(curr_mep->header.offsets(), offsets.data(), offsets.size() * sizeof(EB::offset_type)); + memcpy(curr_mep->header.src_ids(), src_ids.data(), src_ids.size() * sizeof(EB::src_id_type)); + + for (size_t k = 0; k < n_sources; k++) { + size_t size = (reinterpret_cast<EB::MFP*>(MFPs[k].get()))->bytes(); + memcpy(reinterpret_cast<void*>(curr_mep->at(k)), MFPs[k].get(), size); + } + } + + return ret_val; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/MEP_tools.cpp b/Online/EventBuilding/src/MEP_tools.cpp new file mode 100644 index 000000000..8bd5ae8b5 --- /dev/null +++ b/Online/EventBuilding/src/MEP_tools.cpp @@ -0,0 +1,182 @@ +#include "EventBuilding/MEP_tools.hpp" +#include "EventBuilding/MFP_tools.hpp" +#include "EventBuilding/tools.hpp" +#include <sstream> +#include <stdexcept> + +size_t EB::MEP_header::size() const { return mep_header_size(n_MFPs); } + +size_t EB::MEP_header::mem_size() const { return mep_header_mem_size(n_MFPs); } + +EB::src_id_type* EB::MEP_header::src_ids() +{ + return reinterpret_cast<src_id_type*>(reinterpret_cast<uintptr_t>(this) + sizeof(MEP_header)); +} + +const EB::src_id_type* EB::MEP_header::src_ids() const { return const_cast<MEP_header*>(this)->src_ids(); } + +EB::offset_type* EB::MEP_header::offsets() +{ + return reinterpret_cast<offset_type*>( + reinterpret_cast<uintptr_t>(src_ids()) + aligned_array_size<src_id_type>(n_MFPs, MEP_alignment)); +} + +const EB::offset_type* EB::MEP_header::offsets() const { return const_cast<MEP_header*>(this)->offsets(); } + +void* EB::MEP::payload() { return reinterpret_cast<void*>(at(0)); } + +const void* EB::MEP::payload() const { return const_cast<MEP*>(this)->payload(); } + +EB::MFP* EB::MEP::at(int n) +{ + if (n >= header.n_MFPs) { + std::stringstream error_mess; + error_mess << __FUNCTION__ << ": requested MFP of idx " << n << " in a MEP with " << header.n_MFPs << " MFPs"; + throw std::runtime_error(error_mess.str()); + } + return reinterpret_cast<EB::MFP*>(reinterpret_cast<uintptr_t>(this) + header.offsets()[n] * MEP_WORD_SIZE); +} + +const EB::MFP* EB::MEP::at(int n) const { return const_cast<MEP*>(this)->at(n); } + +EB::MFP* EB::MEP::operator[](int n) { return at(n); } +const EB::MFP* EB::MEP::operator[](int n) const { return at(n); } + +bool EB::MEP::is_magic_valid() const { return header.magic == MEP_magic; } +void EB::MEP::set_magic_valid() { header.magic = MEP_magic; } + +bool EB::MEP::is_valid() const +{ + bool ret_val = is_magic_valid(); + if (ret_val) { + uint64_t ev_id = at(0)->header.ev_id; + // We exit the loop as soon as there is one invalid ev_id + for (auto it = this->cbegin(); (it != this->cend()) && (ret_val); it++) { + // for (int k = 1; (k < header.n_MFPs) && (ret_val); k++) { + ret_val &= (ev_id == it->header.ev_id); + } + } + + return ret_val; +} + +EB::MEP_integrity_check EB::MEP::integrity_check() const +{ + EB::MEP_integrity_check ret_val = MEP_OK; + return ret_val; +} + +bool EB::MEP::is_wrap() const { return header.magic == MEP_wrap; } +void EB::MEP::set_wrap() { header.magic = MEP_wrap; } + +size_t EB::MEP::bytes() const +{ + return header.p_words * MEP_WORD_SIZE; // p_words is the size in 32 bits words +} + +size_t EB::MEP::header_size() const { return header.size(); } + +size_t EB::MEP::header_mem_size() const { return header.mem_size(); } + +std::string EB::MEP_header::print() const +{ + std::stringstream os; + os << "\n------MEP HEADER------\n"; + os << "Magic " << std::hex << magic << std::dec << "\n"; + os << "n MFPs " << n_MFPs << "\n"; + os << "p words " << p_words << "\n"; + auto src = src_ids(); + auto off = offsets(); + for (int k = 0; k < n_MFPs; k++) { + os << "MFP " << k << ": source ID " << src[k] << " offset " << off[k] << "\n"; + } + + return os.str(); +} + +std::ostream& EB::operator<<(std::ostream& os, const MEP_header& header) { return os << header.print(); } + +std::ostream& EB::operator<<(std::ostream& os, const MEP& mep) { return os << mep.print(); } + +std::string EB::MEP::print(bool MFP_header_only) const +{ + std::stringstream os; + + os << header; + + if (!MFP_header_only) { + // for (int k = 0; k < header.n_MFPs; k++) { + // os << *(this->at(k)); + for (auto it = this->cbegin(); it != this->cend(); it++) { + // TODO implement print for full MFPs + os << *it; + } + } + + return os.str(); +} + +size_t EB::mep_header_size(int n_MFPs) +{ + return sizeof(MEP_header) + aligned_array_size<src_id_type>(n_MFPs, MEP_alignment) + n_MFPs * sizeof(offset_type); +} + +size_t EB::mep_header_mem_size(int n_MFPs) +{ + size_t base_size = mep_header_size(n_MFPs); + return base_size + get_padding(base_size, 4096); +} + +// ITERATOR +EB::MEP::iterator& EB::MEP::iterator::operator++() +{ + _offset++; + return *this; +} + +EB::MEP::iterator EB::MEP::iterator::operator++(int) +{ + iterator tmp = *this; + ++(*this); + return tmp; +} + +EB::MEP::iterator::reference EB::MEP::iterator::operator*() const { return *_get_ptr(); } +EB::MEP::iterator::pointer EB::MEP::iterator::operator->() { return _get_ptr(); } + +EB::MEP::iterator::pointer EB::MEP::iterator::_get_ptr() const +{ + return reinterpret_cast<pointer>(_base_ptr + (*_offset) * MEP_WORD_SIZE); +} + +bool EB::operator==(const EB::MEP::iterator& a, const EB::MEP::iterator& b) { return a._offset == b._offset; } +bool EB::operator!=(const EB::MEP::iterator& a, const EB::MEP::iterator& b) { return !(a == b); } + +// CONST ITERATOR +EB::MEP::const_iterator& EB::MEP::const_iterator::operator++() +{ + _offset++; + return *this; +} + +EB::MEP::const_iterator EB::MEP::const_iterator::operator++(int) +{ + const_iterator tmp = *this; + ++(*this); + return tmp; +} + +EB::MEP::const_iterator::reference EB::MEP::const_iterator::operator*() const { return *_get_ptr(); } +EB::MEP::const_iterator::pointer EB::MEP::const_iterator::operator->() { return _get_ptr(); } + +EB::MEP::const_iterator::pointer EB::MEP::const_iterator::_get_ptr() const +{ + return reinterpret_cast<pointer>(_base_ptr + (*_offset) * MEP_WORD_SIZE); +} + +bool EB::operator==(const EB::MEP::const_iterator& a, const EB::MEP::const_iterator& b) +{ + return a._offset == b._offset; +} + +bool EB::operator!=(const EB::MEP::const_iterator& a, const EB::MEP::const_iterator& b) { return !(a == b); } \ No newline at end of file diff --git a/Online/EventBuilding/src/MFP_builder.cpp b/Online/EventBuilding/src/MFP_builder.cpp new file mode 100644 index 000000000..a0231f4b6 --- /dev/null +++ b/Online/EventBuilding/src/MFP_builder.cpp @@ -0,0 +1,240 @@ +#include "MFP_builder.hpp" +#include <memory> + +EB::MFP_builder::MFP_builder() {} + +int EB::MFP_builder::append_event(const EB::MDF_block& event) +{ + char* tmp_ptr = event.payload().get(); + char* buffer_end = event.payload().get() + event.payload_size(); + EB::raw_header* tmp_header = reinterpret_cast<EB::raw_header*>(tmp_ptr); + do { + uint8_t key = tmp_header->type; + uint16_t value = tmp_header->src_id; + auto map_it_emplace = _raw_map.emplace(std::make_pair(key, value), std::vector<EB::raw_header*>(1, tmp_header)); + // check if the insertion of the new element succeded + if (!map_it_emplace.second) { + map_it_emplace.first->second.push_back(tmp_header); + } else { + // if the source is a new one the ev_id is set to 0 + _ev_id_map.emplace(std::make_pair(key, value), 0); + } + + tmp_ptr += tmp_header->mem_size(); + tmp_header = reinterpret_cast<EB::raw_header*>(tmp_ptr); + } while (tmp_header->is_valid() && (tmp_ptr < buffer_end)); + // TODO add error checking + return 0; +} + +int EB::MFP_builder::append_events(const std::vector<EB::MDF_block>& events) +{ + for (const auto& event : events) { + append_event(event); + } + // TODO add error checking + return 0; +} + +std::vector<EB::type_id_pair_type> EB::MFP_builder::get_source_mapping() +{ + std::vector<EB::type_id_pair_type> key_list; + key_list.reserve(_raw_map.size()); + for (const auto& map_elem : _raw_map) { + key_list.emplace_back(map_elem.first); + } + + return key_list; +} + +// returns the number of sources +size_t EB::MFP_builder::get_source_number() { return _raw_map.size(); } + +int EB::MFP_builder::build_MFP(size_t packing_fraction, char* buffer, size_t buffer_size, EB::type_id_pair_type key) +{ + int ret_val = 0; + auto map_it = _raw_map.find(key); + auto ev_id_it = _ev_id_map.find(key); + if (map_it != _raw_map.end()) { + if (map_it->second.size() < packing_fraction) { + ret_val = -2; + std::cerr << "ERROR not enough events provided for type " << (uint) map_it->first.first << " id " + << map_it->first.second << " " << map_it->second.size() << "/" << packing_fraction << std::endl; + } else { + uint32_t block_size = 0; + if (buffer_size < MFP_header_size(packing_fraction)) { + // std::cerr << "ERROR insufficient buffer size" << std::endl; + ret_val = -3; + } else { + MFP* next_MFP = reinterpret_cast<MFP*>(buffer); + next_MFP->set_header_valid(); + next_MFP->header.block_version = 0; + next_MFP->header.ev_id = ev_id_it->second; + next_MFP->header.n_banks = packing_fraction; + // the src_id should be the same for all the fragments from the same source + // with the new src_id this can be taken from the map key + // next_MFP->src_id = EB::old_to_new(map_it->second[0]->src_id); + next_MFP->header.src_id = EB::old_to_new(key); + next_MFP->header.align = base_MFP_align; + uint16_t* hdr_sizes = next_MFP->header.bank_sizes(); + uint8_t* hdr_types = next_MFP->header.bank_types(); + // the block size includes the header + // TODO check if we can use an iterator + // char* hdr_payload = reinterpret_cast<char*>(next_MFP->payload()); + auto MFP_it = next_MFP->begin(); + size_t header_size = next_MFP->header.header_size(); + for (size_t k = 0; k < packing_fraction; k++) { + hdr_types[k] = map_it->second[k]->type; + hdr_sizes[k] = map_it->second[k]->payload_size(); + // check if the buffer has enough space for the next fragment + size_t payload_mem_size = map_it->second[k]->payload_mem_size(); + size_t full_bank_size = payload_mem_size + get_padding(payload_mem_size, 1 << base_MFP_align); + if (block_size + header_size + full_bank_size <= buffer_size) { + memcpy(&(*MFP_it), map_it->second[k]->get_payload(), payload_mem_size); + MFP_it++; + // this line inserts a full raw bank uncluding the header it can be used for debugging + // memcpy(hdr_payload + block_size, map_it->second[k], map_it->second[k]->mem_size()); + } else { + // std::cerr << "ERROR insufficient buffer size" << std::endl; + ret_val = -3; + break; + } + block_size += full_bank_size; +#ifdef DEBUG + std::cout << "raw size " << hdr_sizes[k] << " aligned size " << full_bank_size << std::endl; +#endif + // this line should be used when inserting a full raw bank + // block_size += map_it->second[k]->mem_size(); + } + // deleting the processed events from the internal structure + map_it->second.erase(map_it->second.begin(), map_it->second.begin() + packing_fraction); + next_MFP->header.packet_size = block_size + header_size; + (ev_id_it->second) += packing_fraction; + } + } + } else { + // std::cerr << "ERROR key not found type " << (uint) key.first << " id " << key.second << std::endl; + ret_val = -5; + } + return ret_val; +} + +int EB::MFP_builder::build_MFPs( + size_t packing_fraction, + const std::vector<std::shared_ptr<char>>& buffers, + const std::vector<size_t>& buffer_sizes) +{ + int ret_val = 0; + // TODO implement this properly + if ((_raw_map.size() != buffers.size()) || (_raw_map.size() != buffer_sizes.size())) { + ret_val = -1; + std::cerr << "ERROR not enough bufers provided" << std::endl; + } + + if (ret_val == 0) { + int source_idx = 0; + for (const auto map_it : _raw_map) { + // TODO better error code handling + ret_val = build_MFP(packing_fraction, buffers[source_idx].get(), buffer_sizes[source_idx], map_it.first); + // TODO find a better way of breking the loop + if (ret_val != 0) { + break; + } + source_idx++; + } + } + return ret_val; +} + +int EB::MFP_builder::build_MFPs( + size_t packing_fraction, + const std::vector<std::shared_ptr<char>>& buffers, + const std::vector<size_t>& buffer_sizes, + const std::vector<EB::type_id_pair_type> source_mapping) +{ + int ret_val = 0; + if ((source_mapping.size() != buffers.size()) || (source_mapping.size() != buffer_sizes.size())) { + ret_val = -1; + std::cerr << "ERROR not enough bufers provided" << std::endl; + } + + if (ret_val == 0) { + int source_idx = 0; + for (const auto src : source_mapping) { + // TODO better error code handling + ret_val = build_MFP(packing_fraction, buffers[source_idx].get(), buffer_sizes[source_idx], src); + if (ret_val != 0) { + break; + } + source_idx++; + } + } + return ret_val; +} + +int EB::MFP_builder::build_MFPs( + size_t packing_fraction, + const std::vector<char*>& buffers, + const std::vector<size_t>& buffer_sizes) +{ + int ret_val = 0; + // TODO implement this properly + if ((_raw_map.size() != buffers.size()) || (_raw_map.size() != buffer_sizes.size())) { + ret_val = -1; + std::cerr << "ERROR not enough bufers provided" << std::endl; + } + + if (ret_val == 0) { + size_t source_idx = 0; + for (const auto map_it : _raw_map) { + // TODO better error code handling + ret_val = build_MFP(packing_fraction, buffers[source_idx], buffer_sizes[source_idx], map_it.first); + // TODO find a better way of breking the loop + if (ret_val != 0) { + break; + } + source_idx++; + } + } + return ret_val; +} + +int EB::MFP_builder::build_MFPs( + size_t packing_fraction, + const std::vector<char*>& buffers, + const std::vector<size_t>& buffer_sizes, + const std::vector<EB::type_id_pair_type> source_mapping) +{ + int ret_val = 0; + if ((source_mapping.size() != buffers.size()) || (source_mapping.size() != buffer_sizes.size())) { + ret_val = -1; + std::cerr << "ERROR not enough bufers provided" << std::endl; + } + + if (ret_val == 0) { + size_t source_idx = 0; + for (const auto src : source_mapping) { + // TODO better error code handling + ret_val = build_MFP(packing_fraction, buffers[source_idx], buffer_sizes[source_idx], src); + if (ret_val != 0) { + break; + } + source_idx++; + } + } + return ret_val; +} + +void EB::MFP_builder::reset_data() { _raw_map.clear(); } + +void EB::MFP_builder::reset_ev_id() +{ + for (auto& map_elem : _ev_id_map) { + map_elem.second = 0; + } +} +void EB::MFP_builder::reset() +{ + reset_data(); + reset_ev_id(); +} \ No newline at end of file diff --git a/Online/EventBuilding/src/MFP_generator.cpp b/Online/EventBuilding/src/MFP_generator.cpp new file mode 100644 index 000000000..65ad2277e --- /dev/null +++ b/Online/EventBuilding/src/MFP_generator.cpp @@ -0,0 +1,596 @@ +#include <sstream> +#include <stdexcept> +#include <random> +#include <iostream> +#include <string> +#include <cstdlib> +#include <cmath> +#include <algorithm> +#include <unistd.h> +#include <cassert> +#include "EventBuilding/tools.hpp" +#include "EventBuilding/MFP_generator.hpp" +#include "RTL/rtl.h" +#include "numa.h" +#include "PCIE40Data/RawBank40.h" +#include "PCIE40Data/sodin.h" + +EB::MFP_generator::MFP_generator(const std::string& nam, Context& ctxt) : DataflowComponent(nam, ctxt) +{ + logger.set_output_level(online_print_level_to_log_priority(Online::PrintLevel(outputLevel))); + logger.set_name(name); + declareProperty("n_banks", _prop_n_banks = 3000); + declareProperty("src_id", _prop_src_id = "0"); + declareProperty("align", _prop_align = 2); // log2 of base mfp alignment + declareProperty("block_version", _prop_block_version = 0); + declareProperty("event_rate", _event_rate = 30e6); + declareProperty("bank_type", _prop_bank_type = 0); + declareProperty("bank_size", _prop_bank_size = 100); + declareProperty("random_sizes", _random_sizes = false); + declareProperty("random_seed", _random_seed = 0); + declareProperty("shmem_prefix", _shmem_name = "RU"); + declareProperty("numa_layout", _numa_layout); + declareProperty("buffer_size", _prop_buffer_size = 1); + declareProperty("reconnect", _reconnect = true); + declareProperty("stop_timeout", _stop_timeout = 10); + declareProperty("n_preloaded_sizes", _n_preloaded_sizes = 1000000); + declareProperty("enable_test_pattern", _enable_test_pattern = false); + + declareProperty("SODIN_UTGUID", _sodin_utguid = ""); + + // SD specific props + declareProperty("sd_specific_run", _sub_detector_specific_run = false); + declareProperty("velo_UTGUID_override", _velo_utigid_override); + declareProperty("scifi_UTGUID_override", _scifi_utigid_override); + declareProperty("ut_UTGUID_override", _ut_utigid_override); + declareProperty("muon_UTGUID_override", _muon_utigid_override); + declareProperty("hcal_UTGUID_override", _hcal_utigid_override); + declareProperty("ecal_UTGUID_override", _ecal_utigid_override); + declareProperty("rich1_UTGUID_override", _rich1_utigid_override); + declareProperty("rich2_UTGUID_override", _rich2_utigid_override); + + // generic sd mean 150 + declareProperty("rand_lambda", _lambda = 2); + declareProperty("rand_offset", _offset = 150 - 20 * 2); + declareProperty("rand_multi", _multi = 20); + + // velo mean 156 + declareProperty("velo_rand_lambda", _velo_lambda = 2); + declareProperty("velo_rand_offset", _velo_offset = 156 - 20 * 2); + declareProperty("velo_rand_multi", _velo_multi = 20); + + // scifi mean 100 + declareProperty("scifi_rand_lambda", _scifi_lambda = 2); + declareProperty("scifi_rand_offset", _scifi_offset = 100 - 20 * 2); + declareProperty("scifi_rand_multi", _scifi_multi = 20); + + // ut mean 100 + declareProperty("ut_rand_lambda", _ut_lambda = 2); + declareProperty("ut_rand_offset", _ut_offset = 100 - 20 * 2); + declareProperty("ut_rand_multi", _ut_multi = 20); + + // muon mean 156 + declareProperty("muon_rand_lambda", _muon_lambda = 2); + declareProperty("muon_rand_offset", _muon_offset = 156 - 20 * 2); + declareProperty("muon_rand_multi", _muon_multi = 20); + + // hcal mean 156 + declareProperty("hcal_rand_lambda", _hcal_lambda = 2); + declareProperty("hcal_rand_offset", _hcal_offset = 156 - 20 * 2); + declareProperty("hcal_rand_multi", _hcal_multi = 20); + + // hcal mean 156 + declareProperty("ecal_rand_lambda", _ecal_lambda = 2); + declareProperty("ecal_rand_offset", _ecal_offset = 156 - 20 * 2); + declareProperty("ecal_rand_multi", _ecal_multi = 20); + + // rich1 mean 166 + declareProperty("rich1_rand_lambda", _rich1_lambda = 2); + declareProperty("rich1_rand_offset", _rich1_offset = 166 - 20 * 2); + declareProperty("rich1_rand_multi", _rich1_multi = 20); + + // rich2 mean 166 + declareProperty("rich2_rand_lambda", _rich2_lambda = 2); + declareProperty("rich2_rand_offset", _rich2_offset = 166 - 20 * 2); + declareProperty("rich2_rand_multi", _rich2_multi = 20); + + // DF monitoring counters + declareMonitor("Events/IN", _DF_events_in, "Number events received in the RUN"); + declareMonitor("Events/OUT", _DF_events_out, "Number events processed and sent in RUN"); + declareMonitor("Events/ERROR", _DF_events_err, "Number events with errors in the RUN"); +} + +EB::MFP_generator::~MFP_generator() {} + +int EB::MFP_generator::initialize() +{ + int sc = Component::initialize(); + _generator.seed(_random_seed + 2 * getpid()); + if (sc != Online::DF_SUCCESS) { + return error("Failed to initialize service base class."); + } + + logger.set_output_level(online_print_level_to_log_priority(Online::PrintLevel(outputLevel))); + + try { + _local_id = get_idx_UTGID(RTL::processName(), "MFPGen"); + } catch (const std::runtime_error& e) { + logger.error() << "Unable to set local ID from UTGID: " << e.what() << std::flush; + return Online::DF_ERROR; + } + + std::stringstream shmem_name_sstream; + shmem_name_sstream << _shmem_name << "_" << _local_id; + _shmem_name = shmem_name_sstream.str(); + + std::stringstream logger_name; + logger_name << logger.get_name() << " " << _shmem_name; + logger.set_name(logger_name.str()); + + _generate = false; + + sc = config_numa(); + if (sc != Online::DF_SUCCESS) { + return sc; + } + + // TODO add overflow/underflow detection + _n_banks = _prop_n_banks; + _src_id = std::stoi(_prop_src_id); + _align = _prop_align; + _bank_size = _prop_bank_size; + _block_version = _prop_block_version; + _bank_type = _prop_bank_type; + _buffer_size = _prop_buffer_size * 1024 * 1024 * 1024UL; + // interval between the generation of one block and the next one in ns + _sleep_interval_ns = _n_banks / (_event_rate * 1e-9); + logger.info() << "sleep interval " << _sleep_interval_ns << " ns" << std::flush; + if (!std::isfinite(_sleep_interval_ns) || (_sleep_interval_ns <= 0.)) { + logger.warning() << "invalid event rate events will be generated at maximum rate" << std::flush; + _sleep_interval_ns = 0; + } + + logger.info() << "event_rate " << _event_rate << std::flush; + + try { + logger.debug() << "Opening shmem buffer " << _shmem_name << std::flush; + _buffer.reset_backend(std::move( + Shared_mem_buffer_backend(_shmem_name.c_str(), true, _reconnect, true, _buffer_size, 12, _src_id, _numa_node))); + } catch (const std::exception& e) { + logger.error() << __FUNCTION__ << " unable to configure the output buffer " << _shmem_name << " " << e.what() + << std::flush; + return Online::DF_ERROR; + } catch (...) { + logger.error() << __FUNCTION__ << " unexpected exception: output buffer " << _shmem_name << std::flush; + return Online::DF_ERROR; + } + + _is_sodin = string_icompare(RTL::processName(), _sodin_utguid) == 0; + + if (_is_sodin) { + init_sodin(); + } else { + // SODIN doesn't behave like the other SDs + + sc = init_sd(); + if (sc != Online::DF_SUCCESS) { + return sc; + } + + if (_sub_detector_specific_run) { + init_sd_run(); + } + + init_sizes(); + } + + return Online::DF_SUCCESS; +} + +void EB::MFP_generator::init_sodin() +{ + _bank_size = sizeof(Online::pcie40::sodin_t); + _bank_sizes.resize(_n_banks); + + std::fill(_bank_sizes.begin(), _bank_sizes.end(), _bank_size); + + _bank_type = Online::RawBank40::ODIN; + + _run_number = 0; +} + +int EB::MFP_generator::init_sd() +{ + int ret_val = Online::DF_SUCCESS; + if ( + std::find(_velo_utigid_override.begin(), _velo_utigid_override.end(), RTL::processName()) != + _velo_utigid_override.end()) { + _sub_detector = "VA"; + logger.info() << "Overriding default SD with Velo" << std::flush; + } else if ( + std::find(_scifi_utigid_override.begin(), _scifi_utigid_override.end(), RTL::processName()) != + _scifi_utigid_override.end()) { + _sub_detector = "SA"; + logger.info() << "Overriding default SD with SciFi" << std::flush; + } else if ( + std::find(_ut_utigid_override.begin(), _ut_utigid_override.end(), RTL::processName()) != + _ut_utigid_override.end()) { + _sub_detector = "UA"; + logger.info() << "Overriding default SD with UT" << std::flush; + } else if ( + std::find(_muon_utigid_override.begin(), _muon_utigid_override.end(), RTL::processName()) != + _muon_utigid_override.end()) { + _sub_detector = "MA"; + logger.info() << "Overriding default SD with Muon" << std::flush; + } else if ( + std::find(_hcal_utigid_override.begin(), _hcal_utigid_override.end(), RTL::processName()) != + _hcal_utigid_override.end()) { + _sub_detector = "HC"; + logger.info() << "Overriding default SD with HCal" << std::flush; + } else if ( + std::find(_ecal_utigid_override.begin(), _ecal_utigid_override.end(), RTL::processName()) != + _ecal_utigid_override.end()) { + _sub_detector = "EC"; + logger.info() << "Overriding default SD with ECal" << std::flush; + } else if ( + std::find(_rich1_utigid_override.begin(), _rich1_utigid_override.end(), RTL::processName()) != + _rich1_utigid_override.end()) { + _sub_detector = "R1"; + logger.info() << "Overriding default SD with Rich1" << std::flush; + } else if ( + std::find(_rich2_utigid_override.begin(), _rich2_utigid_override.end(), RTL::processName()) != + _rich2_utigid_override.end()) { + _sub_detector = "R2"; + logger.info() << "Overriding default SD with Rich2" << std::flush; + } else { + try { + _sub_detector = get_sub_detector_UTGID(RTL::processName(), "MFPGen"); + } catch (const std::runtime_error& e) { + logger.error() << "Unable to set sub detector from UTGID: " << e.what() << std::flush; + ret_val = Online::DF_ERROR; + } + } + + return ret_val; +} + +void EB::MFP_generator::init_sd_run() +{ + // currently the TD machines are replacing VC ones + if (_sub_detector == "VA" || _sub_detector == "VC" || _sub_detector == "TD") { + logger.info() << "SD selected: Velo" << std::flush; + _lambda = _velo_lambda; + _offset = _velo_offset; + _multi = _velo_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::VP; + } else if (_sub_detector == "SA" || _sub_detector == "SC") { + logger.info() << "SD selected: SciFi" << std::flush; + _lambda = _scifi_lambda; + _offset = _scifi_offset; + _multi = _scifi_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::FTCluster; + } else if (_sub_detector == "UA" || _sub_detector == "UC") { + logger.info() << "SD selected: UT" << std::flush; + _lambda = _ut_lambda; + _offset = _ut_offset; + _multi = _ut_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::UT; + } else if (_sub_detector == "MA" || _sub_detector == "MC") { + logger.info() << "SD selected: Muon" << std::flush; + _lambda = _muon_lambda; + _offset = _muon_offset; + _multi = _muon_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::Muon; + } else if (_sub_detector == "HC") { + logger.info() << "SD selected: HCal" << std::flush; + _lambda = _hcal_lambda; + _offset = _hcal_offset; + _multi = _hcal_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::HcalPacked; + } else if (_sub_detector == "EC") { + logger.info() << "SD selected: ECal" << std::flush; + _lambda = _ecal_lambda; + _offset = _ecal_offset; + _multi = _ecal_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::EcalPacked; + } else if (_sub_detector == "R1") { + logger.info() << "SD selected: Rich1" << std::flush; + _lambda = _rich1_lambda; + _offset = _rich1_offset; + _multi = _rich1_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::Rich; + } else if (_sub_detector == "R2") { + logger.info() << "SD selected: Rich2" << std::flush; + _lambda = _rich2_lambda; + _offset = _rich2_offset; + _multi = _rich2_multi; + // TODO double check the bank types with Roel + _bank_type = Online::RawBank40::Rich; + } else { + logger.warning() << "Unknown sub detector " << _sub_detector << std::flush; + } + + logger.info() << "rand distr params: lambda=" << _lambda << " offset=" << _offset << " multi=" << _multi + << std::flush; +} + +void EB::MFP_generator::init_sizes() +{ + _bank_sizes.resize(_n_preloaded_sizes); + + if (_random_sizes) { + // padding data properly + // TODO add variable distribution + // auto random_distribution = std::uniform_real_distribution<float>(80, 210); + auto random_distribution = std::poisson_distribution<>(_lambda); + + for (auto& elem : _bank_sizes) { + size_t random_size = random_distribution(_generator) * _multi + _offset; + if (random_size <= 0) { + // 1 ensures that at least one aligned word + random_size = 1; + } + elem = random_size + get_padding(random_size, 1 << _align); + } + } else { + // auto padded_size = _bank_size + get_padding(_bank_size, 1 << _align); + std::fill(_bank_sizes.begin(), _bank_sizes.end(), _bank_size); + } + + // if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.info() << "Generated sizes: "; + for (int k = _bank_sizes.size() - 10; k < _bank_sizes.size(); k++) { + if (k >= 0) { + logger.info() << _bank_sizes[k] << ", "; + } + } + logger.info() << std::flush; +} + +int EB::MFP_generator::start() +{ + // TODO check if we need to flush the buffer + _ev_id = 0; + _last_report_ev_id = 0; + _total_timer.reset(); + _random_gen_timer.reset(); + _MFP_write_timer.reset(); + _dead_time_timer.reset(); + + std::lock_guard<decltype(_start_lock)> loop_guard(_start_lock); + + // reset MON counters + _DF_events_out = 0; + _DF_events_in = 0; + _DF_events_err = 0; + + _generate = true; + + return Online::DF_SUCCESS; +} + +int EB::MFP_generator::run() +{ + _ev_id = 0; + std::lock_guard<decltype(_loop_lock)> loop_guard(_loop_lock); + _total_timer.start(); + _MFP_write_timer.start(); + while (_generate) { + _MFP_write_timer.reset(); + write_MFP(); + // Active wait + while (_MFP_write_timer.get_elapsed_time_ns() <= _sleep_interval_ns) + ; + + if (_total_timer.get_elapsed_time_s() > 5) { + _total_timer.stop(); + auto total_time = _total_timer.get_elapsed_time_s(); + auto dead_time = _dead_time_timer.get_elapsed_time_s(); + auto random_gen_time = _random_gen_timer.get_elapsed_time_s(); + auto ev_rate = (double) (_ev_id - _last_report_ev_id) / total_time; + logger.info() << "EV rate " << ev_rate << std::flush; + logger.info() << "dead time " << dead_time << " s " << dead_time / total_time * 100 << "%" << std::flush; + logger.info() << "random gen time " << random_gen_time << " s " << random_gen_time / total_time * 100 << "%" + << std::flush; + _total_timer.reset(); + _random_gen_timer.reset(); + _dead_time_timer.reset(); + _last_report_ev_id = _ev_id; + _total_timer.start(); + } + } + _total_timer.stop(); + _MFP_write_timer.stop(); + + write_end_run(); + + return Online::DF_SUCCESS; +} + +void EB::MFP_generator::write_MFP() +{ + EB::MFP* mfp; + + size_t payload_size = 0; // _bank_size * _n_banks; + + std::vector<EB::bank_size_type> local_sizes(_n_banks); + + _random_gen_timer.start(); + if (!_is_sodin) { + auto rand_distribution = std::uniform_int_distribution<int>(0, _bank_sizes.size() - 1); + for (auto& elem : local_sizes) { + elem = _bank_sizes[rand_distribution(_generator)]; + payload_size += elem + get_padding(elem, 1 << _align); + } + } else { + local_sizes = _bank_sizes; + payload_size = (_bank_sizes[0] + get_padding(_bank_sizes[0], 1 << _align)) * _n_banks; + } + _random_gen_timer.stop(); + + size_t header_size = EB::MFP_header_size(_n_banks); + + _dead_time_timer.start(); + mfp = _buffer.write_next_element(payload_size + header_size); + _dead_time_timer.stop(); + if (mfp != NULL) { + if (_enable_test_pattern) { + memset(mfp, 0xdd, payload_size + header_size); + } + mfp->header.magic = EB::MFP_magic; + mfp->header.n_banks = _n_banks; + mfp->header.packet_size = payload_size + header_size; + mfp->header.ev_id = _ev_id; + mfp->header.src_id = _src_id; + mfp->header.align = _align; + mfp->header.block_version = _block_version; + auto types = mfp->header.bank_types(); + auto sizes = mfp->header.bank_sizes(); + std::copy(local_sizes.begin(), local_sizes.end(), sizes); + std::fill(types, types + _n_banks, _bank_type); + + // test pattern has higher priority + if (_enable_test_pattern) { + write_test_pattern(mfp); + } else if (_is_sodin) { + write_ODIN_banks(mfp); + } + + _DF_events_in += _n_banks; + + logger.debug() << "MFP size " << mfp->bytes() << std::flush; + + _buffer.write_complete(); + _DF_events_out += _n_banks; + _ev_id += _n_banks; + } +} + +void EB::MFP_generator::write_test_pattern(EB::MFP* mfp) +{ + // The global ev id is modified in the write mfp method + uint64_t ev_id = _ev_id; + auto sizes = mfp->header.bank_sizes(); + // for (int k = 0; k < _n_banks; k++) { + int k = 0; + for (auto it = mfp->begin(); it != mfp->end(); it++) { + auto size = sizes[k]; + memset(&(*it), 0xFF & ev_id, size); + memset(&(*it) + size - 1, 0x00, 1); + ev_id++; + k++; + } +} + +void EB::MFP_generator::write_ODIN_banks(EB::MFP* mfp) +{ + // The global ev id is modified in the write mfp method + uint64_t ev_id = _ev_id; + for (auto it = mfp->begin(); it != mfp->end(); it++) { + Online::pcie40::sodin_t* bank = reinterpret_cast<Online::pcie40::sodin_t*>(&(*it)); + memset(bank, 0x0, sizeof(Online::pcie40::sodin_t)); + bank->_run_number = _run_number; + bank->_event_id = ev_id; + ev_id++; + } +} + +void EB::MFP_generator::write_end_run() +{ + EB::MFP* mfp; + // the end of run MFP will have 0 banks a 0 payload, this is not necessary but the MFP needs to be coherent + size_t size = EB::MFP_header_size(0); + mfp = _buffer.write_next_element(size); + // if header si NULL cancel has been issued, no end of run is needed + if (mfp != NULL) { + memset(mfp, 0, size); + mfp->set_end_run(); + mfp->header.packet_size = size; + + _buffer.write_complete(); + } +} + +int EB::MFP_generator::stop() +{ + int ret_val = Online::DF_SUCCESS; + std::unique_lock<std::timed_mutex> loop_guard(_loop_lock, std::chrono::duration<int>(_stop_timeout)); + if (loop_guard) { + logger.info() << "stop executed properly" << std::flush; + } else { + logger.error() << "Unable to execute a clean stop. Aborting" << std::flush; + ret_val = Online::DF_ERROR; + } + _total_timer.stop(); + _random_gen_timer.stop(); + _MFP_write_timer.stop(); + _dead_time_timer.stop(); + _buffer.reset_cancel(); + return ret_val; +} + +int EB::MFP_generator::cancel() +{ + std::lock_guard<decltype(_start_lock)> guard(_start_lock); + _generate = false; + _buffer.cancel(); + return Online::DF_SUCCESS; +} + +int EB::MFP_generator::pause() { return Online::DF_SUCCESS; } + +int EB::MFP_generator::finalize() +{ + _buffer.reset_backend(); + return Online::DF_SUCCESS; +} + +void EB::MFP_generator::handle(const Online::DataflowIncident& inc) +{ + logger.info() << "incident" << std::flush; + // TODO implement this +} + +int EB::MFP_generator::config_numa() +{ + int ret_val = Online::DF_SUCCESS; + + numa_set_strict(1); + + if (_numa_layout.size() == 0) { + _numa_node = -1; + logger.warning() << "No numa topology provided enabling all the nodes" << std::flush; + } else { + _numa_node = 0; + int idx_count = _numa_layout[_numa_node]; + while ((_local_id >= idx_count) && (_numa_node < _numa_layout.size())) { + _numa_node++; + idx_count += _numa_layout[_numa_node]; + } + + if (_numa_node >= _numa_layout.size()) { + _numa_node = -1; + logger.warning() << "Invalid numa topology enabling all the nodes" << std::flush; + } + } + logger.debug() << "Running on NUMA node " << _numa_node << std::flush; + + int numa_err; + numa_err = numa_run_on_node(_numa_node); + if (numa_err != 0) { + logger.error() << __FUNCTION__ << " numa_run_on_node " << _numa_node << ":" << strerror(errno) << std::flush; + ret_val = Online::DF_ERROR; + return ret_val; + } + + numa_set_preferred(_numa_node); + + return ret_val; +} diff --git a/Online/EventBuilding/src/MFP_preloader.cpp b/Online/EventBuilding/src/MFP_preloader.cpp new file mode 100644 index 000000000..8aaba9b2b --- /dev/null +++ b/Online/EventBuilding/src/MFP_preloader.cpp @@ -0,0 +1,103 @@ +#include "MFP_preloader.hpp" +bool EB::MFP_preloader::set_MDF_filename(const char* filename) { return _reader.set_file(filename); } + +void EB::MFP_preloader::set_packing_factor(size_t packing_factor) { _packing_factor = packing_factor; } +size_t EB::MFP_preloader::get_packing_factor() const { return _packing_factor; } + +void EB::MFP_preloader::set_n_MFPs(int n_MFPs) { _n_MFPs = n_MFPs; } +int EB::MFP_preloader::get_n_MFPs() const { return _n_MFPs; } + +int EB::MFP_preloader::set_buffers(std::vector<buffer_ptr_type>& buffers, std::vector<size_t>& buffer_sizes) +{ + int ret_val = 0; + if (buffers.size() == buffer_sizes.size()) { + _buffers = std::move(buffers); + _buffer_sizes = std::move(buffer_sizes); + // reset buffer occupancy + _buffer_occupancy = std::vector<size_t>(_buffers.size(), 0); + } else { + ret_val = -1; + } + + return ret_val; +} + +void EB::MFP_preloader::set_detector_map(const std::vector<EB::type_id_pair_type>& src_map) +{ + _source_mapping = src_map; +} + +std::tuple<std::vector<EB::MFP_preloader::buffer_ptr_type>, std::vector<size_t>, std::vector<size_t>> +EB::MFP_preloader::get_buffers() +{ + return {std::move(_buffers), std::move(_buffer_sizes), std::move(_buffer_occupancy)}; +} + +int EB::MFP_preloader::preload_MFPs() +{ + int ret_val = 0; + std::vector<EB::MDF_block> events; + ret_val = _reader.extract_events(events, _packing_factor * _n_MFPs); + + if (ret_val == 0) { + _builder.append_events(events); + int n_sources; + // no src mapping provided + if (_source_mapping.size() == 0) { + n_sources = _builder.get_source_number(); + } else { + n_sources = _source_mapping.size(); + } + + assert(_buffers.size() == _buffer_sizes.size()); + // no buffers have been provided we allocate some + if (_buffers.size() == 0) { + size_t buff_size = (EB::MFP_header_size(_packing_factor) + _frag_size * _packing_factor) * _n_MFPs; + + assert((_buffer_sizes.size() == 0) && (_buffer_occupancy.size() == 0)); + + _buffers.resize(n_sources); + _buffer_sizes.resize(n_sources, buff_size); + _buffer_occupancy.resize(n_sources, 0); + + for (auto& elem : _buffers) { + // elem = EB::MFP_preloader::buffer_ptr_type(new char[buff_size], [](auto p) {delete;}); + elem = EB::MFP_preloader::buffer_ptr_type(new char[buff_size]); + } + } + + std::vector<char*> write_ptr(n_sources); + // free space in the buffer for convenience + std::vector<size_t> buffer_free = _buffer_sizes; + + for (size_t idx = 0; idx < write_ptr.size(); idx++) { + write_ptr[idx] = _buffers[idx].get(); + } + + for (size_t k = 0; (k < _n_MFPs) && (ret_val >= 0); k++) { + if (_source_mapping.size() == 0) { + ret_val = _builder.build_MFPs(_packing_factor, write_ptr, buffer_free); + } else { + ret_val = _builder.build_MFPs(_packing_factor, write_ptr, buffer_free, _source_mapping); + } + + if (ret_val == 0) { + for (size_t idx = 0; idx < write_ptr.size(); idx++) { + // updateing wrt pointe and buffer occupancy + // TODO this will overlap because the MFP_header does not include the per fragment data + size_t total_block_size = reinterpret_cast<EB::MFP_header*>(write_ptr[idx])->bytes(); + // page aligned MFPs + total_block_size += get_padding(total_block_size, 4096); + write_ptr[idx] += total_block_size; + _buffer_occupancy[idx] += total_block_size; + buffer_free[idx] -= total_block_size; + // this is needed becuase build_MFPs is not aware of padding + if (_buffer_occupancy[idx] >= _buffer_sizes[idx]) { + buffer_free[idx] = 0; + } + } + } + } + } + return ret_val; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/MFP_tools.cpp b/Online/EventBuilding/src/MFP_tools.cpp new file mode 100644 index 000000000..860ff9c8a --- /dev/null +++ b/Online/EventBuilding/src/MFP_tools.cpp @@ -0,0 +1,183 @@ +#include "EventBuilding/MFP_tools.hpp" +#include "EventBuilding/tools.hpp" +#include <iostream> +#include <sstream> + +size_t EB::MFP_header_size(int packing_fraction) +{ + return sizeof(MFP_header) + + aligned_array_end(reinterpret_cast<bank_type_type*>(sizeof(MFP_header)), packing_fraction, MFP_alignment) + + aligned_array_size<bank_size_type>(packing_fraction, MFP_alignment); +} + +EB::bank_type_type* EB::MFP_header::bank_types() +{ + return reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(this) + sizeof(MFP_header)); +} + +const EB::bank_type_type* EB::MFP_header::bank_types() const { return const_cast<MFP_header*>(this)->bank_types(); } + +EB::bank_size_type* EB::MFP_header::bank_sizes() +{ + return reinterpret_cast<bank_size_type*>( + reinterpret_cast<uintptr_t>(bank_types()) + aligned_array_size<bank_type_type>(n_banks, MFP_alignment)); + // this should be used if the ftype array is not aligned + // bank_types() + aligned_array_end(reinterpret_cast<bank_type_type*>(&align), n_banks, MFP_alignment))); +} + +const EB::bank_size_type* EB::MFP_header::bank_sizes() const { return const_cast<MFP_header*>(this)->bank_sizes(); } + +size_t EB::MFP_header::header_size() const { return MFP_header_size(n_banks); } + +size_t EB::MFP_header::bytes() const { return packet_size; } + +void* EB::MFP::payload() +{ + return reinterpret_cast<void*>( + reinterpret_cast<uintptr_t>(header.bank_sizes()) + + aligned_array_size<bank_size_type>(header.n_banks, MFP_alignment)); +} + +const void* EB::MFP::payload() const { return const_cast<MFP*>(this)->payload(); } + +std::string EB::MFP_header::print(bool verbose) const +{ + std::stringstream os; + os << "\n------MFP HEADER------\n"; + os << "Magic " << std::hex << magic << std::dec << "\n"; + os << "event ID " << ev_id << "\n"; + os << "source ID " << src_id << "\n"; + os << "n banks " << n_banks << "\n"; + os << "packet size " << packet_size << "\n"; + if (verbose) { + auto types = bank_types(); + auto sizes = bank_sizes(); + for (int k = 0; k < n_banks; k++) { + os << "bank type " << EB::BankType(types[k]) << " bank size " << sizes[k] << "\n"; + } + } + + return os.str(); +} + +std::ostream& EB::operator<<(std::ostream& os, const MFP_header& header) { return os << header.print(); } + +bool EB::MFP::is_header_valid() const { return (header.magic == MFP_magic); } +void EB::MFP::set_header_valid() { header.magic = MFP_magic; } + +bool EB::MFP::is_valid() const { return is_header_valid() && (bytes() >= header.header_size()); } + +bool EB::MFP::is_end_run() const { return is_header_valid() && (header.ev_id == MFP_end_run); } +void EB::MFP::set_end_run() +{ + // TODO set the correct size + set_header_valid(); + header.ev_id = MFP_end_run; + header.n_banks = 0; +} + +void* EB::MFP::get_bank_n(int n) +{ + void* ret_val; + if (n >= header.n_banks) { + ret_val = nullptr; + } else { + auto it = this->begin(); + for (int k = 0; k < n; k++) { + it++; + } + ret_val = &(*it); + } + return ret_val; +} + +const void* EB::MFP::get_bank_n(int n) const +{ + const void* ret_val; + if (n >= header.n_banks) { + ret_val = nullptr; + } else { + auto it = this->cbegin(); + for (int k = 0; k < n; k++) { + it++; + } + ret_val = &(*it); + } + return ret_val; +} + +void* EB::MFP::operator[](int n) +{ + auto it = this->begin(); + for (int k = 0; k < n; k++) { + it++; + } + return &(*it); +} + +const void* EB::MFP::operator[](int n) const +{ + auto it = this->cbegin(); + for (int k = 0; k < n; k++) { + it++; + } + return &(*it); +} + +bool EB::MFP::is_wrap() const { return header.magic == MFP_wrap; } +void EB::MFP::set_wrap() { header.magic = MFP_wrap; } + +std::string EB::MFP::print(bool verbose) const +{ + std::stringstream os; + os << header.print(verbose); + os << "Payload " << payload() << '\n'; + + if (verbose) { + // TODO add something for the banks + } + + return os.str(); +} +std::ostream& EB::operator<<(std::ostream& os, const MFP& header) { return os << header.print(); } + +// iterator implementation + +EB::MFP::iterator::reference EB::MFP::iterator::operator*() const { return *_bank; } +EB::MFP::iterator::pointer EB::MFP::iterator::operator->() { return _bank; } +EB::MFP::iterator& EB::MFP::iterator::operator++() +{ + auto padded_size = *_size + get_padding(*_size, 1 << _align); + _bank += padded_size; + _size++; + return *this; +} + +EB::MFP::iterator EB::MFP::iterator::operator++(int) +{ + iterator tmp = *this; + ++(*this); + return tmp; +} +bool EB::operator==(const EB::MFP::iterator& a, const EB::MFP::iterator& b) { return a._size == b._size; } +bool EB::operator!=(const EB::MFP::iterator& a, const EB::MFP::iterator& b) { return !(a == b); } + +// const iterator implementation +EB::MFP::const_iterator::reference EB::MFP::const_iterator::operator*() const { return *_bank; } +EB::MFP::const_iterator::pointer EB::MFP::const_iterator::operator->() { return _bank; } +EB::MFP::const_iterator& EB::MFP::const_iterator::operator++() +{ + auto padded_size = *_size + get_padding(*_size, 1 << _align); + _bank += padded_size; + _size++; + return *this; +} + +EB::MFP::const_iterator EB::MFP::const_iterator::operator++(int) +{ + const_iterator tmp = *this; + ++(*this); + return tmp; +} +bool EB::operator==(const EB::MFP::const_iterator& a, const EB::MFP::const_iterator& b) { return a._size == b._size; } +bool EB::operator!=(const EB::MFP::const_iterator& a, const EB::MFP::const_iterator& b) { return a._size != b._size; } diff --git a/Online/EventBuilding/src/Parallel_Comm.cpp b/Online/EventBuilding/src/Parallel_Comm.cpp new file mode 100644 index 000000000..da6281f0a --- /dev/null +++ b/Online/EventBuilding/src/Parallel_Comm.cpp @@ -0,0 +1,360 @@ +#include "Parallel_Comm.hpp" +#include <exception> +#include <iostream> +#include <cstdlib> +#include <unistd.h> +#include <stdexcept> +#include <sstream> +#include <numa.h> + +using namespace Online; + +std::ostream& EB::comm_op::print(std::ostream& os) const +{ + os << "size " << count * datatype << "\n"; + return os; +} + +std::ostream& EB::comm_send::print(std::ostream& os) const +{ + os << "COMM SEND" + << "\n"; + os << "destination " << destination << "\n"; + os << "buffer " << std::hex << snd_buff << std::dec << "\n"; + return comm_op::print(os); +} + +std::ostream& EB::comm_recv::print(std::ostream& os) const +{ + os << "COMM RECV" + << "\n"; + os << "source " << source << "\n"; + os << "buffer " << std::hex << recv_buff << std::dec << "\n"; + return comm_op::print(os); +} + +EB::Parallel_comm::Parallel_comm(Parallel_comm&& src) : _ibObj(std::move(src._ibObj)) {} + +EB::Parallel_comm& EB::Parallel_comm::operator=(Parallel_comm&& src) +{ + if (this != &src) { + this->_ibDestroy(); + this->_ibObj = std::move(src._ibObj); + } + return *this; +} + +EB::Parallel_comm::Parallel_comm(IB_verbs::Parser* prs, std::string logName, Online::PrintLevel logLevel) +{ + logger.set_name(logName); + logger.set_output_level(logLevel); + if (!_ibInit(prs)) throw std::runtime_error("cannot start verbs!!!"); +} + +EB::Parallel_comm::~Parallel_comm() { _ibDestroy(); } + +int EB::Parallel_comm::_ibInit(IB_verbs::Parser* ibprs) +{ + try { + int ret = _ibObj.ibSetHostList(*ibprs); + } catch (std::exception& e) { + logger.error() << "IB config file parser: " << e.what() << std::flush; + return DataflowStatus::DF_ERROR; + } + int devNuma = _ibObj.ibGetNumaNode(); + int numa_err = numa_run_on_node(devNuma); + if (numa_err != 0) { + logger.error() << __FUNCTION__ << " numa_run_on_node " << devNuma << ":" << strerror(errno) << std::flush; + return Online::DF_ERROR; + } + + logger.debug() << "running on NUMA node " << devNuma << std::flush; + + numa_set_preferred(devNuma); + try { + _ibObj.ibInit(); + } catch (std::exception& e) { + logger.error() << "IB init: " << e.what() << std::flush; + return DataflowStatus::DF_ERROR; + } + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::_ibDestroy() +{ + try { + _ibObj.ibDestroy(); + } catch (std::exception& e) { + logger.error() << "IB destroy: " << e.what() << std::flush; + return DataflowStatus::DF_ERROR; + } + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::ibDeregMRs() +{ + try { + _ibObj.ibDeregMRs(); + } catch (std::exception& e) { + logger.error() << "IB dereg MRs: " << e.what() << std::flush; + return DataflowStatus::DF_ERROR; + } + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::getTotalProcesses() { return _ibObj.getTotalProcesses(); } + +int EB::Parallel_comm::getProcessID() { return _ibObj.getProcessID(); } + +int EB::Parallel_comm::addMR(char* bufPtr, size_t bufSize, int access_flags) +{ + if (_ibObj.ibAddMR(bufPtr, bufSize, access_flags) == NULL) { + return DataflowStatus::DF_ERROR; + } + return DataflowStatus::DF_SUCCESS; +} + +void EB::Parallel_comm::ibKillBlocking() { _ibObj.ibKillBlocking(); } + +int EB::Parallel_comm::send(const std::vector<comm_send>& sends) +{ + int ret; + logger.debug() << "waiting sync: " << sends.front().destination << std::flush; + ret = _syncRecv(sends.front().destination); + if (ret != DataflowStatus::DF_SUCCESS) { + return ret; + } + + logger.debug() << "Posting SRs" << std::flush; + ret = _sendV(sends); + if (ret == -5) { + return DataflowStatus::DF_CANCELLED; + } else if (ret != 0) { + return DataflowStatus::DF_ERROR; + } + + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::receive(const std::vector<comm_recv>& recvs) +{ + int ret = DataflowStatus::DF_SUCCESS; + logger.debug() << "Posting RRs" << std::flush; + auto recvsid = _receiveV(recvs); + logger.debug() << "send sync: " << recvs.front().source << std::flush; + ret = _syncSend(recvs.front().source); + if (ret != DataflowStatus::DF_SUCCESS) { + return ret; + } + + logger.debug() << "waiting recv completion" << std::flush; + ret = _waitRecvs(recvsid); + logger.debug() << "recv completed" << std::flush; + return ret; +} + +int EB::Parallel_comm::_waitRecvs(std::vector<uint32_t>& recvs) +{ + int ret = _ibObj.ibWaitAllRecvs(recvs); + if (ret == 0) { + return DataflowStatus::DF_SUCCESS; + } else if (ret == -5) { + return DataflowStatus::DF_CANCELLED; + } + return DataflowStatus::DF_ERROR; +} + +int EB::Parallel_comm::_waitSends(std::vector<uint32_t>& sends) +{ + int ret = _ibObj.ibWaitAllSends(sends); + if (ret == 0) { + return DataflowStatus::DF_SUCCESS; + } else if (ret == -5) { + return DataflowStatus::DF_CANCELLED; + } + return DataflowStatus::DF_ERROR; +} + +int EB::Parallel_comm::ibTestRecvs(std::vector<uint32_t>& recvs) { return _ibObj.ibTestAllRecvs(recvs); } + +std::vector<uint32_t> EB::Parallel_comm::_receiveV(const std::vector<comm_recv>& recvs) +{ + std::vector<uint32_t> req_vec; + for (auto& recv_it : recvs) { + size_t size = recv_it.count * recv_it.datatype; + uint32_t ret = _ibObj.ibRecv((char*) recv_it.recv_buff, size, recv_it.source); + if (ret != 0) { + req_vec.push_back(ret); + } else { + logger.error() << "IB recv FAILED with err: " << ret << std::flush; + } + } + return req_vec; +} + +int EB::Parallel_comm::_sendV(const std::vector<comm_send>& sends) +{ + std::vector<uint32_t> req_vec; + for (auto& send_it : sends) { + size_t size = send_it.count * send_it.datatype; + uint32_t ret = _ibObj.ibSend((char*) send_it.snd_buff, size, send_it.destination); + + if (ret != 0) { + req_vec.push_back(ret); + } else { + logger.error() << "IB send FAILED with err: " << ret << std::flush; + return -1; + } + } + + return _ibObj.ibWaitAllSends(req_vec); +} + +int EB::Parallel_comm::_syncSend(int dest) +{ + int rank = _ibObj.getProcessID(); + logger.debug() << rank << " S SYNC to " << dest << std::flush; + uint32_t wid = _ibObj.ibSendSync(IB_verbs::IB::immediate_t::ONE_TO_ONE, dest); + if (wid == 0) return DataflowStatus::DF_ERROR; + int ret = _ibObj.ibWaitSyncSend(wid); + if (ret == 0) { + return DataflowStatus::DF_SUCCESS; + } else if (ret == -5) { + return DataflowStatus::DF_CANCELLED; + } + return DataflowStatus::DF_ERROR; +} + +uint32_t EB::Parallel_comm::_syncRecv(int src) +{ + int rank = _ibObj.getProcessID(); + logger.debug() << rank << " R SYNC from " << src << std::flush; + int ret = _ibObj.ibWaitSyncRecv(IB_verbs::IB::immediate_t::ONE_TO_ONE, src); + if (ret == 0) { + return DataflowStatus::DF_SUCCESS; + } else if (ret == -5) { + return DataflowStatus::DF_CANCELLED; + } + return DataflowStatus::DF_ERROR; +} + +int EB::Parallel_comm::ibBarrier() +{ + // int ret = _ibObj.ibBarrier(IB_verbs::IB::barrier_t::CENTRAL); + int ret = _ibObj.ibBarrier(); + if (ret == -5) { + return DataflowStatus::DF_CANCELLED; + } else if (ret < 0) { + logger.error() << "Parallel_Comm: Barrier Failed" << std::flush; + return DataflowStatus::DF_ERROR; + } + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::ibScatterV(char* data, size_t n_elem, size_t elem_size, std::vector<int>& dsts) +{ + std::vector<uint32_t> wrids; + int ret_val = 0; + uint32_t data_wrid = 0; + for (int j = 0; j < dsts.size(); j++) { + logger.debug() << "waiting sync from " << dsts.at(j) << std::flush; + ret_val = _syncRecv(dsts.at(j)); + if (ret_val != DataflowStatus::DF_SUCCESS) { + return ret_val; + } + size_t idx = j * n_elem * elem_size; + logger.debug() << "sending sizes to " << dsts.at(j) << ": " << n_elem << std::flush; + data_wrid = _ibObj.ibSend(data + idx, n_elem * elem_size, dsts.at(j)); + if (data_wrid == 0) return DataflowStatus::DF_ERROR; + wrids.push_back(data_wrid); + ret_val = _waitSends(wrids); + if (ret_val != DataflowStatus::DF_SUCCESS) { + return ret_val; + } + } + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::ibBroadcastV(char* data, size_t n_elem, size_t elem_size, std::vector<int>& dsts) +{ + std::vector<uint32_t> wrids; + int ret_val = 0; + uint32_t data_wrid = 0; + for (int j = 0; j < dsts.size(); j++) { + logger.debug() << "waiting sync from " << dsts.at(j) << std::flush; + ret_val = _syncRecv(dsts.at(j)); + if (ret_val != DataflowStatus::DF_SUCCESS) { + return ret_val; + } + logger.debug() << "sending sizes to " << dsts.at(j) << ": " << n_elem << std::flush; + data_wrid = _ibObj.ibSend(data, n_elem * elem_size, dsts.at(j)); + if (data_wrid == 0) return DataflowStatus::DF_ERROR; + wrids.push_back(data_wrid); + ret_val = _waitSends(wrids); + if (ret_val != DataflowStatus::DF_SUCCESS) { + return ret_val; + } + } + return DataflowStatus::DF_SUCCESS; +} + +int EB::Parallel_comm::ibGatherBlockV( + char* data, + int* data_sizes, + int* data_idxs, + size_t elem_size, + std::vector<int>& remotes) +{ + int ret_val = 0; + auto wrids = ibGatherV(data, data_sizes, data_idxs, elem_size, remotes, ret_val); + logger.debug() << "sync done" << std::flush; + ret_val = _ibObj.ibWaitAllRecvs(wrids); + if (ret_val == -5) { + return DataflowStatus::DF_CANCELLED; + } else if (ret_val < 0) { + return DataflowStatus::DF_ERROR; + } + return DataflowStatus::DF_SUCCESS; +} + +std::vector<uint32_t> EB::Parallel_comm::ibGatherV( + char* data, + int* data_sizes, + int* data_idxs, + size_t elem_size, + std::vector<int>& remotes, + int& ret_val) +{ + ret_val = DataflowStatus::DF_SUCCESS; + std::vector<uint32_t> wrids; + std::vector<uint32_t> syncids; + uint32_t data_wrid, sync_wrid; + for (int i = 0; i < remotes.size(); i++) { + logger.debug() << "posting gather recv from " << remotes.at(i) << ": " << data_sizes[i] << ", " + << (uintptr_t) (data) + data_idxs[i] * elem_size << std::flush; + data_wrid = _ibObj.ibRecv(data + data_idxs[i] * elem_size, data_sizes[i] * elem_size, remotes.at(i)); + if (data_wrid == 0) { + ret_val = DataflowStatus::DF_ERROR; + // TODO check if break is a better option + return wrids; + } + wrids.push_back(data_wrid); + logger.debug() << "sending sync to " << remotes.at(i) << std::flush; + sync_wrid = _ibObj.ibSendSync(IB_verbs::IB::immediate_t::ONE_TO_ONE, remotes.at(i)); + if (sync_wrid == 0) { + ret_val = DataflowStatus::DF_ERROR; + // TODO check if break is a better option + return wrids; + } + syncids.push_back(sync_wrid); + } + logger.debug() << "waiting for sync" << std::flush; + int ret = _ibObj.ibWaitAllSyncSends(syncids); + if (ret == -5) { + ret_val = DataflowStatus::DF_CANCELLED; + } else if (ret != 0) { + ret_val = DataflowStatus::DF_ERROR; + } + logger.debug() << "sync done" << std::flush; + return wrids; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/RU.cpp b/Online/EventBuilding/src/RU.cpp new file mode 100644 index 000000000..38dffd20f --- /dev/null +++ b/Online/EventBuilding/src/RU.cpp @@ -0,0 +1,927 @@ +#include "EventBuilding/RU.hpp" +#include "shmem_buffer_reader.hpp" +#include <algorithm> +#include <numeric> +#include <stdexcept> +#include <sstream> +#include <chrono> +#include "MFP_preloader.hpp" +#include "RTL/rtl.h" +#include "EventBuilding/tools.hpp" + +const std::string EB::RU_buffer_type_to_string(RU_buffer_types type) +{ + switch (type) { + case dummy_MFP_buffer: return "dummy_MFP_buffer"; + case shmem_MFP_buffer: return "shmem_MFP_buffer"; + case PCIe40_MFP_buffer: return "PCIe40_MFP_buffer"; + case PCIe40_frag_buffer: return "PCIe40_frag_reader"; + default: return "Error unkown buffer type"; + } +} + +std::ostream& EB::operator<<(std::ostream& os, RU_buffer_types type) { return os << RU_buffer_type_to_string(type); } + +EB::RU::RU(const std::string& nam, DataflowContext& ctxt) : Transport_unit(nam, ctxt) +{ + // TODO declare all the properties + info("RU constructor"); + declareProperty("n_fragment", _n_fragment = 1); + declareProperty("shmem_prefix", _shmem_prefix = "RU"); + declareProperty("buffer_type", _buffer_type); + + declareProperty("write_to_file", _write_to_file); + declareProperty("out_file_prefix", _out_file_prefix = "RU"); + declareProperty("n_MFPs_to_file", _n_MFPs_to_file = 1); + // TODO find a good default value + declareProperty("PCIe40_ids", _PCIe40_ids); + declareProperty("PCIe40_names", _PCIe40_names); + declareProperty("buffer_sizes", _prop_buffer_sizes); + declareProperty("MDF_filename", _MDF_filename); + declareProperty("n_MFPs", _n_MFPs = 1); + declareProperty("stop_timeout", _stop_timeout = 10); + declareProperty("dummy_src_ids", _dummy_src_ids); + declareProperty("SODIN_ID", _SODIN_ID = -1); + declareProperty("SODIN_name", _SODIN_name = ""); + declareProperty("SODIN_stream", _SODIN_stream = 0); + + // DF monitoring counters + declareMonitor("Events/IN", _DF_events_in, "Number events received in the RUN"); + declareMonitor("Events/OUT", _DF_events_out, "Number events processed and sent in RUN"); + declareMonitor("Events/ERROR", _DF_events_err, "Number events with errors in the RUN"); + // DEBUG counters + declareMonitor("run_loop_iteration", _run_loop_iteration, "Iteration fo the run loop in the RUN"); + // profiling counters + declareMonitor("load_mpfs_time_counter", _load_mpfs_time_counter); + declareMonitor("send_sizes_time_counter", _send_sizes_time_counter); + declareMonitor("linear_shift_time_counter", _linear_shift_time_counter); + declareMonitor("send_time_counter", _send_time_counter); + + logger.set_name(name); +} + +EB::RU::~RU() {} + +int EB::RU::initialize() +{ + int sc = Transport_unit::initialize(); + if (sc != DF_SUCCESS) { + return error("Failed to initialize Transport unit base class."); + } + + _my_idx = get_idx(_ru_ranks.begin(), _ru_ranks.end(), _my_rank); + if (_my_idx < 0) { + logger.error() << " this process should not be a RU. Aborting." << std::flush; + return DF_ERROR; + } + + // Addding MPI information to the log name + std::stringstream logger_name; + logger_name << logger.get_name() << " idx " << _my_idx; + logger.set_name(logger_name.str()); + + sc = init_shift(); + if (sc != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " init shift failed" << std::flush; + return sc; + } + + sc = init_dummy_src_ids(); + if (sc != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " init dummy src ids failed" << std::flush; + return sc; + } + + return DF_SUCCESS; +} + +int EB::RU::check_buffers() +{ + int ret_val = DF_SUCCESS; + + if (_buffer_type.size() == 0) { + _buffer_type.resize(_ru_ranks.size(), default_RU_buffer_type); + logger.warning() << __FUNCTION__ << " no buffer types provided setting to default value " + << EB::default_RU_buffer_type << std::flush; + } else if (_buffer_type.size() == 1) { + _buffer_type.resize(_ru_ranks.size(), _buffer_type[0]); + logger.warning() << __FUNCTION__ << " Single buffer type provided: " << _buffer_type[0] << std::flush; + } + + if (_buffer_type.size() != _ru_ranks.size()) { + logger.error() << __FUNCTION__ << " Configuration error: not enough buffer types provided " << _buffer_type.size() + << "/" << _ru_ranks.size() << std::flush; + + ret_val = DF_ERROR; + } + + if (_prop_buffer_sizes.size() == 0) { + _prop_buffer_sizes.resize(_prefix_n_sources_per_ru[_ru_ranks.size()], default_RU_buffer_size); + logger.warning() << __FUNCTION__ << " no buffer sizes provided setting to default value " + << EB::default_RU_buffer_size << std::flush; + } else if (_prop_buffer_sizes.size() == 1) { + _prop_buffer_sizes.resize(_prefix_n_sources_per_ru[_ru_ranks.size()], _prop_buffer_sizes[0]); + logger.warning() << __FUNCTION__ << " Single buffer size provided: " << _prop_buffer_sizes[0] << std::flush; + } + + if (_prop_buffer_sizes.size() != _prefix_n_sources_per_ru[_ru_ranks.size()]) { + logger.error() << __FUNCTION__ << " Configuration error: not enough buffer sizes provided " + << _prop_buffer_sizes.size() << "/" << _prefix_n_sources_per_ru[_ru_ranks.size()] << std::flush; + + ret_val = DF_ERROR; + } + + _buffer_sizes.resize(_prop_buffer_sizes.size()); + std::transform(_prop_buffer_sizes.begin(), _prop_buffer_sizes.end(), _buffer_sizes.begin(), [](auto val) { + return val * 1024 * 1024 * 1024UL; + }); + + if (_write_to_file.size() == 0) { + _write_to_file.resize(_ru_ranks.size(), false); + logger.warning() << __FUNCTION__ << " write to file was not set, setting it to the default value " << false + << std::flush; + } else if (_write_to_file.size() == 1) { + _write_to_file.resize(_ru_ranks.size(), _write_to_file[0]); + logger.warning() << __FUNCTION__ << " Single write to file provided: " << _write_to_file[0] << std::flush; + } + + if (_write_to_file.size() != _ru_ranks.size()) { + logger.error() << __FUNCTION__ << " Configuration error: not enough write to file provided " + << _write_to_file.size() << "/" << _bu_ranks.size() << std::flush; + + ret_val = DF_ERROR; + } + + _buffer_sizes.resize(_prop_buffer_sizes.size()); + std::transform(_prop_buffer_sizes.begin(), _prop_buffer_sizes.end(), _buffer_sizes.begin(), [](auto val) { + return val * 1024 * 1024 * 1024UL; + }); + + return ret_val; +} + +int EB::RU::config_buffers() +{ + int ret_val = DF_SUCCESS; + _buffers.reserve(_n_sources_per_ru[_my_idx]); + + ret_val = check_buffers(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + try { + if (_buffer_type[_my_idx] == dummy_MFP_buffer) { + config_dummy(); + } else if (_buffer_type[_my_idx] == shmem_MFP_buffer) { + config_shmem(); + } else if (_buffer_type[_my_idx] == PCIe40_frag_buffer) { + config_PCIe40_frag(); + } else if (_buffer_type[_my_idx] == PCIe40_MFP_buffer) { + config_PCIe40(); + } else { + logger.error() << __FUNCTION__ << " unsupported buffer type " << _buffer_type[_my_idx] << std::flush; + ret_val = DF_ERROR; + return ret_val; + } + + if (_write_to_file[_my_idx]) { + std::stringstream file_name; + file_name << _out_file_prefix << "_" << _my_idx << ".mfp"; + _file_writer = std::move(File_writer<EB::MFP>(file_name.str())); + } + + } catch (const std::system_error& e) { + logger.error() << __FUNCTION__ << " unable to configure buffer type" << RU_buffer_types(_buffer_type[_my_idx]) + << ". " << e.what() << ": " << strerror(errno) << ". Error code: " << e.code() << std::flush; + ret_val = DF_ERROR; + return ret_val; + } catch (const std::exception& e) { + logger.error() << __FUNCTION__ << " unable to configure buffer type " << RU_buffer_types(_buffer_type[_my_idx]) + << ". " << e.what() << ": " << strerror(errno) << std::flush; + ret_val = DF_ERROR; + return ret_val; + } catch (...) { + logger.error() << __FUNCTION__ << " unexpected exception buffer type " << RU_buffer_types(_buffer_type[_my_idx]) + << std::flush; + ret_val = DF_ERROR; + return ret_val; + } + + return ret_val; +} + +int EB::RU::start() +{ + int ret_val = DF_SUCCESS; + info("RU start"); + int sc = Transport_unit::start(); + if (sc != DF_SUCCESS) { + return error("Failed to start Transport_unit base class."); + } + ret_val = config_buffers(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + // exchange srcids + ret_val = send_src_ids(); + if (ret_val != DF_SUCCESS) return ret_val; + _ibComm->ibDeregMRs(); // clear memory regions + + for (auto& buf : _buffers) { + auto buflist = buf->get_full_buffer(); + for (std::tuple<void*, size_t>& list_it : buflist) { + ret_val = _ibComm->addMR((char*) std::get<void*>(list_it), std::get<size_t>(list_it), 0x0); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " unable to register memory for buffer " << std::get<void*>(list_it) + << std::flush; + return ret_val; + } + } + } + logger.debug() << "data MRs allocated" << std::flush; + // mpfs and sizes per destination per src + size_t mfp_vec_size = _bu_ranks.size() * _buffers.size(); + selected_MFPs.resize(mfp_vec_size); + sizes.resize(mfp_vec_size); + _n_frags_per_dst.resize(_bu_ranks.size()); + // TO DO + ret_val = _ibComm->addMR((char*) &sizes, sizes.size() * sizeof(uint32_t)); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + // END TO DO + logger.debug() << "size MRs allocated dim: " << mfp_vec_size << std::flush; + std::lock_guard<decltype(_start_lock)> loop_guard(_start_lock); + _send_MEPs = true; + reset_counters(); + _end_of_run = true; + return DF_SUCCESS; +} + +int EB::RU::stop() +{ + int ret_val = DF_SUCCESS; + logger.info() << "stop" << std::flush; + std::unique_lock<std::timed_mutex> loop_guard(_loop_lock, std::chrono::duration<int>(_stop_timeout)); + if (loop_guard) { + logger.info() << "stop executed properly" << std::flush; + } else { + logger.error() << "Unable to execute a clean stop. Aborting" << std::flush; + ret_val = DF_ERROR; + } + int sc = Transport_unit::stop(); + if (sc != DF_SUCCESS) { + return error("Failed to stop Transport_unit base class."); + } + if (ret_val != DF_SUCCESS) { + return ret_val; + } + // undo the buffer allocation done in start + // TODO check if the buffers should be cleaned if stop aborts + _buffers.clear(); + + return ret_val; +} + +int EB::RU::cancel() +{ + // TODO implement this + std::lock_guard<decltype(_start_lock)> guard(_start_lock); + logger.info() << "cancel" << std::flush; + _send_MEPs = false; + Transport_unit::cancel(); + for (auto& buffer : _buffers) { + buffer->cancel(); + } + + return DF_SUCCESS; +} + +int EB::RU::pause() +{ + // _send_MEPs = false; + // the EB does not go into pause + return DF_SUCCESS; +} + +int EB::RU::finalize() { return Transport_unit::finalize(); } + +void EB::RU::handle(const DataflowIncident& inc) +{ + info("RU incident"); + // TODO implement this +} + +void EB::RU::config_dummy() +{ + // fast access to my config + auto my_buffer_sizes_begin = _buffer_sizes.begin() + _prefix_n_sources_per_ru[_my_idx]; + auto my_buffer_sizes_end = _buffer_sizes.begin() + _prefix_n_sources_per_ru[_my_idx + 1]; + // config already checked + + // loads data from the MDF file + MFP_preloader preloader; + if (!preloader.set_MDF_filename(_MDF_filename.c_str())) { + std::stringstream error_mess; + error_mess << __FUNCTION__ << ": unable to open MDF file " << _MDF_filename << " " << strerror(errno); + throw std::runtime_error(error_mess.str()); + } + + preloader.set_n_MFPs(_n_MFPs); + + std::vector<MFP_preloader::buffer_ptr_type> buffers(_n_sources_per_ru[_my_idx]); + std::vector<EB::type_id_pair_type> source_mapping(_n_sources_per_ru[_my_idx]); + for (int k = 0; k < _n_sources_per_ru[_my_idx]; k++) { + void* tmp_ptr; + posix_memalign(&tmp_ptr, sysconf(_SC_PAGE_SIZE), *(my_buffer_sizes_begin + k)); + if (tmp_ptr == NULL) { + std::stringstream error_mess; + error_mess << __FUNCTION__ << ": unable to allocate buffer " << k << " " << strerror(errno); + throw std::runtime_error(error_mess.str()); + } + + buffers[k] = MFP_preloader::buffer_ptr_type(reinterpret_cast<char*>(tmp_ptr), free); + source_mapping[k] = EB::new_src_id_to_old(_dummy_src_ids[_prefix_n_sources_per_ru[_my_idx] + k]); + } + + preloader.set_detector_map(source_mapping); + std::vector<size_t> tmp_sizes(my_buffer_sizes_begin, my_buffer_sizes_end); + preloader.set_buffers(buffers, tmp_sizes); + + preloader.set_packing_factor(_n_fragment); + + if (preloader.preload_MFPs() < 0) { + std::stringstream error_mess; + error_mess << __FUNCTION__ << ": unable to preload MFPs from file " << _MDF_filename; + throw std::runtime_error(error_mess.str()); + } + + auto buffs = preloader.get_buffers(); + + for (int k = 0; k < _n_sources_per_ru[_my_idx]; k++) { + _buffers.emplace_back(new Dummy_MFP_buffer( + std::get<0>(buffs)[k], std::get<2>(buffs)[k], _dummy_src_ids[_prefix_n_sources_per_ru[_my_idx] + k])); + } +} + +void EB::RU::config_shmem() +{ + int local_idx; + + local_idx = get_idx_UTGID(RTL::processName(), "RU"); + + int idx_offset = 0; + while (local_idx > 0) { + idx_offset += _n_sources_per_ru[_my_idx - local_idx]; + local_idx--; + } + + for (int k = 0; k < _n_sources_per_ru[_my_idx]; k++) { + std::stringstream shmem_name; + shmem_name << _shmem_prefix << "_" << k + idx_offset; + _buffers.emplace_back(new Shmem_buffer_reader<EB::MFP>(shmem_name.str().c_str())); + } +} + +int EB::RU::stream_select(int id) +{ + int stream; + if (_SODIN_ID != id) { + stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN; + } else { + stream = static_cast<int>(P40_DAQ_STREAM::P40_DAQ_STREAM_ODIN0) + _SODIN_stream; + } + + return stream; +} + +int EB::RU::stream_select(const std::string& name) +{ + int stream; + if (_SODIN_name != name) { + stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN; + } else { + // TODO add multi stream support based on the _SODIN_stream variable + stream = static_cast<int>(P40_DAQ_STREAM::P40_DAQ_STREAM_ODIN0) + _SODIN_stream; + } + + return stream; +} +void EB::RU::config_PCIe40() +{ + if (_PCIe40_ids.size() == _prefix_n_sources_per_ru[_ru_ranks.size()]) { + logger.info() << "PCIe40 selection by ID" << std::flush; + // fast access to my config + auto my_PCIe40_ids_begin = _PCIe40_ids.begin() + _prefix_n_sources_per_ru[_my_idx]; + auto my_PCIe40_ids_end = _PCIe40_ids.begin() + _prefix_n_sources_per_ru[_my_idx + 1]; + + for (auto it = my_PCIe40_ids_begin; it != my_PCIe40_ids_end; it++) { + _buffers.emplace_back(new PCIe40_MFP_reader(*it, stream_select(*it), _n_fragment)); + } + } else if (_PCIe40_names.size() == _prefix_n_sources_per_ru[_ru_ranks.size()]) { + logger.info() << "PCIe40 selection by name" << std::flush; + // fast access to my config + auto my_PCIe40_names_begin = _PCIe40_names.begin() + _prefix_n_sources_per_ru[_my_idx]; + auto my_PCIe40_names_end = _PCIe40_names.begin() + _prefix_n_sources_per_ru[_my_idx + 1]; + + for (auto it = my_PCIe40_names_begin; it != my_PCIe40_names_end; it++) { + _buffers.emplace_back(new PCIe40_MFP_reader(*it, stream_select(*it), _n_fragment)); + } + } else { + // In this set of functions (config_buffers) the errors are handled via expections + std::ostringstream err_mess; + err_mess << "RU " << _my_idx << " " << __FUNCTION__ + << ": Invalid PCIe40 configuration: not enough IDs or names provided. Got " << _PCIe40_names.size() + << " names and " << _PCIe40_ids.size() << " ids for " << _prefix_n_sources_per_ru[_ru_ranks.size()] + << " data sources"; + throw std::runtime_error(err_mess.str()); + } +} + +void EB::RU::config_PCIe40_frag() +{ + // fast access to my config + // buffer_sizes_are checked in the buffer_check method + auto my_buffer_sizes_it = _buffer_sizes.begin() + _prefix_n_sources_per_ru[_my_idx]; + auto my_buffer_sizes_end = _buffer_sizes.begin() + _prefix_n_sources_per_ru[_my_idx + 1]; + auto my_buffer_sizes_size = std::distance(my_buffer_sizes_it, my_buffer_sizes_end); + + if (_PCIe40_ids.size() == _prefix_n_sources_per_ru[_ru_ranks.size()]) { + auto my_PCIe40_ids_it = _PCIe40_ids.begin() + _prefix_n_sources_per_ru[_my_idx]; + for (int k = 0; k < my_buffer_sizes_size; k++) { + _buffers.emplace_back(new PCIe40_frag_reader( + *(my_PCIe40_ids_it), + *(my_buffer_sizes_it), + _n_fragment, + EB::default_PCIe40_alignment, + stream_select(*my_PCIe40_ids_it))); + my_PCIe40_ids_it++; + my_buffer_sizes_it++; + } + } else if (_PCIe40_names.size() == _prefix_n_sources_per_ru[_ru_ranks.size()]) { + auto my_PCIe40_names_it = _PCIe40_names.begin() + _prefix_n_sources_per_ru[_my_idx]; + for (int k = 0; k < my_buffer_sizes_size; k++) { + _buffers.emplace_back(new PCIe40_frag_reader( + *(my_PCIe40_names_it), + *(my_buffer_sizes_it), + _n_fragment, + EB::default_PCIe40_alignment, + stream_select(*my_PCIe40_names_it))); + my_PCIe40_names_it++; + my_buffer_sizes_it++; + } + } else { + // In this set of functions (config_buffers) the errors are handled via expections + std::ostringstream err_mess; + err_mess << "RU " << _my_idx << " " << __FUNCTION__ + << ": Invalid PCIe40 configuration: not enough IDs or names provided. Got " << _PCIe40_names.size() + << " names and " << _PCIe40_ids.size() << " ids for " << _prefix_n_sources_per_ru[_ru_ranks.size()] + << " data sources"; + throw std::runtime_error(err_mess.str()); + } +} + +int EB::RU::init_shift() +{ + // precomputes the linear shift pattern + // this is the shift phase of the current unit i.e. the RU block index plus the number of ghost before the unit + // itself + int ru_idx = 0; + int ru_block_idx = 0; + while (ru_idx + _n_rus_per_nic[ru_block_idx] <= _my_idx) { + ru_idx += _n_rus_per_nic[ru_block_idx]; + ru_block_idx++; + } + + _shift_offset = _BU_shift_pattern; + int shift_idx = get_idx(_RU_shift_pattern.begin(), _RU_shift_pattern.end(), ru_block_idx); + + logger.debug() << "shift idx " << shift_idx << std::flush; + + std::rotate(_shift_offset.begin(), _shift_offset.begin() + shift_idx, _shift_offset.end()); + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "shift vectors: "; + for (auto elem : _shift_offset) { + logger.debug() << elem << " "; + } + + logger.debug() << std::flush; + } + + return DF_SUCCESS; +} + +int EB::RU::run() +{ + // Transport_unit::run(); + info("RU run"); + int ret_val = DF_SUCCESS; + // TODO check if this is a good idea we may don't want to flush the buffers async + if ((_buffer_type[_my_idx] == PCIe40_frag_buffer) || (_buffer_type[_my_idx] == PCIe40_MFP_buffer)) { + for (const auto& buffer : _buffers) { + buffer->flush(); + } + } + // reset the number of MFPs written to file + _n_MFPs_written_to_file = 0; + _received_data = std::vector<bool>(_n_sources_per_ru[_my_idx], false); + _send_empty = false; + init_profiling(); + while (_send_MEPs.load()) { + // TODO add monitoring counters reset + std::lock_guard<decltype(_loop_lock)> loop_guard(_loop_lock); + // TODO add counter rest on end of run + + logger.debug() << "load" << std::flush; + // TODO check for race conditions when start is executed + if (_send_empty) { + ret_val = load_empty(); + _send_empty = false; + } else { + ret_val = load_mfps(); + } + + // DF_CANCELLED means that the STOP signal has been received + // DF_ERROR will trigger a transition into ERROR + if (ret_val != DF_SUCCESS) { + break; + } + // additional sync barrier + ret_val = sync(); + if (ret_val != DF_SUCCESS) { + break; + } + + logger.debug() << "send size" << std::flush; + ret_val = send_sizes(); + if (ret_val != DF_SUCCESS) { + break; + } + + logger.debug() << "shift" << std::flush; + ret_val = linear_shift(); + if (ret_val != DF_SUCCESS) { + break; + } + // DEBUG duplicated events at stop + load_empty(); + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "sleep" << std::flush; + sleep(1); + } + + update_profiling(); + + _run_loop_iteration++; + } + + // this will trigger the transition of the FSM into error + if (ret_val == DF_ERROR) { + fireIncident("DAQ_ERROR"); + } + + return ret_val; +} + +int EB::RU::send_sizes() +{ + _send_sizes_timer.start(); + int ret_val = + _ibComm->ibScatterV(reinterpret_cast<char*>(sizes.data()), _buffers.size(), sizeof(uint32_t), _bu_ranks); + _send_sizes_timer.stop(); + return ret_val; +} + +int EB::RU::send_src_ids() +{ + int ret_val = DF_SUCCESS; + std::vector<EB::src_id_type> temp; + temp.reserve(_n_sources_per_ru[_my_idx]); + for (const auto& buff : _buffers) { + temp.push_back(buff->get_src_id()); + } + logger.debug() << "send src ids " << temp.size() << std::flush; + // register mr + ret_val = _ibComm->addMR(reinterpret_cast<char*>(temp.data()), temp.size() * sizeof(EB::src_id_type)); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " unable to add memory region ptr " << temp.data() << " size " << temp.size() + << std::flush; + return ret_val; + } + + ret_val = + _ibComm->ibBroadcastV(reinterpret_cast<char*>(temp.data()), temp.size(), sizeof(EB::src_id_type), _bu_ranks); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " src id broadcast failed" << std::flush; + return ret_val; + } + return ret_val; +} + +int EB::RU::linear_shift() +{ + _linear_shift_timer.start(); + int ret_val = DF_SUCCESS; + + for (const auto& shift : _shift_offset) { + // sync mpi barrier + logger.debug() << "sync" << std::flush; + ret_val = sync(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + logger.debug() << "on shift " << shift << std::flush; + // skip the ghost nodes + if (shift != -1) { + ret_val = send_MFPs(shift); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + } + } + logger.debug() << "send complete" << std::flush; + // TODO check if this is the best place for this piece of code + for (int src = 0; src < _buffers.size(); src++) { + _buffers[src]->read_complete(); + } + _linear_shift_timer.stop(); + return ret_val; +} + +int EB::RU::send_MFPs(int shift_off) +{ + _send_timer.start(); + int ret_val = DF_SUCCESS; + int comm_err; + int MFPs_size = _buffers.size(); + // this may be done by shift_offset[shift] + int dst = _bu_ranks[shift_off]; + int shift_idx = shift_off * _buffers.size(); + std::vector<comm_send> send_vec(MFPs_size); + size_t total_size = 0; + for (int k = 0; (k < MFPs_size); k++) { + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "Comm_Send MFPs " << k << " size " << sizes[shift_idx + k] << " dst " << dst << "\n"; + if (selected_MFPs[shift_idx + k]) { + if (logger.is_active(Online::PrintLevel::VERBOSE)) { + logger.debug() << reinterpret_cast<const EB::MFP*>(selected_MFPs[shift_idx + k])->print(false); + logger.debug() << std::flush; + } else { + logger.debug() << reinterpret_cast<const EB::MFP*>(selected_MFPs[shift_idx + k])->print(true); + } + } + logger.debug() << std::flush; + } + auto& send = send_vec.at(k); + send.snd_buff = reinterpret_cast<const void*>(selected_MFPs[shift_idx + k]); + send.count = sizes[shift_idx + k]; + send.datatype = sizeof(char); + send.destination = dst; + total_size += sizes[shift_idx + k]; + } + comm_err = _ibComm->send(send_vec); + if (comm_err == DF_CANCELLED) { + ret_val = comm_err; + } else if (comm_err != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " send " << comm_err << std::flush; + ret_val = comm_err; + } + // k=0 first source is taken into account to the event flow + if (selected_MFPs[shift_idx] != 0) { + _DF_events_out += reinterpret_cast<const EB::MFP*>(selected_MFPs[shift_idx])->header.n_banks; + } + + _MFP_count += _buffers.size(); + _snd_bytes += total_size; + _send_timer.stop(); + return ret_val; +} + +int EB::RU::load_mfps() +{ + _load_mpfs_timer.start(); + int ret_val = DF_SUCCESS; + std::vector<EB::MFP*> ptrs(_bu_ranks.size()); + for (int src = 0; src < _buffers.size(); src++) { + int dst; + for (dst = 0; dst < _bu_ranks.size(); dst++) { + EB::MFP* next_MFP = NULL; + EB::Timer idle_timer; + idle_timer.enable(); + idle_timer.start(); + while ((next_MFP == NULL) && _send_MEPs) { + try { + next_MFP = _buffers[src]->try_get_element(); + } catch (const std::exception& e) { + logger.error() << __FUNCTION__ << " Exception while reading buffer " << src << " src ID " + << _buffers[src]->get_src_id() << " " << e.what() << std::flush; + ret_val = DF_ERROR; + return ret_val; + } catch (...) { + logger.error() << __FUNCTION__ << " unexpected exception while reading buffer " << src << " src ID " + << _buffers[src]->get_src_id() << std::flush; + ret_val = DF_ERROR; + return ret_val; + } + + if (next_MFP == NULL) { + // usleep(1); + if (idle_timer.get_elapsed_time_s() > 5) { + logger.warning() << __FUNCTION__ << " Time " << idle_timer.get_elapsed_time_s() << " no data from buffer " + << src << " src ID " << _buffers[src]->get_src_id() << std::flush; + idle_timer.reset(); + } + } else if (next_MFP->is_end_run() && !_received_data[src]) { + // We skip all the END of RUNs received before any valid data + next_MFP = NULL; + } + } + + if (!_send_MEPs) { + logger.info() << "STOP received cancelling pending IO" << std::flush; + return DF_CANCELLED; + } + + if (!next_MFP->is_valid()) { + // TODO check with Paolo the severity of this error + logger.warning() << "invalid MFP from src " << _buffers[src]->get_src_id() << std::flush; + _DF_events_err += 1; + } else { + if (next_MFP->is_end_run()) { + // the end of run will trigger a round of zero-sized MFPs + _end_of_run = true; + _send_empty = true; + logger.warning() << "end of run" << std::flush; + break; + } else { + // TODO check if this keeps coherency in case of truncated events + // fragments from multiple data sources are counted only once + if (src == 0) { + _DF_events_in += next_MFP->header.n_banks; + } + + // assert the flag we received at least one MFP + _received_data[src] = true; + + if (_end_of_run) { + // reset performance counters when a new run starts + reset_counters(); + } + _end_of_run = false; + } + } + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + logger.debug() << "NEXT MFP\n"; + if (logger.is_active(Online::PrintLevel::VERBOSE)) { + logger.debug() << next_MFP->print(true); + logger.debug() << std::flush; + } else { + logger.debug() << next_MFP->print(false); + } + logger.debug() << std::flush; + } + + // Write MFPs to file for debug + + if (_write_to_file[_my_idx] && (_n_MFPs_written_to_file < _n_MFPs_to_file)) { + // TODO add error checking + _file_writer.write(next_MFP); + _n_MFPs_written_to_file++; + } + + int idx = dst * _buffers.size() + src; + selected_MFPs[idx] = reinterpret_cast<const char*>(next_MFP); + sizes[idx] = next_MFP->bytes(); + } + + // All the missing slots are filled up with zero-sized MFPs + for (int k = dst; k < _bu_ranks.size(); k++) { + int idx = dst * _buffers.size() + src; + selected_MFPs[idx] = NULL; + sizes[idx] = 0; + } + } + _load_mpfs_timer.stop(); + + return ret_val; +} + +int EB::RU::load_empty() +{ + _load_mpfs_timer.start(); + for (int src = 0; src < _buffers.size(); src++) { + for (int dst = 0; dst < _bu_ranks.size(); dst++) { + int idx = dst * _buffers.size() + src; + selected_MFPs[idx] = NULL; + sizes[idx] = 0; + } + } + _load_mpfs_timer.stop(); + return DF_SUCCESS; +} + +int EB::RU::init_dummy_src_ids() +{ + int ret_val = DF_SUCCESS; + + if (_dummy_src_ids.size() == 0) { + _dummy_src_ids.resize(_prefix_n_sources_per_ru[_ru_ranks.size()]); + // if src_ids are not assigned values from 0 to n-1 are used + std::iota(_dummy_src_ids.begin(), _dummy_src_ids.end(), 0); + } + + if (logger.is_active(PrintLevel::DEBUG)) { + logger.debug() << "src ids: "; + for (const auto& elem : _dummy_src_ids) { + logger.debug() << elem << " "; + } + logger.debug() << std::flush; + } + + // check config + + if (_dummy_src_ids.size() != _prefix_n_sources_per_ru.back()) { + logger.error() << __FUNCTION__ << " configuration error: incorrect number of src IDs. Got " << _dummy_src_ids.size() + << " IDs for " << _prefix_n_sources_per_ru.back() << " sources" << std::flush; + return DF_ERROR; + } + + return ret_val; +} + +void EB::RU::reset_counters() +{ + // reset counters of the base class + Transport_unit::reset_counters(); + logger.info() << "resetting counters" << std::flush; + _DF_events_out = 0; + _DF_events_in = 0; + _DF_events_err = 0; + _run_loop_iteration = 0; + _load_mpfs_time_counter = 0; + _send_sizes_time_counter = 0; + _linear_shift_time_counter = 0; + _send_time_counter = 0; +} + +void EB::RU::update_profiling() +{ + if (_enable_profiling) { + double total_time = _total_timer.get_elapsed_time_s(); + if (total_time > _profiling_update_interval) { + // This is here to prevent double evaluation of the total_timer + EB::Transport_unit::update_profiling(); + double bw = (_snd_bytes * 8 * 1e-9) / _total_time_counter; + + double load_mpfs_time = _load_mpfs_timer.get_elapsed_time_s(); + double send_sizes_time = _send_sizes_timer.get_elapsed_time_s(); + double linear_shift_time = _linear_shift_timer.get_elapsed_time_s(); + double send_time = _send_timer.get_elapsed_time_s(); + + _load_mpfs_time_counter += load_mpfs_time; + _send_sizes_time_counter += send_sizes_time; + _linear_shift_time_counter += linear_shift_time; + _send_time_counter += send_time; + + if (logger.is_active(Online::PrintLevel::INFO)) { + logger.info() << " load " << load_mpfs_time << " s " << load_mpfs_time / total_time * 100 << " %" << std::flush; + logger.info() << " send size " << send_sizes_time << " s " << send_sizes_time / total_time * 100 << " %" + << std::flush; + logger.info() << " linear shift " << linear_shift_time << " s " << linear_shift_time / total_time * 100 << " %" + << std::flush; + logger.info() << " send data " << send_time << " s " << send_time / total_time * 100 << " %" << std::flush; + logger.info() << " BW " << bw << " Gb/s" << std::flush; + } + + _load_mpfs_timer.reset(); + _send_sizes_timer.reset(); + _linear_shift_timer.reset(); + _send_timer.reset(); + } + } +} + +void EB::RU::init_profiling() +{ + EB::Transport_unit::init_profiling(); + + if (_enable_profiling) { + _load_mpfs_timer.stop(); + _load_mpfs_timer.reset(); + _send_sizes_timer.stop(); + _send_sizes_timer.reset(); + _linear_shift_timer.stop(); + _linear_shift_timer.reset(); + _send_timer.stop(); + _send_timer.reset(); + } else { + _load_mpfs_timer.disable(); + _send_sizes_timer.disable(); + _linear_shift_timer.disable(); + _send_timer.disable(); + } +} \ No newline at end of file diff --git a/Online/EventBuilding/src/buffer_interface.cpp b/Online/EventBuilding/src/buffer_interface.cpp new file mode 100644 index 000000000..baa1279c6 --- /dev/null +++ b/Online/EventBuilding/src/buffer_interface.cpp @@ -0,0 +1,31 @@ +#include "buffer_interface.hpp" +#include <stdexcept> + +EB::Buffer_element::Buffer_element() { _status = 0; } + +EB::Buffer_element::Buffer_element(int payload, size_t size) +{ + _status = 1; + _payload = payload; + _size = sizeof(Buffer_element) + size; +} + +size_t EB::Buffer_element::bytes() { return _size; } + +bool EB::Buffer_element::is_valid() { return _status == 1; } + +bool EB::Buffer_element::is_wrap() { return _status == 2; } + +void EB::Buffer_element::set_wrap() +{ + _status = 2; + _size = 0; + _payload = 0; +} + +void EB::Buffer_element::init(int payload, size_t size) +{ + _status = 1; + _payload = payload; + _size = sizeof(Buffer_element) + size; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/buffer_writer_error.cpp b/Online/EventBuilding/src/buffer_writer_error.cpp new file mode 100644 index 000000000..e1b3881ef --- /dev/null +++ b/Online/EventBuilding/src/buffer_writer_error.cpp @@ -0,0 +1,29 @@ +#include "buffer_writer_error.hpp" + +// Error category definition +namespace { + struct Buffer_writer_error_category : std::error_category { + const char* name() const noexcept override; + std::string message(int ev) const override; + }; + + const char* Buffer_writer_error_category::name() const noexcept { return "buffer_writer"; } + std::string Buffer_writer_error_category::message(int ev) const + { + switch (static_cast<EB::Buffer_writer_error>(ev)) { + case EB::Buffer_writer_error::ALLOC_FAILED: return "Unable to allocate memory"; + case EB::Buffer_writer_error::WRITE_FULL: return "Write to a full buffer"; + case EB::Buffer_writer_error::BUFFER_OVERFLOW: return "Buffer overflow"; + case EB::Buffer_writer_error::NOT_INIT: return "Write to a non initialized buffer"; + default: return "Undefined error"; + } + } + + const Buffer_writer_error_category the_buffer_writer_error_category{}; + +} // namespace + +std::error_code EB::make_error_code(EB::Buffer_writer_error e) +{ + return {static_cast<int>(e), the_buffer_writer_error_category}; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/bw_mon.cpp b/Online/EventBuilding/src/bw_mon.cpp new file mode 100644 index 000000000..585883003 --- /dev/null +++ b/Online/EventBuilding/src/bw_mon.cpp @@ -0,0 +1,42 @@ +#include "bw_mon.hpp" +#include <stdexcept> +#include <cstring> +#include "EventBuilding/tools.hpp" + +EB::Bw_mon::Bw_mon(clockid_t clk_id) : _bytes_sent(0), _timer(clk_id) { _timer.start(); } + +void EB::Bw_mon::reset() +{ + _bytes_sent = 0; + _timer.reset(); +} + +double EB::Bw_mon::get_bw() const { return (double) (_bytes_sent * 8) / _timer.get_elapsed_time_ns(); } + +double EB::Bw_mon::get_bw_and_reset() +{ + double ret_val = get_bw(); + reset(); + return ret_val; +} + +size_t EB::Bw_mon::get_bytes() const { return _bytes_sent; } + +size_t EB::Bw_mon::get_bytes_and_reset() +{ + size_t ret_val = get_bytes(); + reset(); + return ret_val; +} + +void EB::Bw_mon::add_sent_bytes(size_t n_bytes) { _bytes_sent += n_bytes; } + +void EB::Bw_mon::set_clock_id(clockid_t clk_id) +{ + _timer.set_clk_id(clk_id); + reset(); +} + +clockid_t EB::Bw_mon::get_clock_id() const { return _timer.get_clk_id(); } + +double EB::Bw_mon::get_elapsed_time() { return _timer.get_elapsed_time_s(); } diff --git a/Online/EventBuilding/src/circular_buffer_status.cpp b/Online/EventBuilding/src/circular_buffer_status.cpp new file mode 100644 index 000000000..d24c70b1e --- /dev/null +++ b/Online/EventBuilding/src/circular_buffer_status.cpp @@ -0,0 +1,56 @@ +#include "circular_buffer_status.hpp" + +bool EB::Circular_buffer_status::is_empty() const { return (write_stat == read_stat); } + +bool EB::Circular_buffer_status::is_full() const { return (write_ptr() == read_ptr()) && (read_stat != write_stat); } + +bool EB::Circular_buffer_status::same_page() const { return (write_stat & wrap_mask) == (read_stat & wrap_mask); } + +uintptr_t EB::Circular_buffer_status::write_ptr() const { return (write_stat & ptr_mask) << 1; } + +uintptr_t EB::Circular_buffer_status::read_ptr() const { return (read_stat & ptr_mask) << 1; } + +void EB::Circular_buffer_status::set_write_ptr(uintptr_t write_ptr) +{ + write_stat = (write_stat & wrap_mask) | ((write_ptr >> 1) & ptr_mask); +} + +void EB::Circular_buffer_status::set_read_ptr(uintptr_t read_ptr) +{ + read_stat = (read_stat & wrap_mask) | ((read_ptr >> 1) & ptr_mask); +} + +void EB::Circular_buffer_status::toggle_write_wrap() +{ + write_stat = write_stat ^ wrap_mask; // flip MSB +} + +void EB::Circular_buffer_status::toggle_read_wrap() +{ + read_stat = read_stat ^ wrap_mask; // flip MSB +} + +size_t EB::Circular_buffer_status::tail_free_space() const +{ + size_t ret_val; + if (same_page()) { + ret_val = size - write_ptr(); + } else { + ret_val = read_ptr() - write_ptr(); + } + + return ret_val; +} + +size_t EB::Circular_buffer_status::head_free_space() const +{ + size_t ret_val; + if (same_page()) { + ret_val = read_ptr(); + } else { + // in this case there is no head space because the write ptr is chasing the read ptr + ret_val = 0; + } + + return ret_val; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/dummy_mep_buffer_writer.cpp b/Online/EventBuilding/src/dummy_mep_buffer_writer.cpp new file mode 100644 index 000000000..469cbc073 --- /dev/null +++ b/Online/EventBuilding/src/dummy_mep_buffer_writer.cpp @@ -0,0 +1,85 @@ +#include "dummy_mep_buffer_writer.hpp" +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <cstdlib> +#include <cerrno> +#include <cstring> +#include "EventBuilding/tools.hpp" +#include <numa.h> + +EB::Dummy_mep_buffer_writer::Dummy_mep_buffer_writer() {} + +EB::Dummy_mep_buffer_writer::Dummy_mep_buffer_writer(size_t buffer_size, int numa_node) : Dummy_mep_buffer_writer() +{ + if (reset_buffer(buffer_size, numa_node) != 0) { + throw std::error_code(Buffer_writer_error::ALLOC_FAILED); + } +} + +EB::Dummy_mep_buffer_writer::~Dummy_mep_buffer_writer() {} + +int EB::Dummy_mep_buffer_writer::reset_buffer(size_t buffer_size, int numa_node) +{ + int ret_val = 0; + void* ptr; + + ret_val = posix_memalign(&ptr, sysconf(_SC_PAGE_SIZE), buffer_size); + if (ret_val == 0) { + if (numa_node != -1) { + numa_set_strict(1); + numa_tonode_memory(ptr, buffer_size, numa_node); + } + _buffer = buffer_type(ptr, free); + _buffer_size = buffer_size; + _status = EMPTY; + } + + return ret_val; +} + +EB::MEP* EB::Dummy_mep_buffer_writer::try_write_next_element(size_t size) +{ + EB::MEP* ret_val = NULL; + if (_buffer) { + if ((size <= _buffer_size) && (_status == EMPTY)) { + ret_val = reinterpret_cast<EB::MEP*>(_buffer.get()); + _status = FULL; + } else if (_status == FULL) { + throw std::error_code(Buffer_writer_error::WRITE_FULL); + } else { + throw std::error_code(Buffer_writer_error::BUFFER_OVERFLOW); + } + } else { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + return ret_val; +} + +std::vector<std::tuple<void*, size_t>> EB::Dummy_mep_buffer_writer::get_full_buffer() +{ + std::vector<std::tuple<void*, size_t>> ret_val; + + ret_val.push_back(std::make_tuple(_buffer.get(), _buffer_size)); + + return ret_val; +} + +void EB::Dummy_mep_buffer_writer::write_complete() +{ + if (!_buffer) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + _status = EMPTY; +} + +void EB::Dummy_mep_buffer_writer::write_discard() +{ + if (!_buffer) { + throw std::error_code(Buffer_writer_error::NOT_INIT); + } + + _status = EMPTY; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/dummy_mfp_buffer.cpp b/Online/EventBuilding/src/dummy_mfp_buffer.cpp new file mode 100644 index 000000000..9764b3d66 --- /dev/null +++ b/Online/EventBuilding/src/dummy_mfp_buffer.cpp @@ -0,0 +1,86 @@ +#include "dummy_mfp_buffer.hpp" +#include <iostream> + +EB::Dummy_MFP_buffer::Dummy_MFP_buffer(std::shared_ptr<char>& buffer, size_t buffer_size, int src_id) +{ + set_buffer(buffer, buffer_size, src_id); +} + +void EB::Dummy_MFP_buffer::set_buffer(std::shared_ptr<char>& buffer, size_t buffer_size, int src_id) +{ + _buffer = buffer; + _buffer_size = buffer_size; + + _read_ptr = _buffer.get(); + + _src_id = src_id; +} + +EB::MFP* EB::Dummy_MFP_buffer::try_get_element() +{ + EB::MFP* ret_val; + ret_val = reinterpret_cast<EB::MFP*>(get_ptr_at()); + update_read_ptr(); + + return ret_val; +} + +std::vector<std::tuple<void*, size_t>> EB::Dummy_MFP_buffer::get_full_buffer() +{ + std::vector<std::tuple<void*, size_t>> ret_val; + + ret_val.emplace_back(std::make_tuple(reinterpret_cast<void*>(_buffer.get()), _buffer_size)); + + return ret_val; +} + +void EB::Dummy_MFP_buffer::read_complete() {} + +void EB::Dummy_MFP_buffer::flush() { _read_ptr = _buffer.get(); } + +int EB::Dummy_MFP_buffer::get_src_id() const { return _src_id; } + +char* EB::Dummy_MFP_buffer::get_ptr_at(int MFP_number) +{ + std::uintptr_t offset = reinterpret_cast<std::uintptr_t>(_read_ptr) - reinterpret_cast<std::uintptr_t>(_buffer.get()); + char* ret_val = NULL; + for (int k = 0; k < MFP_number; k++) { + if (offset + sizeof(EB::MFP) > _buffer_size) { + offset = 0; +#ifdef DEBUG + std::cerr << "buffer end restarting from the beginning" << std::endl; +#endif // DEBUG + } + ret_val = _buffer.get() + offset; + size_t MFP_size = reinterpret_cast<EB::MFP*>(ret_val)->header.bytes(); + if (offset + MFP_size > _buffer_size) { + std::cerr << "ERROR truncated event resuming from the beginning" << std::endl; + offset = 0; + k--; + } else { + size_t tmp_size = MFP_size + get_padding(MFP_size, 1 << reinterpret_cast<EB::MFP*>(ret_val)->header.align); + // page aligned MFPs + offset += tmp_size + get_padding(tmp_size, 4096); + assert(get_padding(MFP_size, 1 << reinterpret_cast<EB::MFP*>(ret_val)->header.align) == 0); + } + } + return ret_val; +} + +size_t EB::Dummy_MFP_buffer::get_size_at(int MFP_number) +{ + return (reinterpret_cast<EB::MFP*>(get_ptr_at(MFP_number)))->header.bytes(); +} + +std::tuple<char*, size_t> EB::Dummy_MFP_buffer::get_MFP_at(int MFP_number) +{ + char* ptr = get_ptr_at(MFP_number); + + size_t size = (reinterpret_cast<EB::MFP*>(ptr))->header.bytes(); + + return {ptr, size}; +} + +std::tuple<char*, size_t> EB::Dummy_MFP_buffer::operator[](int MFP_number) { return get_MFP_at(MFP_number); } + +void EB::Dummy_MFP_buffer::update_read_ptr(int MFP_number) { _read_ptr = get_ptr_at(MFP_number + 1); } \ No newline at end of file diff --git a/Online/EventBuilding/src/events_dispatch/Builder_dummy_unit.cpp b/Online/EventBuilding/src/events_dispatch/Builder_dummy_unit.cpp new file mode 100644 index 000000000..3edbe2fa4 --- /dev/null +++ b/Online/EventBuilding/src/events_dispatch/Builder_dummy_unit.cpp @@ -0,0 +1,149 @@ +// Framework include files +#include "Dataflow/Incidents.h" +#include "Dataflow/DataflowComponent.h" +#include "../../EventBuilding/events_dispatch/common.hpp" +#include "../../EventBuilding/events_dispatch/Builder_dummy_unit.hpp" + +#include <mutex> +#include <glib.h> + +using namespace std; +using namespace Online; +using namespace DISPATCH; +using namespace EB; + +/// Standard Constructor +Builder_dummy_unit::Builder_dummy_unit(const string& nam, DataflowContext& ctxt) : DataflowComponent(nam, ctxt), Unit() +{ + info("BDU: IN CONSTRUCTOR"); + this->_delay_timer = 0; + + declareProperty("how_many_ous", how_many_ous = 1); + declareProperty("how_many_fus", how_many_fus = 1); + declareProperty("buffer_type", _buffer_type = 1); + declareProperty("MBM_name", _mbm_name = "Buffer"); +} + +/// IService implementation: initialize the service +int Builder_dummy_unit::initialize() +{ + info("BDU: IN INTIALIZE"); + int sc = Component::initialize(); + if (sc != DF_SUCCESS) return error("Failed to initialize base-class"); + MPI_Init(NULL, NULL); + MPI_Comm_rank(MPI_COMM_WORLD, &(this->rank)); + MPI_Comm_size(MPI_COMM_WORLD, &(this->worldSize)); + + info("BDU: MY RANK: %d, OUs NUMBER: %d, FUs NUMBER: %d", this->rank, how_many_ous, how_many_fus); + EB::Buffer_writer<EB::MEP>* write_buff; + if (_buffer_type == 1) { + int bdu_no = (this->rank) - 1 - how_many_ous - how_many_fus; + info("BDU: CREATED SHMEM NUMBER : %d", bdu_no); + + const std::string shmem_name = get_shmem_name("BU", bdu_no).str(); + size_t buff_size = + static_cast<size_t>(BUFFER_RECORD_SIZE_MB) * static_cast<size_t>(MAX_BUFFER_COUNT_BU) * 1024UL * 1024UL; + write_buff = new Shmem_buffer_writer<EB::MEP>(shmem_name, buff_size); + } else if (_buffer_type == 2) { + info("WRITE BUFFER IS MBM\n"); + write_buff = new Mbm_writer<EB::MEP>(context, RTL::processName(), _mbm_name); + } + + this->_buff_writer = write_buff; + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + return sc; +} + +/// IService implementation: finalize the service +int Builder_dummy_unit::finalize() +{ + MPI_Finalize(); + return DF_SUCCESS; +} + +/// TODO +int Builder_dummy_unit::stop() { return DF_SUCCESS; } + +/// Cancel I/O operations of the dataflow component +int Builder_dummy_unit::cancel() +{ + _m_receiveEvts = false; + return DF_SUCCESS; +} + +/// Incident handler implemenentation: Inform that a new incident has occured +void Builder_dummy_unit::handle(const DataflowIncident& inc) +{ + info("BDU Got incident: %s of type %s", inc.name.c_str(), inc.type.c_str()); + // TODO implement this +} + +int Builder_dummy_unit::pause() +{ + // TODO implement this + info("BDU pause\n"); + return DF_SUCCESS; +} + +/// IRunable implementation : Run the class implementation +int Builder_dummy_unit::run() +{ + info("BDU: IN RUN"); + + int64_t probe_start; + this->_probe_global_start = g_get_real_time(); + probe_start = _probe_global_start; + this->_now = probe_start; + this->_timer_start = probe_start; + + int64_t probe_now = g_get_real_time(); + + info("BDU rank %d IN RUN: Warmup done. Starting main loop \n", this->rank); + generate_meps(); + + while (true) { + if (time_elapsed_check() == true) { + probe_now = g_get_real_time(); + // info( + // "[ %.1lf s ] BDU RANK %d : Generating data \n", + // static_cast<double>((probe_now) - (probe_global_start)) / static_cast<double>(US_S), + // rank); + generate_meps(); + } + } + return DF_SUCCESS; +} + +/// Service implementation: start of the service +// TODO +int Builder_dummy_unit::start() +{ + info("BDU: IN START"); + _m_receiveEvts = true; + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + return DF_SUCCESS; +} + +void Builder_dummy_unit::generate_meps() +{ + + FBUFF::generate_data<EB::MEP>(this->_buff_writer, rank, gibit_events_in_one_quantum); +} + +bool Builder_dummy_unit::time_elapsed_check() +{ + _delay_timer++; + if (_delay_timer >= PROBE_EVERY_IT) { + _delay_timer = 0; + _now = g_get_real_time(); + if (_now - _timer_start >= TIME_ELAPSED_FOR_GENERATION) { + _timer_start += TIME_ELAPSED_FOR_GENERATION; + return true; + } + } + return false; +} diff --git a/Online/EventBuilding/src/events_dispatch/Filter_unit.cpp b/Online/EventBuilding/src/events_dispatch/Filter_unit.cpp new file mode 100644 index 000000000..9a7b85315 --- /dev/null +++ b/Online/EventBuilding/src/events_dispatch/Filter_unit.cpp @@ -0,0 +1,405 @@ +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <assert.h> +#include <ctime> +#include <time.h> +#include "string.h" +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> + +#include "Dataflow/Incidents.h" +#include "Dataflow/MBMClient.h" +#include "RTL/rtl.h" + +#include "../../EventBuilding/events_dispatch/Unit.hpp" +#include "../../EventBuilding/events_dispatch/Filter_unit.hpp" +#include "../../EventBuilding/events_dispatch/common.hpp" + +using namespace std; +using namespace Online; +using namespace DISPATCH; +using namespace EB; + +Filter_unit::Filter_unit(const std::string& nam, DataflowContext& ctxt) : DataflowComponent(nam, ctxt) +{ + info("FU: IN CONSTRUCTOR"); + declareProperty("how_many_ous", how_many_ous = 1); + declareProperty("how_many_fus", how_many_fus = 1); + declareProperty("Buffer", _mbm_name = "Events"); +} + +int Filter_unit::initialize() +{ + + info("FU: IN INTIALIZE"); + info("OUs NUMBER: %d, FUs NUMBER: %d", how_many_ous, how_many_fus); + int sc = Component::initialize(); + if (sc != DF_SUCCESS) + return error("Failed to initialize base-class"); + else if (!context.mbm) { + info("mbm in context : %ld", context.mbm); + return error("Failed to access MBM client."); + } + + info("MBM Producer connecting to %s\n", _mbm_name.c_str()); + + MPI_Init(NULL, NULL); + MPI_Comm_rank(MPI_COMM_WORLD, &(this->rank)); + MPI_Comm_size(MPI_COMM_WORLD, &(this->worldSize)); + + info("FU: MY RANK: %d, OUs NUMBER: %d, FUs NUMBER: %d \n", this->rank, how_many_ous, how_many_fus); + + this->_next_probing = 1; + this->_all_finished_granted_transmission = 0; + this->_mpi_fu_ready_request = MPI_REQUEST_NULL; + + this->_mpi_data_sent_requests = new MPI_Request[window_length]; + + this->_mpi_mu_fu_alloc_request = MPI_REQUEST_NULL; + for (int x = 0; x != MAX_FU_CREDITS; x++) { + for (int y = 0; y != window_length; y++) { + _mpi_data_sent_requests[y] = MPI_REQUEST_NULL; + } + } + + this->_mpi_acq_request = MPI_REQUEST_NULL; + this->_data_buffer_current_ptr = 0; + // counter + this->_current_probe_completed_bytes = 0; + // counter + this->_all_completed_bytes = 0; + _fu_ready_message.rank = rank; + + _write_buff = new Mbm_writer<EB::MEP>(context, RTL::processName(), _mbm_name); + + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + + return DF_SUCCESS; +} + +int Filter_unit::finalize() +{ + info("FU: IN INTIALIZE"); + return DF_SUCCESS; +} + +int Filter_unit::start() +{ + info("FU: IN START"); + signal_readiness(); + if (DO_WARMUP) mpi_warmup_run(); + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + return DF_SUCCESS; +} + +int Filter_unit::stop() +{ + // TODO implement this + return DF_SUCCESS; +} + +int Filter_unit::cancel() +{ + // TODO implement this + return DF_SUCCESS; +} + +void Filter_unit::handle(const DataflowIncident& inc) +{ + info("FU Got incident: %s of type %s", inc.name.c_str(), inc.type.c_str()); +} + +int Filter_unit::run() +{ + info("FU: IN RUN"); + + _probe_start = g_get_real_time(); + _global_start = _probe_start; + + // asynchronous receive of message with data size + run_recv(); + MPI_Irecv( + &_alloc_msg, sizeof(mu_fu_alloc_msg), MPI_CHAR, 0, MU_FU_ALLOC_TAG, MPI_COMM_WORLD, &_mpi_mu_fu_alloc_request); + + info("FU rank %d IN RUN. Starting main loop \n", this->rank); + while (true) { + + while (service_mu_alloc_call() == false) { + } + + while (exchange_message_size() == false) { + } + + int total_completions = 0; + + if (_current_transmission_meta.full_transmissions_no > window_length) { + while (true) { + + int indx; + bool data_transmission_complete = probe_for_completion(&indx); + + probe_print_throughput(); + if (data_transmission_complete == true) { + total_completions++; + // info("FU RANK %d: COMPLETION. MAKING NEW REQUEST AT INDEX %d. TOTAL COMPLETIONS %d out of %d \n", + // e rank,indx,total_completions,current_transmission_meta.full_transmissions_no); + + size_t size = entry_size_kb * 1024; + recv_from_bu(size, indx, _ou_fu_mep_size_msg.sender_rank); + _acquired_data_ptr += size; + + _current_probe_completed_bytes += size; + if (total_completions == _current_transmission_meta.full_transmissions_no - window_length) break; + } + } + } + // allBufferEntries + if (_current_transmission_meta.full_transmissions_no != 0) { + // info("FU RANK %d: FINALIZING WINDOWED TRANSMISSIONS \n", rank); + int data_received = false; + while (data_received == false) { + MPI_Testall(window_length, _mpi_data_sent_requests /*[0]*/, &data_received, MPI_STATUS_IGNORE); + probe_print_throughput(); + } + int min = std::min(_current_transmission_meta.full_transmissions_no, window_length); + size_t size = entry_size_kb * 1024; + _current_probe_completed_bytes += min * size; + } + ////info("FU: FINALIZING REMAINDER size %ld \n", currentTransmissionMetadata.remainderSize ); + if (_current_transmission_meta.remainder_size != 0) { + + MPI_Recv( + _acquired_data_ptr, + _current_transmission_meta.remainder_size, + MPI_CHAR, + _ou_fu_mep_size_msg.sender_rank, + BU_RU_DATA_REMAINDER_TAG, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + + ////info("FU: REMAINDER SIZE %ld FINALIZED \n", currentTransmissionMetadata.remainderSize); + _current_probe_completed_bytes += _current_transmission_meta.remainder_size; + } + // int64_t now = g_get_real_time(); + // info("[ %.2lf s ] FU RANK %d: DONE RECEIVING DATA \n", ((double) now - (double) global_start) / (double) + // US_S,rank); + _write_buff->write_complete(); + + probe_print_throughput(); + signal_readiness(); + } + return DF_SUCCESS; +} + +void Filter_unit::signal_readiness(fu_status stat) +{ + MPI_Wait(&(_mpi_fu_ready_request), MPI_STATUS_IGNORE); + _fu_ready_message.status = stat; + MPI_Isend( + &(_fu_ready_message), sizeof(mpi_fu_ready_msg), MPI_CHAR, 0, MU_TAG, MPI_COMM_WORLD, &(_mpi_fu_ready_request)); + // info("FU done signalling readiness. My free space: %ld \n", fu_ready_message.free_space); +} + +int Filter_unit::pause() +{ + // TODO implement this + info("FU pause\n"); + return DF_SUCCESS; +} + +bool Filter_unit::probe_for_completion(int* index) +{ + int data_received = false; + for (int a = 0; a != window_length; a++) { + int test; + // TODO - Remove dummy + MPI_Test(&(_mpi_data_sent_requests /*[0]*/[a]), &test, MPI_STATUS_IGNORE); + if (test == true) { + data_received = true; + *index = a; + break; + } + } + return data_received; +} + +void Filter_unit::recv_from_bu(size_t size, int index, int senderRank, int tag) +{ + char* data = _acquired_data_ptr; + MPI_Wait(&(_mpi_data_sent_requests /*[0]*/[index]), MPI_STATUS_IGNORE); + MPI_Irecv( + data, static_cast<int>(size), MPI_CHAR, senderRank, tag, MPI_COMM_WORLD, &(_mpi_data_sent_requests /*[0]*/[index])); +} + +long unsigned int Filter_unit::get_entry_address(int entryIndex) +{ + long unsigned int addr = entryIndex * entry_size_kb * 1024; + return addr; +} + +void Filter_unit::probe_print_throughput() +{ + int64_t now = g_get_real_time(); + + if (now - _global_start > _next_probing * US_S) { + + double tput_bytes_per_sec = static_cast<double>(_current_probe_completed_bytes) * static_cast<double>(US_S) / + static_cast<double>(now - _probe_start); + double tput_gbits_per_sec = tput_bytes_per_sec * 8.0 / 1000.0 / 1000.0 / 1000.0; + + // info("BYTES : %ld COMPLETED IRECSs %ld time %lf \n",bytes ,currentProbeCompletedIrecvs ,((double)(now - + // probeStart) )); + + _all_completed_bytes += _current_probe_completed_bytes; + double total_tput_bytes_per_sec = + static_cast<double>(_all_completed_bytes) * static_cast<double>(US_S) / static_cast<double>(now - _global_start); + double total_tput_gbits_per_sec = total_tput_bytes_per_sec * 8.0 / 1000.0 / 1000.0 / 1000.0; + + info( + "[ %.1lf s ] FU RANK %d TP %.1lf Gbits/s AVG TP %.1lf Gbits/s\n", + (static_cast<double>(now) - static_cast<double>(_global_start)) / static_cast<double>(US_S), + rank, + tput_gbits_per_sec, + total_tput_gbits_per_sec); + + this->_current_probe_completed_bytes = 0; + _next_probing++; + _probe_start = now; + } +} + +void Filter_unit::mpi_warmup_run() +{ + + /* + const char* mbm_data = mbm_buffer_address(m_producer->id()); + long mbm_size; + mbm_buffer_size(m_producer->id(), &mbm_size); + */ + + std::vector<std::tuple<void*, size_t>> buff_data = _write_buff->get_full_buffer(); + long mbm_size = std::get<1>(buff_data[0]); + const char* mbm_data = (const char*) std::get<0>(buff_data[0]); + + info("FU: mbm size: %ld \n", mbm_size); + int total_iterations = (int) (mbm_size / (size_t) WARMUP_MPI_SIZE); + size_t remainder_size = mbm_size % (size_t) WARMUP_MPI_SIZE; + + info("STARTUP SIZE: %ld AND PTR: %ld . TOTAL ITERATIONS %d\n", mbm_size, mbm_data, total_iterations); + + uint8_t* dummy_buffer = (uint8_t*) memalign(2UL * 1024UL * 1024UL, WARMUP_MPI_SIZE); + mlock(dummy_buffer, WARMUP_MPI_SIZE); + memset(dummy_buffer, 0xFF, WARMUP_MPI_SIZE); + + size_t index = 0; + MPI_Request s_request; + MPI_Request r_request; + for (int it = 0; it != total_iterations; it++) { + info("FU WARMUP PHASE 1 SEND: %d\n", it); + MPI_Irecv(dummy_buffer, WARMUP_MPI_SIZE, MPI_CHAR, rank, MPI_ANY_TAG, MPI_COMM_WORLD, &r_request); + MPI_Isend(&(mbm_data[index]), WARMUP_MPI_SIZE, MPI_CHAR, rank, rank, MPI_COMM_WORLD, &s_request); + MPI_Wait(&s_request, MPI_STATUS_IGNORE); + MPI_Wait(&r_request, MPI_STATUS_IGNORE); + index += WARMUP_MPI_SIZE; + } + + MPI_Irecv(dummy_buffer, remainder_size, MPI_CHAR, rank, MPI_ANY_TAG, MPI_COMM_WORLD, &r_request); + MPI_Isend(&(mbm_data[index]), remainder_size, MPI_CHAR, rank, rank, MPI_COMM_WORLD, &s_request); + MPI_Wait(&s_request, MPI_STATUS_IGNORE); + MPI_Wait(&r_request, MPI_STATUS_IGNORE); + + index = 0; + for (int it = 0; it != total_iterations - 1; it++) { + info("FU WARMUP PHASE 2 SEND: %d\n", it); + MPI_Irecv(dummy_buffer, WARMUP_MPI_SIZE, MPI_CHAR, rank, MPI_ANY_TAG, MPI_COMM_WORLD, &r_request); + MPI_Isend( + &(mbm_data[index + WARMUP_MPI_SIZE / 2]), WARMUP_MPI_SIZE, MPI_CHAR, rank, rank, MPI_COMM_WORLD, &s_request); + MPI_Wait(&s_request, MPI_STATUS_IGNORE); + MPI_Wait(&r_request, MPI_STATUS_IGNORE); + + index += WARMUP_MPI_SIZE; + } + + free(dummy_buffer); +} + +bool Filter_unit::exchange_message_size() +{ + + int flag = false; + MPI_Test(&(_mpi_acq_request), &flag, MPI_STATUS_IGNORE); + + if (flag == true) { + // info("FU RECEIVED MESSAGE SIZE %ld fromi OU RANK %d\n", ou_fu_mep_size_msg.size, ou_fu_mep_size_msg.sender_rank); + int buRank = _ou_fu_mep_size_msg.sender_rank; + + if (_last_allocated_message_size != _ou_fu_mep_size_msg.size) { + info("ERROR - EXCHANGED SIZE DOESN'T EQUAL THE ALLOCATED ONE"); + } + + get_meta(_ou_fu_mep_size_msg.size); + + init_new_transmission(_ou_fu_mep_size_msg.sender_rank); + MPI_Ssend(&(_ou_fu_mep_size_msg), sizeof(_ou_fu_mep_size_msg), MPI_CHAR, buRank, BU_RU_SIZE_TAG, MPI_COMM_WORLD); + // info("FU RANK %d EXCHANGED MESSAGE SIZE: %ld \n", rank, ou_fu_mep_size_msg.size); + run_recv(); + + return true; + } + return false; +} + +void Filter_unit::run_recv() +{ + MPI_Irecv( + &(_ou_fu_mep_size_msg), + sizeof(_ou_fu_mep_size_msg), + MPI_CHAR, + MPI_ANY_SOURCE, + BU_RU_SIZE_TAG, + MPI_COMM_WORLD, + (&_mpi_acq_request)); +} + +void Filter_unit::get_meta(size_t size) +{ + _current_transmission_meta.full_transmissions_no = size / entry_size_b; + _current_transmission_meta.remainder_size = size % entry_size_b; +} + +void Filter_unit::init_new_transmission(int senderRank) +{ + + unsigned int to_send = std::min(window_length, _current_transmission_meta.full_transmissions_no); + for (unsigned int i = 0; i != to_send; i++) { + size_t size = entry_size_kb * 1024; + recv_from_bu(size, i, senderRank); + _acquired_data_ptr += size; + } +} + +bool Filter_unit::service_mu_alloc_call() +{ + int flag; + MPI_Test(&_mpi_mu_fu_alloc_request, &flag, MPI_STATUS_IGNORE); + if (flag) { + EB::MEP* alloc_header = _write_buff->try_write_next_element(_alloc_msg.size); + bool alloc_success = (alloc_header != NULL); + _alloc_msg.success = alloc_success; + if (alloc_success) { + _acquired_data_ptr = (char*) alloc_header; + _last_allocated_message_size = _alloc_msg.size; + } + MPI_Ssend(&_alloc_msg, sizeof(mu_fu_alloc_msg), MPI_CHAR, 0, MU_FU_ALLOC_TAG, MPI_COMM_WORLD); + MPI_Irecv( + &_alloc_msg, sizeof(mu_fu_alloc_msg), MPI_CHAR, 0, MU_FU_ALLOC_TAG, MPI_COMM_WORLD, &_mpi_mu_fu_alloc_request); + return alloc_success; + } + return false; +} diff --git a/Online/EventBuilding/src/events_dispatch/MBM_reader_dummy_unit.cpp b/Online/EventBuilding/src/events_dispatch/MBM_reader_dummy_unit.cpp new file mode 100644 index 000000000..28c511a8a --- /dev/null +++ b/Online/EventBuilding/src/events_dispatch/MBM_reader_dummy_unit.cpp @@ -0,0 +1,131 @@ +#include "Dataflow/Incidents.h" +#include "Dataflow/DataflowComponent.h" +#include "../../EventBuilding/events_dispatch/common.hpp" +#include "../../EventBuilding/events_dispatch/MBM_reader_dummy_unit.hpp" + +#include <memory> +#include <mutex> +#include <glib.h> + +using namespace std; +using namespace Online; +using namespace DISPATCH; +using namespace EB; + +/// Standard Constructor +MBM_reader_dummy_unit::MBM_reader_dummy_unit(const string& nam, DataflowContext& ctxt) : + DataflowComponent(nam, ctxt), Unit() +{ + info("MBM READER: IN CONSTRUCTOR"); + this->_delay_timer = 0; + + declareProperty("how_many_ous", how_many_ous = 1); + declareProperty("how_many_fus", how_many_fus = 1); + declareProperty("Buffer", _m_buffer = "Events"); + declareProperty("Requirements", _m_req); +} + +/// IService implementation: initialize the service +int MBM_reader_dummy_unit::initialize() +{ + info("MBM READER: IN INTIALIZE"); + int sc = Component::initialize(); + if (sc != DF_SUCCESS) return error("Failed to initialize base-class"); + MPI_Init(NULL, NULL); + MPI_Comm_rank(MPI_COMM_WORLD, &(this->rank)); + MPI_Comm_size(MPI_COMM_WORLD, &(this->worldSize)); + + info("MBM READER: MY RANK: %d, OUs NUMBER: %d, FUs NUMBER: %d", this->rank, how_many_ous, how_many_fus); + info("MBM Consumer connecting to %s\n", _m_buffer.c_str()); + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + return sc; +} + +/// IService implementation: finalize the service +int MBM_reader_dummy_unit::finalize() +{ + MPI_Finalize(); + return DF_SUCCESS; +} + +/// IService implementation: finalize the service +/// TODO +int MBM_reader_dummy_unit::stop() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Cancel I/O operations of the dataflow component +int MBM_reader_dummy_unit::cancel() +{ + // TODO implement this + _m_receiveEvts = false; + return DF_SUCCESS; +} + +/// Stop gracefully execution of the dataflow component +int MBM_reader_dummy_unit::pause() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Incident handler implemenentation: Inform that a new incident has occured +void MBM_reader_dummy_unit::handle(const DataflowIncident& inc) +{ + info("MBM_reader_dummy Got incident: %s of type %s", inc.name.c_str(), inc.type.c_str()); +} + +/// IRunable implementation : Run the class implementation +int MBM_reader_dummy_unit::run() +{ + info("MBM READER: IN RUN"); + + int64_t probe_start; + this->_probe_global_start = g_get_real_time(); + probe_start = _probe_global_start; + this->_now = probe_start; + this->_timer_start = probe_start; + + int64_t probe_now = g_get_real_time(); + info("MBM READER rank %d IN RUN: Warmup done. Starting main loop \n", this->rank); + + while (true) { + // if (time_elapsed_check() == true) { + // probe_now = g_get_real_time(); + read_meps(); + //} + } + return DF_SUCCESS; +} + +int MBM_reader_dummy_unit::start() +{ + info("MBM READER: IN START"); + _m_receiveEvts = true; + + _recv_buff = new Mbm_reader<EB::MEP>(context, RTL::processName(), _m_buffer, _m_req); + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + return DF_SUCCESS; +} + +void MBM_reader_dummy_unit::read_meps() { std::vector<mep_entry> mep_entries = FBUFF::get_mep<EB::MEP>(_recv_buff); } + +bool MBM_reader_dummy_unit::time_elapsed_check() +{ + _delay_timer++; + if (_delay_timer >= PROBE_EVERY_IT) { + _delay_timer = 0; + _now = g_get_real_time(); + if (_now - _timer_start >= TIME_ELAPSED_FOR_GENERATION) { + _timer_start += TIME_ELAPSED_FOR_GENERATION; + return true; + } + } + return false; +} diff --git a/Online/EventBuilding/src/events_dispatch/Manager_unit.cpp b/Online/EventBuilding/src/events_dispatch/Manager_unit.cpp new file mode 100644 index 000000000..c91e98e9a --- /dev/null +++ b/Online/EventBuilding/src/events_dispatch/Manager_unit.cpp @@ -0,0 +1,476 @@ +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <assert.h> +#include <ctime> +#include <thread> +#include <glib.h> +#include <limits> + +#include "Dataflow/Incidents.h" +#include "Dataflow/MBMClient.h" +#include "RTL/rtl.h" + +#include "../../EventBuilding/events_dispatch/Unit.hpp" +#include "../../EventBuilding/events_dispatch/Manager_unit.hpp" +#include "../../EventBuilding/events_dispatch/common.hpp" + +using namespace Online; +using namespace std; +using namespace DISPATCH; + +Manager_unit::Manager_unit(const string& nam, DataflowContext& ctxt) : DataflowComponent(nam, ctxt), Unit() +{ + declareProperty("how_many_ous", _how_many_ous = 1); + declareProperty("how_many_fus", _how_many_fus = 1); +} + +int Manager_unit::initialize() +{ + + info("MU: IN INTIALIZE"); + + int sc = Component::initialize(); + if (sc != DF_SUCCESS) return error("Failed to initialize base-class"); + MPI_Init(NULL, NULL); + MPI_Comm_rank(MPI_COMM_WORLD, &(this->rank)); + MPI_Comm_size(MPI_COMM_WORLD, &(this->worldSize)); + + info("MU: MY RANK: %d, OUs NUMBER: %d, FUs NUMBER: %d", this->rank, _how_many_ous, _how_many_fus); + + this->_bu_to_grant = 0; + this->_fu_to_grant = 0; + + this->_bus_ranks = new int[_how_many_ous]; + this->_fus_ranks = new int[_how_many_fus]; + this->_bus_meps_granted_bytes = new size_t[_how_many_ous]; + this->_fus_ranks_ready = new int[_how_many_fus]; + this->_bu_grants = new int[_how_many_ous]; + this->_free_bu_grants = new int[_how_many_ous]; + this->_granted_bu_for_fu = new int[_how_many_fus]; + this->_trans_fu_no = new int[_how_many_fus]; + + this->_fu_ready_requests = new MPI_Request[_how_many_fus]; + this->_bu_ready_requests = new MPI_Request[_how_many_ous]; + + this->_fu_ready_messages = new mpi_fu_ready_msg[_how_many_fus]; + this->_bu_ready_messages = new mpi_bu_ready_msg[_how_many_ous]; + + this->_trans_grant_messages = new mpi_bu_transmission_grant_msg[_how_many_ous]; + this->_trans_grant_requests = new MPI_Request[_how_many_ous]; + + this->_bu_meps_sizes_vectors = new std::vector<size_t>[_how_many_ous]; + + this->_ready_mep_array = new size_t[MAX_MEPS]; + + this->_bus_total_granted_bytes_array = new size_t[_how_many_ous]; + for (int rank_it = 0; rank_it != _how_many_ous; rank_it++) { + _bus_total_granted_bytes_array[rank_it] = 0; + } + + this->_fus_total_granted_bytes_array = new size_t[_how_many_fus]; + for (int rank_it = 0; rank_it != _how_many_fus; rank_it++) { + _fus_total_granted_bytes_array[rank_it] = 0; + } + + for (int rank_it = 0; rank_it != _how_many_ous; rank_it++) { + this->_free_bu_grants[rank_it] = MAX_BU_CREDITS; + this->_bus_meps_granted_bytes[rank_it] = 0; + this->_bus_ranks[rank_it] = rank_it + 1; + this->_trans_grant_requests[rank_it] = MPI_REQUEST_NULL; + this->_bu_ready_requests[rank_it] = MPI_REQUEST_NULL; + this->_bu_grants[rank_it] = 0; + } + + for (int rank_it = 0; rank_it != _how_many_fus; rank_it++) { + _fu_ready_requests[rank_it] = MPI_REQUEST_NULL; + this->_fus_ranks_ready[rank_it] = 0; + this->_fus_ranks[rank_it] = rank_it + 1 + _how_many_ous; + info("MU: fu rank is %d for index %d \n"); + } + + // TODO - disable for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + + return DF_SUCCESS; +} + +int Manager_unit::finalize() +{ + MPI_Finalize(); + return DF_SUCCESS; +} +/// IService implementation: finalize the service +/// TODO +int Manager_unit::stop() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Cancel I/O operations of the dataflow component +int Manager_unit::cancel() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Stop gracefully execution of the dataflow component +int Manager_unit::pause() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Incident handler implemenentation: Inform that a new incident has occured +void Manager_unit::handle(const DataflowIncident& inc) +{ + // TODO implement this + info("MU Got incident: %s of type %s", inc.name.c_str(), inc.type.c_str()); +} + +int Manager_unit::run() +{ + info("MU: IN RUN"); + if (DO_WARMUP) mpi_warmup_run(); + + info("MU rank %d IN RUN: Warmup done. Starting main loop \n", this->rank); + while (true) { + get_ready_fus(); + get_meps_bus(); + grant_transmissions_to_bus(); + } + + return DF_SUCCESS; +} + +int Manager_unit::start() +{ + info("MU: IN START"); + + this->_start_probe = g_get_real_time(); + + initialize_receiving_fus(); + initialize_receiving_bus(); + + // TODO - disable for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + + return DF_SUCCESS; +} + +void Manager_unit::get_ready_fus() +{ + int recv_flag = false; + int recv_index; + + MPI_Testany(_how_many_fus, _fu_ready_requests, &recv_index, &recv_flag, MPI_STATUS_IGNORE); + if (recv_flag == true) { + + fu_status status = _fu_ready_messages[recv_index].status; + + // transmission finished - free resources + if (status == TRANSMISSION_DONE) { + int relieved_bu_rank = _granted_bu_for_fu[recv_index]; + _bu_grants[relieved_bu_rank]--; + _fus_ranks_ready[recv_index]++; + } + + MPI_Wait(&(_fu_ready_requests[recv_index]), MPI_STATUS_IGNORE); + MPI_Irecv( + &(_fu_ready_messages[recv_index]), + sizeof(mpi_fu_ready_msg), + MPI_CHAR, + _fus_ranks[recv_index], + MU_TAG, + MPI_COMM_WORLD, + &(_fu_ready_requests[recv_index])); + } +} + +void Manager_unit::grant_transmissions_to_bus() +{ + + int fu_ind, ou_ind; + bool rdy_ou = get_next_bu_rank_ready_w_lowest_bytes(&ou_ind); + bool rdy_fu; + if (rdy_ou) rdy_fu = get_next_free_fu_rank_ready_w_lowest_bytes(&fu_ind, ou_ind); + if (rdy_ou && rdy_fu) { + + size_t mep_size = get_next_bu_mep_size_to_transmit(ou_ind); + bool alloc_attempt = try_fu_alloc(fu_ind, mep_size); + if (alloc_attempt != true) { + return; + } + // alloc succesful, continuing + + erase_next_bu_mep_size(ou_ind); + + _bus_total_granted_bytes_array[ou_ind] += mep_size; + _fus_total_granted_bytes_array[fu_ind] += mep_size; + this->_bu_grants[ou_ind]++; + this->_granted_bu_for_fu[fu_ind] = ou_ind; + _fus_ranks_ready[fu_ind]--; + + send_bus_transmisison_grant(ou_ind, fu_ind); + } +} + +void Manager_unit::initialize_receiving_bus() +{ + for (int i = 0; i < _how_many_ous; i++) { + MPI_Wait(&(_bu_ready_requests[i]), MPI_STATUS_IGNORE); + MPI_Irecv( + &(_bu_ready_messages[i]), + sizeof(mpi_bu_ready_msg), + MPI_CHAR, + _bus_ranks[i], + MU_TAG, + MPI_COMM_WORLD, + &(_bu_ready_requests[i])); + } +} + +void Manager_unit::initialize_receiving_fus() +{ + for (int i = 0; i < _how_many_fus; i++) { + MPI_Wait(&(_fu_ready_requests[i]), MPI_STATUS_IGNORE); + MPI_Irecv( + &(_fu_ready_messages[i]), + sizeof(mpi_fu_ready_msg), + MPI_CHAR, + _fus_ranks[i], + MU_TAG, + MPI_COMM_WORLD, + &(_fu_ready_requests[i])); + + MPI_Wait(&(_fu_ready_requests[i]), MPI_STATUS_IGNORE); + + // info("EM INIT: GOT MESSAGE FROM FU RANK %d. ITS FREE SPACE %ld \n ",fus_ranks[i],fus_free_bytes_array[i]); + + MPI_Irecv( + &(_fu_ready_messages[i]), + sizeof(mpi_fu_ready_msg), + MPI_CHAR, + _fus_ranks[i], + MU_TAG, + MPI_COMM_WORLD, + &(_fu_ready_requests[i])); + + _fus_ranks_ready[i]++; + } +} + +void Manager_unit::get_meps_bus() +{ + int recv_flag = false; + int recv_index; + MPI_Testany(_how_many_ous, _bu_ready_requests, &recv_index, &recv_flag, MPI_STATUS_IGNORE); + if (recv_flag == true) { + // info("MU started exchanging message with BU \n"); + size_t untransmitted_meps_no = _bu_ready_messages[recv_index].untransmitted_meps_number; + int bu_rank = _bu_ready_messages[recv_index].rank; + MPI_Recv( + _ready_mep_array, + untransmitted_meps_no * sizeof(size_t), + MPI_CHAR, + bu_rank, + MU_MEPS_TAG, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + + get_vector_of_meps(recv_index, untransmitted_meps_no); + + int64_t now = g_get_real_time(); + // info("MU GOT OU MESSAGE \n"); + // info("[ %.2lf s ] EM GOT OU MESSAGE \n",(now-start_timer)/(double)US_S); + MPI_Wait(&(_bu_ready_requests[recv_index]), MPI_STATUS_IGNORE); + MPI_Irecv( + &(_bu_ready_messages[recv_index]), + sizeof(mpi_bu_ready_msg), + MPI_CHAR, + _bus_ranks[recv_index], + MU_TAG, + MPI_COMM_WORLD, + &(_bu_ready_requests[recv_index])); + } +} + +void Manager_unit::send_bus_transmisison_grant(int ou_ind, int fu_ind) +{ + _trans_grant_messages[ou_ind].send_to_which_fu = _fus_ranks[fu_ind]; + MPI_Wait(&(_trans_grant_requests[ou_ind]), MPI_STATUS_IGNORE); + MPI_Isend( + &(_trans_grant_messages[ou_ind]), + sizeof(mpi_bu_transmission_grant_msg), + MPI_CHAR, + _bus_ranks[ou_ind], + MU_TAG, + MPI_COMM_WORLD, + &(_trans_grant_requests[ou_ind])); +} + +int Manager_unit::get_bu_rank_ready_with_least_rus() +{ + this->_bu_to_grant++; + if (this->_bu_to_grant >= _how_many_ous) this->_bu_to_grant = 0; + return this->_bu_to_grant; +} + +int Manager_unit::get_next_bu_ind() +{ + this->_bu_to_grant++; + if (this->_bu_to_grant >= _how_many_ous) this->_bu_to_grant = 0; + return this->_bu_to_grant; +} + +int Manager_unit::get_next_fu_ind() +{ + this->_fu_to_grant++; + if (this->_fu_to_grant >= _how_many_fus) this->_fu_to_grant = 0; + return this->_fu_to_grant; +} + +bool Manager_unit::get_next_free_fu_rank_ready_w_lowest_bytes(int* fu_index, int chosen_bu_index) +{ + // info("EM in getting FU\n"); + int tested_fu_indx = this->_fu_to_grant; + int min_indx; + bool was_free = false; + + for (int i = 0; i != _how_many_fus; i++) { + + tested_fu_indx = get_next_fu_ind(); + + if (_fus_ranks_ready[tested_fu_indx] != 0) { + // info("EM HAS AVAILABLE FU RANK %d with granted credits so far: + // %d\n",fusRanks[indx],fuGrantedCreditsArray[indx]); + if (was_free == false) { + was_free = true; + min_indx = tested_fu_indx; + *fu_index = tested_fu_indx; + } else if (_fus_total_granted_bytes_array[min_indx] > _fus_total_granted_bytes_array[tested_fu_indx]) { + // info("EM index min value: %d current index value: %d min index: %d current index: %d + // \n",fuGrantedCreditsArray[min_indx],fuGrantedCreditsArray[indx], min_indx,indx); + // info("EM i : %d. MIN INDX %d TESTED FU INDX %d\n",i,min_indx,tested_fu_indx); + min_indx = tested_fu_indx; + *fu_index = min_indx; + } + } + } + return was_free; +} + +bool Manager_unit::get_next_bu_rank_ready_w_lowest_bytes(int* bu_index) +{ + int tested_bu_indx = this->_bu_to_grant; + int min_indx; + bool was_free = false; + + for (int i = 0; i != _how_many_ous; i++) { + tested_bu_indx = get_next_bu_ind(); + if (_bu_meps_sizes_vectors[tested_bu_indx].size() != 0 && this->_bu_grants[tested_bu_indx] < MAX_BU_CREDITS) { + // info("EM HAS AVAILABLE OU RANK %d with granted credits so far: + // %d\n",busRanks[indx],buGrantedCreditsArray[indx]); + if (was_free == false) { + was_free = true; + min_indx = tested_bu_indx; + *bu_index = tested_bu_indx; + } else { + if (_bus_total_granted_bytes_array[min_indx] > _bus_total_granted_bytes_array[tested_bu_indx]) { + min_indx = tested_bu_indx; + *bu_index = tested_bu_indx; + } + } + } + } + return was_free; +} + +void Manager_unit::mpi_warmup_run() +{ + /* + // INITIALIZE BU->EM messages path (EVENTS READY) + for (int i = 0; i < how_many_ous; i++) { + MPI_Irecv( + &(bu_ready_messages[i]), + sizeof(mpi_bu_ready_msg), + MPI_CHAR, + bus_ranks[i], + MU_TAG, + MPI_COMM_WORLD, + &(bu_ready_requests[i])); + MPI_Wait(&(bu_ready_requests[i]), MPI_STATUS_IGNORE); + } + + // INITIALIZE EM->OU messages path (GRANT TRANSMISSION) + for (int i = 0; i < how_many_ous; i++) { + MPI_Isend( + &(trans_grant_messages[i]), + sizeof(mpi_bu_transmission_grant_msg), + MPI_CHAR, + bus_ranks[i], + MU_TAG, + MPI_COMM_WORLD, + &(trans_grant_requests[i])); + MPI_Wait(&(trans_grant_requests[i]), MPI_STATUS_IGNORE); + // + MPI_Irecv(&(buReadyMessages[i]),sizeof(MpiBuReadyMsg),MPI_CHAR,busRanks[i],MU_TAG,MPI_COMM_WORLD,&(buReadyRequests[i])); + // MPI_Wait(&(buReadyRequests[i]), MPI_STATUS_IGNORE); + } + + // INITIALIZE FU->EM (READINESS) + for (int i = 0; i < how_many_fus; i++) { + MPI_Irecv( + &(fu_ready_messages[i]), + sizeof(mpi_fu_ready_msg), + MPI_CHAR, + fus_ranks[i], + MU_TAG, + MPI_COMM_WORLD, + &(fu_ready_requests[i])); + MPI_Wait(&(fu_ready_requests[i]), MPI_STATUS_IGNORE); + // info("EM GOT FROM RANK %d\n",fusRanks[i]); + } + */ +} + +size_t Manager_unit::get_next_bu_mep_size_to_transmit(int bu_ind) +{ + size_t size = _bu_meps_sizes_vectors[bu_ind][0]; + return size; +} + +void Manager_unit::erase_next_bu_mep_size(int bu_ind) +{ + _bu_meps_sizes_vectors[bu_ind].erase(_bu_meps_sizes_vectors[bu_ind].begin()); +} + +bool Manager_unit::try_fu_alloc(int fu_ind, size_t size) +{ + MPI_Request alloc_request; + // info("EM trying alloc with fu %d and size %ld", fus_ranks[fu_ind], size); + mu_fu_alloc_msg msg; + msg.size = size; + MPI_Isend( + &msg, sizeof(mu_fu_alloc_msg), MPI_CHAR, _fus_ranks[fu_ind], MU_FU_ALLOC_TAG, MPI_COMM_WORLD, &alloc_request); + MPI_Wait(&alloc_request, MPI_STATUS_IGNORE); + // info("EM sent the message \n"); + MPI_Recv( + &msg, sizeof(mu_fu_alloc_msg), MPI_CHAR, _fus_ranks[fu_ind], MU_FU_ALLOC_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // info("EM received FU feedback. Status: %d \n", msg.success); + // + // sizeof(mpi_fu_ready_msg), + // MPI_CHAR, + // + return msg.success; +} + +void Manager_unit::get_vector_of_meps(int bu_index, int entries_no) +{ + for (int i = 0; i != entries_no; i++) { + _bu_meps_sizes_vectors[bu_index].push_back(_ready_mep_array[i]); + } +} diff --git a/Online/EventBuilding/src/events_dispatch/Output_unit.cpp b/Online/EventBuilding/src/events_dispatch/Output_unit.cpp new file mode 100644 index 000000000..6ab42fe77 --- /dev/null +++ b/Online/EventBuilding/src/events_dispatch/Output_unit.cpp @@ -0,0 +1,524 @@ +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <assert.h> +#include <ctime> +#include <time.h> +#include <sys/timerfd.h> +#include <glib.h> +#include <sys/mman.h> +#include <algorithm> + +#include "../../EventBuilding/events_dispatch/Output_unit.hpp" +#include "../../EventBuilding/events_dispatch/common.hpp" + +using namespace Online; +using namespace DISPATCH; +using namespace EB; + +/// Standard Constructor +Output_unit::Output_unit(const std::string& nam, DataflowContext& ctxt) : DataflowComponent(nam, ctxt), Unit() +{ + info("OU: IN CONSTRUCTOR"); + declareProperty("how_many_ous", how_many_ous = 1); + declareProperty("how_many_fus", how_many_fus = 1); + declareProperty("buffer_type", _buffer_type = 1); + declareProperty("Buffer", _mbm_name = "Buffer"); + declareProperty("Requirements", _m_req); +} + +/// IService implementation: initialize the service +int Output_unit::initialize() +{ + info("OU: IN INTIALIZE"); + + int sc = Component::initialize(); + if (sc != DF_SUCCESS) return error("Failed to initialize base-class"); + MPI_Init(NULL, NULL); + MPI_Comm_rank(MPI_COMM_WORLD, &(this->rank)); + MPI_Comm_size(MPI_COMM_WORLD, &(this->worldSize)); + + info("OU: MY RANK: %d, OUs NUMBER: %d, FUs NUMBER: %d", this->rank, how_many_ous, how_many_fus); + + this->_next_probing = 1; + this->_delay_timer = 0; + this->_total_serviced_events = 0; + + this->_started_credited_transmissions = new int[MAX_BU_CREDITS]; + for (auto i = 0; i != MAX_BU_CREDITS; i++) { + this->_started_credited_transmissions[i] = 0; + } + + this->_dataTransmissionRequests = new MPI_Request*[MAX_BU_CREDITS]; + for (auto i = 0; i != MAX_BU_CREDITS; i++) { + this->_dataTransmissionRequests[i] = new MPI_Request[window_length]; + } + + this->_current_transmission_meta = new current_transmission_metadata[MAX_BU_CREDITS]; + + this->_credit_free_array = new bool[MAX_BU_CREDITS]; + for (auto x = 0; x != MAX_BU_CREDITS; x++) { + this->_credit_free_array[x] = true; + } + + for (auto x = 0; x != MAX_BU_CREDITS; x++) { + for (auto y = 0; y != window_length; y++) { + this->_dataTransmissionRequests[x][y] = MPI_REQUEST_NULL; + } + } + + this->_bu_ready_requests = MPI_REQUEST_NULL; + this->_trans_granted_requests = MPI_REQUEST_NULL; + this->_pending_credits_no = 0; + this->_credits_to_rank_array = new int[MAX_BU_CREDITS]; + this->_pending_credits_array = new int[MAX_BU_CREDITS]; + + this->_ready_mep_array = new size_t[MAX_MEPS]; + + this->_all_completed_bytes = 0; + this->_current_probe_completed_bytes = 0; + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + + return sc; +} + +/// IService implementation: finalize the service +int Output_unit::finalize() +{ + MPI_Finalize(); + return DF_SUCCESS; +} + +/// IService implementation: finalize the service +/// TODO +int Output_unit::stop() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Cancel I/O operations of the dataflow component +int Output_unit::cancel() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Stop gracefully execution of the dataflow component +int Output_unit::pause() +{ + // TODO implement this + return DF_SUCCESS; +} + +/// Incident handler implemenentation: Inform that a new incident has occured +void Output_unit::handle(const DataflowIncident& inc) +{ + info("OU Got incident: %s of type %s", inc.name.c_str(), inc.type.c_str()); +} + +/// Service implementation: start of the service +// TODO +int Output_unit::start() +{ + info("OU: IN START"); + + if (_buffer_type == 1) { + info("OU: SHMEM INIT"); + std::stringstream shmem_name = get_shmem_name("BU", (this->rank) - 1); + info("In config_shmem. Shmem name: %s", shmem_name.str().c_str()); + _recv_buff = new Shmem_buffer_reader<EB::MEP>(shmem_name.str()); + } else if (_buffer_type == 2) { + info("OU: MBM INIT. MBM Name %s", _mbm_name.c_str()); + _recv_buff = new Mbm_reader<EB::MEP>(context, RTL::processName(), _mbm_name, _m_req); + info("OU: PAST MBM INIT"); + } + + if (DO_WARMUP) mpi_warmup_run(); + + // disabled for the WinCC runs + if (use_debug_mpi_barriers) MPI_Barrier(MPI_COMM_WORLD); + + return DF_SUCCESS; +} + +/// IRunable implementation : Run the class implementation +int Output_unit::run() +{ + info("OU: IN RUN"); + + int64_t probe_start; + this->probe_global_start = g_get_real_time(); + probe_start = probe_global_start; + this->_now = probe_start; + this->_start_timer = probe_start; + + start_receive_from_mu(); + + info("OU rank %d IN RUN: Warmup done. Starting main loop \n", this->rank); + + while (true) { + if (_ready_mep_vector.empty()) { + std::vector<mep_entry> new_mep_vector = get_meps_vector(); + if (!new_mep_vector.empty()) { + signal_new_meps_ready(new_mep_vector); + _ready_mep_vector.insert(_ready_mep_vector.end(), new_mep_vector.begin(), new_mep_vector.end()); + } + } + + update_granted_transmissions(); + + if (_pending_credits_no > 0 && _ready_mep_vector.size() != 0) { + + _current_transmission = _ready_mep_vector[0]; + int ready_rank = _pending_credits_array[_pending_credits_no - 1]; + _pending_credits_no--; + int slot = get_free_slot(); + get_meta(std::get<1>(_current_transmission), slot); + exchange_message_size(ready_rank, std::get<1>(_current_transmission)); + + this->_credit_free_array[slot] = false; + this->_started_credited_transmissions[slot] = 0; + this->_credits_to_rank_array[slot] = ready_rank; + start_send_data_to_fu(ready_rank, slot); + } + + int ready_rank = 0; + if (check_if_granted_transmission(&ready_rank) == true) { + // int64_t probe_time = g_get_real_time(); + ////printf("[ %.4lf s ] OU RANK %d WAS GRANTED TRANSMISSION to RANK %d + ///\n",((double)probe_time-(double)probe_global_start)/(double)US_S,this->rank,ready_rank); + _pending_credits_array[_pending_credits_no] = ready_rank; + _pending_credits_no++; + start_receive_from_mu(); + } + + int64_t probe_now = g_get_real_time(); + if (probe_now - probe_global_start > _next_probing * US_S) { + double tput_bytes_per_sec = static_cast<double>(_current_probe_completed_bytes) * static_cast<double>(US_S) / + (static_cast<double>(probe_now - probe_start)); + double tput_gbits_per_sec = tput_bytes_per_sec * 8.0 / 1000.0 / 1000.0 / 1000.0; + + _all_completed_bytes += _current_probe_completed_bytes; + double total_tput_bytes_per_sec = static_cast<double>(_all_completed_bytes) * static_cast<double>(US_S) / + (static_cast<double>(probe_now - probe_global_start)); + double total_tput_gbits_per_sec = total_tput_bytes_per_sec * 8.0 / 1000.0 / 1000.0 / 1000.0; + info( + "[ %.1lf s ] OU RANK %d TP %.4lf Gbits/s AVG TP Gbits/s %.1lf\n", + static_cast<double>((probe_now) - (probe_global_start)) / static_cast<double>(US_S), + rank, + tput_gbits_per_sec, + total_tput_gbits_per_sec); + + probe_start = probe_now; + _next_probing++; + _current_probe_completed_bytes = 0; + } + } + return DF_SUCCESS; +} + +void Output_unit::start_send_data_to_fu(int rank, int slot) +{ + // int64_t now = g_get_real_time(); + // printf("[ %.1lf s ] OU RANK: %d FIRST SENDING TO FU %d. ADDR %ld size %ld \n",(((double) now - (double) + // probe_global_start) / (double) US_S), this->rank,rank, std::get<0>(currentTransmission) - dataBufferPtr->data, + // std::get<1>(currentTransmission)); + unsigned int to_send = std::min(window_length, _current_transmission_meta[slot].full_transmissions_no); + + // size_t off =(size_t)std::get<0>(currentTransmission); + // printf("offset for RANK %ld: %ld\n",off-(size_t)this->dataBufferPtr->data, rank); + // printf("OU : initializing with %d transmissions out of %d \n", to_send, + // currentTransmissionMetadata[slot].fullTransmissionsNo); + for (unsigned int i = 0; i != to_send; i++) { + size_t addr = + static_cast<size_t>(_started_credited_transmissions[slot]) * static_cast<size_t>(entry_size_kb) * 1024UL; + char* offset = std::get<0>(_current_transmission) + addr; + + MPI_Wait(&(_dataTransmissionRequests[slot][i]), MPI_STATUS_IGNORE); + MPI_Isend( + offset, + entry_size_kb * 1024, + MPI_CHAR, + rank, + BU_RU_DATA_TAG, + MPI_COMM_WORLD, + &(_dataTransmissionRequests[slot][i])); + + _started_credited_transmissions[slot]++; + } +} + +void Output_unit::signal_new_meps_ready(std::vector<mep_entry> new_mep_vector) +{ + // printf("""SENDING EVENTS READY TO MU \n"); + _bu_ready_message.rank = this->rank; + _bu_ready_message.untransmitted_meps_number = new_mep_vector.size(); + + get_array_of_meps(new_mep_vector); + MPI_Send(&(_bu_ready_message), sizeof(mpi_bu_ready_msg), MPI_CHAR, 0, MU_TAG, MPI_COMM_WORLD); + MPI_Send( + _ready_mep_array, + sizeof(size_t) * _bu_ready_message.untransmitted_meps_number, + MPI_CHAR, + 0, + MU_MEPS_TAG, + MPI_COMM_WORLD); + + // printf("DONE SENDING EVENTS READY TO MU \n"); +} + +bool Output_unit::time_elapsed_check() +{ + _delay_timer++; + if (_delay_timer >= PROBE_EVERY_IT) { + _delay_timer = 0; + _now = g_get_real_time(); + if (_now - _start_timer >= TIME_ELAPSED_FOR_GENERATION) { + _start_timer += TIME_ELAPSED_FOR_GENERATION; + return true; + } + } + return false; +} + +bool Output_unit::check_if_granted_transmission(int* readyRank) +{ + int dataReceived; + + MPI_Test(&_trans_granted_requests, &dataReceived, MPI_STATUS_IGNORE); + + if (dataReceived == true) *readyRank = _trans_granted_message.send_to_which_fu; + + return dataReceived; +} + +void Output_unit::start_receive_from_mu() +{ + MPI_Irecv( + &_trans_granted_message, + sizeof(mpi_bu_transmission_grant_msg), + MPI_CHAR, + 0, + MU_TAG, + MPI_COMM_WORLD, + &(_trans_granted_requests)); +} + +void Output_unit::update_granted_transmissions() +{ + for (int i = 0; i != MAX_BU_CREDITS; i++) { + if (this->_credit_free_array[i] == false) { + if (_started_credited_transmissions[i] < _current_transmission_meta[i].full_transmissions_no) { + int indx; + int dataReceived; + MPI_Testany(window_length, _dataTransmissionRequests[i], &indx, &dataReceived, MPI_STATUS_IGNORE); + // int64_t now = g_get_real_time(); + // printf("[ %.1lf s ] OU RANK %d: CHECKING \n",(((double) now - (double) probe_global_start) / (double) + // US_S),this->rank); + + if (dataReceived == true) { + _current_probe_completed_bytes += entry_size_kb * 1024; + + char* addr = std::get<0>(_current_transmission); + addr += _started_credited_transmissions[i] * entry_size_kb * 1024; + + // printf("OFFSET : %ld DATA SIZE %ld \n", addr-this->dataBufferPtr->data, entry_size_kb * 1024); + // int64_t now = g_get_real_time(); + // printf("[ %.3lf s ] OU RANK %d: RESENDING TO %d SERVICED TRANSMISSIONS %d \n",(((double) now - (double) + // probe_global_start) / (double) US_S),this->rank,creditsToRankArray[i], + // startedCreditedTransmissions[i]); + + MPI_Wait(&(_dataTransmissionRequests[i][indx]), MPI_STATUS_IGNORE); + MPI_Isend( + addr, + entry_size_kb * 1024, + MPI_CHAR, + _credits_to_rank_array[i], + BU_RU_DATA_TAG, + MPI_COMM_WORLD, + &(_dataTransmissionRequests[i][indx])); + + _now = g_get_real_time(); + // info("[ %.3lf s ] OU RANK %d: AFTER RESENDING TO %d SERVICED TRANSMISSIONS %d \n",(((double) now - + // (double) probe_global_start) / (double) US_S),this->rank,creditsToRankArray[i], + // startedCreditedTransmissions[i]); + + _started_credited_transmissions[i]++; + } + } else { + unsigned int to_send = std::min(window_length, _current_transmission_meta[i].full_transmissions_no); + // info("OU RANK %d: TESTING WINDOW. TO SEND %d \n", rank, to_send); + MPI_Waitall(window_length, _dataTransmissionRequests[i], MPI_STATUSES_IGNORE); + _current_probe_completed_bytes += entry_size_kb * 1024 * to_send; + + if (_current_transmission_meta[i].remainder_size != 0) { + ////info("OU SENDING REMAINDER size %ld \n", currentTransmissionMetadata[i].remainderSize); + size_t addr = _started_credited_transmissions[i] * entry_size_kb * 1024; + // info("OFFSET : %ld DATA SIZE %ld \n", std::get<0>(currentTransmission) + addr - + // this->dataBufferPtr->data, currentTransmissionMetadata[i].remainderSize); + MPI_Send( + std::get<0>(_current_transmission) + addr, + _current_transmission_meta[i].remainder_size, + MPI_CHAR, + _credits_to_rank_array[i], + BU_RU_DATA_REMAINDER_TAG, + MPI_COMM_WORLD); + + _current_probe_completed_bytes += _current_transmission_meta[i].remainder_size; + } + + // int64_t now = g_get_real_time(); + // info("[ %.1lf s ] OU RANK %d : REMAINDER size %d AND ALL %d FULL TRANSMISSIONS FINALIZED. REMAINING + // TRANSMISISONS %ld \n", + //(((double) now - (double) probe_global_start) / (double) US_S), + // rank, + // current_transmission_meta[i].remainder_size, + // current_transmission_meta[i].full_transmissions_no, + // ready_mep_vector.size()); + + // info("OU SETTING TO TRUE \n"); + this->_credit_free_array[i] = true; + + // int64_t probe_time = g_get_real_time(); + // info(" [ %.2lf s ] OU RANK %d GRANTS AVAILABLE: %lu OCCUPANCY %lu \n", + // ((double)probe_time-(double)probe_global_start)/(double)US_S, rank, readyMepVector.size(), + // FBUFF::getBufferOccupancy( *(this->dataBufferPtr))); + + this->_total_serviced_events++; + // sync after transmitting all data from vector + _ready_mep_vector.erase(_ready_mep_vector.begin()); + if (_ready_mep_vector.empty()) { + // info("OU RANK %d VECTOR EMPTIED\n",rank); + _recv_buff->read_complete(); + } + // all serviced and eventual remainder + } + } + } +} +int Output_unit::get_free_slot() +{ + + for (auto i = 0; i != MAX_BU_CREDITS; i++) { + if (_credit_free_array[i] == true) return i; + } + + info("OU ERROR - SHOULD NOT BE HERE ! \n"); + return -1; +} + +void Output_unit::mpi_warmup_run() +{ + /* + int64_t t_init_start = g_get_real_time(); + // send + // INITIALIZE OU->EM messages path (EVENTS READY) + MPI_Isend(&(bu_ready_message), sizeof(mpi_bu_ready_msg), MPI_CHAR, 0, MU_TAG, MPI_COMM_WORLD, &(bu_ready_requests)); + MPI_Wait(&(bu_ready_requests), MPI_STATUS_IGNORE); + + MPI_Irecv( + &trans_granted_message, + sizeof(mpi_bu_transmission_grant_msg), + MPI_CHAR, + 0, + MU_TAG, + MPI_COMM_WORLD, + &(trans_granted_requests)); + MPI_Wait(&(bu_ready_requests), MPI_STATUS_IGNORE); + */ + // TODO + // TODO//std::vector<std::tuple<void*, size_t>> buff_out = buff_reader->get_full_buffer(); + // TODO// + + std::vector<std::tuple<void*, size_t>> buff_data = _recv_buff->get_full_buffer(); + long size = std::get<1>(buff_data[0]); + const char* ptr = (const char*) std::get<0>(buff_data[0]); + + // size_t size = std::get<1>(buff_out[0]); + // char* ptr = reinterpret_cast<char*>(std::get<0>(buff_out[0])); + int total_iterations = (int) (size / (size_t) WARMUP_MPI_SIZE); + size_t remainder_size = size % (size_t) WARMUP_MPI_SIZE; + + info("STARTUP SIZE: %ld AND PTR: %ld . TOTAL ITERATIONS %d\n", size, ptr, total_iterations); + + uint8_t* dummy_buffer = (uint8_t*) memalign(2UL * 1024UL * 1024UL, WARMUP_MPI_SIZE); + mlock(dummy_buffer, WARMUP_MPI_SIZE); + memset(dummy_buffer, 0xFF, WARMUP_MPI_SIZE); + + size_t index = 0; + MPI_Request s_request; + MPI_Request r_request; + for (int it = 0; it != total_iterations; it++) { + info("OU WARMUP PHASE 1 SEND: %d\n", it); + MPI_Irecv(dummy_buffer, WARMUP_MPI_SIZE, MPI_CHAR, rank, MPI_ANY_TAG, MPI_COMM_WORLD, &r_request); + MPI_Isend(&(ptr[index]), WARMUP_MPI_SIZE, MPI_CHAR, rank, rank, MPI_COMM_WORLD, &s_request); + MPI_Wait(&s_request, MPI_STATUS_IGNORE); + MPI_Wait(&r_request, MPI_STATUS_IGNORE); + + index += WARMUP_MPI_SIZE; + } + + /// remainder + MPI_Irecv(dummy_buffer, remainder_size, MPI_CHAR, rank, MPI_ANY_TAG, MPI_COMM_WORLD, &r_request); + MPI_Isend(&(ptr[index]), remainder_size, MPI_CHAR, rank, rank, MPI_COMM_WORLD, &s_request); + MPI_Wait(&s_request, MPI_STATUS_IGNORE); + MPI_Wait(&r_request, MPI_STATUS_IGNORE); + + /// phase two + index = 0; + for (int it = 0; it != total_iterations - 1; it++) { + info("OU WARMUP PHASE 2 SEND: %d\n", it); + MPI_Irecv(dummy_buffer, WARMUP_MPI_SIZE, MPI_CHAR, rank, MPI_ANY_TAG, MPI_COMM_WORLD, &r_request); + MPI_Isend(&(ptr[index + WARMUP_MPI_SIZE / 2]), WARMUP_MPI_SIZE, MPI_CHAR, rank, rank, MPI_COMM_WORLD, &s_request); + MPI_Wait(&s_request, MPI_STATUS_IGNORE); + MPI_Wait(&r_request, MPI_STATUS_IGNORE); + + index += WARMUP_MPI_SIZE; + } + + free(dummy_buffer); +} + +std::vector<mep_entry> Output_unit::get_meps_vector() +{ + return FBUFF::get_mep<EB::MEP>(_recv_buff); // return FBUFF::get_meps(*(this->buff_reader)); +} + +void Output_unit::exchange_message_size(int fu_rank, size_t size) +{ + _bu_fu_mep_size_msg.size = size; + _bu_fu_mep_size_msg.sender_rank = this->rank; + + // info("OU RANK %d IN EXCHANGE: MEP SIZE: %ld AT ADDR %ld\n", rank,size , + // std::get<0>(currentTransmission)-dataBufferPtr->data); + + MPI_Ssend(&(_bu_fu_mep_size_msg), sizeof(_bu_fu_mep_size_msg), MPI_CHAR, fu_rank, BU_RU_SIZE_TAG, MPI_COMM_WORLD); + MPI_Recv( + &(_bu_fu_mep_size_msg), + sizeof(_bu_fu_mep_size_msg), + MPI_CHAR, + fu_rank, + BU_RU_SIZE_TAG, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + + // info("OU RANK %d SUCCESFULLY EXCHANGED MESSAGE SIZE: %ld \n", rank,size); +} + +void Output_unit::get_meta(size_t size, int ind) +{ + _current_transmission_meta[ind].full_transmissions_no = size / entry_size_b; + _current_transmission_meta[ind].remainder_size = size % entry_size_b; +} + +void Output_unit::get_array_of_meps(std::vector<mep_entry> new_mep_vector) +{ + for (unsigned int a = 0; a != new_mep_vector.size(); a++) { + _ready_mep_array[a] = std::get<1>(new_mep_vector[a]); + } +} diff --git a/Online/EventBuilding/src/events_dispatch/common.cpp b/Online/EventBuilding/src/events_dispatch/common.cpp new file mode 100644 index 000000000..b6124242c --- /dev/null +++ b/Online/EventBuilding/src/events_dispatch/common.cpp @@ -0,0 +1,33 @@ +#include "../../EventBuilding/events_dispatch/common.hpp" + +namespace DISPATCH { + int how_many_fus = 1; + + int how_many_ous = 1; + + // int how_many_processes = 1; + + int window_length = 40; + + size_t entry_size_kb = 4096; + + size_t entry_size_b = entry_size_kb * 1024; + + // size_t bundled_transmissions = MB_IN_GRANT * 1024 / (entry_size_kb); + + bool perform_data_check = false; + + bool constant_size = true; + + bool use_debug_mpi_barriers = true; + + unsigned int gibit_events_in_one_quantum = 86; + + std::stringstream get_shmem_name(std::string shmem_name, int rank) + { + std::stringstream buff_name; + buff_name << shmem_name << "_" << (rank); + return buff_name; + } + +} // namespace DISPATCH diff --git a/Online/EventBuilding/src/generic_block.cpp b/Online/EventBuilding/src/generic_block.cpp new file mode 100644 index 000000000..4c1faa9f5 --- /dev/null +++ b/Online/EventBuilding/src/generic_block.cpp @@ -0,0 +1,27 @@ +#include "EventBuilding/generic_block.hpp" + +EB::Generic_block::Generic_block() { _payload_alloc_size = 0; } + +EB::Generic_block::Generic_block(std::shared_ptr<char> payload, size_t size) { set_payload(payload, size); } + +std::shared_ptr<char> EB::Generic_block::payload() const { return _payload; } + +void EB::Generic_block::set_payload(std::shared_ptr<char> payload, size_t size) +{ + _payload = payload; + _payload_alloc_size = size; +} + +bool EB::Generic_block::realloc_payload(size_t size) +{ + bool ret_val; + + if (_payload.use_count() <= 1) { + set_payload(std::shared_ptr<char>(new char[size]), size); + ret_val = true; + } else { + ret_val = false; + } + + return ret_val; +} diff --git a/Online/EventBuilding/src/infiniband_net/ib.cpp b/Online/EventBuilding/src/infiniband_net/ib.cpp new file mode 100644 index 000000000..feeecc486 --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/ib.cpp @@ -0,0 +1,672 @@ +/** + * @file IB.cpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ + +#include "ib.hpp" +#include <cstdio> +#include <ctime> +#include <chrono> +#include <cmath> +#include <cerrno> +#include <cstring> +#include <sstream> +#include <iostream> +using namespace std; +#ifndef P_INFO +#define P_INFO "Rank " << this->_procNum << ": " +#endif + +IB_verbs::IB::IB() +{ + memset(&this->_port_attr, 0, sizeof(_port_attr)); + memset(&this->_dev_attr, 0, sizeof(_dev_attr)); +} + +IB_verbs::IB::IB(IB&& src) +{ + this->_hosts = move(src._hosts); + this->_memMap = move(src._memMap); + this->_devNum = src._devNum; + this->_procNum = src._procNum; + this->_totalProcs = src._totalProcs; + this->_ctx = src._ctx; + this->_pd = src._pd; + this->_sendcq = src._sendcq; + this->_recvcq = src._recvcq; + this->_wcsend = move(src._wcsend); + this->_wcrecv = move(src._wcrecv); + this->_wcsyncr = move(src._wcsyncr); + this->_wcsyncs = move(src._wcsyncs); + this->_port_attr = src._port_attr; + this->_dev_attr = src._dev_attr; + this->_wrId = src._wrId.load(); + this->_sockObj = move(src._sockObj); + src._ctx = NULL; + src._pd = NULL; + src._sendcq = NULL; + src._recvcq = NULL; + src._wrId = 0; +} + +IB_verbs::IB& IB_verbs::IB::operator=(IB&& src) noexcept +{ + if (this != &src) { + try { + this->ibDestroy(); + } catch (...) { + } + this->_hosts = move(src._hosts); + this->_memMap = move(src._memMap); + this->_devNum = src._devNum; + this->_procNum = src._procNum; + this->_totalProcs = src._totalProcs; + this->_ctx = src._ctx; + this->_pd = src._pd; + this->_sendcq = src._sendcq; + this->_recvcq = src._recvcq; + this->_wcsend = move(src._wcsend); + this->_wcrecv = move(src._wcrecv); + this->_wcsyncr = move(src._wcsyncr); + this->_wcsyncs = move(src._wcsyncs); + this->_port_attr = src._port_attr; + this->_dev_attr = src._dev_attr; + this->_wrId = src._wrId.load(); + this->_sockObj = move(src._sockObj); + src._ctx = NULL; + src._pd = NULL; + src._sendcq = NULL; + src._recvcq = NULL; + src._wrId = 0; + } + return *this; +} + +IB_verbs::IB::IB(const char* filename, const int nProc) +{ + memset(&this->_port_attr, 0, sizeof(_port_attr)); + memset(&this->_dev_attr, 0, sizeof(_dev_attr)); + this->ibParseHosts(filename, nProc); + this->ibInit(); +} + +IB_verbs::IB::IB(const char* filename) +{ + memset(&this->_port_attr, 0, sizeof(_port_attr)); + memset(&this->_dev_attr, 0, sizeof(_dev_attr)); + this->ibParseHosts(filename); + this->ibInit(); +} + +IB_verbs::IB::~IB() noexcept +{ + try { + this->ibDestroy(); + } catch (...) { + } +} + +int IB_verbs::IB::getProcessID() const { return this->_procNum; } + +int IB_verbs::IB::ibGetDevNum() const { return this->_devNum; } + +int IB_verbs::IB::ibGetNumaNode() const { return this->_numaNode; } + +int IB_verbs::IB::getTotalProcesses() const { return this->_totalProcs; } + +void IB_verbs::IB::_destroyQP(ibv_qp* qp) +{ + + if (qp) { + // transition qp to ERROR + ibv_qp_attr qp_attr; + memset(&qp_attr, 0, sizeof(qp_attr)); + qp_attr.qp_state = IBV_QPS_ERR; + int ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE); + if (ret != 0) { + throw runtime_error("Failed to modify qp to ERROR"); + } + // destroy qp + ret = ibv_destroy_qp(qp); + if (ret != 0) { + throw runtime_error("Failed to destroy qp"); + } + qp = NULL; + } +} + +int IB_verbs::IB::_ibSetQP(Proc& host) +{ + // DATA QPs + { + int ret = 0; + { + + ibv_qp_attr qp_attr = {}; + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.qp_access_flags = + IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_ATOMIC; + qp_attr.pkey_index = 0; + qp_attr.port_num = this->_portNum; + ret = ibv_modify_qp(host.qp, &qp_attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS); + if (ret != 0) { + throw runtime_error("Failed to modify qp to INIT"); + } + } + { + ibv_ah_attr ah_attr = {}; + ah_attr.dlid = host.remote_lid; + ah_attr.sl = 0; + ah_attr.src_path_bits = 0; + ah_attr.is_global = 0; + ah_attr.port_num = this->_portNum; + + ibv_qp_attr qp_attr = {}; + qp_attr.qp_state = IBV_QPS_RTR; + qp_attr.path_mtu = IBV_MTU_4096; + qp_attr.rq_psn = 0; + qp_attr.dest_qp_num = host.remote_qp_num; + qp_attr.ah_attr = ah_attr; + qp_attr.max_dest_rd_atomic = 2; + qp_attr.min_rnr_timer = 12; + + ret = ibv_modify_qp( + host.qp, + &qp_attr, + IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU | IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER); + if (ret != 0) { + throw runtime_error("Failed to modify qp to RTR\n"); + } + } + { + ibv_qp_attr qp_attr = {}; + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 0; + qp_attr.max_rd_atomic = 2; + qp_attr.timeout = 14; + qp_attr.retry_cnt = 7; + qp_attr.rnr_retry = 7; + + ret = ibv_modify_qp( + host.qp, + &qp_attr, + IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT | IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN | IBV_QP_MAX_QP_RD_ATOMIC); + if (ret != 0) { + throw runtime_error("Failed to modify qp to RTS\n"); + } + } + } + // SYNC QP + int ret = 0; + { + + ibv_qp_attr qp_attr = {}; + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.qp_access_flags = + IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_ATOMIC; + qp_attr.pkey_index = 0; + qp_attr.port_num = this->_portNum; + + ret = ibv_modify_qp(host.sync_qp, &qp_attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS); + if (ret != 0) { + throw runtime_error("Failed to modify qp to INIT\n"); + } + } + { + ibv_ah_attr ah_attr = {}; + ah_attr.dlid = host.remote_lid; + ah_attr.sl = 0; + ah_attr.src_path_bits = 0; + ah_attr.is_global = 0; + ah_attr.port_num = this->_portNum; + + ibv_qp_attr qp_attr = {}; + qp_attr.qp_state = IBV_QPS_RTR; + qp_attr.path_mtu = IBV_MTU_4096; + qp_attr.rq_psn = 0; + qp_attr.dest_qp_num = host.remote_sync_qp_num; + qp_attr.ah_attr = ah_attr; + qp_attr.max_dest_rd_atomic = 2; + qp_attr.min_rnr_timer = 12; + + ret = ibv_modify_qp( + host.sync_qp, + &qp_attr, + IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU | IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER); + if (ret != 0) { + throw runtime_error("Failed to modify qp to RTR\n"); + } + } + { + ibv_qp_attr qp_attr = {}; + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 0; + qp_attr.max_rd_atomic = 2; + qp_attr.timeout = 14; + qp_attr.retry_cnt = 7; + qp_attr.rnr_retry = 7; + + ret = ibv_modify_qp( + host.sync_qp, + &qp_attr, + IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT | IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN | IBV_QP_MAX_QP_RD_ATOMIC); + if (ret != 0) { + throw runtime_error("Failed to modify qp to RTS\n"); + } + } + return 0; +} + +ibv_mr* IB_verbs::IB::ibAddMR(char* bufPtr, size_t bufSize, int access_flags) +{ + ibv_mr* memr = NULL; + // FIXME uninitialized return value + if (bufPtr == NULL && bufSize == 0) return memr; + if (_memMap.size() > 0) { + for (size_t i = 0; i < _memMap.size(); i++) { + if (_memMap.at(i)._bufPtr == bufPtr) { + // same pointer + if (_memMap.at(i)._bufSize >= bufSize) { + return _memMap.at(i)._mr; + } + } else if ( + bufPtr > _memMap.at(i)._bufPtr && bufPtr < (_memMap.at(i)._bufPtr + _memMap.at(i)._bufSize) && + (_memMap.at(i)._bufPtr + _memMap.at(i)._bufSize) >= (bufSize + bufPtr)) { + return _memMap.at(i)._mr; + } + } + } + memr = ibv_reg_mr(this->_pd, (void*) bufPtr, bufSize, access_flags | IBV_ACCESS_RELAXED_ORDERING); + if (memr == NULL) { + return NULL; + } + memreg item = {}; + item._mr = memr; + item._bufPtr = bufPtr; + item._bufSize = bufSize; + + _memMap.push_back(item); + return memr; +} + +int IB_verbs::IB::ibRemoveMR(char* bufPtr, size_t bufSize) +{ + if (_memMap.size() > 0) { + for (size_t i = 0; i < _memMap.size(); i++) { + if (_memMap.at(i)._bufPtr == bufPtr && _memMap.at(i)._bufSize == bufSize) { + if (ibv_dereg_mr(_memMap.at(i)._mr) == 0) { + _memMap.at(i) = _memMap.back(); + _memMap.pop_back(); + return 0; + } + } + } + } + return -1; +} + +int IB_verbs::IB::ibParseHosts(const char* filename, const int nProc) +{ + try { + Parser prs(filename, nProc); + this->_totalProcs = prs.getTotalProcesses(); + this->_procNum = prs.getProcessId(); + this->_devName = prs.getIbDevString(); + this->_devNum = prs.getIbDevNum(); + this->_numaNode = prs.getIbNumaNode(); + auto list = prs.getHostList(); + _hosts.resize(list.size()); + for (size_t i = 0; i < list.size(); i++) { + _hosts[i].sockAddr = list[i]; + } + } catch (const std::exception& e) { + throw; + } + return 0; +} + +int IB_verbs::IB::ibParseHosts(const char* filename) +{ + try { + Parser prs(filename); + this->_totalProcs = prs.getTotalProcesses(); + this->_procNum = prs.getProcessId(); + this->_devName = prs.getIbDevString(); + this->_devNum = prs.getIbDevNum(); + this->_numaNode = prs.getIbNumaNode(); + auto list = prs.getHostList(); + _hosts.resize(list.size()); + for (size_t i = 0; i < list.size(); i++) { + _hosts[i].sockAddr = list[i]; + } + } catch (const std::exception& e) { + throw; + } + return 0; +} + +int IB_verbs::IB::ibSetHostList(Parser& hostParser) +{ + try { + auto list = hostParser.getHostList(); + this->_totalProcs = hostParser.getTotalProcesses(); + this->_procNum = hostParser.getProcessId(); + this->_devName = hostParser.getIbDevString(); + this->_devNum = hostParser.getIbDevNum(); + this->_numaNode = hostParser.getIbNumaNode(); + _hosts.resize(list.size()); + for (size_t i = 0; i < list.size(); i++) { + _hosts[i].sockAddr = list[i]; + } + } catch (const std::exception& e) { + throw; + } + return 0; +} + +int IB_verbs::IB::_getDevInfo() +{ + int num_devs = 0; + this->_dev_list = ibv_get_device_list(&num_devs); + if (this->_dev_list == NULL) { + throw runtime_error("cannot find IB devices"); + } + this->_devNum = -1; + for (int i = 0; i < num_devs; i++) { + string tmp(ibv_get_device_name(this->_dev_list[i])); + if (this->_devName == tmp) { + _devNum = i; + break; + } + } + if (_devNum == -1) { + throw runtime_error("cannot find the device"); + } + string path(this->_dev_list[this->_devNum]->ibdev_path); + string numastr; + ifstream numafile(path + "/device/numa_node"); + if (numafile.is_open()) { + numafile >> numastr; + this->_numaNode = stoi(numastr); + numafile.close(); + } else { + this->_numaNode = -1; + } + return 0; +} + +void IB_verbs::IB::ibInit() +{ +#ifdef IB_DUMP_FILE + std::stringstream base_dump_filename; + char* utgid = getenv("UTGID"); + base_dump_filename << _dump_file_path << "/" << utgid; + _wc_dump_file = std::ofstream(base_dump_filename.str() + "_wc_dump.txt"); + _wr_dump_file = std::ofstream(base_dump_filename.str() + "_wr_dump.txt"); + if (!_wc_dump_file.is_open() or !_wr_dump_file.is_open()) { + throw runtime_error("cannot open IB dump files " + base_dump_filename.str()); + } +#endif + + // if no dev list (can happen if ibInit is recalled) + int num_devs; + if (this->_dev_list == NULL) { + this->_dev_list = ibv_get_device_list(&num_devs); + if (this->_dev_list == NULL) { + string err_mess("Error while opening IB devices: "); + err_mess += strerror(errno); + throw runtime_error(err_mess); + } else if (num_devs == 0) { + throw runtime_error("cannot find IB devices"); + } + } + // open the device + this->_ctx = ibv_open_device(this->_dev_list[this->_devNum]); + if (this->_ctx == NULL) { + throw runtime_error("cannot open IB device"); + } + ibv_free_device_list(_dev_list); + // allocate protection domain + this->_pd = ibv_alloc_pd(this->_ctx); + if (this->_pd == NULL) { + throw runtime_error("cannot allocate protection domain"); + } + // query dev port + int ret = ibv_query_port(this->_ctx, this->_portNum, &this->_port_attr); + if (ret < 0) { + throw runtime_error("cannot query IB port on device"); + } + if (this->_port_attr.state != IBV_PORT_ACTIVE) { + throw runtime_error("IB port is not active, check cable"); + } + if (this->_port_attr.phys_state != 5 /*LINKUP*/) { + throw runtime_error("IB port physical link error, check SM"); + } + // get dev info + ret = ibv_query_device(this->_ctx, &(this->_dev_attr)); + if (ret < 0) { + throw runtime_error("cannot query device for attributes"); + } + // create completion queues + this->_sendcq = ibv_create_cq(this->_ctx, (this->_dev_attr.max_cqe) / 3, NULL, NULL, 0); + if (this->_sendcq == NULL) { + throw runtime_error("cannot create data send completion queue"); + } + this->_recvcq = ibv_create_cq(this->_ctx, (this->_dev_attr.max_cqe) / 3, NULL, NULL, 0); + if (this->_recvcq == NULL) { + throw runtime_error("cannot create data receive completion queue"); + } + this->_syncScq = ibv_create_cq(this->_ctx, (this->_dev_attr.max_cqe) / 3, NULL, NULL, 0); + if (this->_syncScq == NULL) { + throw runtime_error("cannot create sync send completion queue"); + } + this->_syncRcq = ibv_create_cq(this->_ctx, (this->_dev_attr.max_cqe) / 3, NULL, NULL, 0); + if (this->_syncRcq == NULL) { + throw runtime_error("cannot create sync receive completion queue"); + } + + // CREATING QUEUE PAIRS FOR EVERY REMOTE + ibv_qp_cap cap = {}; + cap.max_send_wr = 8192; + cap.max_recv_wr = (unsigned int) this->_dev_attr.max_qp_wr; + cap.max_send_sge = 1; + cap.max_recv_sge = 1; + + ibv_qp_init_attr qp_init_attr = {}; + qp_init_attr.send_cq = this->_sendcq; + qp_init_attr.recv_cq = this->_recvcq; + qp_init_attr.cap = cap; + qp_init_attr.qp_type = IBV_QPT_RC; + + ibv_qp_init_attr qp_sync_init_attr = {}; + qp_sync_init_attr.send_cq = this->_syncScq; + qp_sync_init_attr.recv_cq = this->_syncRcq; + qp_sync_init_attr.cap = cap; + qp_sync_init_attr.qp_type = IBV_QPT_RC; + + // creating queue pairs + for (size_t i = 0; i < _hosts.size(); i++) { + // data qp + _hosts.at(i).qp = ibv_create_qp(this->_pd, &qp_init_attr); + if (_hosts.at(i).qp == NULL) { + throw runtime_error("cannot create data queue pair"); + } + // sync qp + _hosts.at(i).sync_qp = ibv_create_qp(this->_pd, &qp_sync_init_attr); + if (_hosts.at(i).sync_qp == NULL) { + throw runtime_error("cannot query sync queue pair"); + } + } + // adding thread for recv qp data over tcp + std::atomic<int> _retsocket = {0}; + _QPrecv = std::thread(&Sock::recvQPs, &_sockObj, this->_procNum, std::ref(this->_hosts), std::ref(_retsocket)); + ret = 0; + int timeout = 0; + // sending qp data over tcp + for (size_t i = 0; i < _hosts.size(); i++) { + timeout = 0; + _hosts.at(i).local_lid = this->_port_attr.lid; + while (_sockObj.sendQP(this->_procNum, _hosts.at(i)) < 0) { + sleep(1); + timeout++; + if (timeout > 120) { + ret = -1; + } + int rtc = _retsocket; + if (rtc != 0) { + if (!_QPrecv.joinable()) throw runtime_error("cannot join socket thread"); + _QPrecv.join(); + } + switch (rtc) { + case -1: throw runtime_error("socket bind error"); break; + case -2: throw runtime_error("socket listen error"); break; + case -3: throw runtime_error("exchange accept error"); break; + case -4: throw runtime_error("exchange receive error"); break; + case -5: throw runtime_error("exchange shutdown error"); break; + case -6: throw runtime_error("exchange close error"); break; + case -7: throw runtime_error("socket close error"); break; + } + } + } + // waiting for all qp data to be received + if (!_QPrecv.joinable()) throw runtime_error("cannot join socket thread"); + _QPrecv.join(); + if (ret == -1) { + throw runtime_error("timeout sending qp info to remote"); + } + // setting up the qps + for (size_t i = 0; i < _hosts.size(); i++) { + try { + this->_ibSetQP(_hosts.at(i)); + } catch (...) { + throw; + } + } + // FILLING REVERSE LUT + for (size_t i = 0; i < _hosts.size(); i++) { + uint32_t qp_n = _hosts.at(i).sync_qp->qp_num; + _reverse_hosts[qp_n] = i; + } + // PRIMING SYNC RECVS + if (_syncInit() != 0) { + throw runtime_error("sync init failed"); + } + // STARTING SYNC THREAD + _syncThread = std::thread(&IB_verbs::IB::_syncFunc, this, std::ref(_runsync)); + // COMPUTE LUT FOR BARRIER + _initTournament(); +} + +int IB_verbs::IB::ibDeregMRs() +{ + int ret = 0; + for (size_t i = 0; i < this->_memMap.size(); i++) { + ret += ibv_dereg_mr(_memMap.at(i)._mr); + _memMap.at(i)._mr = NULL; + } + if (ret != 0) throw runtime_error(string("cannot dereg memory region. Err: ").append(strerror(errno))); + _memMap.clear(); + return ret; +} + +void IB_verbs::IB::ibKillBlocking() { _kill_blocking = true; } + +void IB_verbs::IB::ibDestroy() +{ + int ret = 0; + _runsync = false; + if (_syncThread.joinable()) { + _syncThread.join(); + } + for (size_t i = 0; i < this->_hosts.size(); i++) { + try { + _destroyQP(this->_hosts.at(i).qp); + } catch (...) { + throw; + } + try { + _destroyQP(this->_hosts.at(i).sync_qp); + } catch (...) { + throw; + } + } + _hosts.clear(); + if (this->_sendcq) { + ret = ibv_destroy_cq(this->_sendcq); + if (ret != 0) throw runtime_error(string("cannot destroy send cq. Err: ").append(strerror(errno))); + this->_sendcq = NULL; + } + if (this->_recvcq) { + ret = ibv_destroy_cq(this->_recvcq); + if (ret != 0) throw runtime_error(string("cannot destroy recv cq. Err: ").append(strerror(errno))); + this->_recvcq = NULL; + } + if (this->_syncScq) { + ret = ibv_destroy_cq(this->_syncScq); + if (ret != 0) throw runtime_error(string("cannot destroy sync send cq. Err: ").append(strerror(errno))); + this->_syncScq = NULL; + } + if (this->_syncRcq) { + ret = ibv_destroy_cq(this->_syncRcq); + if (ret != 0) throw runtime_error(string("cannot destroy sync recv cq. Err: ").append(strerror(errno))); + this->_syncRcq = NULL; + } + try { + ibDeregMRs(); + } catch (...) { + throw; + } + if (this->_pd) { + ret = ibv_dealloc_pd(this->_pd); + if (ret != 0) throw runtime_error(string("cannot destroy protection domain. Err: ").append(strerror(errno))); + this->_pd = NULL; + } + if (this->_ctx) { + ret = ibv_close_device(this->_ctx); + if (ret != 0) throw runtime_error(string("cannot close device. Err: ").append(strerror(errno))); + this->_ctx = NULL; + } +#ifdef IB_DUMP_FILE + _wc_dump_file.close(); + _wr_dump_file.close(); +#endif +} + +uint32_t IB_verbs::IB::_ibGetNextWrId() +{ + uint32_t ret_val = _wrId.fetch_add(1); + // 0 is not a valid ID + if (ret_val == 0) { + return _ibGetNextWrId(); + } + return ret_val; +} + +#ifdef IB_DUMP_FILE +void IB_verbs::IB::_dump_wc(const struct ibv_wc& wc) +{ + std::lock_guard<std::mutex> file_guard(_wc_dump_file_mutex); + _wc_dump_file << wc.qp_num; + _wc_dump_file << "," << wc.status << "," << wc.opcode << "," << wc.wr_id << std::endl; +} + +void IB_verbs::IB::_dump_wr(const IB_verbs::IB::ib_wr& wr) +{ + std::lock_guard<std::mutex> file_guard(_wr_dump_file_mutex); + _wr_dump_file << wr.qp_num << "," << wr.src_qp; + if (!wr.receive) { + _wr_dump_file << "," << wr.opcode; + } else { + _wr_dump_file << ",recv"; + } + _wr_dump_file << std::endl; +} +#endif diff --git a/Online/EventBuilding/src/infiniband_net/ib_collective.cpp b/Online/EventBuilding/src/infiniband_net/ib_collective.cpp new file mode 100644 index 000000000..c3779860d --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/ib_collective.cpp @@ -0,0 +1,152 @@ +/** + * @file ib_collective.cpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library - Collective Methods + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#include "ib.hpp" +#include <cstdio> +#include <ctime> +#include <random> +#include <chrono> +#include <cmath> + +using namespace std; + +#ifndef P_INFO +#define P_INFO "Rank " << procNum << ": " +#endif + +int IB_verbs::IB::ibBarrier(barrier_t type) +{ + switch (type) { + case TOURNAMENT: return this->_runTournament(); break; + case CENTRAL: return this->_runCentral(); break; + default: return this->_runTournament(); break; + } +} + +int IB_verbs::IB::_initTournament() +{ + // all of this can be put in init! + array<uint32_t, 2> req; + req[0] = BARRIER; + int rounds = static_cast<int>(log2(this->_totalProcs)); + int sz = this->_totalProcs; + int procNum = this->_procNum; + for (int i = 1; i <= rounds; i++) { + if (procNum % (1 << i) == 0) { + if (procNum <= (this->_totalProcs - (1 << i))) { + int src = (procNum + (1 << (i - 1))); + + // cout << P_INFO << "S recv " << src << endl; + req[1] = src; + _tournament_lut.push_back(req); + _tournament_hlist.push_back(src); + int mod = sz % ((1 << i)); + if (mod != 0) { // add receive for _tournament_lonely processes + if (procNum == (sz - 3 * (1 << (i - 1)))) { + int src = (sz - (1 << (i - 1))); + + // cout << P_INFO << "D recv " << src << endl; + req[1] = src; + _tournament_lut.push_back(req); + _tournament_hlist.push_back(src); + _tournament_lonely = true; // for release sync + } + sz -= mod; + } + } else { + int src = (procNum - (1 << i)); + + // cout << P_INFO << "RD recv " << src << endl; + req[1] = src; + _tournament_lut.push_back(req); // recv release + _tournament_dst = src; + break; + } + } else { + int src = (procNum - (1 << (i - 1))); + + // cout << P_INFO << "R recv " << src << endl; + req[1] = src; + _tournament_lut.push_back(req); // recv release + _tournament_dst = src; + break; + } + } + return 0; +} +int IB_verbs::IB::_runTournament() +{ + int res; + if (_tournament_dst > -1) { + uint32_t wr = this->ibSendSync(BARRIER, _tournament_dst); // blocking to mantain sync + if (wr == 0) return -1; + res = this->ibWaitSyncSend(wr); + if (res != 0) return res; + } + res = this->ibWaitAllSyncRecvs(_tournament_lut); + if (res != 0) return res; + + int idx = _tournament_hlist.size() - 1; + uint32_t _tournament_lonely_send = 0; + if (_tournament_lonely) { + _tournament_lonely_send = + this->ibSendSync(BARRIER, _tournament_hlist.at(idx)); // syncing with _tournament_lonely processes simultaneously + if (_tournament_lonely_send == 0) return -1; + idx--; + } + while (idx >= 0) { + + uint32_t temp_send = this->ibSendSync(BARRIER, _tournament_hlist.at(idx)); + if (temp_send == 0) return -1; + if (_tournament_lonely) { + res = this->ibWaitSyncSend(_tournament_lonely_send); + if (res != 0) return res; + _tournament_lonely = false; + } + res = this->ibWaitSyncSend(temp_send); + if (res != 0) return res; + idx--; + } + return 0; +} + +int IB_verbs::IB::_runCentral() +{ + int res; + int procNum = this->_procNum; + if (procNum == 0) { + vector<array<uint32_t, 2>> recvs_ids; + for (int i = 1; i < this->_totalProcs; i++) { + array<uint32_t, 2> req; + req[0] = BARRIER; + req[1] = i; + recvs_ids.push_back(req); + } + res = this->ibWaitAllSyncRecvs(recvs_ids); + if (res != 0) return res; + vector<uint32_t> send_ids; + uint32_t temp_wr; + for (int i = 1; i < this->_totalProcs; i++) { + temp_wr = this->ibSendSync(BARRIER, i); + if (temp_wr == 0) return -1; + send_ids.push_back(temp_wr); + } + res = this->ibWaitAllSyncSends(send_ids); + if (res != 0) return res; + } else { + uint32_t wrid = this->ibSendSync(BARRIER, 0); + if (wrid == 0) return -1; + res = this->ibWaitSyncSend(wrid); + if (res != 0) return res; + res = this->ibWaitSyncRecv(BARRIER, 0); + if (res != 0) return res; + } + return 0; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/infiniband_net/ib_comms.cpp b/Online/EventBuilding/src/infiniband_net/ib_comms.cpp new file mode 100644 index 000000000..eb9ae5883 --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/ib_comms.cpp @@ -0,0 +1,127 @@ +/** + * @file ib_comms.cpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library - Communication Methods + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#include "ib.hpp" +#include <cstdio> +#include <ctime> +#include <random> +#include <chrono> +#include <cmath> + +using namespace std; + +#ifndef P_INFO +#define P_INFO "Rank: " << this->_procNum << ": " +#endif + +uint32_t IB_verbs::IB::ibRecv(char* bufPtr, uint32_t bufSize, uint32_t sender) +{ + ibv_mr* mr = this->ibAddMR(bufPtr, bufSize); + // TODO fix error condition + // if (mr == NULL) { + // return 0; + // } + uint32_t wrId = this->_ibRecv(mr, (char*) bufPtr, bufSize, sender); + return wrId; +} + +uint32_t IB_verbs::IB::ibSend(char* bufPtr, uint32_t bufSize, uint32_t dest) +{ + ibv_mr* mr = this->ibAddMR(bufPtr, bufSize); + // TODO fix error condition + // if (mr == NULL) { + // return 0; + // } + uint32_t wrId = this->_ibSend(mr, (char*) bufPtr, bufSize, dest); + return wrId; +} + +uint32_t IB_verbs::IB::_ibRecv(ibv_mr* mr, char* bufPtr, uint32_t bufSize, uint32_t sender) +{ + Proc& host = _hosts.at(sender); + ibv_recv_wr* bad_recv_wr; + ibv_sge list; + memset(&list, 0, sizeof(list)); + list.addr = (uintptr_t) bufPtr; + list.length = bufSize; + uint32_t wrId = _ibGetNextWrId(); // get unique wr_id + int nsge = 1; + if (bufPtr == NULL && bufSize == 0) { + nsge = 0; // zero-byte msg + list.lkey = 0; + } else { + list.lkey = mr->lkey; + } + ibv_recv_wr recv_wr; + memset(&recv_wr, 0, sizeof(recv_wr)); + recv_wr.wr_id = wrId; + recv_wr.sg_list = &list; + recv_wr.num_sge = nsge; +// //cout << P_INFO << "receiving on " << host.remote_qp_num[idx] << "-" << host.qp[idx]->qp_num << "\r"; +#ifdef IB_DUMP_FILE + ib_wr wr; + wr.qp_num = host.qp->qp_num; + wr.src_qp = host.remote_qp_num; + wr.receive = true; + _dump_wr(wr); +#endif + int ret = ibv_post_recv(host.qp, &recv_wr, &bad_recv_wr); + if (ret < 0) return 0; + return wrId; +} + +uint32_t IB_verbs::IB::_ibSend(ibv_mr* mr, char* bufPtr, uint32_t bufSize, uint32_t dest) +{ + Proc& host = _hosts.at(dest); + ibv_send_wr* bad_send_wr; + ibv_sge list; + memset(&list, 0, sizeof(list)); + list.addr = (uintptr_t) bufPtr; + list.length = bufSize; + uint32_t wrId = _ibGetNextWrId(); // get unique wr_id + int nsge = 1; + if (bufPtr == NULL && bufSize == 0) { + nsge = 0; // zero-byte msg + list.lkey = 0; + } else { + list.lkey = mr->lkey; + } + ibv_send_wr send_wr; + memset(&send_wr, 0, sizeof(send_wr)); + send_wr.wr_id = wrId; + send_wr.sg_list = &list; + send_wr.num_sge = nsge; + send_wr.opcode = IBV_WR_SEND; + send_wr.send_flags = IBV_SEND_SIGNALED; +// //cout << P_INFO << "sending on " << host.remote_qp_num[idx] << "-" << host.qp[idx]->qp_num << "\r"; +#ifdef IB_DUMP_FILE + ib_wr wr; + wr.src_qp = host.qp->qp_num; + wr.qp_num = host.remote_qp_num; + wr.receive = false; + wr.opcode = send_wr.opcode; + _dump_wr(wr); +#endif + int ret = ibv_post_send(host.qp, &send_wr, &bad_send_wr); + if (ret < 0) return 0; + return wrId; +} + +int IB_verbs::IB::ibBlockRecv(char* bufPtr, uint32_t bufSize, uint32_t sender) +{ + uint32_t wrId = this->ibRecv(bufPtr, bufSize, sender); + return this->ibWaitRecvCQ(wrId); +} + +int IB_verbs::IB::ibBlockSend(char* bufPtr, uint32_t bufSize, uint32_t dest) +{ + uint32_t wrId = this->ibSend(bufPtr, bufSize, dest); + return this->ibWaitSendCQ(wrId); +} diff --git a/Online/EventBuilding/src/infiniband_net/ib_polling.cpp b/Online/EventBuilding/src/infiniband_net/ib_polling.cpp new file mode 100644 index 000000000..34ce4296d --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/ib_polling.cpp @@ -0,0 +1,276 @@ +/** + * @file ib_polling.cpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library - CQ polling methods + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ + +#include "ib.hpp" +#include <cstdio> +#include <ctime> +#include <chrono> +#include <cmath> + +using namespace std; +#ifndef P_INFO +#define P_INFO "Rank " << this->_procNum << ": " +#endif + +int IB_verbs::IB::_pollRCQ() +{ + int n; + int wr_ids = PARALLEL_WRS; + struct ibv_wc wc[PARALLEL_WRS]; + if ((n = ibv_poll_cq(this->_recvcq, wr_ids, wc)) < 0) { + return -1; + } + // add new WCs to vector + for (int i = 0; i < n; i++) { + _wcrecv[wc[i].wr_id] = wc[i]; +#ifdef IB_DUMP_FILE + _dump_wc(wc[i]); +#endif + } + return 0; +} + +int IB_verbs::IB::_pollSCQ() +{ + int n; + int wr_ids = PARALLEL_WRS; + struct ibv_wc wc[PARALLEL_WRS]; + if ((n = ibv_poll_cq(this->_sendcq, wr_ids, wc)) < 0) { + return -1; + } + // add new WCs to vector + for (int i = 0; i < n; i++) { + _wcsend[wc[i].wr_id] = wc[i]; +#ifdef IB_DUMP_FILE + _dump_wc(wc[i]); +#endif + } + + return 0; +} + +int IB_verbs::IB::ibTestSendCQ(uint32_t wrId) +{ + // check if anything new is present + int ret_val = 0; + unordered_map<uint32_t, ibv_wc>::iterator p = _wcsend.find(wrId); + if (p != _wcsend.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + ret_val = -1; + return ret_val; + } else { + _wcsend.erase(p); + return ret_val; + } + } else { + // poll cq + ret_val = _pollSCQ(); + if (ret_val != 0) { + return ret_val; + } + p = _wcsend.find(wrId); + if (p != _wcsend.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + ret_val = -1; + return ret_val; + } else { + _wcsend.erase(p); + return 0; + } + } + } + return 1; +} + +int IB_verbs::IB::ibTestRecvCQ(uint32_t wrId) +{ + // check if anything new is present + int err_code = 0; + unordered_map<uint32_t, ibv_wc>::iterator p = _wcrecv.find(wrId); + if (p != _wcrecv.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + return -1; + } else { + _wcrecv.erase(p); + return 0; + } + } else { + err_code = this->_pollRCQ(); + if (err_code != 0) { + return err_code; + } + p = _wcrecv.find(wrId); + if (p != _wcrecv.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + return -1; + } else { + _wcrecv.erase(p); + return 0; + } + } + } + return 1; +} + +int IB_verbs::IB::ibWaitSendCQ(uint32_t wrId) +{ + int run = 1; + while (run) { + run = this->ibTestSendCQ(wrId); + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + } + return run; +} + +int IB_verbs::IB::ibWaitRecvCQ(uint32_t wrId) +{ + int run = 1; + while (run) { + run = this->ibTestRecvCQ(wrId); + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + } + return run; +} + +int IB_verbs::IB::ibWaitAllSends(std::vector<uint32_t>& wrs) +{ + int x = wrs.size(); + int ret = 0; + while (x > 0) { + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestSendCQ(wrs.at(i)); + if (ret == 0) { + wrs.at(i) = wrs.back(); + wrs.pop_back(); + x--; + } else if (ret < 0) { + return -1; + } + // //cout << P_INFO << static_cast<double>(delta)<<"\n"; + } + } + return 0; +} +int IB_verbs::IB::ibWaitAllRecvs(std::vector<uint32_t>& wrs) +{ + int x = wrs.size(); + int ret = 0; + while (x > 0) { + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestRecvCQ(wrs.at(i)); + if (ret == 0) { + wrs.at(i) = wrs.back(); + wrs.pop_back(); + x--; + } else if (ret < 0) { + return -1; + } + } + } + return 0; +} + +std::vector<int> IB_verbs::IB::ibTestAnySends(std::vector<uint32_t>& wrs) +{ + int ret = 0; + vector<int> res; + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestSendCQ(wrs.at(i)); + res.push_back(ret); + } + return res; +} + +std::vector<int> IB_verbs::IB::ibTestAnyRecvs(std::vector<uint32_t>& wrs) +{ + int ret = 0; + vector<int> res; + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestRecvCQ(wrs.at(i)); + res.push_back(ret); + } + return res; +} + +int IB_verbs::IB::ibTestAllRecvs(std::vector<uint32_t>& wrs) +{ + int ret = 0; + vector<int> res; + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestRecvCQ(wrs.at(i)); + if (ret == 0) { + wrs.at(i) = wrs.back(); + wrs.pop_back(); + } else if (ret == -1) { + return -1; + } + } + if (wrs.size() > 0) { + return 1; + } + return 0; +} + +std::vector<int> IB_verbs::IB::ibWaitAnySends(std::vector<uint32_t>& wrs) +{ + int ret = 0; + bool run = true; + vector<int> res(wrs.size()); + while (run) { + if (_kill_blocking) { + _kill_blocking = false; + return {}; + } + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestSendCQ(wrs.at(i)); + res.at(i) = ret; + } + for (size_t i = 0; i < res.size(); i++) { + if (res.at(i) == 0) return res; + } + } + return res; +} + +std::vector<int> IB_verbs::IB::ibWaitAnyRecvs(std::vector<uint32_t>& wrs) +{ + int ret = 0; + bool run = true; + vector<int> res(wrs.size()); + while (run) { + if (_kill_blocking) { + _kill_blocking = false; + return {}; + } + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestRecvCQ(wrs.at(i)); + res.at(i) = ret; + } + for (size_t i = 0; i < res.size(); i++) { + if (res.at(i) == 0) return res; + } + } + return res; +} diff --git a/Online/EventBuilding/src/infiniband_net/ib_rdma_ops.cpp b/Online/EventBuilding/src/infiniband_net/ib_rdma_ops.cpp new file mode 100644 index 000000000..98703714e --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/ib_rdma_ops.cpp @@ -0,0 +1,110 @@ +/** + * @file ib_rdma_ops.cpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library - RDMA Methods + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#include "ib.hpp" +#include <cstdio> +#include <ctime> +#include <random> +#include <chrono> +#include <cmath> + +using namespace std; + +#ifndef P_INFO +#define P_INFO "Rank " << this->_procNum << ": " +#endif + +uint32_t IB_verbs::IB::_RDMAop(char* bufPtr, uint32_t bufSize, uint32_t dest, bool opType /*true read, false write*/) +{ + Proc& host = _hosts.at(dest); + ibv_mr* mr = this->ibAddMR(bufPtr, bufSize); + ibv_send_wr* bad_send_wr; + ibv_sge list = {}; + list.addr = (uintptr_t) bufPtr; + list.length = bufSize; + list.lkey = mr->lkey; + ibv_send_wr send_wr; + memset(&send_wr, 0, sizeof(send_wr)); + uint32_t wrId = _ibGetNextWrId(); // get random wr_id + + send_wr.wr_id = wrId, send_wr.sg_list = &list, send_wr.num_sge = 1, + send_wr.opcode = (opType ? IBV_WR_RDMA_READ : IBV_WR_RDMA_WRITE), send_wr.send_flags = IBV_SEND_SIGNALED, + send_wr.wr.rdma.remote_addr = host.rdma.addr; + send_wr.wr.rdma.rkey = host.rdma.rkey; +#ifdef IB_DUMP_FILE + ib_wr wr; + wr.src_qp = host.qp->qp_num; + wr.qp_num = host.remote_qp_num; + wr.receive = false; + wr.opcode = send_wr.opcode; + _dump_wr(wr); +#endif + int ret = ibv_post_send(host.qp, &send_wr, &bad_send_wr); + if (ret < 0) return 0; + + return wrId; +} + +int IB_verbs::IB::ibRecvRDMAInfo(char* bufPtr, uint32_t bufSize, uint32_t src) +{ + Proc& host = _hosts.at(src); + ibv_mr* mr = this->ibAddMR(bufPtr, bufSize); // MR where we want RDMA on + if (mr == NULL) return -1; + // post RR to get remote MR info + int ret = this->ibBlockRecv((char*) &host.rdma, sizeof(Proc::MRInfo), src); + return ret; +} + +int IB_verbs::IB::ibSendRDMAInfo(char* bufPtr, uint32_t bufSize, uint32_t dest) +{ + // post SR to send remote MR info + ibv_mr* mr = this->ibAddMR(bufPtr, bufSize); // MR where we want RDMA on + if (mr == NULL) return -1; + _hosts.at(this->_procNum).rdma.rkey = mr->rkey; + _hosts.at(this->_procNum).rdma.rkey = (uintptr_t) mr->addr; + int ret = this->ibBlockSend((char*) &_hosts.at(this->_procNum).rdma, sizeof(Proc::MRInfo), dest); + return ret; +} + +uint32_t IB_verbs::IB::ibRDMAWrite(char* bufPtr, uint32_t bufSize, uint32_t dest) +{ + uint32_t wrId = _RDMAop(bufPtr, bufSize, dest, false); + return wrId; +} + +uint32_t IB_verbs::IB::ibRDMARead(char* bufPtr, uint32_t bufSize, uint32_t dest) +{ + uint32_t wrId = _RDMAop(bufPtr, bufSize, dest, true); + return wrId; +} + +int IB_verbs::IB::ibBlockRDMAWrite(char* bufPtr, uint32_t bufSize, uint32_t dest, bool sendComplete) +{ + uint32_t wrId = _RDMAop(bufPtr, bufSize, dest, false); + int ret = ibWaitSendCQ(wrId); + if (ret != 0) return ret; + if (sendComplete) { + wrId = ibSendSync(RDMA_OP_COMPLETE, dest); + return ibWaitSyncSend(wrId); + } + return 0; +} + +int IB_verbs::IB::ibBlockRDMARead(char* bufPtr, uint32_t bufSize, uint32_t dest, bool sendComplete) +{ + uint32_t wrId = _RDMAop(bufPtr, bufSize, dest, true); + int ret = ibWaitSendCQ(wrId); + if (ret != 0) return ret; + if (sendComplete) { + wrId = ibSendSync(RDMA_OP_COMPLETE, dest); + return ibWaitSyncSend(wrId); + } + return 0; +} diff --git a/Online/EventBuilding/src/infiniband_net/ib_sync.cpp b/Online/EventBuilding/src/infiniband_net/ib_sync.cpp new file mode 100644 index 000000000..766521124 --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/ib_sync.cpp @@ -0,0 +1,275 @@ +/** + * @file ib_sync.cpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief InfiniBand Communication Library - Syncronization Methods + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#include "ib.hpp" +#include <cstdio> +#include <ctime> +#include <chrono> +#include <cmath> + +using namespace std; + +constexpr int SYNC_BASELINE = 10; +#ifndef P_INFO +#define P_INFO "Rank " << this->_procNum << ": " +#endif + +void IB_verbs::IB::_syncFunc(std::atomic<bool>& run) +{ + while (run) { + _pollSyncRCQ(); + } +} + +int IB_verbs::IB::_syncInit() +{ + for (size_t i = 0; i < _hosts.size(); i++) { + if (i != this->_procNum) { + for (int k = 0; k < SYNC_BASELINE; k++) { + int ret = ibRecvSync(i); + if (ret == 0) return -1; + } + } + } + return 0; +} + +uint32_t IB_verbs::IB::ibSendSync(immediate_t imm_code, uint32_t dest) +{ + Proc& host = _hosts.at(dest); + ibv_send_wr* bad_send_wr; + ibv_sge list; + list.addr = (uintptr_t) NULL; + list.length = 0; + uint32_t wrId = _ibGetNextWrId(); // get random wr_id + int nsge = 0; // zero-byte msg + list.lkey = 0; + ibv_send_wr send_wr; + memset(&send_wr, 0, sizeof(send_wr)); + send_wr.wr_id = wrId, send_wr.sg_list = &list, send_wr.num_sge = nsge, send_wr.opcode = IBV_WR_SEND_WITH_IMM, + send_wr.send_flags = IBV_SEND_SIGNALED, send_wr.imm_data = htonl(imm_code); + +#ifdef IB_DUMP_FILE + ib_wr wr; + wr.src_qp = host.sync_qp->qp_num; + wr.qp_num = host.remote_qp_num; + wr.receive = false; + wr.opcode = send_wr.opcode; + _dump_wr(wr); +#endif + + int ret = ibv_post_send(host.sync_qp, &send_wr, &bad_send_wr); + if (ret < 0) return 0; + return wrId; +} + +uint32_t IB_verbs::IB::ibRecvSync(uint32_t src) +{ + Proc& host = _hosts.at(src); + ibv_recv_wr* bad_recv_wr; + ibv_sge list; + list.addr = (uintptr_t) NULL; + list.length = 0; + uint32_t wrId = _ibGetNextWrId(); // get random wr_id + int nsge = 0; // zero-byte msg + list.lkey = 0; + ibv_recv_wr recv_wr; + memset(&recv_wr, 0, sizeof(recv_wr)); + recv_wr.wr_id = wrId; + recv_wr.sg_list = &list; + recv_wr.num_sge = nsge; + // //cout << P_INFO << "receiving on " << host.remote_qp_num[idx] << "-" << host.qp[idx]->qp_num << "\r"; +#ifdef IB_DUMP_FILE + ib_wr wr; + wr.qp_num = host.qp->qp_num; + wr.src_qp = host.remote_qp_num; + wr.receive = true; + _dump_wr(wr); +#endif + int ret = ibv_post_recv(host.sync_qp, &recv_wr, &bad_recv_wr); + if (ret < 0) return 0; + return wrId; +} + +int IB_verbs::IB::_pollSyncRCQ() +{ + int n; + int wr_ids = PARALLEL_WRS; + struct ibv_wc wc[PARALLEL_WRS]; + if ((n = ibv_poll_cq(this->_syncRcq, wr_ids, wc)) < 0) { + return -1; + } + // add new WCs to vector + for (int i = 0; i < n; i++) { +#ifdef IB_DUMP_FILE + _dump_wc(wc[i]); +#endif + uint32_t qp_n = wc[i].qp_num; + uint64_t hash = ((uint64_t) qp_n << 32); // compute key + hash |= ntohl(wc[i].imm_data); + { + const std::lock_guard<std::mutex> lock(this->_mtx_sync); + _wcsyncr[hash] = wc[i]; + } + // post new recvs for consumed ones + // cout << P_INFO << "received from " << _reverse__hosts[qp_n] << " hash "<<(uintptr_t)hash<< endl; + ibRecvSync(_reverse_hosts[qp_n]); + } + return 0; +} + +int IB_verbs::IB::ibTestSyncSend(uint32_t wrId) +{ + int n; + int wr_ids = PARALLEL_WRS; + struct ibv_wc wc[PARALLEL_WRS]; + // check if anything new is present + unordered_map<uint32_t, ibv_wc>::iterator p = _wcsyncs.find(wrId); + if (p != _wcsyncs.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + return -1; + } else { + _wcsyncs.erase(p); + + return 0; + } + } else { + // poll cq + if ((n = ibv_poll_cq(this->_syncScq, wr_ids, wc)) < 0) { + return -1; + } + // add new WCs to vector + for (int i = 0; i < n; i++) { + _wcsyncs[wc[i].wr_id] = wc[i]; +#ifdef IB_DUMP_FILE + _dump_wc(wc[i]); +#endif + } + p = _wcsyncs.find(wrId); + if (p != _wcsyncs.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + return -1; + } else { + _wcsyncs.erase(p); + return 0; + } + } + } + return 1; +} + +int IB_verbs::IB::ibWaitSyncSend(uint32_t wrId) +{ + int run = 1; + while (run) { + run = this->ibTestSyncSend(wrId); + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + } + return run; +} + +int IB_verbs::IB::ibWaitAllSyncSends(std::vector<uint32_t>& wrs) +{ + int x = wrs.size(); + int ret = 0; + while (x > 0) { + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + for (size_t i = 0; i < wrs.size(); i++) { + ret = this->ibTestSyncSend(wrs.at(i)); + if (ret == 0) { + wrs.at(i) = wrs.back(); + wrs.pop_back(); + x--; + } else if (ret < 0) { + return -1; + } + // //cout << P_INFO << static_cast<double>(delta)<<"\n"; + } + } + return 0; +} + +int IB_verbs::IB::_ibSync(uint64_t key) +{ + const std::lock_guard<std::mutex> lock(this->_mtx_sync); + unordered_map<uint64_t, ibv_wc>::iterator p = _wcsyncr.find(key); + if (p != _wcsyncr.end()) { + if (p->second.status != IBV_WC_SUCCESS) { + return -1; + } else { + _wcsyncr.erase(p); + return 0; + } + } + return 1; +} + +int IB_verbs::IB::ibTestSyncRecv(immediate_t imm_code, uint32_t src) +{ + uint32_t lqp = _hosts.at(src).sync_qp->qp_num; // to do: manage multiple qps + uint64_t key = ((uint64_t) lqp << 32); + key |= imm_code; + + return this->_ibSync(key); +} + +int IB_verbs::IB::ibWaitSyncRecv(immediate_t imm_code, uint32_t src) +{ + int run = 1; + uint32_t lqp = _hosts.at(src).sync_qp->qp_num; // to do: manage multiple qps + uint64_t key = ((uint64_t) lqp << 32); + key |= imm_code; + // cout << "searching for "<< (uintptr_t)key<<endl; + while (run) { + run = this->_ibSync(key); + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + } + return run; +} + +int IB_verbs::IB::ibWaitAllSyncRecvs(std::vector<std::array<uint32_t, 2>>& wrs) +{ + size_t x = wrs.size(); + int ret = 0; + std::vector<uint64_t> keys; + // compute keys + for (size_t i = 0; i < x; i++) { + uint32_t lqp = _hosts.at(wrs.at(i)[1]).sync_qp->qp_num; // to do: manage multiple qps + uint64_t key = ((uint64_t) lqp << 32); + key |= wrs.at(i)[0]; + keys.push_back(key); + } + while (x > 0) { + if (_kill_blocking) { + _kill_blocking = false; + return -5; + } + for (size_t i = 0; i < keys.size(); i++) { + ret = this->_ibSync(keys.at(i)); + if (ret == 0) { + keys.at(i) = keys.back(); + keys.pop_back(); + x--; + } else if (ret < 0) { + return -1; + } + } + } + return 0; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/infiniband_net/parser.cpp b/Online/EventBuilding/src/infiniband_net/parser.cpp new file mode 100644 index 000000000..2bc3ccdab --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/parser.cpp @@ -0,0 +1,232 @@ +/** + * @file parser.hpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief Parser for InfiniBand Library + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#include "parser.hpp" +#include <cerrno> +#include <cstring> + +using namespace std; + +IB_verbs::Parser::Parser(const char* filename) +{ + _getMyNetInfo(); + _readHostFile(filename); + _getMyIbDevInfo(); +} + +IB_verbs::Parser::Parser(const char* filename, const int rankid) +{ + _getMyNetInfo(); + _readHostFile(filename, rankid); + _getMyIbDevInfo(); +} + +IB_verbs::Parser::~Parser() {} + +int IB_verbs::Parser::getProcessId() const { return this->_globalProc; } + +int IB_verbs::Parser::getTotalProcesses() const { return this->_totalProcs; } + +int IB_verbs::Parser::getIbDevNum() const { return this->_ibDevNum; } + +int IB_verbs::Parser::getIbNumaNode() const { return this->_ibNumaNode; } + +std::string IB_verbs::Parser::getMyHostname() const { return this->_myHostName; } + +std::string IB_verbs::Parser::getMyIp() const { return this->_myIP; } + +int IB_verbs::Parser::_getMyNetInfo() +{ + char buf[256]; + char* ip; + hostent* host; + int ret = gethostname(buf, sizeof(buf)); + if (ret == -1) return ret; + this->_myHostName = string(buf); + host = gethostbyname(buf); + if (host == NULL) return -1; + ip = inet_ntoa(*((in_addr*) host->h_addr_list[0])); + this->_myIP = string(ip); + return 0; +} + +void IB_verbs::Parser::_getMyIbDevInfo() +{ + int num_devs = 0; + auto dev_list = ibv_get_device_list(&num_devs); + if (dev_list == NULL) { + string err_mess("Error while opening IB devices: "); + err_mess += strerror(errno); + throw runtime_error(err_mess); + } else if (num_devs == 0) { + throw runtime_error("cannot find IB devices"); + } + this->_ibDevNum = -1; + for (int i = 0; i < num_devs; i++) { + string tmp(ibv_get_device_name(dev_list[i])); + if (this->_ibDevString == tmp) { + _ibDevNum = i; + break; + } + } + if (_ibDevNum == -1) { + throw runtime_error("cannot find the device"); + } + string path(dev_list[this->_ibDevNum]->ibdev_path); + string numastr; + ifstream numafile(path + "/device/numa_node"); + if (numafile.is_open()) { + numafile >> numastr; + this->_ibNumaNode = stoi(numastr); + numafile.close(); + } else { + this->_ibNumaNode = -1; + } + + ibv_free_device_list(dev_list); +} + +std::string IB_verbs::Parser::_getIpByHostname(std::string hostname) +{ + char* ip; + hostent* host; + host = gethostbyname(hostname.c_str()); + ip = inet_ntoa(*((in_addr*) host->h_addr_list[0])); + return string(ip); +} + +int IB_verbs::Parser::getIpPort() const { return this->_ipPort; } + +std::string IB_verbs::Parser::getIbDevString() const { return this->_ibDevString; } + +void IB_verbs::Parser::_readHostFile(const char* filename, const int nProc) +{ + DynamicJsonDocument doc(1e6); + ifstream hostFile(filename); + deserializeJson(doc, hostFile); + JsonArray hostsArray = doc["hosts"]; + // get hosts size + int procs = hostsArray.size(); + // resize lut + _hostvec.resize(procs); + sockaddr_in tmp = {}; + std::fill(_hostvec.begin(), _hostvec.end(), tmp); + this->_totalProcs = procs; + string curr_ip = ""; + int hostn = 0; + // REMOTES + for (int i = 0; i < procs; i++) { + sockaddr_in temp; + int rankid = hostsArray[i]["rankid"].as<int>(); + if (rankid >= procs) { + throw runtime_error("rank ID out of range."); + } + if (hostsArray[i].containsKey("ip")) + curr_ip = hostsArray[i]["ip"].as<std::string>(); + else + curr_ip = this->_getIpByHostname(hostsArray[i]["hostname"].as<std::string>()); + hostn = hostsArray[i]["port"].as<int>(); + // cout << curr_ip << ":" << hostn << endl; + temp.sin_family = AF_INET; + inet_pton(AF_INET, curr_ip.c_str(), &temp.sin_addr); + temp.sin_port = htons(hostn); + // cout << i << endl; + if (rankid == nProc) { + if (curr_ip.compare(this->_myIP) == 0) { + this->_globalProc = nProc; + this->_ibDevString = hostsArray[i]["ibdev"].as<std::string>(); + } else { + throw runtime_error("Hostname and rank id mismatch."); + } + } + if (_hostvec[rankid].sin_port != 0) { + throw runtime_error("duplicate rank id."); + } + _hostvec[rankid] = temp; + } + doc.clear(); + hostFile.close(); +} + +void IB_verbs::Parser::_readHostFile(const char* filename) +{ + DynamicJsonDocument doc(1e6); + ifstream hostFile(filename); + deserializeJson(doc, hostFile); + JsonArray hostsArray = doc["hosts"]; + // get hosts size + int procs = hostsArray.size(); + // resize lut + _hostvec.resize(procs); + sockaddr_in tmp = {}; + std::fill(_hostvec.begin(), _hostvec.end(), tmp); + this->_totalProcs = procs; + string curr_ip = ""; + int hostn; + // REMOTES + bool is_this_process = false; + for (int i = 0; i < procs; i++) { + sockaddr_in temp; + int rankid = hostsArray[i]["rankid"].as<int>(); + string utgid = hostsArray[i]["utgid"].as<std::string>(); + if (rankid >= procs) { + throw runtime_error(utgid + ": rank ID out of range."); + } + // look for ip + if (hostsArray[i].containsKey("ip")) + curr_ip = hostsArray[i]["ip"].as<std::string>(); + else + curr_ip = this->_getIpByHostname(hostsArray[i]["hostname"].as<std::string>()); + // look for port + if (hostsArray[i].containsKey("port")) + hostn = hostsArray[i]["port"].as<int>(); + else + hostn = 10000 + rankid; + + temp.sin_family = AF_INET; + inet_pton(AF_INET, curr_ip.c_str(), &temp.sin_addr); + temp.sin_port = htons(hostn); + // cout << i << endl; + char* env = getenv("UTGID"); + if (env == NULL) { + doc.clear(); + hostFile.close(); + throw runtime_error("Cannot find UTGID env variable."); + } + string env_utgid(env); + + // compare utgid + if (env_utgid.compare(utgid) == 0) { + if (curr_ip.compare(this->_myIP) == 0) { + this->_globalProc = rankid; + this->_ibDevString = hostsArray[i]["ibdev"].as<std::string>(); + is_this_process = true; + } else { + doc.clear(); + hostFile.close(); + throw runtime_error("Hostname and UTGID mismatch."); + } + } + + if (_hostvec[rankid].sin_port != 0) { + throw runtime_error(utgid + ": duplicate rank id."); + } + _hostvec[rankid] = temp; + } + if (!is_this_process) { + doc.clear(); + hostFile.close(); + throw runtime_error("Haven't found this process in the config file, UTGID mismatch."); + } + doc.clear(); + hostFile.close(); +} + +std::vector<sockaddr_in> IB_verbs::Parser::getHostList() { return _hostvec; } diff --git a/Online/EventBuilding/src/infiniband_net/sock.cpp b/Online/EventBuilding/src/infiniband_net/sock.cpp new file mode 100644 index 000000000..77daa29e9 --- /dev/null +++ b/Online/EventBuilding/src/infiniband_net/sock.cpp @@ -0,0 +1,96 @@ +/** + * @file sock.hpp + * @author Alberto Perro (alberto.perro@cern.ch) + * @brief Socket Communication for InfiniBand Library + * @version 0.1.7 + * @date 24/03/2021 + * + * @copyright Copyright (c) 2020-2021 + * + */ +#include "sock.hpp" + +using namespace std; + +IB_verbs::Sock::Sock() {} +IB_verbs::Sock::~Sock() {} + +void IB_verbs::Sock::recvQPs(const int rankid, const std::vector<Proc>& k, std::atomic<int>& ret) +{ + ret = 0; + vector<Proc>& hosts = const_cast<vector<Proc>&>(k); + int connfd = socket(AF_INET, SOCK_STREAM, 0); + // Preventing the OS from keeping the socket open after close() + struct linger sl; + sl.l_onoff = 1; /* non-zero value enables linger option in kernel */ + sl.l_linger = 0; /* timeout interval in seconds */ + if (setsockopt(connfd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)) < 0) { + // TODO find a better err code + ret = -20; + return; + } + int reuse_addr = 1; + if (setsockopt(connfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0) { + // TODO find a better err code + ret = -21; + return; + } + + sockaddr_in server; + server.sin_family = AF_INET; + server.sin_port = hosts.at(rankid).sockAddr.sin_port; + server.sin_addr.s_addr = INADDR_ANY; + if (bind(connfd, (struct sockaddr*) &server, sizeof(server)) < 0) { + ret = -1; + return; + } + if (listen(connfd, 50) < 0) { + ret = -2; + return; + } + QPInfo tmp_qp_info; + int host_size = hosts.size(); + for (int i = 0; i < host_size; i++) { + int fd = accept(connfd, (struct sockaddr*) NULL, NULL); + if (fd < 0) { + ret = -3; + return; + } + int rcv = recv(fd, (char*) &tmp_qp_info, sizeof(QPInfo), 0); + if (rcv < 0) { + ret = -4; + return; + } + int idx = ntohl(tmp_qp_info.procNum); + hosts.at(idx).remote_lid = ntohs(tmp_qp_info.lid); + hosts.at(idx).remote_sync_qp_num = ntohl(tmp_qp_info.sync_qp_num); + hosts.at(idx).remote_qp_num = ntohl(tmp_qp_info.qp_num); + if (shutdown(fd, SHUT_RDWR) != 0) { + ret = -5; + return; + } + if (close(fd) != 0) { + ret = -6; + return; + } + } + if (close(connfd) != 0) { + ret = -7; + return; + } +} + +int IB_verbs::Sock::sendQP(const int rankid, Proc& rem) +{ // send local qp infos + QPInfo tmp_qp_info; + tmp_qp_info.lid = htons(rem.local_lid); + tmp_qp_info.qp_num = htonl(rem.qp->qp_num); + tmp_qp_info.sync_qp_num = htonl(rem.sync_qp->qp_num); + tmp_qp_info.procNum = htonl(rankid); + int connfd = socket(AF_INET, SOCK_STREAM, 0); + if (connfd < 0) return -1; + if (connect(connfd, (sockaddr*) &rem.sockAddr, sizeof(rem.sockAddr)) < 0) return -1; + send(connfd, (char*) &tmp_qp_info, sizeof(QPInfo), 0); + close(connfd); + return 0; +} diff --git a/Online/EventBuilding/src/logger.cpp b/Online/EventBuilding/src/logger.cpp new file mode 100644 index 000000000..bfa84e607 --- /dev/null +++ b/Online/EventBuilding/src/logger.cpp @@ -0,0 +1,188 @@ +#include "logger.hpp" +#include <exception> +#include <system_error> + +std::string EB::log_priority_to_string(const EB::Log_priority& elem) +{ + switch (elem) { + case Log_priority::kLogEmerg: return "EMERGENCY"; + case Log_priority::kLogAlert: return "ALERT"; + case Log_priority::kLogCrit: return "CRITICAL"; + case Log_priority::kLogErr: return "ERROR"; + case Log_priority::kLogWarning: return "WARNING"; + case Log_priority::kLogNotice: return "NOTICE"; + case Log_priority::kLogInfo: return "INFO"; + case Log_priority::kLogDebug: return "DEBUG"; + default: return "Unsupported log priority"; + } +} + +EB::Log_priority EB::online_print_level_to_log_priority(const Online::PrintLevel& elem) +{ + switch (elem) { + case Online::PrintLevel::VERBOSE: return Log_priority::kLogDebug; + case Online::PrintLevel::DEBUG: return Log_priority::kLogDebug; + case Online::PrintLevel::INFO: return Log_priority::kLogInfo; + case Online::PrintLevel::WARNING: return Log_priority::kLogWarning; + case Online::PrintLevel::ERROR: return Log_priority::kLogErr; + case Online::PrintLevel::FATAL: return Log_priority::kLogAlert; + case Online::PrintLevel::ALWAYS: return Log_priority::kLogEmerg; + case Online::PrintLevel::NOLOG: return Log_priority::kLogNoLog; + default: return Log_priority::kLogNoLog; + } +} + +Online::PrintLevel EB::log_priority_to_online_print_level(const EB::Log_priority& elem) +{ + switch (elem) { + case Log_priority::kLogEmerg: return Online::PrintLevel::ALWAYS; + case Log_priority::kLogAlert: return Online::PrintLevel::FATAL; + case Log_priority::kLogCrit: return Online::PrintLevel::ERROR; + case Log_priority::kLogErr: return Online::PrintLevel::ERROR; + case Log_priority::kLogWarning: return Online::PrintLevel::WARNING; + case Log_priority::kLogNotice: return Online::PrintLevel::INFO; + case Log_priority::kLogInfo: return Online::PrintLevel::INFO; + case Log_priority::kLogDebug: return Online::PrintLevel::DEBUG; + case Log_priority::kLogNoLog: return Online::PrintLevel::NOLOG; + default: return Online::PrintLevel::NOLOG; + } +} + +EB::Log::Log(std::string name, Log_priority log_level, bool enable_syslog, bool enable_online, int facility) +{ + Log_initializer::init_log(); + _log_level = log_level; + _name = name; + _facility = facility; + _online_ena = enable_online; + _syslog_ena = enable_syslog; + _UTGID = RTL::processName(); +} + +void EB::Log::set_log_level(const Log_priority& log_level) { _log_level = log_level; } +EB::Log_priority EB::Log::get_log_level() const { return _log_level; } + +void EB::Log::set_name(const std::string& name) { _name = name; } +std::string EB::Log::get_name() const { return _name; } + +void EB::Log::set_facility(int facility) { _facility = facility; } +int EB::Log::get_facility() const { return _facility; } + +void EB::Log::enable_syslog(bool flag) { _syslog_ena = flag; } +void EB::Log::enable_online(bool flag) { _online_ena = flag; } +bool EB::Log::syslog_enabled() const { return _syslog_ena; } +bool EB::Log::online_enabled() const { return _online_ena; } + +int EB::Log::sync() +{ + if (_buffer.length()) { + // the facility can be ored with the log level, the default value will leave it unchanged + if (_syslog_ena) { + syslog(static_cast<int>(_log_level) | _facility, "%s %s: %s", _UTGID.c_str(), _name.c_str(), _buffer.c_str()); + } + if (_online_ena) { + Online::printout(log_priority_to_online_print_level(_log_level), _name.c_str(), _buffer.c_str()); + } + _buffer.erase(); + } + return 0; +} + +int EB::Log::overflow(int c) +{ + if (c != EOF) { + _buffer += static_cast<char>(c); + } else { + sync(); + } + return c; +} + +EB::Log_stream::Log_stream( + std::string name, + Log_priority out_level, + bool enable_syslog, + bool enable_online, + int facility) : + std::ostream(new Log(name, EB::default_log, enable_syslog, enable_online, facility)) +{ + set_output_level(out_level); + _buff.reset(rdbuf()); +} + +EB::Log_stream::Log_stream(Log_stream&& other) : + std::ostream(std::move(other)), _output_level(std::move(other._output_level)), _buff(std::move(other._buff)) +{ + // the rdbuf is not changed by the move operator + rdbuf(other.rdbuf()); + other.rdbuf(NULL); +} + +EB::Log_stream& EB::Log_stream::operator=(Log_stream&& rhs) +{ + // protection against self move + if (&rhs != this) { + std::ostream::operator=(std::move(rhs)); + // the rdbuf is not changed by the move operator + rdbuf(rhs.rdbuf()); + rhs.rdbuf(NULL); + _output_level = rhs._output_level; + _buff = std::move(rhs._buff); + } + return *this; +} + +void EB::Log_stream::set_output_level(const EB::Log_priority& output_level) +{ + // NoLog can't be printed out + if (output_level != Log_priority::kLogNoLog) { + _output_level = output_level; + } else { + throw std::system_error( + static_cast<int>(std::errc::invalid_argument), std::generic_category(), "Requesting invalid output level"); + } +} +void EB::Log_stream::set_output_level(const Online::PrintLevel& output_level) +{ + set_output_level(online_print_level_to_log_priority(output_level)); +} + +EB::Log_priority EB::Log_stream::get_output_level() const { return _output_level; } + +void EB::Log_stream::set_name(const std::string& name) { reinterpret_cast<Log*>(rdbuf())->set_name(name); } +std::string EB::Log_stream::get_name() const { return reinterpret_cast<Log*>(rdbuf())->get_name(); } + +void EB::Log_stream::enable_syslog(bool flag) { static_cast<Log*>(rdbuf())->enable_syslog(flag); } +void EB::Log_stream::enable_online(bool flag) { static_cast<Log*>(rdbuf())->enable_online(flag); } +bool EB::Log_stream::syslog_enabled() const { return static_cast<Log*>(rdbuf())->syslog_enabled(); } +bool EB::Log_stream::online_enabled() const { return static_cast<Log*>(rdbuf())->online_enabled(); } + +EB::Log_stream& EB::Log_stream::set_log_level(const EB::Log_priority& log_level) +{ + static_cast<Log*>(rdbuf())->set_log_level(log_level); + return *this; +} +EB::Log_stream& EB::Log_stream::set_log_level(const Online::PrintLevel& log_level) +{ + return set_log_level(online_print_level_to_log_priority(log_level)); +} + +EB::Log_priority EB::Log_stream::get_log_level() const { return static_cast<Log*>(rdbuf())->get_log_level(); } + +bool EB::Log_stream::is_active(const EB::Log_priority& priority) const { return priority <= _output_level; } +bool EB::Log_stream::is_active(const Online::PrintLevel& priority) const +{ + return is_active(online_print_level_to_log_priority(priority)); +} + +std::ostream& operator<<(std::ostream& os, EB::Log_priority const& log_priority) +{ + os << EB::log_priority_to_string(log_priority); + return os; +} + +EB::Log_stream& operator<<(EB::Log_stream& os, EB::Log_priority const& log_priority) +{ + static_cast<EB::Log*>(os.rdbuf())->set_log_level(log_priority); + return os; +} diff --git a/Online/EventBuilding/src/mdf_reader.cpp b/Online/EventBuilding/src/mdf_reader.cpp new file mode 100644 index 000000000..5dbc80c32 --- /dev/null +++ b/Online/EventBuilding/src/mdf_reader.cpp @@ -0,0 +1,105 @@ +#include "mdf_reader.hpp" +#include <system_error> + +EB::MDF_reader::MDF_reader(const char* file_name) +{ + _input_fd = open(file_name, O_RDONLY); + if (_input_fd < 0) { + throw std::system_error(errno, std::generic_category(), file_name); + } +} + +bool EB::MDF_reader::set_file(const char* file_name) +{ + close(_input_fd); + + _input_fd = open(file_name, O_RDONLY); + + return (_input_fd >= 0); +} + +int EB::MDF_reader::extract_event(EB::MDF_block& block) { return block.read_block(_input_fd); } + +int EB::MDF_reader::extract_event(EB::MDF_block& block, void* buffer, size_t size) +{ + // return block.read_block(input_fd, buffer, size); + // TODO implement this + return 0; +} + +int EB::MDF_reader::extract_events(std::vector<EB::MDF_block>& blocks, int n_events) +{ + int ret_val = 0; + blocks.reserve(blocks.size() + n_events); + for (int k = 0; (k < n_events) && (ret_val >= 0); k++) { + blocks.emplace_back(); + ret_val = extract_event(blocks.back()); + if (ret_val != 0) { + // if there is an error the last element of the blocks array is not valid so we remove it + blocks.pop_back(); + } + } + return ret_val; +} + +int EB::MDF_reader::extract_events(std::vector<EB::MDF_block>& blocks, int n_events, void* buffer, size_t size) +{ + int ret_val = 0; + blocks.reserve(blocks.size() + n_events); + for (int k = 0; (k < n_events) && (ret_val >= 0); k++) { + blocks.emplace_back(); + ret_val = extract_event(blocks.back(), buffer, size); + if (ret_val >= 0) { + // if the external buffer was provided the pointers must be moved and the size adjusted + size_t last_payload_size = blocks.back().payload_size(); + buffer = reinterpret_cast<char*>(buffer) + last_payload_size; + size -= last_payload_size; + ret_val += last_payload_size; + } else { + // if there is an error the last element of the blocks array is not valid so we remove it + blocks.pop_back(); + } + } + return ret_val; +} + +int EB::MDF_reader::extract_events(std::vector<EB::MDF_block>& blocks) +{ + int ret_val = 0; + bool stop = false; + while (!stop) { + blocks.emplace_back(); + ret_val = extract_event(blocks.back()); + if (ret_val >= 0) { + // if the external buffer was provided the pointers must be moved and the size adjusted + ret_val += blocks.back().payload_size(); + } else { + // if there is an error the last element of the blocks array is not valid so we remove it + blocks.pop_back(); + stop = true; + } + } + return ret_val; +} + +int EB::MDF_reader::extract_events(std::vector<EB::MDF_block>& blocks, void* buffer, size_t size) +{ + int ret_val = 0; + bool stop = false; + while (!stop) { + blocks.emplace_back(); + ret_val = extract_event(blocks.back(), buffer, size); + if (ret_val >= 0) { + // if the external buffer was provided the pointers must be moved and the size adjusted + size_t last_payload_size = blocks.back().payload_size(); + buffer = reinterpret_cast<char*>(buffer) + last_payload_size; + size -= last_payload_size; + ret_val += last_payload_size; + } else { + // if there is an error the last element of the blocks array is not valid so we remove it + blocks.pop_back(); + stop = true; + } + } + return ret_val; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/mdf_tools.cpp b/Online/EventBuilding/src/mdf_tools.cpp new file mode 100644 index 000000000..84d992b57 --- /dev/null +++ b/Online/EventBuilding/src/mdf_tools.cpp @@ -0,0 +1,95 @@ +#include "EventBuilding/mdf_tools.hpp" +EB::MDF_block::MDF_block() : Generic_block() {} +EB::MDF_block::MDF_block(int fd) : Generic_block() +{ + + int ret_val = read_block(fd); + if (ret_val < 0) { + throw std::system_error(-ret_val, std::generic_category(), "MDF_block"); + } +} + +EB::MDF_block::MDF_block(std::shared_ptr<char> payload, size_t size) : Generic_block(payload, size) { header = {0}; } + +EB::MDF_block::MDF_block(int fd, std::shared_ptr<char> payload, size_t size) : Generic_block(payload, size) +{ + int ret_val = read_block(fd); + if (ret_val < 0) { + throw std::system_error(-ret_val, std::generic_category(), "MDF_block"); + } +} + +void EB::MDF_header::print() const +{ + std::cout << "is valid " << generic.is_valid() << std::endl; + + std::cout << "size " << generic.size[0] << std::endl; + std::cout << "compression " << (generic.compression_information & 0xF) << std::endl; + std::cout << "run " << specific.run << std::endl; + std::cout << "bx id " << specific.bxid << std::endl; + std::cout << "data type " << (uint32_t) generic.data_type << std::endl; +} + +// TODO this should accomodate for header type variability +size_t EB::MDF_block::payload_size() const { return header.generic.size[0] - sizeof(header); } + +int EB::MDF_block::read_header(int fd) +{ + int ret_val = 0; + int n_bytes; + + n_bytes = read(fd, reinterpret_cast<char*>(&header), sizeof(header)); + + if (n_bytes != sizeof(header)) { + std::cerr << "end of file reached no more events" << std::endl; + ret_val = EOF; + } else if (!header.generic.is_valid()) { + ret_val = -EINVAL; + } + + return ret_val; +} + +int EB::MDF_block::read_block(int fd) +{ + int ret_val = 0; + int n_bytes; + + ret_val = read_header(fd); + + if (ret_val == 0) { + size_t payload_size = this->payload_size(); + + // allocating a new buffer and handling memory operations + bool realloc_ok = true; + if (_payload_alloc_size < payload_size) { + realloc_ok = realloc_payload(payload_size); + } + + if (realloc_ok) { + n_bytes = read(fd, _payload.get(), payload_size); + if (n_bytes != payload_size) { + std::cerr << "ERROR truncated file" << std::endl; + ret_val = -EINVAL; + } + } else { + ret_val = -ENOMEM; + } + } + return ret_val; +} + +int EB::MDF_block::read_block(int fd, std::shared_ptr<char> buffer, size_t buffer_size) +{ + set_payload(buffer, buffer_size); + + return read_block(fd); +} + +int EB::MDF_block::write_block(int fd) const +{ + write(fd, &header, sizeof(header)); + write(fd, _payload.get(), payload_size()); + + return 0; +} diff --git a/Online/EventBuilding/src/options.cpp b/Online/EventBuilding/src/options.cpp new file mode 100644 index 000000000..d7160e3bf --- /dev/null +++ b/Online/EventBuilding/src/options.cpp @@ -0,0 +1,220 @@ +#include "options.hpp" +#include <algorithm> +#include <iostream> +#include <iomanip> +#include <cstring> +#include <cstdlib> + +EB::Options::Options(int argc, char** argv) +{ + _argc = argc; + _argv = argv; + add_option("help", 'h', "Print this help and exit", false, [this](const char* arg) { + this->print_usage(); + exit(0); + }); +} + +EB::Options::~Options() +{ + for (auto& elem : _options) { + delete elem.name; + } +} + +// TODO add check for duplicated options + +void EB::Options::add_option( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + std::function<void(const char*)> user_funct, + bool has_args) +{ + // we need deep copy + char* long_name_copy = new char[long_name.size() + 1]; + long_name.copy(long_name_copy, long_name.size(), 0); + long_name_copy[long_name.size()] = '\0'; + _options.emplace_back(option{long_name_copy, has_args, NULL, short_name}); + _lambdas.emplace_back(user_funct); + + _short_names.emplace_back(short_name); + _required.emplace_back(is_required); + _help.emplace_back(help); + + _max_text_aling = std::max(_max_text_aling, strlen(long_name_copy)); +} + +template<> +void EB::Options::add_option<int>( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + int& out_var) +{ + auto funct = [&out_var](const char* arg) { out_var = atoi(arg); }; + + add_option(long_name, short_name, help, is_required, funct, true); +} + +template<> +void EB::Options::add_option<unsigned long int>( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + unsigned long int& out_var) +{ + // TODO add error checking + auto funct = [&out_var](const char* arg) { out_var = strtoul(arg, NULL, 0); }; + + add_option(long_name, short_name, help, is_required, funct, true); +} + +template<> +void EB::Options::add_option<double>( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + double& out_var) +{ + auto funct = [&out_var](const char* arg) { out_var = atof(arg); }; + + add_option(long_name, short_name, help, is_required, funct, true); +} + +template<> +void EB::Options::add_option<std::string>( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + std::string& out_var) +{ + auto funct = [&out_var](const char* arg) { out_var.assign(arg); }; + + add_option(long_name, short_name, help, is_required, funct, true); +} + +void EB::Options::add_flag( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + bool& out_flag) +{ + out_flag = false; + + auto funct = [&out_flag](const char* arg) { out_flag = true; }; + + add_option(long_name, short_name, help, is_required, funct, false); +} + +void EB::Options::add_counter( + const std::string& long_name, + char short_name, + const std::string& help, + bool is_required, + int& counter) +{ + counter = 0; + + auto funct = [&counter](const char* arg) { counter++; }; + + add_option(long_name, short_name, help, is_required, funct, false); +} + +bool EB::Options::parse_args() +{ + bool ret_val = true; + // the list must be null terminated + _options.emplace_back(option{0, 0, 0, 0}); + + auto short_options = build_short_options(); + + int index; + int c; + + std::vector<bool> required_not_set(_required); + + while ((c = getopt_long(_argc, _argv, short_options.c_str(), _options.data(), &index)) != -1) { + if (c == '?') { + // error in option parsing + ret_val = false; + } else { + if (c != 0) { + auto it = std::find(_short_names.begin(), _short_names.end(), c); + index = std::distance(_short_names.begin(), it); + } + apply_lambda(index); + + required_not_set[index] = false; + } + } + + // check if any required option is not set + for (size_t k = 0; k < required_not_set.size(); k++) { + if (required_not_set[k]) { + ret_val = false; + std::cerr << "error missing mandatory option" << std::endl; + print_option(k); + } + } + + return ret_val; +} + +std::string EB::Options::build_short_options() +{ + std::string ret_val; + + for (size_t k = 0; k < _short_names.size(); k++) { + ret_val += _short_names[k]; + if (_options[k].has_arg != 0) { + ret_val += ':'; + } + } + + return ret_val; +} + +void EB::Options::apply_lambda(int idx) { _lambdas[idx](optarg); } + +void EB::Options::print_usage() const +{ + std::cerr << "USAGE:" << std::endl; + std::cerr << _argv[0]; + for (size_t k = 0; k < _short_names.size(); k++) { + if (!_required[k]) { + std::cerr << " ["; + } + std::cerr << " -" << _short_names[k]; + if (_options[k].has_arg) { + std::cerr << " <" << _options[k].name << ">"; + } + if (!_required[k]) { + std::cerr << " ]"; + } + } + + std::cerr << std::endl; + for (size_t k = 0; k < _help.size(); k++) { + print_option(k); + } +} + +void EB::Options::print_option(int idx) const +{ + std::cerr << " -" << _short_names[idx] << " --" << _options[idx].name + << std::setw(_max_text_aling - strlen(_options[idx].name) + 2); + if (_options[idx].has_arg) { + // TODO align print properly + std::cerr << "<" << _options[idx].name << ">"; + } else { + std::cerr << " " << std::setw(_max_text_aling - strlen(_options[idx].name) + 2) << " "; + } + std::cerr << std::setw(_max_text_aling - strlen(_options[idx].name) + 2) << " " << _help[idx] << std::endl; +} \ No newline at end of file diff --git a/Online/EventBuilding/src/pcie40_reader.cpp b/Online/EventBuilding/src/pcie40_reader.cpp new file mode 100644 index 000000000..b417ec9f8 --- /dev/null +++ b/Online/EventBuilding/src/pcie40_reader.cpp @@ -0,0 +1,704 @@ +#include "pcie40_reader.hpp" +#include "EventBuilding/tools.hpp" +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <limits> +#include <cstdlib> +#include <system_error> + +EB::PCIe40_reader::PCIe40_reader() { init_internal_status(); } + +EB::PCIe40_reader::PCIe40_reader(int id, int stream, bool enable_MFP, int packing_factor) : PCIe40_reader() +{ + _stream = stream; + std::error_code err_val = open(id); + if (err_val) { + throw std::system_error(err_val, std::to_string(id)); + } + + if (enable_MFP) { + err_val = set_packing_factor(packing_factor); + if (err_val) { + throw std::system_error(err_val, std::to_string(id)); + } + + err_val = enable_MFP_stream(); + if (err_val) { + throw std::system_error(err_val, std::to_string(id)); + } + + } else { + err_val = disable_MFP_stream(); + if (err_val) { + throw std::system_error(err_val, std::to_string(id)); + } + } +} + +EB::PCIe40_reader::PCIe40_reader(const std::string& name, int stream, bool enable_MFP, int packing_factor) : + PCIe40_reader() +{ + _stream = stream; + std::error_code err_val = open(name); + if (err_val) { + throw std::system_error(err_val, name); + } + + if (enable_MFP) { + err_val = set_packing_factor(packing_factor); + if (err_val) { + throw std::system_error(err_val, name); + } + + err_val = enable_MFP_stream(); + if (err_val) { + throw std::system_error(err_val, name); + } + + } else { + err_val = disable_MFP_stream(); + if (err_val) { + throw std::system_error(err_val, name); + } + } +} + +EB::PCIe40_reader::~PCIe40_reader() { close(); } + +void EB::PCIe40_reader::init_internal_status() +{ + _stream = P40_DAQ_STREAM::P40_DAQ_STREAM_NULL; + _stream_fd = -1; + _id_fd = -1; + _ctrl_fd = -1; + _meta_fd = -1; + _buffer = NULL; + _buffer_size = 0; + _requested_size = 0; + _available_data = 0; + _name = "undefined_device"; +} + +EB::PCIe40_reader::PCIe40_reader(PCIe40_reader&& other) : + _buffer(other._buffer), _buffer_size(other._buffer_size), _internal_read_off(other._internal_read_off), + _device_read_off(other._device_read_off), _available_data(other._available_data), + _requested_size(other._requested_size), _stream(other._stream), _id_fd(other._id_fd), _stream_fd(other._stream_fd), + _ctrl_fd(other._ctrl_fd), _meta_fd(other._meta_fd), _name(std::move(other._name)), + PCIe40_alignment(other.PCIe40_alignment) +{ + // Reset internal status of the moved object + other.init_internal_status(); +} + +EB::PCIe40_reader& EB::PCIe40_reader::operator=(PCIe40_reader&& other) +{ + // protection against self move + if (this != &other) { + // Close currently open stream + close(); + + _buffer = other._buffer; + _buffer_size = other._buffer_size; + _internal_read_off = other._internal_read_off; + _device_read_off = other._device_read_off; + _available_data = other._available_data; + _requested_size = other._requested_size; + _stream = other._stream; + _id_fd = other._id_fd; + _stream_fd = other._stream_fd; + _ctrl_fd = other._ctrl_fd; + _meta_fd = other._meta_fd; + _name = std::move(other._name); + PCIe40_alignment = other.PCIe40_alignment; + + // Reset internal status of the moved object + other.init_internal_status(); + } + + return *this; +} + +std::error_code EB::PCIe40_reader::open(const std::string& name) +{ + std::error_code err_code{}; + int id = p40_id_find(name.c_str()); + if (id >= 0) { + err_code = open(id); + } else { + + err_code = PCIe40_errors::ID_FIND; + } + + return err_code; +} + +std::error_code EB::PCIe40_reader::open(int id) +{ + std::error_code err_code{}; + + if (is_open()) { + close(); + } + + _id_fd = p40_id_open(id); + + if (_id_fd < 0) { + err_code = PCIe40_errors::ID_OPEN; + close(); + return err_code; + } + + _meta_fd = p40_stream_open(id, P40_DAQ_STREAM_META); + if (_meta_fd < 0) { + err_code = PCIe40_errors::META_STREAM_OPEN; + close(); + return err_code; + } + + _stream_fd = p40_stream_open(id, static_cast<P40_DAQ_STREAM>(_stream)); + if (_stream_fd < 0) { + err_code = PCIe40_errors::STREAM_OPEN; + close(); + return err_code; + } + + int enabled = p40_stream_enabled(_stream_fd); + if (enabled < 0) { + err_code = PCIe40_errors::STREAM_GET_ENABLED; + close(); + return err_code; + } else if (enabled == 0) { + err_code = PCIe40_errors::STREAM_ENABLED; + close(); + return err_code; + } + + if (p40_stream_lock(_stream_fd) < 0) { + err_code = PCIe40_errors::STREAM_LOCK; + close(); + return err_code; + } + + ssize_t size = p40_stream_get_host_buf_bytes(_stream_fd); + if (size < 0) { + err_code = PCIe40_errors::STREAM_SIZE; + close(); + return err_code; + } + + _buffer_size = size; + _buffer = p40_stream_map(_stream_fd); + if (_buffer == NULL) { + err_code = PCIe40_errors::STREAM_MAP; + close(); + return err_code; + } + + _ctrl_fd = p40_ctrl_open(id); + if (_ctrl_fd < 0) { + err_code = PCIe40_errors::CTRL_STREAM_OPEN; + close(); + return err_code; + } + + err_code = update_device_ptr(); + if (err_code) { + close(); + return err_code; + } + + _internal_read_off = _device_read_off; + _requested_size = 0; + + // TODO check with Paolo if there is a constant defined somewhere + char name[16]; + + if (p40_id_get_name(_id_fd, name, sizeof(name)) != 0) { + err_code = PCIe40_errors::GET_NAME; + close(); + return err_code; + } + + _name = name; + + int vers_id = p40_id_get_source(_id_fd); + + _src_id = (vers_id & (src_num_mask | src_subsystem_mask)) >> src_num_shift; + _block_version = (vers_id & src_version_mask) >> src_version_shift; + + return err_code; +} + +std::error_code EB::PCIe40_reader::set_packing_factor(int packing_factor) +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + int ret_code = p40_stream_set_meta_packing(_stream_fd, packing_factor); + if (ret_code != 0) { + err_code = PCIe40_errors::SET_META_PACKING; + return err_code; + } + + return err_code; +} + +std::error_code EB::PCIe40_reader::enable_MFP_stream() +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + int ret_code = p40_stream_enable(_meta_fd); + if (ret_code != 0) { + err_code = PCIe40_errors::META_STREAM_ENABLE; + return err_code; + } + + return err_code; +} + +std::error_code EB::PCIe40_reader::disable_MFP_stream() +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + int ret_code = p40_stream_disable(_meta_fd); + if (ret_code != 0) { + err_code = PCIe40_errors::META_STREAM_DISABLE; + return err_code; + } + + return err_code; +} + +std::error_code EB::PCIe40_reader::reset() +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + // ret_val = p40_ctrl_reset_logic(_ctrl_fd); + int ret_code = p40_stream_reset_logic(_stream_fd); + if (ret_code != 0) { + err_code = PCIe40_errors::LOGIC_RESET; + return err_code; + } + + err_code = update_device_ptr(); + if (err_code) { + return err_code; + } + + _internal_read_off = _device_read_off; + _requested_size = 0; + update_usage(); + + return err_code; +} + +const std::string EB::PCIe40_reader::get_name() const { return _name; } + +void EB::PCIe40_reader::close() +{ + // Make sure that this function does not change errno, so it's easier to use in cleanups + int saved_errno = errno; + + if (_stream_fd >= 0) { + p40_stream_unlock(_stream_fd); + // No need to call p40_stream_unmap: p40_stream_close does it for us. + p40_stream_close(_stream_fd, _buffer); + } + if (_id_fd >= 0) { + p40_id_close(_id_fd); + } + if (_ctrl_fd >= 0) { + p40_ctrl_close(_ctrl_fd); + } + + if (_meta_fd >= 0) { + p40_stream_close(_meta_fd, NULL); + } + + init_internal_status(); + + errno = saved_errno; +} + +bool EB::PCIe40_reader::is_open() +{ + return (_id_fd >= 0) && (_stream_fd >= 0) && (_meta_fd >= 0) && (_ctrl_fd >= 0) && (_buffer != NULL); +} + +std::error_code EB::PCIe40_reader::update_device_ptr() +{ + std::error_code err_code; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + _device_read_off = p40_stream_get_host_buf_read_off(_stream_fd); + + if (_device_read_off < 0) { + err_code = PCIe40_errors::HOST_READ_OFF; + return err_code; + } + + return err_code; +} + +std::vector<std::tuple<void*, size_t>> EB::PCIe40_MFP_reader::get_full_buffer() +{ + std::vector<std::tuple<void*, size_t>> ret_val; + if (is_open()) { + // double the size because of the double mapping + ret_val.emplace_back(std::make_pair(_buffer, 2 * _buffer_size)); + } + + return ret_val; +} + +// TODO check if something special is needed for fragments +template<> +pcie40_hdr_frg_nometa* EB::PCIe40_reader::extract_element() +{ + pcie40_hdr_frg_nometa* ret_val = NULL; + if (!is_open()) { + throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + } + size_t size; + if (_available_data >= sizeof(pcie40_hdr_frg_nometa)) { + ret_val = reinterpret_cast<pcie40_hdr_frg_nometa*>(reinterpret_cast<uintptr_t>(_buffer) + _internal_read_off); + if (ret_val->ghdr.is_invalid()) { + throw std::error_code(PCIe40_errors::CORRUPTED_DATA); + } + + size = ret_val->bytes(); + size += ret_val->padding(); + + int err_code = update_read_off(size); + if (err_code != 0) { + // if the read offset can't be updated the data is not valid + ret_val = NULL; + } + } + + return ret_val; +} + +template<> +EB::MFP* EB::PCIe40_reader::extract_element() +{ + EB::MFP* ret_val = NULL; + if (!is_open()) { + throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + } + size_t size; + if (_available_data >= sizeof(EB::MFP)) { + ret_val = reinterpret_cast<EB::MFP*>(reinterpret_cast<uintptr_t>(_buffer) + _internal_read_off); + if (!ret_val->is_valid()) { + throw std::error_code(PCIe40_errors::CORRUPTED_DATA); + } + + size = ret_val->bytes(); + size += get_padding(size, 1 << PCIe40_alignment); + + int err_code = update_read_off(size); + if (err_code != 0) { + // if the read offset can't be updated the data is not valid + ret_val = NULL; + } + } + + return ret_val; +} + +int EB::PCIe40_reader::update_read_off(size_t size) +{ + int ret_val = 0; + if (_available_data < size) { + // The amount of data requested is more than the amount of data availabel in the buffer we can't update the read + // offset + ret_val = 1; + } else { + _internal_read_off += size; + _requested_size += size; + _available_data -= size; + // wrap around (the memory region is mapped two times contiguosly) + if (_internal_read_off > _buffer_size) { + _internal_read_off -= _buffer_size; + } + } + + return ret_val; +} + +void EB::PCIe40_reader::update_usage() +{ + _available_data = p40_stream_get_host_buf_bytes_used(_stream_fd); + _available_data -= _requested_size; +} + +void EB::PCIe40_reader::ack_read() +{ + if (!is_open()) { + throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + } + + if (p40_stream_free_host_buf_bytes(_stream_fd, _requested_size) < 0) { + throw std::error_code(PCIe40_errors::HOST_FREE_BUFF); + } + + std::error_code err_code = update_device_ptr(); + + if (err_code) { + throw err_code; + } + + _internal_read_off = _device_read_off; + _requested_size = 0; + update_usage(); +} + +void EB::PCIe40_reader::cancel_pending() +{ + // All the calls in this method are local and do not query the device + _internal_read_off = _device_read_off; + _available_data += _requested_size; + _requested_size = 0; +} + +EB::MFP* EB::PCIe40_MFP_reader::try_get_element() +{ + update_usage(); + return extract_element<EB::MFP>(); +} + +void EB::PCIe40_MFP_reader::read_complete() { ack_read(); } + +void EB::PCIe40_MFP_reader::flush() { reset(); } + +int EB::PCIe40_MFP_reader::get_src_id() const { return _src_id; } + +EB::PCIe40_MFP_reader::PCIe40_MFP_reader() : PCIe40_reader() {} + +EB::PCIe40_MFP_reader::PCIe40_MFP_reader(int id, int stream, int packing_factor) : + PCIe40_reader(id, stream, true, packing_factor) +{} + +EB::PCIe40_MFP_reader::PCIe40_MFP_reader(const std::string& name, int stream, int packing_factor) : + PCIe40_reader(name, stream, true, packing_factor) +{} + +EB::PCIe40_frag_reader::PCIe40_frag_reader() : _pcie40_reader(), _packing_factor(1) {} + +// TODO rename n_frag -> packing factor +EB::PCIe40_frag_reader::PCIe40_frag_reader( + int id, + size_t buffer_size, + int n_frags, + size_t buffer_alignment, + int stream) : + _pcie40_reader(id, stream, false) +{ + set_n_frags(n_frags); + Shared_ptr_buffer_backend buffer_reader_backend(buffer_size, buffer_alignment); + // TODO maybe there is a better way to copy this + Shared_ptr_buffer_backend buffer_writer_backend(buffer_reader_backend); + _internal_buffer_reader.reset_backend(std::move(buffer_reader_backend)); + _internal_buffer_writer.reset_backend(std::move(buffer_writer_backend)); +} + +EB::PCIe40_frag_reader::PCIe40_frag_reader( + const std::string& name, + size_t buffer_size, + int n_frags, + size_t buffer_alignment, + int stream) : + _pcie40_reader(name, stream, false) +{ + set_n_frags(n_frags); + Shared_ptr_buffer_backend buffer_reader_backend(buffer_size, buffer_alignment); + // TODO maybe there is a better way to copy this + Shared_ptr_buffer_backend buffer_writer_backend(buffer_reader_backend); + _internal_buffer_reader.reset_backend(std::move(buffer_reader_backend)); + _internal_buffer_writer.reset_backend(std::move(buffer_writer_backend)); +} + +void EB::PCIe40_frag_reader::set_n_frags(int n_frags) +{ + if ((n_frags > 0) && (n_frags <= std::numeric_limits<decltype(_packing_factor)>::max())) { + _packing_factor = n_frags; + _frag_list.reserve(_packing_factor); + _type_list.reserve(_packing_factor); + _size_list.reserve(_packing_factor); + } else { + throw std::error_code(PCIe40_errors::INVALID_PACKING_FACTOR); + } +} + +int EB::PCIe40_frag_reader::get_n_frags() const { return _packing_factor; } + +EB::MFP* EB::PCIe40_frag_reader::try_get_element() +{ + if (!_pcie40_reader.is_open()) { + throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + } + + _pcie40_reader.update_usage(); + + // all the fragments from the buffer are read and the MFPs are generated + // TODO check if the FPGA is no overwhelming us + if (!_flush_pending) { + scan_frag_list(); + } + + std::error_code mfp_err = build_MFP(); + if (mfp_err) { + if ((mfp_err == PCIe40_errors::INTERNAL_BUFFER_FULL) || (mfp_err == PCIe40_errors::INTERNAL_BUFFER_FULL_FLUSH)) { + return NULL; + } else { + throw mfp_err; + } + } + + // _pcie40_reader.ack_read(); + // _internal_buffer_writer.write_complete(); + + return _internal_buffer_reader.try_get_element(); +} + +void EB::PCIe40_frag_reader::scan_frag_list() +{ + if (!_pcie40_reader.is_open()) { + throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + } + + while (_frag_list.size() < _packing_factor) { + pcie40_hdr_frg_nometa* next_frag = _pcie40_reader.extract_element<pcie40_hdr_frg_nometa>(); + // no more data into the device buffer + if (next_frag == NULL) { + _flush = false; + break; + } else if (next_frag->flushed()) { + // The flush fragment is discarted + // The first flush ends this loop and triggers the generation of an end of run MFP, all the subsequent + // consecutive flushes are simply ignored + if (!_flush) { + _flush = true; + break; + } else { + continue; + } + } else { + // Valid data deassert the flush flag + _flush = false; + } + + // we strip off the fragment header + size_t header_offset = sizeof(next_frag->le_evid) + sizeof(next_frag->ghdr); + _frag_list.emplace_back(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(next_frag) + header_offset)); + _size_list.emplace_back(next_frag->bytes() - header_offset); + _type_list.emplace_back(next_frag->ghdr.type()); + _total_size += _size_list.back() + get_padding(_size_list.back(), 1 << _align); + // we store only the first ev_id + if (_frag_list.size() == 1) { + _ev_id = next_frag->evid(); + _version = next_frag->ghdr.version(); + } + } +} + +std::error_code EB::PCIe40_frag_reader::build_MFP() +{ + std::error_code err_val{}; + + // TODO check how the flushed events should be handled + if ((_frag_list.size() == _packing_factor) || _flush) { + // If the buffer was full when writing flush the frag list is empty and no MFP should be generated + if (_frag_list.size() > 0) { + // TODO remove the padding for the last element + size_t MFP_size = + // EB::MFP_header_size(_frag_list.size(), 1 << _align) + _total_size - get_padding(_size_list.back(), 1 << + // _align); + EB::MFP_header_size(_frag_list.size()) + _total_size; + EB::MFP* new_MFP = _internal_buffer_writer.try_write_next_element(MFP_size); + if (new_MFP != NULL) { + new_MFP->set_header_valid(); + new_MFP->header.n_banks = _frag_list.size(); + new_MFP->header.packet_size = MFP_size; + new_MFP->header.ev_id = _ev_id; + new_MFP->header.src_id = _pcie40_reader._src_id; + new_MFP->header.align = _align; + new_MFP->header.block_version = _version; + + std::memcpy(new_MFP->header.bank_types(), _type_list.data(), _type_list.size() * sizeof(_type_list.front())); + std::memcpy(new_MFP->header.bank_sizes(), _size_list.data(), _size_list.size() * sizeof(_size_list.front())); + // copy the list of fragments + EB::MFP::iterator MFP_it = new_MFP->begin(); + for (int index = 0; index < _frag_list.size(); index++) { + std::memcpy(reinterpret_cast<void*>(&(*MFP_it)), _frag_list[index], _size_list[index]); + MFP_it++; + } + + // the last fragment has no padding + // std::memcpy(reinterpret_cast<void*>(&(*MFP_it)), _frag_list.back(), _size_list.back()); + + _internal_buffer_writer.write_complete(); + _pcie40_reader.ack_read(); + _frag_list.clear(); + _type_list.clear(); + _size_list.clear(); + _total_size = 0; + } else { + err_val = PCIe40_errors::INTERNAL_BUFFER_FULL; + return err_val; + } + } + + if (_flush) { + size_t MFP_size = EB::MFP_header_size(0); + EB::MFP* new_MFP = _internal_buffer_writer.try_write_next_element(MFP_size); + if (new_MFP != NULL) { + _flush_pending = false; + new_MFP->set_end_run(); + new_MFP->header.packet_size = MFP_size; + _internal_buffer_writer.write_complete(); + } else { + _flush_pending = true; + err_val = PCIe40_errors::INTERNAL_BUFFER_FULL_FLUSH; + return err_val; + } + } + } + + return err_val; +} + +void EB::PCIe40_frag_reader::read_complete() { _internal_buffer_reader.read_complete(); } + +void EB::PCIe40_frag_reader::flush() +{ + // TODO check retrun value of reset + _pcie40_reader.reset(); + _internal_buffer_reader.flush(); +} + +int EB::PCIe40_frag_reader::get_src_id() const { return _pcie40_reader._src_id; } + +std::vector<std::tuple<void*, size_t>> EB::PCIe40_frag_reader::get_full_buffer() +{ + return _internal_buffer_reader.get_full_buffer(); +} \ No newline at end of file diff --git a/Online/EventBuilding/src/pcie40_reader_error.cpp b/Online/EventBuilding/src/pcie40_reader_error.cpp new file mode 100644 index 000000000..8b271c3ec --- /dev/null +++ b/Online/EventBuilding/src/pcie40_reader_error.cpp @@ -0,0 +1,44 @@ +#include "pcie40_reader_error.hpp" + +// Error category definition +namespace { + struct PCIe40_error_category : std::error_category { + const char* name() const noexcept override; + std::string message(int ev) const override; + }; + + const char* PCIe40_error_category::name() const noexcept { return "PCIe40_reader"; } + std::string PCIe40_error_category::message(int ev) const + { + switch (static_cast<EB::PCIe40_errors>(ev)) { + case EB::PCIe40_errors::ID_OPEN: return "Unable to open the device"; + case EB::PCIe40_errors::ID_FIND: return "Unable to find device name"; + case EB::PCIe40_errors::STREAM_OPEN: return "Unable to open the main stream"; + case EB::PCIe40_errors::META_STREAM_OPEN: return "Unable to open the meta stream"; + case EB::PCIe40_errors::META_STREAM_ENABLE: return "Unable to enable the meta stream"; + case EB::PCIe40_errors::META_STREAM_DISABLE: return "Unable to disable the meta stream"; + case EB::PCIe40_errors::CTRL_STREAM_OPEN: return "Unable to open the control stream"; + case EB::PCIe40_errors::STREAM_GET_ENABLED: return "Failed to get main stream status"; + case EB::PCIe40_errors::STREAM_ENABLED: return "Main stream disabled"; + case EB::PCIe40_errors::STREAM_LOCK: return "Unable to lock the main stream"; + case EB::PCIe40_errors::STREAM_SIZE: return "Unable to get the stream size"; + case EB::PCIe40_errors::STREAM_MAP: return "Unable to map the stream"; + case EB::PCIe40_errors::HOST_READ_OFF: return "Unable to read the host read offset"; + case EB::PCIe40_errors::HOST_FREE_BUFF: return "Unable to free buffer space"; + case EB::PCIe40_errors::GET_NAME: return "Unable to get device name"; + case EB::PCIe40_errors::DEVICE_NOT_OPEN: return "Requesting access on a not open device"; + case EB::PCIe40_errors::SET_META_PACKING: return "Unable to set the packing factor"; + case EB::PCIe40_errors::LOGIC_RESET: return "Unable to perform a logic reset"; + case EB::PCIe40_errors::CORRUPTED_DATA: return "Corrupted data in the stream"; + case EB::PCIe40_errors::INVALID_PACKING_FACTOR: return "Invalid packing factor"; + case EB::PCIe40_errors::INTERNAL_BUFFER_FULL: return "Internal buffer full on data write"; + case EB::PCIe40_errors::INTERNAL_BUFFER_FULL_FLUSH: return "Internal buffer full on flush"; + default: return "Undefined error"; + } + } + + const PCIe40_error_category the_PCIe40_error_category{}; + +} // namespace + +std::error_code EB::make_error_code(EB::PCIe40_errors e) { return {static_cast<int>(e), the_PCIe40_error_category}; } \ No newline at end of file diff --git a/Online/EventBuilding/src/raw_tools.cpp b/Online/EventBuilding/src/raw_tools.cpp new file mode 100644 index 000000000..cddb623ff --- /dev/null +++ b/Online/EventBuilding/src/raw_tools.cpp @@ -0,0 +1,141 @@ +#include "EventBuilding/raw_tools.hpp" +#include "EventBuilding/tools.hpp" +// TODO check why this file breaks linking if include in header file +#include <lhcb/daq40/sourceid.h> + +EB::raw_block::raw_block() : Generic_block() { header = {}; } + +EB::raw_block::raw_block(std::shared_ptr<char> payload, size_t size) : Generic_block(payload, size) { header = {}; } + +std::ostream& EB::raw_header::print(std::ostream& os) const +{ + os << "------RAW HEADER------" << std::endl; + os << "magic: " << (magic == EB::block_magic ? "OK" : "NOT OK") << std::endl; + os << "size: " << size << std::endl; + os << "type: " << BankType(type) << std::endl; + os << "version: " << (uint) version << std::endl; + os << "source id: " << src_id << std::endl; + return os; +} + +std::ostream& EB::operator<<(std::ostream& os, const EB::raw_header& header) { return header.print(os); } + +// size_t EB::raw_header::real_size() const { return size + size % raw::block_alignment; } +size_t EB::raw_header::mem_size() const { return size + get_padding(size, EB::block_alignment); } + +size_t EB::raw_header::payload_mem_size() const { return mem_size() - sizeof(this); } + +size_t EB::raw_header::payload_size() const { return size - sizeof(this); } + +int EB::raw_header::get_sys_src_id() const { return SourceId_sys(src_id); } +int EB::raw_header::get_src_id_num() const { return SourceId_num(src_id); } + +void EB::raw_header::set_sys_src_id(uint16_t sys_src_id) { src_id = (sys_src_id << 11) | (src_id & 0x1F); } +void EB::raw_header::set_src_id_num(uint16_t src_id_num) { src_id = (src_id & 0xF800) | (src_id_num & 0x7FF); } + +const std::string EB::ToString(const BankType b_type) +{ + switch (b_type) { + case L0Calo: return "L0Calo"; + case L0DU: return "L0DU"; + case PrsE: return "PrsE"; + case EcalE: return "EcalE"; + case HcalE: return "HcalE"; + case PrsTrig: return "PrsTrig"; + case EcalTrig: return "EcalTrig"; + case HcalTrig: return "HcalTrig"; + case Velo: return "Velo"; + case Rich: return "Rich"; + case TT: return "TT"; + case IT: return "IT"; + case OT: return "OT"; + case Muon: return "Muon"; + case L0PU: return "L0PU"; + case DAQ: return "DAQ"; + case ODIN: return "ODIN"; + case HltDecReports: return "HltDecReports"; + case VeloFull: return "VeloFull"; + case TTFull: return "TTFull"; + case ITFull: return "ITFull"; + case EcalPacked: return "EcalPacked"; + case HcalPacked: return "HcalPacked"; + case PrsPacked: return "PrsPacked"; + case L0Muon: return "L0Muon"; + case ITError: return "ITError"; + case TTError: return "TTError"; + case ITPedestal: return "ITPedestal"; + case TTPedestal: return "TTPedestal"; + case VeloError: return "VeloError"; + case VeloPedestal: return "VeloPedestal"; + case VeloProcFull: return "VeloProcFull"; + case OTRaw: return "OTRaw"; + case OTError: return "OTError"; + case EcalPackedError: return "EcalPackedError"; + case HcalPackedError: return "HcalPackedError"; + case PrsPackedError: return "PrsPackedError"; + case L0CaloFull: return "L0CaloFull"; + case L0CaloError: return "L0CaloError"; + case L0MuonCtrlAll: return "L0MuonCtrlAll"; + case L0MuonProcCand: return "L0MuonProcCand"; + case L0MuonProcData: return "L0MuonProcData"; + case L0MuonRaw: return "L0MuonRaw"; + case L0MuonError: return "L0MuonError"; + case GaudiSerialize: return "GaudiSerialize"; + case GaudiHeader: return "GaudiHeader"; + case TTProcFull: return "TTProcFull"; + case ITProcFull: return "ITProcFull"; + case TAEHeader: return "TAEHeader"; + case MuonFull: return "MuonFull"; + case MuonError: return "MuonError"; + case TestDet: return "TestDet"; + case L0DUError: return "L0DUError"; + case HltRoutingBits: return "HltRoutingBits"; + case HltSelReports: return "HltSelReports"; + case HltVertexReports: return "HltVertexReports"; + case HltLumiSummary: return "HltLumiSummary"; + case L0PUFull: return "L0PUFull"; + case L0PUError: return "L0PUError"; + case DstBank: return "DstBank"; + case DstData: return "DstData"; + case DstAddress: return "DstAddress"; + case FileID: return "FileID"; + case VP: return "VP"; + case FTCluster: return "FTCluster"; + case VL: return "VL"; + case UT: return "UT"; + case UTFull: return "UTFull"; + case UTError: return "UTError"; + case UTPedestal: return "UTPedestal"; + case HC: return "HC"; + case HltTrackReports: return "HltTrackReports"; + case HCError: return "HCError"; + case VPRetinaCluster: return "VPRetinaCluster"; + case LastType: return "LastType"; + default: return "Undefined Type"; + } +} + +std::ostream& EB::operator<<(std::ostream& os, const BankType b_type) { return os << ToString(b_type); } + +uint16_t EB::type_to_partition_id(const BankType b_type) +{ + switch (b_type) { + case VP: return SourceIdSys_VELO_A; + case FTCluster: return SourceIdSys_SCIFI_A; + case UT: return SourceIdSys_UT_A; + case Muon: return SourceIdSys_MUON_A; + case EcalPacked: return SourceIdSys_ECAL; + case HcalPacked: return SourceIdSys_HCAL; + case Rich: return SourceIdSys_RICH_1; + case ODIN: return SourceIdSys_ODIN; + // TODO probably TDET is not a good default value + default: return SourceIdSys_TDET; + } +} + +EB::type_id_pair_type EB::new_src_id_to_old(uint16_t src_id) { return std::make_pair(EB::BankType::UT, src_id); } + +uint16_t EB::old_to_new(EB::type_id_pair_type src_id_type) +{ + return (type_to_partition_id(static_cast<BankType>(src_id_type.first)) << 11) | (src_id_type.second & 0x7FF); +} diff --git a/Online/EventBuilding/src/shared_mem_buffer_backend.cpp b/Online/EventBuilding/src/shared_mem_buffer_backend.cpp new file mode 100644 index 000000000..baf525dd0 --- /dev/null +++ b/Online/EventBuilding/src/shared_mem_buffer_backend.cpp @@ -0,0 +1,407 @@ +#include "shared_mem_buffer_backend.hpp" +#include <cstdlib> +#include <sstream> +#include <stdexcept> +#include "EventBuilding/tools.hpp" +#include <unistd.h> +#include <fcntl.h> /* For O_* constants */ +#include <sys/mman.h> +#include <cstring> +#include <sstream> +#include <string> +#include <memory> +#include <iostream> +#include <tuple> +#include <cerrno> +#include <cstring> + +EB::Shared_mem_buffer_backend::Shared_mem_buffer_backend() : + _buffer(0), _remote_buffer_status(nullptr), _local_buffer_status(), _shmem_name(""), _shmem_fd(-1), _is_writer(false), + _allow_unlink(false), _reader_lock_name(""), _reader_lock_fd(-1), _writer_lock_name(""), _writer_lock_fd(-1) +{} + +EB::Shared_mem_buffer_backend::Shared_mem_buffer_backend(Shared_mem_buffer_backend&& other) : + _buffer(other._buffer), _remote_buffer_status(other._remote_buffer_status), + _local_buffer_status(std::move(other._local_buffer_status)), _shmem_name(std::move(other._shmem_name)), + _shmem_fd(other._shmem_fd), _is_writer(other._is_writer), _allow_unlink(other._allow_unlink), + _shm_area(std::move(other._shm_area)), _reader_lock_name(std::move(other._reader_lock_name)), + _reader_lock_fd(other._reader_lock_fd), _writer_lock_name(std::move(other._writer_lock_name)), + _writer_lock_fd(other._writer_lock_fd) +{ + // put the class into a safe state + other._buffer = 0; + other._shmem_name = ""; + other._reader_lock_name = ""; + other._writer_lock_name = ""; + other._reader_lock_fd = -1; + other._writer_lock_fd = -1; + other._remote_buffer_status = nullptr; +} + +EB::Shared_mem_buffer_backend::Shared_mem_buffer_backend( + const std::string& name, + bool is_writer, + bool allow_reconnect, + bool allow_unlink, + size_t size, + size_t alignment, + int id, + int numa_node) : + _shmem_name(name), + _is_writer(is_writer), _allow_unlink(allow_unlink) +{ + if (!is_writer) { + try { + open_shmem(); + try_lock_reader(); + shm_map(); + } catch (...) { + clean_up(); + throw; + } + } else { + if (allow_reconnect) { + try { + open_shmem(); + try_lock_writer(); + shm_map(); + } catch (...) { + clean_up(); + // clean up resets the _shmem_name + _shmem_name.assign(name); + } + } + try { + create_locks(); + try_lock_writer(); + try_lock_reader(); + create_shmem(); + init_buffer(size, alignment, id); + release_reader(); + shm_map(numa_node); + } catch (...) { + clean_up(); + throw; + } + } +} + +EB::Shared_mem_buffer_backend& EB::Shared_mem_buffer_backend::operator=(Shared_mem_buffer_backend&& other) +{ + this->clean_up(); + _buffer = other._buffer; + _remote_buffer_status = other._remote_buffer_status; + _local_buffer_status = std::move(other._local_buffer_status); + _shmem_name = std::move(other._shmem_name); + _shmem_fd = other._shmem_fd; + _is_writer = other._is_writer; + _allow_unlink = other._allow_unlink; + _shm_area = std::move(other._shm_area); + _reader_lock_name = std::move(other._reader_lock_name); + _reader_lock_fd = other._reader_lock_fd; + _writer_lock_name = std::move(other._writer_lock_name); + _writer_lock_fd = other._writer_lock_fd; + + // put the class into a safe state + other._buffer = 0; + other._shmem_name = ""; + other._reader_lock_name = ""; + other._writer_lock_name = ""; + other._reader_lock_fd = -1; + other._writer_lock_fd = -1; + other._remote_buffer_status = nullptr; + + return *this; +} + +EB::Shared_mem_buffer_backend::~Shared_mem_buffer_backend() { clean_up(); } + +std::tuple<void*, size_t> EB::Shared_mem_buffer_backend::get_buffer() +{ + return std::make_tuple(reinterpret_cast<void*>(_buffer), _local_buffer_status.size); +} + +bool EB::Shared_mem_buffer_backend::is_set() { return (_buffer != 0) && (_remote_buffer_status != nullptr); } + +void EB::Shared_mem_buffer_backend::create_locks() +{ + _reader_lock_name = "/tmp/"; + _reader_lock_name += _shmem_name; + _reader_lock_name += "_reader.lock"; + + _writer_lock_name = "/tmp/"; + _writer_lock_name += _shmem_name; + _writer_lock_name += "_writer.lock"; + + auto old_mask = umask(~permission_mask); + _reader_lock_fd = open(_reader_lock_name.c_str(), O_CREAT | O_RDWR, permission_mask); + umask(old_mask); + + if (_reader_lock_fd < 0) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " read lock open on shmem" << _shmem_name << ": " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + old_mask = umask(~permission_mask); + _writer_lock_fd = open(_writer_lock_name.c_str(), O_CREAT | O_RDWR, permission_mask); + umask(old_mask); + + if (_writer_lock_fd < 0) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " write lock open on shmem" << _shmem_name << ": " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +void EB::Shared_mem_buffer_backend::init_buffer(size_t size, size_t alignment, int id) +{ + // the max alignment size will be one page, because the memory mapped address is always page aligned it is not + // possible to align to something bigger than a page, unless some offset is used + // TODO investigate HUGE_PAGES + + long page_size = sysconf(_SC_PAGE_SIZE); + + if (1 << alignment > page_size) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " ERROR alignment > page size on shmem " << _shmem_name + << " alignment: " << (1 << alignment) << " page size: " << page_size; + throw std::invalid_argument(err_mess.str()); + } + + this->_local_buffer_status.read_stat = 0; + this->_local_buffer_status.write_stat = 0; + this->_local_buffer_status.set_read_ptr(0); + this->_local_buffer_status.set_write_ptr(0); + + this->_local_buffer_status.id = id; + + this->_local_buffer_status.size = size; + this->_local_buffer_status.alignment = alignment; + + // mmapped memory is always page aligned + + size_t buffer_start = sizeof(Circular_buffer_status) + get_padding(sizeof(Circular_buffer_status), 1 << alignment); + + if ( + write(this->_shmem_fd, &(this->_local_buffer_status), sizeof(this->_local_buffer_status)) != + sizeof(Circular_buffer_status)) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " ERROR write to shmem failed " << this->_shmem_name; + throw std::runtime_error(err_mess.str()); + } + + if (lseek(this->_shmem_fd, 0, SEEK_SET) == -1) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " lseek: " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + if (ftruncate(this->_shmem_fd, buffer_start + size) == -1) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " ftruncate: " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + asm volatile("mfence" ::: "memory"); +} + +void EB::Shared_mem_buffer_backend::create_shmem() +{ + // int ret_val = 0; + + auto old_mask = umask(~permission_mask); + int fd = shm_open(_shmem_name.c_str(), O_CREAT | O_RDWR, permission_mask); + umask(old_mask); + + if (fd < 0) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " create_shmem: " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + _shmem_fd = fd; +} + +void EB::Shared_mem_buffer_backend::open_shmem() +{ + int fd = shm_open(_shmem_name.c_str(), O_RDWR, 0); + if (fd < 0) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " shm_open " << _shmem_name << " : " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + _shmem_fd = fd; + + _reader_lock_name = "/tmp/"; + _reader_lock_name += _shmem_name; + _reader_lock_name += "_reader.lock"; + + _writer_lock_name = "/tmp/"; + _writer_lock_name += _shmem_name; + _writer_lock_name += "_writer.lock"; + + _reader_lock_fd = open(_reader_lock_name.c_str(), O_RDWR); + + if (_reader_lock_fd < 0) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " read lock open on shmem" << _shmem_name << ": " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + _writer_lock_fd = open(_writer_lock_name.c_str(), O_RDWR); + + if (_writer_lock_fd < 0) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " write lock open on shmem" << _shmem_name << ": " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +void EB::Shared_mem_buffer_backend::shm_map(int numa_node) +{ + struct stat shmem_stat; + + if (fstat(_shmem_fd, &shmem_stat) == -1) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " fstat: " << strerror(errno) << std::endl; + throw std::runtime_error(err_mess.str()); + } + + if (shmem_stat.st_size < sizeof(Circular_buffer_status)) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " Shmem region " << _shmem_name + << " too small to contain valid metadata"; + throw std::runtime_error(err_mess.str()); + } + + size_t read_size = read(_shmem_fd, &(_local_buffer_status), sizeof(Circular_buffer_status)); + lseek(_shmem_fd, 0, SEEK_SET); + + if (read_size != sizeof(Circular_buffer_status)) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " ERROR: unable to read buffer status from shmem " << _shmem_name + << " read " << read_size << "/" << sizeof(Circular_buffer_status) << " B" << std::endl; + throw std::runtime_error(err_mess.str()); + } + + uintptr_t buffer_offset = + sizeof(Circular_buffer_status) + get_padding(sizeof(Circular_buffer_status), 1 << _local_buffer_status.alignment); + size_t shmem_size = buffer_offset + _local_buffer_status.size; + + if (shmem_stat.st_size != shmem_size) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " ERROR shmem data corrupted expected shmem file size " << shmem_size + << " actual size " << shmem_stat.st_size << std::endl; + throw std::runtime_error(err_mess.str()); + } + + _shm_area = std::move( + shmem_ptr_type(mmap(NULL, shmem_size, PROT_READ | PROT_WRITE, MAP_SHARED, _shmem_fd, 0), [shmem_size](void* ptr) { + munmap(ptr, shmem_size); + })); + + if (_shm_area.get() == MAP_FAILED) { + std::ostringstream err_mess; + err_mess << __FILE__ << ":" << __LINE__ << " mmap: " << strerror(errno) << std::endl; + throw std::runtime_error(err_mess.str()); + } + + if (numa_node != -1) { + numa_tonode_memory(_shm_area.get(), shmem_size, numa_node); + } + + _remote_buffer_status = reinterpret_cast<Circular_buffer_status*>(_shm_area.get()); + + _buffer = reinterpret_cast<uintptr_t>(_shm_area.get()) + buffer_offset; + +#ifdef DEBUG + std::cout << "mapping shmem " << _shmem_name << " on fd " << _shmem_fd << std::endl; + std::cout << "map ptr " << map_ptr << std::endl; + std::cout << "buffer " << (void*) (_buffer) << std::endl; + std::cout << "size " << (void*) (_local_buffer_status.size) << std::endl; + std::cout << "alignment " << (1 << _local_buffer_status.alignment) << std::endl; + std::cout << "read status " << (void*) (_local_buffer_status.read_stat) << std::endl; + std::cout << "write status " << (void*) (_local_buffer_status.write_stat) << std::endl; +#endif // DEBUG +} + +bool EB::Shared_mem_buffer_backend::is_open() +{ + return (_shmem_fd >= 0) && (_reader_lock_fd >= 0) && (_writer_lock_fd >= 0); +} + +void EB::Shared_mem_buffer_backend::try_lock_reader() +{ + if (lockf(_reader_lock_fd, F_TLOCK, 0) != 0) { + std::ostringstream err_mess; + err_mess << "EB::Shared_mem_buffer_backend: Unable to lock read " << _shmem_name << " " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +void EB::Shared_mem_buffer_backend::release_reader() +{ + if (lockf(_reader_lock_fd, F_ULOCK, 0) != 0) { + std::ostringstream err_mess; + err_mess << "EB::Shared_mem_buffer_backend: Unable to release read " << _shmem_name << " " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +void EB::Shared_mem_buffer_backend::try_lock_writer() +{ + if (lockf(_writer_lock_fd, F_TLOCK, 0) != 0) { + std::ostringstream err_mess; + err_mess << "EB::Shared_mem_buffer_backend: Unable to lock write " << _shmem_name << " " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +void EB::Shared_mem_buffer_backend::release_writer() +{ + if (lockf(_writer_lock_fd, F_ULOCK, 0) != 0) { + std::ostringstream err_mess; + err_mess << "EB::Shared_mem_buffer_backend: Unable to release write " << _shmem_name << " " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } +} + +void EB::Shared_mem_buffer_backend::close_fd(int& fd) +{ + if (fd >= 0) { + close(fd); + } + + fd = -1; +} + +void EB::Shared_mem_buffer_backend::clean_up() +{ + // no exceptions + try { + auto save_errno = errno; + release_reader(); + release_writer(); + + close_fd(_reader_lock_fd); + close_fd(_writer_lock_fd); + close_fd(_shmem_fd); + + if (_allow_unlink) { + unlink(_reader_lock_name.c_str()); + unlink(_writer_lock_name.c_str()); + shm_unlink(_shmem_name.c_str()); + } + + _reader_lock_name.assign(""); + _writer_lock_name.assign(""); + _shmem_name.assign(""); + + _buffer = 0; + _remote_buffer_status = NULL; + + errno = save_errno; + } catch (...) { + } +} \ No newline at end of file diff --git a/Online/EventBuilding/src/shared_ptr_buffer_backend.cpp b/Online/EventBuilding/src/shared_ptr_buffer_backend.cpp new file mode 100644 index 000000000..87bbf6488 --- /dev/null +++ b/Online/EventBuilding/src/shared_ptr_buffer_backend.cpp @@ -0,0 +1,31 @@ +#include "shared_ptr_buffer_backend.hpp" +#include <cstdlib> +#include <sstream> + +EB::Shared_ptr_buffer_backend::Shared_ptr_buffer_backend(size_t size, size_t alignment, int id, int numa_node) : + _remote_buffer_status(new Circular_buffer_status(size, alignment, id)), _local_buffer_status(size, alignment, id), + _buffer_ptr(aligned_alloc(1 << alignment, size), [](auto p) { free(p); }) +{ + if (_buffer_ptr.get() == NULL) { + throw std::bad_alloc{}; + } + + if (numa_node != -1) { + numa_tonode_memory(_buffer_ptr.get(), size, numa_node); + } + + _buffer = reinterpret_cast<uintptr_t>(_buffer_ptr.get()); +} + +EB::Shared_ptr_buffer_backend::~Shared_ptr_buffer_backend() {} + +std::tuple<void*, size_t> EB::Shared_ptr_buffer_backend::get_buffer() +{ + return std::make_tuple(_buffer_ptr.get(), _local_buffer_status.size); +} + +bool EB::Shared_ptr_buffer_backend::is_set() +{ + return (_remote_buffer_status.get() != NULL) && (_remote_buffer_status.use_count() != 0) && + (_buffer_ptr.get() != NULL) && (_buffer_ptr.use_count() != 0); +} \ No newline at end of file diff --git a/Online/EventBuilding/src/timer.cpp b/Online/EventBuilding/src/timer.cpp new file mode 100644 index 000000000..65d0e28bd --- /dev/null +++ b/Online/EventBuilding/src/timer.cpp @@ -0,0 +1,75 @@ +#include "timer.hpp" +#include "EventBuilding/tools.hpp" +#include <stdexcept> +#include <cstring> + +EB::Timer::Timer(clockid_t clk_id) +{ + _clock_id = clk_id; + reset(); + _is_running = false; + _is_enabled = true; +} + +clockid_t EB::Timer::get_clk_id() const { return _clock_id; } + +void EB::Timer::set_clk_id(clockid_t clk_id) +{ + _clock_id = clk_id; + reset(); +} + +void EB::Timer::start() +{ + if (_is_enabled) { + _is_running = true; + int error = clock_gettime(_clock_id, &_start_time); + if (error != 0) { + throw std::runtime_error(strerror(error)); + } + } +} + +void EB::Timer::stop() +{ + if (_is_enabled) { + _elapsed_time = get_elapsed_time_ns(); + _is_running = false; + } +} + +void EB::Timer::reset() +{ + if (_is_enabled) { + int error = clock_gettime(_clock_id, &_start_time); + if (error != 0) { + throw std::runtime_error(strerror(error)); + } + + _elapsed_time = 0; + } +} + +clock_t EB::Timer::get_elapsed_time_ns() const +{ + clock_t ret_val = 0; + if (_is_enabled) { + ret_val = _elapsed_time; + if (_is_running) { + timespec stop_time; + int error = clock_gettime(_clock_id, &stop_time); + if (error != 0) { + throw std::runtime_error(strerror(error)); + } + + ret_val += timespec_diff_ns(stop_time, _start_time); + } + } + return ret_val; +} + +double EB::Timer::get_elapsed_time_s() const { return get_elapsed_time_ns() / 1.e9; } + +void EB::Timer::disable() { _is_enabled = false; } +void EB::Timer::enable() { _is_enabled = true; } +bool EB::Timer::is_enabled() { return _is_enabled; } \ No newline at end of file diff --git a/Online/EventBuilding/src/tools.cpp b/Online/EventBuilding/src/tools.cpp new file mode 100644 index 000000000..8a619b550 --- /dev/null +++ b/Online/EventBuilding/src/tools.cpp @@ -0,0 +1,185 @@ +#include "EventBuilding/tools.hpp" +#include <ctime> +#include <iostream> +#include <unistd.h> +#include <string> +#include <cstring> +#include <iostream> +#include <sstream> +#include <errno.h> +#include <algorithm> +#include <cctype> + +timespec EB::timespec_diff(timespec lhs, timespec rhs) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (lhs.tv_nsec < rhs.tv_nsec) { + int nsec = (rhs.tv_nsec - lhs.tv_nsec) / 1000000000UL + 1; + rhs.tv_nsec -= 1000000000UL * nsec; + rhs.tv_sec += nsec; + } + + if (lhs.tv_nsec - rhs.tv_nsec > 1000000000UL) { + int nsec = (lhs.tv_nsec - rhs.tv_nsec) / 1000000000UL; + rhs.tv_nsec += 1000000000UL * nsec; + rhs.tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + tv_nsec is certainly positive. */ + lhs.tv_sec -= rhs.tv_sec; + lhs.tv_nsec -= rhs.tv_nsec; + + return lhs; +} + +timespec EB::timespec_plus(timespec lhs, timespec rhs) +{ + if (lhs.tv_nsec + rhs.tv_nsec > 1000000000UL) { + int nsec = (lhs.tv_nsec + rhs.tv_nsec) / 1000000000UL; + rhs.tv_nsec -= 1000000000UL * nsec; + rhs.tv_sec += nsec; + } + + lhs.tv_sec += rhs.tv_sec; + lhs.tv_nsec += rhs.tv_nsec; + + return lhs; +} + +clock_t EB::timespec_to_ns(const timespec& lhs) { return lhs.tv_sec * 1000000000L + lhs.tv_nsec; } + +clock_t EB::timespec_diff_ns(const timespec& lhs, const timespec& rhs) +{ + return timespec_to_ns(lhs) - timespec_to_ns(rhs); +} + +clock_t EB::timespec_plus_ns(const timespec& lhs, const timespec& rhs) +{ + return timespec_to_ns(lhs) + timespec_to_ns(rhs); +} + +std::vector<std::string> EB::str_split(const std::string& string, const std::string& delim) +{ + std::vector<std::string> ret_val; + std::string tmp_string = string; + size_t pos = 0; + std::string token; + + while ((pos = tmp_string.find(delim)) != std::string::npos) { + token = tmp_string.substr(0, pos); + ret_val.emplace_back(token); + tmp_string.erase(0, pos + delim.length()); + } + ret_val.emplace_back(tmp_string); + + return ret_val; +} + +// TODO do a better implementation of this +int EB::string_icompare(const std::string& lhs, const std::string& rhs) +{ + std::string local_lhs(lhs); + std::string local_rhs(rhs); + + std::transform( + local_lhs.begin(), local_lhs.end(), local_lhs.begin(), [](unsigned char c) { return std::tolower(c); }); + std::transform( + local_rhs.begin(), local_rhs.end(), local_rhs.begin(), [](unsigned char c) { return std::tolower(c); }); + + return local_lhs.compare(local_rhs); +} + +int EB::verify_UTGID(const std::string& UTGID, const std::string& unit_name, const std::string& hostname) +{ + int ret_val = 0; + auto utgid_tokens = str_split(UTGID, "_"); + + if (utgid_tokens.size() != 4) { + ret_val = 1; + return ret_val; + } + + if (utgid_tokens[2] != unit_name) { + ret_val |= 1 << 2; + } + + if (string_icompare(utgid_tokens[1], std::string(hostname)) != 0) { + ret_val |= 1 << 3; + } + + return ret_val; +} + +std::string EB::get_sub_detector_UTGID(const std::string& UTGID, const std::string& unit_name) +{ + auto utgid_tokens = str_split(UTGID, "_"); + + // hostname should be smaller than 253 char + constexpr int hostname_length = 256; + char hostname[hostname_length]; + int hostname_err; + + hostname_err = gethostname(hostname, hostname_length); + + if (hostname_err != 0) { + std::ostringstream err_mess; + err_mess << "Unable to get hostname " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + int UTGID_err = verify_UTGID(UTGID, unit_name, hostname); + + if (UTGID_err != 0) { + std::ostringstream err_mess; + err_mess << "Invalid UTGID: the UTGID should be EB_" << hostname << "_" << unit_name << "_<idx>. UTGID: " << UTGID; + throw std::runtime_error(err_mess.str()); + } + + return utgid_tokens[1].substr(0, 2); +} + +int EB::get_idx_UTGID(const std::string& UTGID, const std::string& unit_name) +{ + int ret_val; + auto utgid_tokens = str_split(UTGID, "_"); + + // hostname should be smaller than 253 char + constexpr int hostname_length = 256; + char hostname[hostname_length]; + int hostname_err; + + hostname_err = gethostname(hostname, hostname_length); + + if (hostname_err != 0) { + std::ostringstream err_mess; + err_mess << "Unable to get hostname " << strerror(errno); + throw std::runtime_error(err_mess.str()); + } + + int UTGID_err = verify_UTGID(UTGID, unit_name, hostname); + + if (UTGID_err != 0) { + std::ostringstream err_mess; + err_mess << "Invalid UTGID: the UTGID should be EB_" << hostname << "_" << unit_name << "_<idx>. UTGID: " << UTGID; + throw std::runtime_error(err_mess.str()); + } + + try { + ret_val = stoi(utgid_tokens.back()); + } catch (const std::invalid_argument& e) { + std::ostringstream err_mess; + err_mess << "Invalid UTGID: invalid multiplicity index " << e.what(); + throw std::runtime_error(err_mess.str()); + } catch (const std::out_of_range& e) { + std::ostringstream err_mess; + err_mess << "Invalid UTGID: multiplicity index out of range " << e.what(); + throw std::runtime_error(err_mess.str()); + } catch (...) { + std::ostringstream err_mess; + err_mess << __FUNCTION__ << " unexpected exception: Invalid UTGID " << UTGID; + throw std::runtime_error(err_mess.str()); + } + + return ret_val; +} diff --git a/Online/EventBuilding/src/transport_unit.cpp b/Online/EventBuilding/src/transport_unit.cpp new file mode 100644 index 000000000..b8c6e3af7 --- /dev/null +++ b/Online/EventBuilding/src/transport_unit.cpp @@ -0,0 +1,474 @@ +#include "transport_unit.hpp" +#include "EventBuilding/tools.hpp" +#include <algorithm> +#include <functional> +#include <numeric> +#include <unistd.h> +#include <iostream> +#include <sstream> +#include <type_traits> +#include "infiniband_net/sock.hpp" +#include "infiniband_net/parser.hpp" + +bool EB::is_bu(int rank, const std::vector<int>& n_rus_nic) +{ + bool ret_val = false; + int idx = 0; + int k = 0; + while (idx <= rank) { + ret_val = (rank - idx) == n_rus_nic[k]; + idx += n_rus_nic[k] + 1; // +1 for the BU + k++; + } + + return ret_val; +} + +bool EB::is_ru(int rank, const std::vector<int>& n_rus_nic) +{ + bool ret_val = false; + int idx = 0; + int k = 0; + while (idx <= rank) { + ret_val = (rank - idx) < n_rus_nic[k]; + idx += n_rus_nic[k] + 1; // +1 for the BU + k++; + } + + return ret_val; +} + +EB::Transport_unit::Transport_unit(const std::string& name, Context& framework) : DataflowComponent(name, framework) +{ + declareProperty("RUs_per_nic", _n_rus_per_nic); + // TODO check if this property is needed + declareProperty("n_par_mess", _n_par_mess = 1); + declareProperty("n_sources_per_ru", _n_sources_per_ru); + // the default value is the self assignment + declareProperty("RU_ranks", _ru_ranks); + declareProperty("BU_ranks", _bu_ranks); + declareProperty("shift_pattern", _shift_pattern); + declareProperty("RU_shift_pattern", _RU_shift_pattern); + declareProperty("BU_shift_pattern", _BU_shift_pattern); + declareProperty("ib_config_file", _ib_config_file); + // This property is deprecated + declareProperty("MPI_errors_return", _MPI_errors_return = false); + + declareProperty("profiling_update_interval", _profiling_update_interval = 5); + declareProperty("enable_profiling", _enable_profiling = false); + + // DEBUG counters + declareMonitor("barrier_count", _barrier_count, "Number of barriers completed in the RUN"); + declareMonitor("pre_barrier_count", _pre_barrier_count, "Number of barriers reached in the RUN"); + // profiling counters + declareMonitor("sync_time_counter", _sync_time_counter); + declareMonitor("total_time_counter", _total_time_counter); +} + +EB::Transport_unit::~Transport_unit() {} + +int EB::Transport_unit::init_ranks() +{ + + std::stringstream logger_name; + logger_name << logger.get_name() << " rank " << _my_rank; + logger.set_name(logger_name.str()); + + // TODO don't assume same number of BUs and RUs + if (_n_rus_per_nic.size() == 0) { + // if 0 size self assign 1 RU per NIC + _n_rus_per_nic.resize(_world_size / 2, 1); + logger.warning() << __FUNCTION__ << " no number of RUs per NIC provided setting to default value " << 1 + << std::flush; + } else if (_n_rus_per_nic.size() == 1) { + _n_rus_per_nic.resize(_world_size / 2, _n_rus_per_nic[0]); + logger.warning() << __FUNCTION__ << " Single number of RUs per NIC provided setting to default value " + << _n_rus_per_nic[0] << std::flush; + } + + if ((_bu_ranks.size() == 0) && (_ru_ranks.size() == 0)) { + // if 0 size self assign + logger.info() << "Self assigning RU and BU ranks" << std::flush; + _ru_ranks.reserve(_world_size); + _bu_ranks.reserve(_world_size); + for (int k = 0; k < _world_size; k++) { + // TODO this is not implemented in the fastest way, in any case this should not be used in the real system + if (is_bu(k, _n_rus_per_nic)) { + _bu_ranks.push_back(k); + } else if (is_ru(k, _n_rus_per_nic)) { + _ru_ranks.push_back(k); + } else { + logger.error() << "rank " << k << " cannot be assigned to any unit" << std::flush; + } + } + } + + if (logger.is_active(PrintLevel::DEBUG)) { + logger.debug() << "RU ranks: "; + for (const auto& elem : _ru_ranks) { + logger.debug() << elem << " "; + } + logger.debug() << std::flush; + + logger.debug() << "BU ranks: "; + for (const auto& elem : _bu_ranks) { + logger.debug() << elem << " "; + } + logger.debug() << std::flush; + } + + return check_ranks(); +} + +int EB::Transport_unit::check_ranks() +{ + std::vector<int> all_ranks(_world_size); + std::iota(all_ranks.begin(), all_ranks.end(), 0); + logger.debug() << "all ranks: "; + for (const auto& elem : all_ranks) { + logger.debug() << elem << " "; + } + logger.debug() << std::flush; + + std::vector<int> configured_ranks; + configured_ranks.reserve(_world_size); + configured_ranks.insert(configured_ranks.end(), _ru_ranks.begin(), _ru_ranks.end()); + configured_ranks.insert(configured_ranks.end(), _bu_ranks.begin(), _bu_ranks.end()); + std::sort(configured_ranks.begin(), configured_ranks.end()); + + // if this condition is met all the ranks are properly set + if (all_ranks != configured_ranks) { + // if there is a mismatch we need to go deeper + std::vector<int> error_ranks(std::max(configured_ranks.size(), all_ranks.size())); + std::vector<int>::iterator rank_error_it; + + // search for duplicated ranks + rank_error_it = find_all_rep(configured_ranks.begin(), configured_ranks.end(), error_ranks.begin()); + if (rank_error_it != error_ranks.begin()) { + logger.error() << __FUNCTION__ << " Invalid RU & BU rank configuration, repeated ranks: "; + for (auto it = error_ranks.begin(); it != rank_error_it; it++) { + logger.error() << *it << " "; + } + logger.error() << std::flush; + } + + // after reporting duplicates uniq on the configured ranks + rank_error_it = std::unique(configured_ranks.begin(), configured_ranks.end()); + configured_ranks.erase(rank_error_it, configured_ranks.end()); + + // search for missing ranks + rank_error_it = std::set_difference( + all_ranks.begin(), all_ranks.end(), configured_ranks.begin(), configured_ranks.end(), error_ranks.begin()); + + if (rank_error_it != error_ranks.begin()) { + logger.error() << __FUNCTION__ << " Invalid RU & BU rank configuration, missing ranks: "; + for (auto it = error_ranks.begin(); it != rank_error_it; it++) { + logger.error() << *it << " "; + } + logger.error() << std::flush; + } + + // search for non existing ranks + rank_error_it = std::set_difference( + configured_ranks.begin(), configured_ranks.end(), all_ranks.begin(), all_ranks.end(), error_ranks.begin()); + + if (rank_error_it != error_ranks.begin()) { + logger.error() << __FUNCTION__ << " Invalid RU & BU rank configuration, non existing ranks: "; + for (auto it = error_ranks.begin(); it != rank_error_it; it++) { + logger.error() << *it << " "; + } + logger.error() << std::flush; + } + return DF_ERROR; + } + + // It is enough to check this because the total number of ranks has already been tested + + if (_n_rus_per_nic.size() != _bu_ranks.size()) { + logger.error() << __FUNCTION__ + << " Invalid configuration, the number of RUs per NICs has to be provided for every RU/BU group: " + << _bu_ranks.size() << " BUs provided with " << _n_rus_per_nic.size() << " RUs groups" << std::flush; + return DF_ERROR; + } + + int num_rus = std::accumulate(_n_rus_per_nic.begin(), _n_rus_per_nic.end(), 0); + + if (_ru_ranks.size() != num_rus) { + logger.error() << __FUNCTION__ << " Invalid configuration: the number of processes and units does not match. Got " + << _bu_ranks.size() << " BUs instead of " << _world_size - num_rus << " and " << _ru_ranks.size() + << " RUs instead of " << num_rus << std::flush; + return DF_ERROR; + } + + // Check if the configuration is the same on all the nodes + + return DF_SUCCESS; +} + +void EB::Transport_unit::set_rank(int rank) +{ + // TODO this may not be the best sanity check + if (!logger.is_active(Online::PrintLevel::DEBUG)) { + logger.always() << __FILE__ << ":" << __LINE__ << ": WARNING this function is for DEBUG only" << std::endl; + } + _my_rank = rank; +} + +int EB::Transport_unit::initialize() +{ + int ret_val; + ret_val = DataflowComponent::initialize(); + if (ret_val != DF_SUCCESS) { + return error("Failed to initialize service base class."); + } + logger.set_output_level(online_print_level_to_log_priority(Online::PrintLevel(outputLevel))); + + try { + _ibParser = std::make_unique<IB_verbs::Parser>(_ib_config_file.c_str()); + } catch (std::exception& e) { + logger.error() << "IB file parser: " << e.what() << std::flush; + return 0; + } + _my_rank = _ibParser->getProcessId(); + logger.debug() << "my rank is " << _my_rank << std::flush; + + _world_size = _ibParser->getTotalProcesses(); + logger.debug() << "world size is " << _world_size << std::flush; + if (_world_size == 0) return DF_ERROR; + ret_val = init_ranks(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + _numa_node = _ibParser->getIbNumaNode(); + + ret_val = init_n_sources(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + ret_val = init_pattern(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + return ret_val; +} + +int EB::Transport_unit::start() +{ + try { + _ibComm = std::make_unique<Parallel_comm>( + _ibParser.get(), logger.get_name(), log_priority_to_online_print_level(logger.get_output_level())); + } catch (std::exception& e) { + logger.error() << "Parallel Comm Constructor: " << e.what() << std::flush; + return 0; + } + logger.debug() << "verbs started" << std::flush; + return 1; +} + +int EB::Transport_unit::cancel() +{ + _ibComm->ibKillBlocking(); + return DF_SUCCESS; +} + +int EB::Transport_unit::stop() +{ + _ibComm.reset(nullptr); + logger.debug() << "verbs stopped" << std::flush; + return 1; +} + +int EB::Transport_unit::finalize() +{ + // TODO maybe we want a barrier here + _ibParser.reset(nullptr); + return DataflowComponent::finalize(); +} + +int EB::Transport_unit::sync() +{ + _sync_timer.start(); + int ret_val = DF_SUCCESS; + _pre_barrier_count++; + ret_val = _ibComm->ibBarrier(); + _barrier_count++; + _sync_timer.stop(); + return ret_val; +} + +int EB::Transport_unit::init_pattern() +{ + int ret_val = DF_SUCCESS; + + if ((_RU_shift_pattern.size() == 0) && (_shift_pattern.size() == 0)) { + _RU_shift_pattern = init_shift_pattern(_ru_ranks); + } else { + // enabling simmetric shift pattern + if (_shift_pattern.size() != 0) { + logger.warning() << "Enabling simmetric shift pattern" << std::flush; + _RU_shift_pattern = _shift_pattern; + } + ret_val = check_shift_pattern(_ru_ranks, _RU_shift_pattern); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + } + + if ((_BU_shift_pattern.size() == 0) && (_shift_pattern.size() == 0)) { + _BU_shift_pattern = init_shift_pattern(_bu_ranks); + } else { + // enabling simmetric shift pattern + if (_shift_pattern.size() != 0) { + logger.warning() << "Enabling simmetric shift pattern" << std::flush; + _BU_shift_pattern = _shift_pattern; + } + ret_val = check_shift_pattern(_bu_ranks, _BU_shift_pattern); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + } + + if (_BU_shift_pattern.size() != _RU_shift_pattern.size()) { + logger.error() << "Invalid shift pattern: BUs and RUs have shift pattern of different length. BU:" + << _BU_shift_pattern.size() << ", RU:" << _RU_shift_pattern.size() << std::flush; + return DF_ERROR; + } + + return ret_val; +} + +// TODO refactor errors and use exceptions +int EB::Transport_unit::check_shift_pattern(const std::vector<int>& ranks, const std::vector<int>& pattern) +{ + int ret_val = DF_SUCCESS; + std::vector<int> nodes; + + // copy of the vector without the ghost nodes + std::copy_if(pattern.begin(), pattern.end(), std::back_inserter(nodes), [](int val) { return (val >= 0); }); + + int num_ghost = pattern.size() - nodes.size(); + int num_nodes = nodes.size(); + + // this function is not called if the shift pattern is auto generated + auto base_pattern = init_shift_pattern(ranks); + + std::sort(nodes.begin(), nodes.end()); + + if (pattern.size() < ranks.size()) { + logger.error() << "Invalid shift pattern: the shift pattern should have at least " << ranks.size() + << " nodes, got only " << pattern.size() << " nodes" << std::flush; + ret_val = DF_ERROR; + } else if (pattern.size() - num_ghost != ranks.size()) { + logger.error() << "Invalid shift pattern: expecting " << pattern.size() - ranks.size() << " ghost nodes, got " + << num_ghost << " ghost nodes" << std::flush; + ret_val = DF_ERROR; + } else if (nodes != base_pattern) { + logger.error() << "Invalid shift pattern:"; + for (const auto& elem : _RU_shift_pattern) { + logger.error() << " " << elem; + } + logger.error() << std::flush; + ret_val = DF_ERROR; + } + + return ret_val; +} + +std::vector<int> EB::Transport_unit::init_shift_pattern(const std::vector<int>& ranks) +{ + std::vector<int> base_pattern(ranks.size()); + std::iota(base_pattern.begin(), base_pattern.end(), 0); + return base_pattern; +} + +int EB::Transport_unit::init_n_sources() +{ + int ret_val = DF_SUCCESS; + if (_n_sources_per_ru.size() == 0) { + _n_sources_per_ru.resize(_ru_ranks.size(), 1); + logger.warning() << __FUNCTION__ << " no number of sources per RU provided setting to default value: " << 1 + << std::flush; + } else if (_n_sources_per_ru.size() == 1) { + _n_sources_per_ru.resize(_ru_ranks.size(), _n_sources_per_ru[0]); + logger.warning() << __FUNCTION__ << " Single number of sources per RU provided: " << _n_sources_per_ru[0] + << std::flush; + } + + else if (_n_sources_per_ru.size() != _ru_ranks.size()) { + logger.error() << __FUNCTION__ << " configuration error: incorrect number of sources per RU. Got " + << _n_sources_per_ru.size() << " values for " << _ru_ranks.size() << " RUs" << std::flush; + ret_val = DF_ERROR; + } + + auto zero_src_it = std::find(_n_sources_per_ru.begin(), _n_sources_per_ru.end(), 0); + if (zero_src_it != _n_sources_per_ru.end()) { + auto ru_idx = std::distance(_n_sources_per_ru.begin(), zero_src_it); + logger.error() << __FUNCTION__ << " configuration error: RU id " << ru_idx << " got 0 sources." << std::flush; + ret_val = DF_ERROR; + } + + // the last element is the used for the MPI gather and represents the number of sources of the BU so it is set to 0 + _n_sources_per_ru.emplace_back(0); + + // n RU + 2 elements the first element is 0 and the last two the number total number of sources (the last element is + // the used for the MPI gather and represents the number of sources of the BU) + _prefix_n_sources_per_ru.resize(_n_sources_per_ru.size() + 1); + _prefix_n_sources_per_ru[0] = 0; + std::partial_sum(_n_sources_per_ru.begin(), _n_sources_per_ru.end(), _prefix_n_sources_per_ru.begin() + 1); + + return ret_val; +} + +void EB::Transport_unit::reset_counters() +{ + _pre_barrier_count = 0; + _barrier_count = 0; + _total_time_counter = 0; + _sync_time_counter = 0; +} + +void EB::Transport_unit::update_profiling() +{ + if (_enable_profiling) { + double total_time = _total_timer.get_elapsed_time_s(); + if (total_time > _profiling_update_interval) { + double sync_time = _sync_timer.get_elapsed_time_s(); + _total_time_counter += total_time; + _sync_time_counter += sync_time; + if (logger.is_active(Online::PrintLevel::INFO)) { + logger.info() << "Profiling counters" << std::flush; + logger.info() << " sync " << sync_time << " s " << sync_time / total_time * 100 << " %" << std::flush; + } + + _total_timer.reset(); + _sync_timer.reset(); + } + } +} + +void EB::Transport_unit::init_profiling() +{ + if (_enable_profiling) { + _total_timer.stop(); + _total_timer.reset(); + _sync_timer.stop(); + _sync_timer.reset(); + // start the total timer + _total_timer.start(); + } else { + _total_timer.disable(); + _sync_timer.disable(); + } +} + +// EB::Transport_unit::Shift_pattern_exception( +// int err_code, +// const std::vector<int>& pattern, +// int rank_size, +// int num_ghost) : +// exception(), +// err_code(err_code), pattern(pattern), rank_size(rank_size), num_ghost(num_ghost) +// {} \ No newline at end of file diff --git a/Online/EventBuilding/test.mdf b/Online/EventBuilding/test.mdf new file mode 100644 index 000000000..e69de29bb -- GitLab From 19149d76db2c5c30ff5f7966ed0a355ec15b5ca0 Mon Sep 17 00:00:00 2001 From: Flavio Pisani <flavio.pisani@cern.ch> Date: Mon, 6 Dec 2021 14:25:42 +0100 Subject: [PATCH 3/4] added Online/FarmConfig from Online (Online/fpisani_eb_dev) --- .git-lb-checkout | 3 + Online/FarmConfig/CMakeLists.txt | 6 + Online/FarmConfig/job/Adder.py | 212 ++++++++++++ Online/FarmConfig/job/Adder.sh | 1 + .../FarmConfig/job/AddersFromArchitecture.py | 279 +++++++++++++++ Online/FarmConfig/job/AligAdder.sh | 17 + Online/FarmConfig/job/AligDrv.sh | 114 ++++++ Online/FarmConfig/job/AligWrk.sh | 109 ++++++ Online/FarmConfig/job/AlignReader.sh | 14 + Online/FarmConfig/job/AlignWriter.sh | 12 + Online/FarmConfig/job/BU.sh | 21 ++ Online/FarmConfig/job/ClassTask.sh | 22 ++ Online/FarmConfig/job/CleanAlignment.sh | 5 + Online/FarmConfig/job/Controller.sh | 80 +++++ Online/FarmConfig/job/EBAdder.sh | 12 + Online/FarmConfig/job/EBPartAdder.sh | 12 + Online/FarmConfig/job/EBPartPublisher.sh | 12 + Online/FarmConfig/job/EBPartSaver.sh | 12 + Online/FarmConfig/job/EBPass.sh | 26 ++ Online/FarmConfig/job/EBReader.sh | 27 ++ Online/FarmConfig/job/EBSender.sh | 39 +++ Online/FarmConfig/job/EBStorage.sh | 12 + Online/FarmConfig/job/EBSubDetAdder.sh | 12 + Online/FarmConfig/job/FileRawSizeMon.sh | 16 + Online/FarmConfig/job/FileTest.sh | 2 + Online/FarmConfig/job/HLT2Adder.sh | 12 + Online/FarmConfig/job/HLT2Pass.sh | 12 + Online/FarmConfig/job/HLT2Publisher.sh | 12 + Online/FarmConfig/job/HLT2Reader.sh | 12 + Online/FarmConfig/job/HLT2SFAdder.sh | 13 + Online/FarmConfig/job/HLT2Saver.sh | 12 + Online/FarmConfig/job/HLT2TopAdder.sh | 12 + Online/FarmConfig/job/MFPGen.sh | 17 + Online/FarmConfig/job/MonRegistrar.sh | 30 ++ Online/FarmConfig/job/Moore.sh | 13 + Online/FarmConfig/job/Moore1.sh | 24 ++ Online/FarmConfig/job/Moore2.sh | 36 ++ Online/FarmConfig/job/NodeAdder.sh | 28 ++ Online/FarmConfig/job/NodeBusyMon.sh | 21 ++ Online/FarmConfig/job/Passthrough.py | 87 +++++ Online/FarmConfig/job/RU.sh | 17 + Online/FarmConfig/job/createEnvironment.sh | 161 +++++++++ Online/FarmConfig/job/interSetup.sh | 130 +++++++ Online/FarmConfig/job/makeData.py | 12 + Online/FarmConfig/job/preamble.sh | 27 ++ Online/FarmConfig/job/runStandalone.sh | 176 ++++++++++ Online/FarmConfig/job/runTask.sh | 88 +++++ Online/FarmConfig/job/startGDB.sh | 108 ++++++ Online/FarmConfig/old/EmptyList.xml | 2 + Online/FarmConfig/old/MBM_setup.opts | 19 + Online/FarmConfig/old/OnlineEnvironment.opts | 7 + Online/FarmConfig/old/PLUS04.opts | 5 + Online/FarmConfig/old/Tasklist.xml | 81 +++++ Online/FarmConfig/options/AligDrv.opts | 23 ++ Online/FarmConfig/options/AligWrk.opts | 26 ++ Online/FarmConfig/options/AlignReader.opts | 31 ++ Online/FarmConfig/options/AlignWriter.opts | 142 ++++++++ Online/FarmConfig/options/BusyPub.opts | 80 +++++ .../options/CCESCAN.prescaler-requirements | 3 + .../COLLISION-LEAD.prescaler-requirements | 12 + .../COLLISION-VDM.prescaler-requirements | 12 + .../COLLISION-pHe.prescaler-requirements | 12 + .../COLLISION-pNe.prescaler-requirements | 12 + .../Collision-HiMu.prescaler-requirements | 12 + .../options/Default.prescaler-requirements | 12 + Online/FarmConfig/options/EBMBM.opts | 9 + Online/FarmConfig/options/EBReader.opts | 66 ++++ Online/FarmConfig/options/EBSender.opts | 39 +++ Online/FarmConfig/options/EBStorage.opts | 31 ++ Online/FarmConfig/options/EBStorageNFS.opts | 18 + Online/FarmConfig/options/Empty.opts | 0 Online/FarmConfig/options/HLT2MBM.opts | 12 + Online/FarmConfig/options/HLT2Reader.opts | 62 ++++ Online/FarmConfig/options/HLT2Writer.opts | 31 ++ .../FarmConfig/options/HLT2WriterPosix.opts | 8 + Online/FarmConfig/options/Hlt2Reader.opts | 49 +++ Online/FarmConfig/options/Logging.opts | 5 + Online/FarmConfig/options/MonAdder.opts | 29 ++ Online/FarmConfig/options/Monitoring.opts | 6 + Online/FarmConfig/options/OnlineStreams.opts | 324 ++++++++++++++++++ .../FarmConfig/options/PartAdderStatic.opts | 11 + Online/FarmConfig/options/RCV.opts | 17 + .../options/SMOG.prescaler-requirements | 9 + Online/FarmConfig/options/Sender.opts | 22 ++ Online/FarmConfig/options/StorageReader.opts | 36 ++ Online/FarmConfig/options/StorageWriter.opts | 47 +++ Online/FarmConfig/options/TopBsyAdder.opts | 68 ++++ 87 files changed, 3527 insertions(+) create mode 100755 Online/FarmConfig/CMakeLists.txt create mode 100644 Online/FarmConfig/job/Adder.py create mode 120000 Online/FarmConfig/job/Adder.sh create mode 100644 Online/FarmConfig/job/AddersFromArchitecture.py create mode 100755 Online/FarmConfig/job/AligAdder.sh create mode 100755 Online/FarmConfig/job/AligDrv.sh create mode 100755 Online/FarmConfig/job/AligWrk.sh create mode 100755 Online/FarmConfig/job/AlignReader.sh create mode 100755 Online/FarmConfig/job/AlignWriter.sh create mode 100755 Online/FarmConfig/job/BU.sh create mode 100755 Online/FarmConfig/job/ClassTask.sh create mode 100755 Online/FarmConfig/job/CleanAlignment.sh create mode 100755 Online/FarmConfig/job/Controller.sh create mode 100755 Online/FarmConfig/job/EBAdder.sh create mode 100755 Online/FarmConfig/job/EBPartAdder.sh create mode 100755 Online/FarmConfig/job/EBPartPublisher.sh create mode 100755 Online/FarmConfig/job/EBPartSaver.sh create mode 100755 Online/FarmConfig/job/EBPass.sh create mode 100644 Online/FarmConfig/job/EBReader.sh create mode 100755 Online/FarmConfig/job/EBSender.sh create mode 100755 Online/FarmConfig/job/EBStorage.sh create mode 100755 Online/FarmConfig/job/EBSubDetAdder.sh create mode 100755 Online/FarmConfig/job/FileRawSizeMon.sh create mode 100755 Online/FarmConfig/job/FileTest.sh create mode 100755 Online/FarmConfig/job/HLT2Adder.sh create mode 100755 Online/FarmConfig/job/HLT2Pass.sh create mode 100755 Online/FarmConfig/job/HLT2Publisher.sh create mode 100755 Online/FarmConfig/job/HLT2Reader.sh create mode 100755 Online/FarmConfig/job/HLT2SFAdder.sh create mode 100755 Online/FarmConfig/job/HLT2Saver.sh create mode 100755 Online/FarmConfig/job/HLT2TopAdder.sh create mode 100755 Online/FarmConfig/job/MFPGen.sh create mode 100644 Online/FarmConfig/job/MonRegistrar.sh create mode 100755 Online/FarmConfig/job/Moore.sh create mode 100755 Online/FarmConfig/job/Moore1.sh create mode 100755 Online/FarmConfig/job/Moore2.sh create mode 100755 Online/FarmConfig/job/NodeAdder.sh create mode 100755 Online/FarmConfig/job/NodeBusyMon.sh create mode 100644 Online/FarmConfig/job/Passthrough.py create mode 100755 Online/FarmConfig/job/RU.sh create mode 100755 Online/FarmConfig/job/createEnvironment.sh create mode 100755 Online/FarmConfig/job/interSetup.sh create mode 100755 Online/FarmConfig/job/makeData.py create mode 100755 Online/FarmConfig/job/preamble.sh create mode 100755 Online/FarmConfig/job/runStandalone.sh create mode 100755 Online/FarmConfig/job/runTask.sh create mode 100755 Online/FarmConfig/job/startGDB.sh create mode 100755 Online/FarmConfig/old/EmptyList.xml create mode 100755 Online/FarmConfig/old/MBM_setup.opts create mode 100755 Online/FarmConfig/old/OnlineEnvironment.opts create mode 100755 Online/FarmConfig/old/PLUS04.opts create mode 100755 Online/FarmConfig/old/Tasklist.xml create mode 100755 Online/FarmConfig/options/AligDrv.opts create mode 100755 Online/FarmConfig/options/AligWrk.opts create mode 100755 Online/FarmConfig/options/AlignReader.opts create mode 100755 Online/FarmConfig/options/AlignWriter.opts create mode 100755 Online/FarmConfig/options/BusyPub.opts create mode 100755 Online/FarmConfig/options/CCESCAN.prescaler-requirements create mode 100755 Online/FarmConfig/options/COLLISION-LEAD.prescaler-requirements create mode 100755 Online/FarmConfig/options/COLLISION-VDM.prescaler-requirements create mode 100755 Online/FarmConfig/options/COLLISION-pHe.prescaler-requirements create mode 100755 Online/FarmConfig/options/COLLISION-pNe.prescaler-requirements create mode 100644 Online/FarmConfig/options/Collision-HiMu.prescaler-requirements create mode 100755 Online/FarmConfig/options/Default.prescaler-requirements create mode 100644 Online/FarmConfig/options/EBMBM.opts create mode 100644 Online/FarmConfig/options/EBReader.opts create mode 100755 Online/FarmConfig/options/EBSender.opts create mode 100644 Online/FarmConfig/options/EBStorage.opts create mode 100644 Online/FarmConfig/options/EBStorageNFS.opts create mode 100755 Online/FarmConfig/options/Empty.opts create mode 100644 Online/FarmConfig/options/HLT2MBM.opts create mode 100644 Online/FarmConfig/options/HLT2Reader.opts create mode 100644 Online/FarmConfig/options/HLT2Writer.opts create mode 100644 Online/FarmConfig/options/HLT2WriterPosix.opts create mode 100755 Online/FarmConfig/options/Hlt2Reader.opts create mode 100644 Online/FarmConfig/options/Logging.opts create mode 100755 Online/FarmConfig/options/MonAdder.opts create mode 100755 Online/FarmConfig/options/Monitoring.opts create mode 100644 Online/FarmConfig/options/OnlineStreams.opts create mode 100755 Online/FarmConfig/options/PartAdderStatic.opts create mode 100755 Online/FarmConfig/options/RCV.opts create mode 100755 Online/FarmConfig/options/SMOG.prescaler-requirements create mode 100755 Online/FarmConfig/options/Sender.opts create mode 100644 Online/FarmConfig/options/StorageReader.opts create mode 100644 Online/FarmConfig/options/StorageWriter.opts create mode 100755 Online/FarmConfig/options/TopBsyAdder.opts diff --git a/.git-lb-checkout b/.git-lb-checkout index f88cba926..2b8eaeac7 100644 --- a/.git-lb-checkout +++ b/.git-lb-checkout @@ -1,3 +1,6 @@ [lb-checkout "Online.Online/EventBuilding"] base = e70832481d09f05ee80b0ee52c8348d12e1458bf imported = af6da089bf25cd1560da4842765386550f7488b9 +[lb-checkout "Online.Online/FarmConfig"] + base = fc228470bd0c57dcc9b17dc62e9d8e87a480d191 + imported = af6da089bf25cd1560da4842765386550f7488b9 diff --git a/Online/FarmConfig/CMakeLists.txt b/Online/FarmConfig/CMakeLists.txt new file mode 100755 index 000000000..30c95b55b --- /dev/null +++ b/Online/FarmConfig/CMakeLists.txt @@ -0,0 +1,6 @@ +################################################################################ +# Package: FarmConfig +################################################################################ +gaudi_subdir(FarmConfig v0r28) + +gaudi_env(SET FARMCONFIG_OPTIONS "\${FARMCONFIGROOT}/options") diff --git a/Online/FarmConfig/job/Adder.py b/Online/FarmConfig/job/Adder.py new file mode 100644 index 000000000..6024cf13e --- /dev/null +++ b/Online/FarmConfig/job/Adder.py @@ -0,0 +1,212 @@ +""" + Online Passthrough application configuration + + @author M.Frank +""" +__version__ = "1.0" +__author__ = "Markus Frank <Markus.Frank@cern.ch>" + +import Gaudi.Configuration as Gaudi +from GaudiOnline.OnlineApplication import * +import Configurables +from Configurables import MonitorSvc +from Configurables import AdderSvc +from xml.dom import minidom +import os + +def TaskListfromArch(archfile, tasklist): + xmldoc = minidom.parse(archfile) + itemlist = xmldoc.getElementsByTagName('task') +# tasklist = [] + for s in itemlist: + nam = s.attributes['name'] +# if not nam.find('MEPR')>=0: + tasklist.append(s.attributes['name'].value) + + +# BusySvc = Configurables.BusySvc +HistPers = Configurables.HistogramPersistencySvc +print 'MSG_INFO: ',MSG_INFO + +def SetupNodeAdder(svc,nam,type,partitionName): + svc.PartitionName = partitionName + if type == "Histo": + s = nam#+"HistAdder" + snam = "Histos" + svc.AdderClass = "hists" + else: + s = nam#+"CounterAdder" + snam = "Counter" + svc.AdderClass = "Counter" + svc.MyName = "<part>_<node>_"+nam + svc.TaskPattern = "<part>_<node>_"+nam+"_(.*)" + svc.ServicePattern = "MON_<part>_<node>_"+nam+"_(.*)/"+snam+"/" + svc.ReceiveTimeout = 5 +# if dohostdns: +# AddS.InDNS = InDns +# AddS.OutDNS = OutDns + if partitionName == "LHCbA": # overwrite certain options for the Alignment... + svc.SaveInterval = -1 + svc.SaveonUpdate = False + svc.SaveSetTaskName = s; + svc.ReceiveTimeout = 1 + svc.EoRTmoFactor = 2 + svc.GotoPause = False + +def SetupSFAdder(svc,nam,type,partitionName): + svc.PartitionName = partitionName + svc.AdderClass = "hists" + if type == "Histo": + s = nam+"HistAdder" + snam = "Histos" + svc.AdderClass = "hists" + else: + s = nam+"CounterAdder" + snam = "Counter" + svc.AdderClass = "Counter" + svc.MyName = "<part>_<node>_"+nam + svc.TaskPattern = "<part>_<node>[0-9][0-9]_NodeAdder_0" + svc.ServicePattern = "MON_<part>_<node>[0-9][0-9]_"+nam+"/"+snam+"/" + svc.ReceiveTimeout = 8 +# if dohostdns: +# AddS.InDNS = InDns +# AddS.OutDNS = OutDns + if partitionName == "LHCbA": # overwrite certain options for the Alignment... + svc.SaveInterval = -1 + svc.SaveonUpdate = False + svc.SaveSetTaskName = s; + svc.ReceiveTimeout = 1 + svc.EoRTmoFactor = 8 + svc.GotoPause = False + +def SetupTopAdder(svc,nam,type,partitionName): + svc.PartitionName = partitionName + svc.AdderClass = "hists" + if type == "Histo": + s = nam+"HistAdder" + snam = "Histos" + svc.AdderClass = "hists" + else: + s = nam+"CounterAdder" + snam = "Counter" + svc.AdderClass = "Counter" + svc.MyName = "<part>_"+nam+"_00" + svc.TaskPattern = "<part>_HLT[a-z][0-9][0-9]_SubFarmAdder_(.*)" + svc.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_"+nam+"/"+snam+"/" + svc.ReceiveTimeout = 5 +# if dohostdns: +# AddS.InDNS = InDns +# AddS.OutDNS = OutDns + if partitionName == "LHCbA": # overwrite certain options for the Alignment... + svc.SaveInterval = -1 + svc.SaveonUpdate = False + svc.SaveSetTaskName = s; + svc.ReceiveTimeout = 1 + svc.EoRTmoFactor = 2 + svc.GotoPause = False + +def SetupSaver(svc,nam,type,partitionName): + svc.PartitionName = partitionName + svc.AdderClass = "hists" + if type == "Histo": + s = nam+"HistAdder" + snam = "Histos" + svc.AdderClass = "hists" + else: + return + svc.MyName = "<part>_Saverhlt01_"+nam+"_00" + svc.TaskPattern = "MON_<part>_HLT02_PartAdder_0" + svc.ServicePattern = "MON_<part>_hlt01_"+nam+"_00/Histos/" + svc.ReceiveTimeout = 12 + svc.SaveRootDir = "/hist/Savesets" + svc.IsSaver = True + svc.SaveInterval = 900 + svc.SaveonUpdate = False + svc.SaveSetTaskName= s +# if dohostdns: +# AddS.InDNS = InDns +# AddS.OutDNS = OutDns + if partitionName == "LHCbA": # overwrite certain options for the Alignment... + svc.SaveInterval = -1 + svc.SaveonUpdate = False + svc.SaveSetTaskName = s; + svc.ReceiveTimeout = 1 + svc.EoRTmoFactor = 2 + svc.GotoPause = False + + +class AdderApp(Application): + def __init__(self, outputLevel, partitionName='SF', partitionID=0xFFFF, level="1", archname=""): + Application.__init__(self, + outputLevel=outputLevel, + partitionName=partitionName, + partitionID=partitionID, + classType=Class1) + if level=="1": + InDns = os.getenv("InDns","<dns>") + OutDns = os.getenv("OutDns","<dns>") + SetupFunc = "SetupNodeAdder" + if level =="2": + InDns = os.getenv("InDns","<node>") + OutDns = os.getenv("OutDns","hlt01") + SetupFunc = "SetupSFAdder" + elif level == "3": + InDns = os.getenv("InDns","hlt01") + OutDns = os.getenv("OutDns","mona08") + SetupFunc = "SetupTopAdder" + elif level == "3.1": + InDns = os.getenv("InDns","mona08") + OutDns = os.getenv("OutDns","mona08") + SetupFunc = "SetupSaver" + elif level == "4": + InDns = os.getenv("InDns","mona08") + OutDns = os.getenv("OutDns","mona08") + + self.config.autoStart = False + self.app.HistogramPersistency = 'NONE' + HistPers.Warnings = False; + msv = MonitorSvc() + msv.OutputLevel = outputLevel + msv.CounterUpdateInterval = 5; + msv.PartitionName = partitionName; + msv.ExpandCounterServices = True +# print msv +# msv.OutDns = "ecs03" + self.app.ExtSvc.append(msv) + tasklist = [] +# arch = os.getenv("ARCH",arch) + dohostdns = (archname == "Calib") + archfile = "/group/online/dataflow/architectures/lbDataflowArch_"+archname+".xml" + TaskListfromArch(archfile, tasklist) + histsvc = [] + cntsvc = [] + for s in tasklist: + if 'NodeAdder' in s: + continue + if 'AligAdder' in s: + continue + if 'SubFarmAdder' in s: + continue + tsk = s.encode()#+"HistAdder" + AddS = AdderSvc(tsk+"HistAdder") + globals()[SetupFunc](AddS,tsk,"Histo",partitionName) + AddS.InDNS = InDns + AddS.OutDNS = OutDns; + print AddS.MyName, AddS.InDNS, AddS.OutDNS,AddS.TaskPattern, AddS.ServicePattern + self.app.ExtSvc.append(AddS) + AddS = AdderSvc(tsk+"CountAdder") + globals()[SetupFunc](AddS,tsk,"Counter",partitionName) + AddS.InDNS = InDns + AddS.OutDNS = OutDns; + print AddS.MyName, AddS.InDNS, AddS.OutDNS,AddS.TaskPattern, AddS.ServicePattern + self.app.ExtSvc.append(AddS) +# histsvc.append(hsvc) +# cntsvc.append(csvc) + +Level = os.getenv("AdderLevel","") +Arch = os.getenv("ARCH_FILE","") +app = AdderApp(MSG_DEBUG, partitionName='LHCb',level=Level,archname=Arch) +print 'Setup complete....' +# print dir(app) + + diff --git a/Online/FarmConfig/job/Adder.sh b/Online/FarmConfig/job/Adder.sh new file mode 120000 index 000000000..36c7a2281 --- /dev/null +++ b/Online/FarmConfig/job/Adder.sh @@ -0,0 +1 @@ +NodeAdder.sh \ No newline at end of file diff --git a/Online/FarmConfig/job/AddersFromArchitecture.py b/Online/FarmConfig/job/AddersFromArchitecture.py new file mode 100644 index 000000000..76c313c84 --- /dev/null +++ b/Online/FarmConfig/job/AddersFromArchitecture.py @@ -0,0 +1,279 @@ +from xml.dom import minidom +import os +import sys +import Gaudi +import Configurables +from GaudiOnline import Class0 +from GaudiOnline import Class1 +from GaudiOnline import Class2 +from GaudiOnline import Application +from GauchoAppl import GauchoApplConf + +#SAVESET_DIRECTORY = '/group/online/dataflow/cmtuser/Savesets' +SAVESET_DIRECTORY = '/hist/Savesets' +HLT_TOP_NODE = "hlt01" +MON_TOP_NODE = "mon01" + +EventLoopMgr = Gaudi.Configurables.EventLoopMgr +ApplicationMgr = Gaudi.Configuration.ApplicationMgr +CounterDebugSvcs = ["DskWriter"] +HistDebugSvcs = ["AligWrk"] +vnode = False + +global adder_debug_flag +adder_debug_flag = False + +def VictimNode(): + import socket + import re + victimnodes_re = [] + vnodes="" + vnodes=os.getenv("victimnodes","") + if vnodes!="": + victimnodes = vnodes.split(",") + for i in victimnodes: + victimnodes_re.append(re.compile(i,re.IGNORECASE)) + hname = socket.gethostname().split('.')[0] + for i in victimnodes_re: + if i.match(hname) != None: + return True + +def TaskListfromArch(arch): + tasklist = [] + xmldoc = minidom.parse(arch) + itemlist = xmldoc.getElementsByTagName('task') + for s in itemlist: + nam = s.attributes['name'] + tasklist.append(s.attributes['name'].value) + return tasklist + +# =========================================================================================== +# +# Class to simplyfy the building of adder services +# +# =========================================================================================== +class Adder: + def __init__(self, task, nodes, tasks, partition, typ, in_dns=None, out_dns=None, ext=None, debug=False, run_aware=False): + task_name = str(task) + tname = task_name + if ext: tname = task_name + ext + if typ == "counter": + adder = GauchoApplConf.AdderSvc("C_"+task_name) + adder.ServicePattern = "MON_<part>_"+nodes+"_"+tname+"/Counter/" + else: + adder = GauchoApplConf.AdderSvc("H_"+task_name) + adder.ServicePattern = "MON_<part>_"+nodes+"_"+tname+"/Histos/" + + adder.MyName = "<part>_<node>_"+task_name + adder.PartitionName = partition + if tasks: + adder.TaskPattern = "<part>_"+nodes+"_"+str(tasks)+"_(.*)" + else: + adder.TaskPattern = "<part>_"+nodes+"_"+task_name + + if adder_debug_flag: + print("%-8s Service pattern: %s Task pattern: %s Debug: %s"\ + %("INFO", adder.ServicePattern, adder.TaskPattern, str(debug), )) + + adder.AdderClass = typ + adder.RunAware = run_aware + adder.DebugOn = debug + if in_dns: + adder.InDNS = in_dns + if out_dns: + adder.OutDNS = out_dns + self.task_name = task_name + self.obj = adder + #if partition == 'FEST': + # adder.DebugOn = True + + def setTaskPattern(self, pattern): + self.obj.TaskPattern = pattern + return self + + def setServicePattern(self, pattern): + self.obj.ServicePattern = pattern + return self + + def enableSaving(self, recv_tmo, interval, saveset_dir): + self.obj.ReceiveTimeout = recv_tmo + self.obj.IsSaver = True + self.obj.SaveInterval = interval + self.obj.SaveOnUpdate = False + self.obj.SaveRootDir = saveset_dir + self.obj.SaveSetTaskName = self.task_name + return self + + +# =========================================================================================== +# +# Function to determine the adders from the architecture file +# +# =========================================================================================== +def AddersfromTasks(tasklist, adder_type, partition, dohostdns): + global adder_debug_flag + service_list = [] + adder_task_class = Class1 + adder_debug_flag = True + + if adder_type=="HltNode" or adder_type == "EventBuilder": + adder_task_class = Class1 + for task_name in tasklist: + if 'EBAdder' in task_name: continue + if 'HLT2Adder' in task_name: continue + if 'NodeAdder' in task_name: continue + if 'AlignAdder' in task_name: continue + adder = Adder(task_name, "<node>", None, partition, "counter", "<dns>", "<dns>", ext="_(.*)") + service_list.append(adder.obj) + + adder = Adder(task_name, "<node>", None, partition, "hists", "<dns>", "<dns>", ext="_(.*)") + service_list.append(adder.obj) + # =========================================================================================== + + elif adder_type == "HltSubfarm": + adder_task_class = Class1 + adder_debug_flag = True + for task_name in tasklist: + adder = Adder(task_name, "<node>[0-9][0-9]", "HLT2Adder", partition, "counter", "<node>", HLT_TOP_NODE) + #adder.obj.DebugOn = True + service_list.append(adder.obj) + adder = Adder(task_name, "<node>[0-9][0-9]", "HLT2Adder", partition, "hists", "<node>", HLT_TOP_NODE) + #adder.obj.DebugOn = True + service_list.append(adder.obj) + # =========================================================================================== + + elif adder_type=="HltTop": + adder_task_class = Class1 + adder_debug_flag = True + for task_name in tasklist: + adder = Adder(task_name, "hlt[0-2][0-9][0-9]", "HLT2SFAdder", partition, "counter", HLT_TOP_NODE, MON_TOP_NODE) + #adder.obj.DebugOn = True + service_list.append(adder.obj) + adder = Adder(task_name, "hlt[0-2][0-9][0-9]", "HLT2SFAdder", partition, "hists", HLT_TOP_NODE, MON_TOP_NODE) + #adder.obj.DebugOn = True + service_list.append(adder.obj) + # =========================================================================================== + + elif adder_type == "HltSaver": + adder_debug_flag = True + adder_task_class = Class1 + for task_name in tasklist: + top = "hlt[0-2][0-9][0-9]" # HLT_TOP_NODE + adder = Adder(task_name, top, "HLT2TopAdder", partition, "hists", MON_TOP_NODE, MON_TOP_NODE) \ + .enableSaving(12, 900, SAVESET_DIRECTORY) + service_list.append(adder.obj) + # =========================================================================================== + + elif adder_type=="HltPublisher": + adder_task_class = Class0 + for task in tasklist: + task_name = str(task) + publisher = GauchoApplConf.GenStatSvc('Pub'+task_name) + top = "hlt0[0-9]" # HLT_TOP_NODE + publisher.ServicePattern = "MON_<part>_"+top+"_"+task_name+"/Counter/" + publisher.TaskPattern = "<part>_HLT0[0-9]_HLT2TopAdder_(.*)" + publisher.MyName = "<part>_<node>_"+task_name + publisher.PartitionName = partition + publisher.InDNS = MON_TOP_NODE + publisher.OutDNS = HLT_TOP_NODE + publisher.AdderClass = "counter" + publisher.ServicePrefix = "/Stat/<part>/"+task_name; + if adder_debug_flag: + print("%-8s Service pattern: %s Task pattern: %s"\ + %("INFO", publisher.ServicePattern, publisher.TaskPattern, )) + service_list.append(publisher) + # =========================================================================================== + + elif adder_type=="EBPartAdder": + adder_task_class = Class1 + for task_name in tasklist: + adder = Adder(task_name, "[a-z][a-z]eb[0-9][0-9]", "EBAdder", partition, "counter", "dataflow01", MON_TOP_NODE) + adder.obj.ExpandRate = 1 + #adder.obj.DebugOn = 1 + service_list.append(adder.obj) + adder = Adder(task_name, "[a-z][a-z]eb[0-9][0-9]", "EBAdder", partition, "hists", "dataflow01", MON_TOP_NODE) + #adder.obj.DebugOn = 1 + service_list.append(adder.obj) + # =========================================================================================== + elif adder_type=="EBPartSaver": + adder_task_class = Class1 + for task_name in tasklist: + adder = Adder(task_name, "dataflow02", "EBPartAdder", partition, "hists", MON_TOP_NODE, MON_TOP_NODE) \ + .enableSaving(12, 900, SAVESET_DIRECTORY) + #adder.obj.DebugOn = 1 + service_list.append(adder.obj) + # =========================================================================================== + elif adder_type=="EBPartPublisher": + for task in tasklist: + task_name = str(task) + publisher = GauchoApplConf.GenStatSvc('Pub'+task_name) + publisher.ServicePattern = "MON_<part>_<node>_"+task_name+"/Counter/" + publisher.TaskPattern = "<part>_<node>_EBPartAdder_(.*)" + publisher.MyName = "<part>_<node>_"+task_name + publisher.PartitionName = partition + publisher.InDNS = MON_TOP_NODE + publisher.OutDNS = MON_TOP_NODE + publisher.AdderClass = "counter" + publisher.ServicePrefix = "/Stat/<part>/"+task_name; + #publisher.DebugOn = True + if adder_debug_flag: + print("%-8s Service pattern: %s Task pattern: %s"\ + %("INFO", publisher.ServicePattern, publisher.TaskPattern, )) + service_list.append(publisher) + + return (adder_task_class, service_list) + +class AdderApp(Application): + def __init__(self, outputLevel, partitionName='OFFLINE', partitionID=0xFFFF, adders=[]): + import _fifo_log + Application.__init__(self, + outputLevel=outputLevel, + partitionName=partitionName, + partitionID=partitionID) + # First setup printing device: + self.config.logDeviceType = 'RTL::Logger::LogDevice' + self.config.logDeviceFormat = '%-8LEVEL %-24SOURCE' + self.config.logDeviceType = 'fifo' + _fifo_log.logger_set_tag(partitionName) + _fifo_log.logger_start() + # Now the rest: + self.config.numEventThreads = 0 + self.config.numStatusThreads = 0 + self.config.autoStart = False + self.app = ApplicationMgr() + self.app.MessageSvcType = 'MessageSvc' + self.app.EvtSel = 'NONE' + self.app.EvtMax = -1 + self.app.AppName = "" # utgid + self.app.HistogramPersistency = "NONE" + self.app.EvtSel = "NONE" + self.app.ExtSvc = adders + EventLoopMgr().Warnings = False + +def run_adder(): + import errno + import OnlineEnvBase + vnode = VictimNode() + part = OnlineEnvBase.PartitionName + try: + # arch = OnlineEnvBase.WorkerArchitecture + arch = os.getenv("ARCHITECTURE") + if not arch: + arch = '/group/online/dataflow/options/'+part+'/Architecture.xml' + os.stat(arch) + except: + print('[FATAL] Adder: Failed to access the architecture file: %s for partition: %s'%(arch, part,)) + sys.exit(errno.ENOENT) + + hostdns = False + adder_type = os.getenv("ADDER_TYPE","1") + print("[INFO] Adder: AdderType: %s Partition: %s Architecture: %s"%(adder_type, part, arch)) + + tasklist = TaskListfromArch(arch) + cls,adderlist = AddersfromTasks(tasklist,adder_type,part,hostdns) + outputLevel = OnlineEnvBase.OutputLevel + #outputLevel = 3 + app = AdderApp(outputLevel=outputLevel,partitionName=part,adders=adderlist) + app.config.classType = cls +# Invoke the adder application: +run_adder() diff --git a/Online/FarmConfig/job/AligAdder.sh b/Online/FarmConfig/job/AligAdder.sh new file mode 100755 index 000000000..6be77e049 --- /dev/null +++ b/Online/FarmConfig/job/AligAdder.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +export PYTHONPATH=${ONLINE_ENV_DIR}:${PYTHONPATH} +export AdderOptsFile=/tmp/${PARTITION_NAME}_AdderOpts.opts +export victimnodes="hlt02(.*)" +python ./Tasklist_from_architecture.py 1 ${AdderOptsFile} +#export LD_LIBRARY_PATH=/home/beat/cmtuser/myOnline/InstallArea/x86_64-slc6-gcc48-dbg/lib/:$LD_LIBRARY_PATH +exec -a ${UTGID} ${Class1_task} -opts=../options/genAdder.opts diff --git a/Online/FarmConfig/job/AligDrv.sh b/Online/FarmConfig/job/AligDrv.sh new file mode 100755 index 000000000..395d797c7 --- /dev/null +++ b/Online/FarmConfig/job/AligDrv.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the data writer task on a farm node +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +fix_python() +{ + export UTGID; + PY=`which python`; + PY=`dirname ${PY}`; + export PYTHONHOME=`dirname ${PY}`; + unset PY; +} +# +# +act=${RUN_TYPE} +if [ "$act" = "Alignment|Muon" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligIterator import doIt; doIt('MuonAlignment');" +elif [ "$act" = "Alignment|Tracker" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligIterator import doIt; doIt('TrackerAlignment');" +elif [ "$act" = "Alignment|Velo" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligIterator import doIt; doIt('VeloAlignment');" +elif [ "$act" = "Alignment|VeloHalf" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligIterator import doIt; doIt('VeloHalfAlignment');" +elif [ "$act" = "Alignment|TED" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligIterator import doIt; doIt('TEDAlignment');" +elif [ "$act" = "Alignment|Rich1" ]; then +# . /group/rich/sw/cmtuser/AlignmentOnlineDev_v11r0/setup.x86_64-slc6-gcc49-opt.vars + . /group/rich/sw/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH +# export PYTHONPATH=/home/raaij/pydim/x86_64-slc6-gcc49-opt/lib/python2.7/site-packages:$PYTHONPATH + python -c "from PyMirrAlignOnline import Iterator; Iterator.run(1)" +elif [ "$act" = "Alignment|Rich2" ]; then +# . /group/rich/sw/cmtuser/AlignmentOnlineDev_v11r0/setup.x86_64-slc6-gcc49-opt.vars + . /group/rich/sw/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH +# export PYTHONPATH=/home/raaij/pydim/x86_64-slc6-gcc49-opt/lib/python2.7/site-packages:$PYTHONPATH + python -c "from PyMirrAlignOnline import Iterator; Iterator.run(2)" +elif [ "$act" = "Calibration|Calo" ]; then + #. /group/calo/cmtuser/DaVinciDev_v41r2p2/setup.x86_64-slc6-gcc49-opt.vars +# . /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-centos7-gcc62-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-slc6-gcc49-opt.vars +#work . /group/calo/cmtuser/DaVinciDev_v42r3_cleaning/setup.x86_64-slc6-gcc49-do0.vars +# + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# + fix_python; + export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH; + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} python -c "from PyKaliOnline import IteratorStep1; IteratorStep1.run('/group/online/CalibWork')" +elif [ "$act" = "Calibration|CaloStep2" ]; then + #. /group/calo/cmtuser/DaVinciDev_v41r2p2/setup.x86_64-slc6-gcc49-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-slc6-gcc49-opt.vars +#work . /group/calo/cmtuser/DaVinciDev_v42r3_cleaning/setup.x86_64-slc6-gcc49-do0.vars +# + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# + fix_python; + export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH; + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH +#work export NO_GIT_CONDDB=1 + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} python -c "from PyKaliOnline import IteratorStep2; IteratorStep2.run('/group/online/CalibWork')" +elif [ "$act" = "Calibration|CaloPi0" ]; then + #. /group/calo/cmtuser/DaVinciDev_v41r2p1/setup.x86_64-slc6-gcc62-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v41r2p1/setup.x86_64-slc6-gcc49-opt.vars + ##. /group/calo/cmtuser/DaVinciDev_v41r2p1/setup.x86_64-slc6-gcc49-do0.vars + #. /group/calo/cmtuser/DaVinciDev_v41r2p2/setup.x86_64-slc6-gcc49-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-slc6-gcc49-opt.vars + . /group/calo/cmtuser/DaVinciDev_v42r3_cleaning/setup.x86_64-slc6-gcc49-do0.vars + #. /group/calo/cmtuser/CaloCalibrationDev_v10r4p1/setup.x86_64-slc6-gcc48-dbg.vars + fix_python; + export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH; + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} python -c "from PyKaliOnline import Iterator; Iterator.run('/group/online/CalibWork')" +elif [ "$act" = "BWDivision" ]; then + . /group/online/bw_division/cmtuser/BWDivisionDev/setup.x86_64-slc6-gcc48-opt.vars + fix_python + . /group/online/bw_division/root/bin/thisroot.sh + export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH + export OUTPUTDIR=/group/online/bw_division/output + export UTGID + exec -a ${UTGID} python -c "from PyGeneticOnline import Iterator; Iterator.run()" +elif [ "$act" = "L0" ]; then + . /group/hlt/sattelite/MooreOnlinePit_v24r4p1/InstallArea/x86_64-slc6-gcc49-opt/setupMoore.sh + fix_python + export UTGID + exec -a ${UTGID} python -c "from PyAlignOnline import Iterator; Iterator.run(1)" +fi diff --git a/Online/FarmConfig/job/AligWrk.sh b/Online/FarmConfig/job/AligWrk.sh new file mode 100755 index 000000000..f15871ba9 --- /dev/null +++ b/Online/FarmConfig/job/AligWrk.sh @@ -0,0 +1,109 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the data writer task on a farm node +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +fix_python() +{ + export UTGID; + PY=`which python`; + PY=`dirname ${PY}`; + export PYTHONHOME=`dirname ${PY}`; + export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH; + unset PY; +} +# +# +renice -n 11 -p $$ >>/dev/null +act=${RUN_TYPE} +if [ "$act" = "Alignment|Muon" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligAnalyzer import doIt; doIt('/localdisk/Alignment/Muon', 'MuonAlignment');" +elif [ "$act" = "Alignment|Tracker" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job +# export LD_PRELOAD=/group/online/dataflow/cmtuser/OnlineDev_v5r31/InstallArea/x86_64-slc6-gcc49-do0/lib/libGaucho.so:$LD_PRELOAD + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligAnalyzer import doIt; doIt('/localdisk/Alignment/Tracker', 'TrackerAlignment');" +elif [ "$act" = "Alignment|Velo" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligAnalyzer import doIt; doIt('/localdisk/Alignment/Velo', 'VeloAlignment');" +elif [ "$act" = "Alignment|VeloHalf" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligAnalyzer import doIt; doIt('/localdisk/Alignment/Velo', 'VeloHalfAlignment');" +elif [ "$act" = "Alignment|TED" ]; then + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + export PYTHONPATH=${ALIGNONLINEROOT}/python:$PYTHONPATH + cd ${FARMCONFIGROOT}/job + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from TrAligAnalyzer import doIt; doIt('/localdisk/Alignment/Tracker', 'TEDAlignment');" +elif [ "$act" = "Alignment|Rich1" ]; then +# . /group/rich/sw/cmtuser/AlignmentOnlineDev_v11r0/setup.x86_64-slc6-gcc49-dbg.vars + . /group/rich/sw/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH +# export PYTHONPATH=/home/raaij/pydim/lib/python2.7/site-packages:$PYTHONPATH + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from PyMirrAlignOnline import RichAnalyzer; RichAnalyzer.doIt(filename = '/localdisk/Alignment/Rich', whichRich = 1);" +elif [ "$act" = "Alignment|Rich2" ]; then +# . /group/rich/sw/cmtuser/AlignmentOnlineDev_v11r0/setup.x86_64-slc6-gcc49-dbg.vars + . /group/rich/sw/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:$PYTHONPATH + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH +# export PYTHONPATH=/home/raaij/pydim/lib/python2.7/site-packages:$PYTHONPATH + exec -a ${UTGID} ${Class1_task} libGaudiOnline.so OnlineTask -tasktype=LHCb::Class1Task -main=/group/online/dataflow/templates/options/Main.opts -opt=command="import Gaudi,GaudiKernel.ProcessJobOptions; from Gaudi.Configuration import importOptions; GaudiKernel.ProcessJobOptions.printing_level=999; from PyMirrAlignOnline import RichAnalyzer; RichAnalyzer.doIt(filename = '/localdisk/Alignment/Rich', whichRich = 2);" +elif [ "$act" = "Calibration|Calo" ]; then + #. /group/calo/cmtuser/DaVinciDev_v41r2p2/setup.x86_64-slc6-gcc49-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-slc6-gcc49-opt.vars +#work . /group/calo/cmtuser/DaVinciDev_v42r3_cleaning/setup.x86_64-slc6-gcc49-do0.vars +# + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars +# +# . /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-centos7-gcc62-opt.vars + fix_python; + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH; + cd ${FARMCONFIGROOT}/job; + echo $GAUDIROOT + echo $PYTHONHOME + echo $PYTHONPATH + exec -a ${UTGID} python -c "from PyKaliOnline import AnalyzerStep1; AnalyzerStep1.run(0, '/group/online/CalibWork', '/localdisk/Alignment/Calo')" +elif [ "$act" = "Calibration|CaloStep2" ]; then + #. /group/calo/cmtuser/DaVinciDev_v41r2p2/setup.x86_64-slc6-gcc49-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-slc6-gcc49-opt.vars +#work . /group/calo/cmtuser/DaVinciDev_v42r3_cleaning/setup.x86_64-slc6-gcc49-do0.vars + . /group/online/dataflow/cmtuser/AlignmentRelease/setup.x86_64-centos7-gcc62-opt.vars + fix_python; + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH; +#work export NO_GIT_CONDDB=1 + cd ${FARMCONFIGROOT}/job; + exec -a ${UTGID} python -c "from PyKaliOnline import AnalyzerStep2; AnalyzerStep2.run(0, '/group/online/CalibWork', '/localdisk/Alignment/Calo')" +elif [ "$act" = "Calibration|CaloPi0" ]; then + #. /group/calo/cmtuser/DaVinciDev_v41r2p1/setup.x86_64-slc6-gcc62-do0.vars + ##. /group/calo/cmtuser/DaVinciDev_v41r2p1/setup.x86_64-slc6-gcc49-do0.vars + #. /group/calo/cmtuser/DaVinciDev_v42r1/setup.x86_64-slc6-gcc49-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v41r2p2/setup.x86_64-slc6-gcc49-opt.vars + #. /group/calo/cmtuser/DaVinciDev_v42r3/setup.x86_64-slc6-gcc49-opt.vars + . /group/calo/cmtuser/DaVinciDev_v42r3_cleaning/setup.x86_64-slc6-gcc49-do0.vars + # . /group/calo/cmtuser/CaloCalibrationDev_v10r4p1/setup.x86_64-slc6-gcc48-dbg.vars; + fix_python; + export PYTHONPATH=/group/online/dataflow/options/LHCbA/HLT:$PYTHONPATH; + cd ${FARMCONFIGROOT}/job; + exec -a ${UTGID} python -c "from PyKaliOnline import Analyzer; Analyzer.run(0, '/group/online/CalibWork', '/localdisk/Alignment/Calo')" +elif [ "$act" = "BWDivision" ]; then + . /group/online/bw_division/cmtuser/BWDivisionDev/setup.x86_64-slc6-gcc48-opt.vars + fix_python; + export PYTHONPATH=/group/online/bw_division/pydim/lib/python2.7/site-packages:/scratch/jenkins/benchmark/python:$PYTHONPATH + export OUTPUTDIR=/group/online/bw_division/output + export UTGID + exec -a ${UTGID} python -c "from PyGeneticOnline import Analyzer; Analyzer.run()" +fi diff --git a/Online/FarmConfig/job/AlignReader.sh b/Online/FarmConfig/job/AlignReader.sh new file mode 100755 index 000000000..0fc3fc7be --- /dev/null +++ b/Online/FarmConfig/job/AlignReader.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# +NODE=`hostname -s | tr a-z A-Z`; +export NODE_OPTIONS=${DYNAMIC_OPTS}/Nodes/${NODE}_TriggerInfo.opts; +export GO_SERVICE_NAME=""#${PARTITION_NAME}_${NODE}/Trigger; +if test "$NODE" = "ignore-test-HLTC1020"; then + export LD_LIBRARY_PATH=/home/frankm/cmtuser/OnlineDev_v5r31/InstallArea/x86_64-slc6-gcc49-do0/lib:$LD_LIBRARY_PATH; + export PATH=/home/frankm/cmtuser/OnlineDev_v5r31/InstallArea/x86_64-slc6-gcc49-do0/bin:$PATH; + echo "[WARNING] Running TEST version of HLT2 reader"; +fi; +##echo "[error] Go service name is: ${GO_SERVICE_NAME}"; +act=${RUN_TYPE} +export AlignDir="/localdisk/Alignment/`echo $act|cut -d "|" -f 2`" +exec -a ${UTGID} ${DATAFLOW_task} -class=Class2 -opts=../options/${TASK_TYPE}.opts diff --git a/Online/FarmConfig/job/AlignWriter.sh b/Online/FarmConfig/job/AlignWriter.sh new file mode 100755 index 000000000..3cc933541 --- /dev/null +++ b/Online/FarmConfig/job/AlignWriter.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the data writer task on a farm node +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +exec -a ${UTGID} ${DATAFLOW_task} -class=Class1 -opts=../options/${TASK_TYPE}.opts; diff --git a/Online/FarmConfig/job/BU.sh b/Online/FarmConfig/job/BU.sh new file mode 100755 index 000000000..fcb73e7df --- /dev/null +++ b/Online/FarmConfig/job/BU.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +unset PYTHONPATH; +unset PYTHONHOME; +eval `/usr/bin/python2 -c "import os;s=os.environ['UTGID'];print 'export BU_OPTIONS='+s[s.find('BU'):]+'.opts'"`; +#. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64-centos7-gcc9-opt.vars; +. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64_v2-centos7-gcc10-do0.vars; +#. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64_v2-centos7-gcc10-opt.vars; +# . /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.${CMTCONFIG}.vars; +cd ${FARMCONFIGROOT}/job; +# +`dataflow_task Class1` -opts=../../EventBuilding/options/${BU_OPTIONS} ${AUTO_STARTUP} ${DEBUG_STARTUP}; diff --git a/Online/FarmConfig/job/ClassTask.sh b/Online/FarmConfig/job/ClassTask.sh new file mode 100755 index 000000000..26b93e2e7 --- /dev/null +++ b/Online/FarmConfig/job/ClassTask.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the storage/monitoring nodes +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +##echo "[ERROR] exec -a ${UTGID} ${DATAFLOW_task} -class=${TASK_CLASS} -opts=${TASK_OPTIONS}"; +test_release=/home/frankm/cmtuser/OnlineDev_v6r4; +if test -z "$test_release";then + if test -f ${test_release}/Online/FarmConfig/options/${TASKTYPE}.opts; then + cd ${test_release}; + . setup.${CMTCONFIG}.vars; + cd ${FARMCONFIGROOT}/job; + echo "[WARN] +++ Starting experimental task ${TASKTYPE} from ${test_release}"; + fi; +fi; +###echo "${UTGID} DATAINTERFACE: ${DATAINTERFACE} Opts: ${TASK_OPTIONS}" +exec -a ${UTGID} ${DATAFLOW_task} -class=${TASK_CLASS} -opts=${TASK_OPTIONS}; diff --git a/Online/FarmConfig/job/CleanAlignment.sh b/Online/FarmConfig/job/CleanAlignment.sh new file mode 100755 index 000000000..c66b5739b --- /dev/null +++ b/Online/FarmConfig/job/CleanAlignment.sh @@ -0,0 +1,5 @@ +cd /group/online/dataflow/cmtuser/OnlineRelease/Online/FarmConfig/job +#cd /group/online/dataflow/cmtuser/OnlineDev_v6r7/Online/FarmConfig/job +python CleanAlignment.py /localdisk/Alignment/Calo/ Calo +python CleanAlignment.py /localdisk/Alignment/Rich/ Rich +#python CleanAlignment.py /localdisk/Alignment/Muon/ Muon \ No newline at end of file diff --git a/Online/FarmConfig/job/Controller.sh b/Online/FarmConfig/job/Controller.sh new file mode 100755 index 000000000..165936e78 --- /dev/null +++ b/Online/FarmConfig/job/Controller.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# ========================================================================= +# +# Farm worker node controller startup script +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +HOST=`hostname -s | tr a-z A-Z`; +HOST_LONG=`hostname -f | tr a-z A-Z`; +# +# Check the existence of various arguments. +# Otherwise use default values. +# +if test -z "${LOGFIFO}"; then + export LOGFIFO=/run/fmc/logSrv.fifo; +fi; +if test "${LOGFIFO}" = "/run/fmc/logSrv.fifo" -a -e "/dev/shm/logs.dev"; then + export LOGFIFO=/dev/shm/logs.dev; +fi; +if test -z "${TMS_DNS}"; then + export TMS_DNS=${HOST_LONG}; +fi; +if test -z "${SMI_DNS}"; then + export SMI_DNS=${HOST_LONG}; +fi; +if test -z "${SMI_FILE}"; then + export SMI_FILE=${SMICONTROLLERROOT}/options/MonNode +fi; +if test -z "${SMI_DOMAIN}"; then + export SMI_DOMAIN=${PARTITION_NAME}_${HOST}_SMI; +fi; +if test -z "${DIM_DNS_NODE}"; then + export DIM_DNS_NODE=${HOST_LONG}; +fi; +# +# +# +DEBUG_ARGS=; +# +# DEBUG_ARGS="-debug"; +# echo "${UTGID} [ERROR] ${HOST}"; +SMI_DEBUG=0; +if test "${HOST}" = "TDEB03"; then +# cd /group/online/dataflow/cmtuser/OnlineDev_v7r11; +# . setup.x86_64_v2-centos7-gcc10-do0.vars; + SMI_DEBUG=0; +fi; +# +make_gdb_input() { + echo "run" > /tmp/gdb_commands.txt; + echo "thread apply all bt" >> /tmp/gdb_commands.txt; + echo "quit" >> /tmp/gdb_commands.txt; + echo "y" >> /tmp/gdb_commands.txt; + echo "y" >> /tmp/gdb_commands.txt; + echo "y" >> /tmp/gdb_commands.txt; +} +# +exec -a ${UTGID} `which genRunner.exe` libSmiController.so smi_controller \ + -print=4 \ + -logger=fifo \ + -part=${PARTITION_NAME} \ + -dns=${DIM_DNS_NODE} \ + -tmsdns=${TMS_DNS} \ + -smidns=${SMI_DNS} \ + -smidomain=${SMI_DOMAIN} \ + -smidebug=${SMI_DEBUG} \ + -smifile=${SMI_FILE} \ + -count=${NBOFSLAVES} \ + -service=none \ + -runinfo=${RUNINFO} \ + -taskconfig=${ARCH_FILE} \ + "${CONTROLLER_REPLACEMENTS}" \ + -standalone=1 \ + -bindcpus=0 ${DEBUG_ARGS} +## +## +## < /tmp/gdb_commands.txt 2>&1 > /dev/shm/logs.dev; diff --git a/Online/FarmConfig/job/EBAdder.sh b/Online/FarmConfig/job/EBAdder.sh new file mode 100755 index 000000000..3c2883985 --- /dev/null +++ b/Online/FarmConfig/job/EBAdder.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=EventBuilder; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/EBPartAdder.sh b/Online/FarmConfig/job/EBPartAdder.sh new file mode 100755 index 000000000..a40a1f02c --- /dev/null +++ b/Online/FarmConfig/job/EBPartAdder.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=${TASK_TYPE}; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/EBPartPublisher.sh b/Online/FarmConfig/job/EBPartPublisher.sh new file mode 100755 index 000000000..a40a1f02c --- /dev/null +++ b/Online/FarmConfig/job/EBPartPublisher.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=${TASK_TYPE}; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/EBPartSaver.sh b/Online/FarmConfig/job/EBPartSaver.sh new file mode 100755 index 000000000..a40a1f02c --- /dev/null +++ b/Online/FarmConfig/job/EBPartSaver.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=${TASK_TYPE}; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/EBPass.sh b/Online/FarmConfig/job/EBPass.sh new file mode 100755 index 000000000..368ffbbdb --- /dev/null +++ b/Online/FarmConfig/job/EBPass.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +if [[ "$UTGID" == *"${TASK_TYPE}_0"* ]]; then + export MBM_INPUT_BUFFER=Events_0; +elif [[ "$UTGID" == *"${TASK_TYPE}_1"* ]]; then + export MBM_INPUT_BUFFER=Events_1; +elif [[ "$UTGID" == *"${TASK_TYPE}_2"* ]]; then + export MBM_INPUT_BUFFER=Events_0; +elif [[ "$UTGID" == *"${TASK_TYPE}_3"* ]]; then + export MBM_INPUT_BUFFER=Events_1; +elif [[ "$UTGID" == *"${TASK_TYPE}_4"* ]]; then + export MBM_INPUT_BUFFER=Events_0; +else + export MBM_INPUT_BUFFER=Events_1; +fi; +# +execute `gaudi_event_task ${FARMCONFIGROOT}/job/Passthrough.py`; diff --git a/Online/FarmConfig/job/EBReader.sh b/Online/FarmConfig/job/EBReader.sh new file mode 100644 index 000000000..d16c15c62 --- /dev/null +++ b/Online/FarmConfig/job/EBReader.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +if [[ "$UTGID" == *"${TASK_TYPE}_0"* ]]; then + export MBM_OUTPUT_BUFFER=Events_0; +elif [[ "$UTGID" == *"${TASK_TYPE}_1"* ]]; then + export MBM_OUTPUT_BUFFER=Events_1; +elif [[ "$UTGID" == *"${TASK_TYPE}_2"* ]]; then + export MBM_OUTPUT_BUFFER=Events_0; +elif [[ "$UTGID" == *"${TASK_TYPE}_3"* ]]; then + export MBM_OUTPUT_BUFFER=Events_1; +elif [[ "$UTGID" == *"${TASK_TYPE}_4"* ]]; then + export MBM_OUTPUT_BUFFER=Events_0; +else + export MBM_OUTPUT_BUFFER=Events_1; +fi; +export RUN_NUMBER_SERVICE=${PARTITION}/RunInfo/RunNumber; +# +execute `dataflow_task Class1` -opts=${STATIC_OPTS}/${TASK_TYPE}.opts ${AUTO_STARTUP} ${DEBUG_STARTUP}; diff --git a/Online/FarmConfig/job/EBSender.sh b/Online/FarmConfig/job/EBSender.sh new file mode 100755 index 000000000..2d3814257 --- /dev/null +++ b/Online/FarmConfig/job/EBSender.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +export PYTHONPATH=${ONLINE_ENV_DIR}:${PYTHONPATH}; +# +rfilen() +{ + export PRESCALER_REQUIREMENTS=Default.prescaler-requirements + act1=$1 + IFS="|" read -a splt <<<"$act1" + for ((i=${#splt[@]};i>0;i--)) + do + fn=${splt[0]} + for ((x=1;x<$i;x++)) + do + echo $x + fn+="-" + fn+=${splt[x]} + done + rfn="../options/" + rfn+=$fn".prescaler-requirements" + echo $rfn + if [ -f ${rfn} ]; + then + export PRESCALER_REQUIREMENTS=${rfn}; + break + fi + done +} +act=${RUN_TYPE} +# +rfilen ${act} +export EVENTSELECTOR_REQ1="EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0"; +export TAN_PORT=YES; +export TAN_NODE=${DATAINTERFACE}; +export SENDER_TARGET="${MONITORING_DISTBOX}::${PARTITION}_${MONITORING_DISTBOX}_RCVMon"; +####export SENDER_TARGET="${MONITORING_DISTBOX}::LHCb_${MONITORING_DISTBOX}_RCVMon"; +echo [INFO] Eventselector request: ${EVENTSELECTOR_REQ1}; +echo [INFO] Prescaler Requirement File: ${PRESCALER_REQUIREMENTS}; +execute `dataflow_task Class2` -opts=${STATIC_OPTS}/${TASK_TYPE}.opts ${AUTO_STARTUP} ${DEBUG_STARTUP}; diff --git a/Online/FarmConfig/job/EBStorage.sh b/Online/FarmConfig/job/EBStorage.sh new file mode 100755 index 000000000..bdf20c369 --- /dev/null +++ b/Online/FarmConfig/job/EBStorage.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +execute `dataflow_task Class1` -opts=${STATIC_OPTS}/${TASK_TYPE}.opts ${AUTO_STARTUP} ${DEBUG_STARTUP}; diff --git a/Online/FarmConfig/job/EBSubDetAdder.sh b/Online/FarmConfig/job/EBSubDetAdder.sh new file mode 100755 index 000000000..939038190 --- /dev/null +++ b/Online/FarmConfig/job/EBSubDetAdder.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=EventBuilderSubDet; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/FileRawSizeMon.sh b/Online/FarmConfig/job/FileRawSizeMon.sh new file mode 100755 index 000000000..6c4141087 --- /dev/null +++ b/Online/FarmConfig/job/FileRawSizeMon.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start a dummy task only following FSM transitions +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +export LOGFIFO=/run/fmc/logSrv.fifo; +export EVENTSELECTOR_OPTIONS; +export WORKING_DIRECTORY; +cd ${WORKING_DIRECTORY}; +exec -a ${UTGID} ${Class1_task} -opt=${FARMCONFIGROOT}/options/FileRawSizeMon.opts diff --git a/Online/FarmConfig/job/FileTest.sh b/Online/FarmConfig/job/FileTest.sh new file mode 100755 index 000000000..4bd88dd49 --- /dev/null +++ b/Online/FarmConfig/job/FileTest.sh @@ -0,0 +1,2 @@ +cd ../../DefHLTUtils/scripts +. FileTest.sh diff --git a/Online/FarmConfig/job/HLT2Adder.sh b/Online/FarmConfig/job/HLT2Adder.sh new file mode 100755 index 000000000..13df8c23c --- /dev/null +++ b/Online/FarmConfig/job/HLT2Adder.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=HltNode; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/HLT2Pass.sh b/Online/FarmConfig/job/HLT2Pass.sh new file mode 100755 index 000000000..cac3ba3ae --- /dev/null +++ b/Online/FarmConfig/job/HLT2Pass.sh @@ -0,0 +1,12 @@ +#!/bin/bash +## ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +exec -a ${UTGID} genPython.exe `which gaudirun.py` ${FARMCONFIGROOT}/job/Passthrough.py --application=Online::OnlineEventApp; diff --git a/Online/FarmConfig/job/HLT2Publisher.sh b/Online/FarmConfig/job/HLT2Publisher.sh new file mode 100755 index 000000000..6c3a81bd6 --- /dev/null +++ b/Online/FarmConfig/job/HLT2Publisher.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=HltPublisher; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/HLT2Reader.sh b/Online/FarmConfig/job/HLT2Reader.sh new file mode 100755 index 000000000..e52fa34bc --- /dev/null +++ b/Online/FarmConfig/job/HLT2Reader.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Generic farm task startup script +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +#`dataflow_task Class2` -opts=/group/online/dataflow/cmtuser/OnlineRelease/TestBeam/options/MDFProd.opts +`dataflow_task Class2` -opts=../options/HLT2Reader.opts diff --git a/Online/FarmConfig/job/HLT2SFAdder.sh b/Online/FarmConfig/job/HLT2SFAdder.sh new file mode 100755 index 000000000..8ec005e5b --- /dev/null +++ b/Online/FarmConfig/job/HLT2SFAdder.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=HltSubfarm; +echo "WARNING Starting subfarm adder ${UTGID}"; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/HLT2Saver.sh b/Online/FarmConfig/job/HLT2Saver.sh new file mode 100755 index 000000000..31c40de0b --- /dev/null +++ b/Online/FarmConfig/job/HLT2Saver.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=HltSaver; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/HLT2TopAdder.sh b/Online/FarmConfig/job/HLT2TopAdder.sh new file mode 100755 index 000000000..8a8cc45ac --- /dev/null +++ b/Online/FarmConfig/job/HLT2TopAdder.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export ADDER_TYPE=HltTop; +exec -a ${UTGID} genPython.exe `which gaudirun.py` ./AddersFromArchitecture.py --application=Online::OnlineApplication; diff --git a/Online/FarmConfig/job/MFPGen.sh b/Online/FarmConfig/job/MFPGen.sh new file mode 100755 index 000000000..2655c0ed4 --- /dev/null +++ b/Online/FarmConfig/job/MFPGen.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +# . /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64-centos7-gcc9-opt.vars; +. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64_v2-centos7-gcc10-opt.vars; +#. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.${CMTCONFIG}.vars; +cd ${FARMCONFIGROOT}/job; +# +`dataflow_task Class1` -opts=../../EventBuilding/options/${TASK_TYPE}.opts ${AUTO_STARTUP} ${DEBUG_STARTUP}; diff --git a/Online/FarmConfig/job/MonRegistrar.sh b/Online/FarmConfig/job/MonRegistrar.sh new file mode 100644 index 000000000..025968f28 --- /dev/null +++ b/Online/FarmConfig/job/MonRegistrar.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# ========================================================================= +# +# Script to start the monitoring registrar +# +# Author R. Aaij +# Version: 1.0 +# Date: 19/07/2017 +# +# ========================================================================= +# +export TAN_PORT=YES; +export TAN_NODE=${DATAINTERFACE}; +if test "`uname -a | grep \".el6\"`" != ""; # SLC6 +then + export CMTCONFIG=x86_64-slc6-gcc62-dbg +elif test "`uname -a | grep el7`" != ""; # SLC7 (Centos 7) +then + export CMTCONFIG=x86_64-centos7-gcc62-dbg +fi; + +read COMMAND <<EOF +from Monitoring import Registrar;\ +Registrar.run(auto=True) +EOF + +. /group/hlt/monitoring/ONLINE/ONLINE_v6r3/setup.$CMTCONFIG.vars +export UTGID +python -c "${COMMAND}" +# exec -a ${UTGID} ${Class1_task} -opt=command="${COMMAND}" diff --git a/Online/FarmConfig/job/Moore.sh b/Online/FarmConfig/job/Moore.sh new file mode 100755 index 000000000..834ed58d1 --- /dev/null +++ b/Online/FarmConfig/job/Moore.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start MOORE on a farm node. +# +# Author M.Frank +# Version: 1.0 +# Date: 20/08/2013 +# +# ========================================================================= +# +export CMTCONFIG=x86_64-slc6-gcc49-opt; +. /group/hlt/MOORE/${MOOREONLINE_VERSION}/InstallArea/runMooreOnline_EFF.sh ${DIM_DNS_NODE} ${PARTITION_NAME} ${NBOFSLAVES} diff --git a/Online/FarmConfig/job/Moore1.sh b/Online/FarmConfig/job/Moore1.sh new file mode 100755 index 000000000..103860b20 --- /dev/null +++ b/Online/FarmConfig/job/Moore1.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the HLT1 task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +if test "`uname -a | grep \".el6\"`" != ""; # SLC6 +then + export CMTCONFIG=x86_64-slc6-gcc62-opt; +elif test "`uname -a | grep el7`" != ""; # SLC7 (Centos 7) +then + export CMTCONFIG=x86_64-centos7-gcc62-opt +fi; +export CHECKPOINTING_CONFIG=${CMTCONFIG}; +##echo "[ERROR] Moore1: version: ${MOORE_VERSION} Using ${CHECKPOINTING_CONFIG} CMTCONFIG:${CMTCONFIG}"; +export NiceLevel=10; +export DAQ_INHIBIT_FINALIZE=ON; +. /group/hlt/MOORE/${MOOREONLINE_VERSION}/InstallArea/runMooreHlt1Online_EFF.sh ${DIM_DNS_NODE} ${PARTITION_NAME} ${NBOFSLAVES}; +#. ${FARMCONFIGROOT}/job/runMooreHlt1Online_EFF.sh ${DIM_DNS_NODE} ${PARTITION_NAME} ${NBOFSLAVES}; diff --git a/Online/FarmConfig/job/Moore2.sh b/Online/FarmConfig/job/Moore2.sh new file mode 100755 index 000000000..e542fd31f --- /dev/null +++ b/Online/FarmConfig/job/Moore2.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +if test "`uname -a | grep \".el6\"`" != ""; # SLC6 +then + export CMTCONFIG=x86_64-slc6-gcc62-opt; +elif test "`uname -a | grep el7`" != ""; # SLC7 (Centos 7) +then + export CMTCONFIG=x86_64-centos7-gcc62-opt +fi; +export DAQ_INHIBIT_FINALIZE=ON; +export NiceLevel=17; +export HN=`hostname -s | tr a-z A-Z`; +if [ "${PARTITION_NAME}" == "LHCb1" ]; then + . /group/hlt/MOORE/${MOOREONLINE_VERSION}/InstallArea/runMooreHlt2Online_EFF.sh ${DIM_DNS_NODE} ${PARTITION_NAME} ${NBOFSLAVES}; +else +if test -f "/group/online/dataflow/options/LHCb2/Nodes/${HN}_TriggerInfo.py"; +then + export PYTHONPATH=/group/online/dataflow/options/LHCb2/Nodes; + unset MOOREONLINE_VERSION; + export MOOREONLINE_VERSION=`python -c "import ${HN}_TriggerInfo as H; print H.MooreOnlineVersion"`; + ### export CMTCONFIG=x86_64-slc6-gcc48-dbg; + ### source ${FARMCONFIGROOT}/job/runMooreHlt2Online_EFF.sh ${DIM_DNS_NODE} ${PARTITION_NAME} ${NBOFSLAVES}; + . /group/hlt/MOORE/${MOOREONLINE_VERSION}/InstallArea/runMooreHlt2Online_EFF.sh ${DIM_DNS_NODE} ${PARTITION_NAME} ${NBOFSLAVES}; +else + echo "[ERROR] Cannot determine MOOREONLINE_VERSION. No file: /group/online/dataflow/options/LHCb2/Nodes/${HN}_TriggerInfo.py"; +fi; +fi; diff --git a/Online/FarmConfig/job/NodeAdder.sh b/Online/FarmConfig/job/NodeAdder.sh new file mode 100755 index 000000000..f08d3eab7 --- /dev/null +++ b/Online/FarmConfig/job/NodeAdder.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the event reader task on the HLT farm +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +#export victimnodes="hltb0113(.*)" +export PYTHONPATH=${ONLINE_ENV_DIR}:${PYTHONPATH}; +export AdderOptsFile=/tmp/${PARTITION_NAME}_AdderOpts.opts; +export AdderStaticOpts=../options/NodeAdderStatic.opts +python ./Tasklist_from_architecture.py 1 ${AdderOptsFile}; +#export RTL_SLEEP_ON_FATAL=1 +if test "${PARTITION_NAME}" = "LHCb"; then + exec -a ${UTGID} ${Class1_task} -opts=../options/genAdder.opts; +# exec -a ${UTGID} ~beat/scripts/debug --command=~beat/AdderDebugScript --args ${Class1_task} -opts=../options/genAdder.opts; +fi +if test "${PARTITION_NAME}" = "LHCbA"; then + exec -a ${UTGID} ${Class1_task} -opts=../options/genAdder.opts; +# exec -a ${UTGID} ~beat/scripts/debug --command=~beat/AdderDebugScript --args ${Class1_task} -opts=../options/genAdder.opts; +else + exec -a ${UTGID} ${Class1_task} -opts=../options/genAdder.opts; +fi +#exec -a ${UTGID} ${Class0_task} -opt=../options/Daemon.opts -main=../options/genAdder.opts diff --git a/Online/FarmConfig/job/NodeBusyMon.sh b/Online/FarmConfig/job/NodeBusyMon.sh new file mode 100755 index 000000000..11a47adbe --- /dev/null +++ b/Online/FarmConfig/job/NodeBusyMon.sh @@ -0,0 +1,21 @@ +#!/bin/bash +cd /group/online/dataflow/cmtuser +export User_release_area=`pwd`; +export CMTPROJECTPATH=`pwd`:${CMTPROJECTPATH}; +source OnlineRelease/setup.x86_64-centos7-gcc62-do0.vars +cd OnlineRelease/Online/FarmConfig/job +export HOST=`hostname` +export UTGID=GEN_${HOST}_BusyMon +export LOGFIFO=/run/fmc/logGaudi.fifo +export AddTest=AddTest_Victim.opts +export vnodes="hlt[a-f](.*)" +if [ -z `echo $HOST |egrep -e $vnodes` ] ; then export AddTest=AddTest_EMPTY.opts ; fi +echo "[INFO] AddTest = $AddTest" +###exec -a ${UTGID} +#export LD_LIBRARY_PATH="/home/beat/cmtuser/OnlineDev_v5r31/InstallArea/x86_64-slc6-gcc49-do0/lib:/group/online/dataflow/cmtuser/OnlineDev_v5r31/InstallArea/x86_64-slc6-gcc49-do0/lib:/cvmfs/lhcb.cern.ch/lib/lcg/releases/Boost/1.59.0_python2.7-682d6/x86_64-slc6-gcc49-dbg/lib:$LD_LIBRARY_PATH" +GaudiOnlineExe.exe \ + libGaudiOnline.so OnlineTask \ + -msgsvc=LHCb::FmcMessageSvc \ + -tasktype=LHCb::Class2Task \ + -main=/group/online/dataflow/templates/options/Main.opts \ + -opts=../options/NodeBsyMon.opts -auto diff --git a/Online/FarmConfig/job/Passthrough.py b/Online/FarmConfig/job/Passthrough.py new file mode 100644 index 000000000..dab28d710 --- /dev/null +++ b/Online/FarmConfig/job/Passthrough.py @@ -0,0 +1,87 @@ +""" + Minimal Gaudi task in the online environment + + @author M.Frank +""" +from __future__ import print_function +__version__ = "1.0" +__author__ = "Markus Frank <Markus.Frank@cern.ch>" + +import os +import sys +import Configurables +import Gaudi.Configuration as Gaudi + +import GaudiOnline +import OnlineEnvBase as OnlineEnv + +from Configurables import Online__FlowManager as FlowManager +application = GaudiOnline.Passthrough(outputLevel=OnlineEnv.OutputLevel, + partitionName=OnlineEnv.PartitionName, + partitionID=OnlineEnv.PartitionID, + classType=GaudiOnline.Class1) +application.setup_fifolog() +application.config.debug = False +buffer_name = os.getenv("MBM_INPUT_BUFFER","Events") +application.setup_mbm_access(buffer_name, True) +writer = application.setup_mbm_output('EventOutput') +writer.MBM_maxConsumerWait = 10 +writer.MBM_allocationSize = 1024*1024*10 +writer.MBM_burstPrintCount = 25000 +writer.MaxEventsPerTransaction = 10 +writer.UseRawData = False +writer.RequireODIN = False + +writer.UseRawData = True + +ev_size = Configurables.Online__EventSize('EventSize') + +explorer = Configurables.StoreExplorerAlg('Explorer') +explorer.Load = 1 +explorer.PrintFreq = 0.0000001 +#explorer.OutputLevel = 1 + +##have_odin = False +part = OnlineEnv.PartitionName +###if part == 'FEST' or part == 'LHCb2' or part == 'TDET': +have_odin = True + +application.setup_hive(FlowManager("EventLoop"), 40) +application.setup_monitoring(have_odin=have_odin) +#application.setup_algorithms(writer, 0.05) +application.setup_algorithms([ev_size,explorer,writer], 1.0) +application.monSvc.DimUpdateInterval = 1 +application.monSvc.CounterClasses = [ + "AuxCounters 10 (.*)EventInput/daqCounter.(.*)", + "DAQErrors 3 (.*)EventInput/daqError.(.*)" +]; + +application.config.expandTAE = False +application.config.burstPrintCount = 30000 + +# Mode slection:: synch: 0 async_queued: 1 sync_queued: 2 +application.config.execMode = 1 +application.config.numEventThreads = 15 +application.config.MBM_numConnections = 8 +application.config.MBM_numEventThreads = 5 +# +application.config.numEventThreads = 5 +application.config.MBM_numConnections = 3 +application.config.MBM_numEventThreads = 4 +# +# Enable this for debugging +# +_dbg = 1 +if _dbg: + application.config.execMode = 0 + application.config.numEventThreads = 1 + application.config.MBM_numConnections = 1 + application.config.MBM_numEventThreads = 1 +# +application.config.MBM_requests = [ + 'EvType=2;TriggerMask=0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0', + 'EvType=1;TriggerMask=0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0' +] +# +print('Setup complete.... Have ODIN: '+str(have_odin)) + diff --git a/Online/FarmConfig/job/RU.sh b/Online/FarmConfig/job/RU.sh new file mode 100755 index 000000000..b95211bc3 --- /dev/null +++ b/Online/FarmConfig/job/RU.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start the buffer manager on the HLT farm worker node +# +# Author M.Frank +# Version: 1.0 +# Date: 05/03/2021 +# +# ========================================================================= +# +#. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64_v2-centos7-gcc10-opt.vars; +. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64_v2-centos7-gcc10-do0.vars; +# . /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.x86_64-centos7-gcc9-opt.vars; +#. /group/online/dataflow/EventBuilder/EventBuilderRelease/setup.${CMTCONFIG}.vars; +cd ${EVENTBUILDINGROOT}/options; +`dataflow_task Class1` -opts=EB_RU.opts ${AUTO_STARTUP} ${DEBUG_STARTUP} diff --git a/Online/FarmConfig/job/createEnvironment.sh b/Online/FarmConfig/job/createEnvironment.sh new file mode 100755 index 000000000..2ed888ba2 --- /dev/null +++ b/Online/FarmConfig/job/createEnvironment.sh @@ -0,0 +1,161 @@ +#!/bin/bash +# ========================================================================= +# +# Generic farm task startup script +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +export UTGID=${UTGID} +if test -n "${LOGFIFO}"; then + export LOGFIFO=${LOGFIFO}; +fi; +if test -z "${LOGFIFO}" -a -e /dev/shm/logs.dev; then + export LOGFIFO=/dev/shm/logs.dev; +fi; +if test -z "${DIM_DNS_NODE}"; then + if [ -r /etc/sysconfig/dim ]; then + . /etc/sysconfig/dim; + if test "`echo $DIM_DNS_NODE | cut -b 1-5`" = "fmc01"; then + DIM_DNS_NODE=`hostname -s`; + fi; + export DIM_DNS_NODE; + fi; +fi; +export DIM_DNS_NODE; +# +export CLASS=Class1; +# +# Evaluate the information in the runinfo file +# -------------------------------------------- +eval `python3 <<EOF +import os, sys, importlib + +dbg = False + +def _p(x): + if dbg: print('echo '+os.environ['UTGID']+' '+x+';') + print (x+';') + +args = "$*".split() +runinfo = None +while len(args): + itms = args[0].split('=') + type = itms[0].lower() + value = '' + if len(itms)>1: value=itms[1] + del args[0] + + if type == '-type': + _p('export TASK_TYPE='+value) + elif type == '-partition': + _p('export PARTITION='+value) + _p('export PARTITION_NAME='+value) + elif type == '-runinfo': + _p('export RUNINFO='+value) + runinfo = value + elif type == '-taskconfig': + _p('export ARCH_FILE='+value) + elif type == '-taskinfo': + _p('export ARCH_FILE='+value) + elif type == '-architecture': + _p('export ARCHITECTURE='+value) + elif type == '-application': + _p('export APPLICATION='+value) + elif type == '-count': + _p('export NBOFSLAVES='+value) + elif type == '-instances': + _p('export NBOFSLAVES='+value) + elif type == '-utgid': + _p('export UTGID='+value) + elif type == '-logfifo': + _p('export LOGFIFO='+value) + elif type == '-script': + _p('export TASK_SCRIPT='+value) + elif type == '-auto': + _p('export AUTO_STARTUP=-auto') + elif type == '-dimdns': + _p('export DIM_DNS_NODE='+value) + elif type == '-tmsdns': + _p('export TMS_DNS='+value) + elif type == '-smidns': + _p('export SMI_DNS='+value) + elif type == '-smidomain': + _p('export SMI_DOMAIN='+value) + elif type == '-options': + _p('export OPTIONS='+value) + elif type == '-class': + _p('export CLASS='+value) + elif type == '-environ': + _p('export '+itms[1]+'='+itms[2]) + elif type == '-debug': + _p('export DEBUG_STARTUP=-debug') + elif type[:8] == '-replace': + _p('export CONTROLLER_REPLACEMENTS="-replacements='+value+'"') + else: + _p('echo Unknown task argument '+type) + + +if runinfo is None: + _p('echo '+os.environ['UTGID']+': [ERROR] Failed to find RUNINFO file. Cannot start task;') + _p('exit 11') + sys.exit(11); +try: + dir,fname = os.path.split(runinfo) + nam,ext = os.path.splitext(fname) + sys.path.insert(1,dir) + # mod = importlib.find_module(nam,None) + Online=importlib.import_module(nam) #,mod[0],mod[1],mod[2]) + OnlineVersion = Online.OnlineVersion + idx = OnlineVersion.find('Online_') + if OnlineVersion == 'Online': + OnlineVersion = 'OnlineRelease' + elif idx >= 0: + OnlineVersion = OnlineVersion.replace('Online_','OnlineDev_') + _p('export ONLINE_ENV_DIR='+dir) + _p('export PARTITION='+str(Online.PartitionName)) + _p('export PARTITION_NAME='+str(Online.PartitionName)) + _p('export RUN_TYPE='+str(Online.Activity).replace('|','\|')) + _p('export MOOREONLINE_VERSION='+str(Online.MooreOnlineVersion)) + _p('export MOORE_VERSION='+str(Online.MooreVersion)) + _p('export ONLINE_VERSION='+str(OnlineVersion)) + _p('export OUTPUT_LEVEL='+str(Online.OutputLevel)) + _p('export MBM_SETUP_OPTIONS=/group/online/dataflow/options/'+str(Online.PartitionName)+'/HLT/MBM_setup.opts') + if hasattr(Online,'TAE') and Online.TAE != 0: + _p('export TAE_PROCESSING=TAE') + if os.environ.get('CREATE_CHECKPOINT'): + _p('export MOORESTARTUP_MODE=CREATE_CHECKPOINT') + elif os.environ.get('TEST_CHECKPOINT'): + _p('export MOORESTARTUP_MODE=RESTORE') + elif hasattr(Online,'MooreStartupMode'): + if Online.MooreStartupMode==0: + _p('export MOORESTARTUP_MODE=NORMAL') + elif Online.MooreStartupMode==1: + _p('export MOORESTARTUP_MODE=FORKING') + elif Online.MooreStartupMode==2: + _p('export MOORESTARTUP_MODE=RESTORE') + if hasattr(Online,'HLTType') and hasattr(Online,'HltArchitecture'): + fn = '/group/online/dataflow/cmtuser/checkpoints/' + str(Online.HLTType) + '/' + \ + str(Online.OnlineVersion) + '/' + str(Online.HltArchitecture) + _p('export CHECKPOINT_DIR='+fn) + +except Exception as X: + _p('echo '+str(X)) + _p('exit 11') + +EOF` +# +# +setup_options_path() { + if test -n "${1}"; then + export GEN_OPTIONS=/group/online/dataflow/options/${PARTITION}/${1}; + else + export GEN_OPTIONS=/group/online/dataflow/options/${PARTITION}; + fi; + export INFO_OPTIONS=${GEN_OPTIONS}/OnlineEnv.opts; + export PYTHONPATH=${GEN_OPTIONS}:${PYTHONPATH}; + #echo "ERROR: PYTHONPATH=${PYTHONPATH}"; +} diff --git a/Online/FarmConfig/job/interSetup.sh b/Online/FarmConfig/job/interSetup.sh new file mode 100755 index 000000000..e301bdaff --- /dev/null +++ b/Online/FarmConfig/job/interSetup.sh @@ -0,0 +1,130 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start any task on the HLT farm. +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# + +#from /group/online/dataflow/runFarmTask.sh +echo "===========>from /group/online/dataflow/runFarmTask.sh" + +#!/bin/bash +# ========================================================================= +# +# Generic farm task startup script +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +export UTGID=${UTGID} +# +# Evaluate the information in the runinfo file +# -------------------------------------------- +eval `python <<EOF +import os, sys, imp + +dbg = False + +def _p(x): + if dbg: print 'echo '+x+';' + print x+';' + +args = "$*".split() +print args +runinfo = None +if len(args) == 1: + partition_name = args[0] + print partition_name +if runinfo is None: + runinfo = '/group/online/dataflow/options/'+partition_name+'/HLT/OnlineEnvBase.py' + _p('export RUNINFO='+runinfo) +try: + #_p('echo '+runinfo) + dir,fname = os.path.split(runinfo) + nam,ext = os.path.splitext(fname) + sys.path.insert(1,dir) + mod = imp.find_module(nam,None) + Online=imp.load_module(nam,mod[0],mod[1],mod[2]) + archfile = '/group/online/dataflow/architectures/lbDataflowArch_'+str(Online.HltArchitecture)+'.xml' + _p('export ARCH_FILE='+archfile) + _p('export LOGFIFO='+str('/run/fmc/logGaudi.fifo')) + _p('export ONLINE_ENV_DIR='+dir) + _p('export PARTITION_NAME='+str(Online.PartitionName)) + _p('export RUN_TYPE='+str(Online.Activity)) + _p('export MOOREONLINE_VERSION='+str(Online.MooreOnlineVersion)) + _p('export MOORE_VERSION='+str(Online.MooreVersion)) + _p('export ONLINE_VERSION='+str(Online.OnlineVersion)) + _p('export OUTPUT_LEVEL='+str(Online.OutputLevel)) + _p('export MBM_SETUP_OPTIONS=/group/online/dataflow/options/'+str(Online.PartitionName)+'/HLT/MBM_setup.opts') + if Online.TAE != 0: + _p('export TAE_PROCESSING=TAE') + if os.environ.has_key('CREATE_CHECKPOINT'): + _p('export MOORESTARTUP_MODE=CREATE_CHECKPOINT') + elif os.environ.has_key('TEST_CHECKPOINT'): + _p('export MOORESTARTUP_MODE=RESTORE') + elif Online.MooreStartupMode==0: + _p('export MOORESTARTUP_MODE=NORMAL') + elif Online.MooreStartupMode==1: + _p('export MOORESTARTUP_MODE=FORKING') + elif Online.MooreStartupMode==2: + _p('export MOORESTARTUP_MODE=RESTORE') + fn = '/group/online/dataflow/cmtuser/checkpoints/' + str(Online.HLTType) + '/' + \ + str(Online.OnlineVersion) + '/' + str(Online.HltArchitecture) + _p('export CHECKPOINT_DIR='+fn) + +except Exception,X: + _p('echo '+str(X)) + _p('exit 11') + +EOF` +# +# Switch to the task directory and execute the controller process +# --------------------------------------------------------------- +#### export ONLINE_VERSION=Online_v5r5; +if test "`uname -a | grep \".el6\"`" != ""; # SLC6 + then + export CMTCONFIG=x86_64-slc6-gcc46-dbg; + export CMTCONFIG=x86_64-slc6-gcc48-dbg; + #export ONLINE_VERSION=Online_v5r8; +elif test "`uname -a | grep el5`" != ""; # SLC5 + then + export CMTCONFIG=x86_64-slc5-gcc46-dbg; +fi; +. /group/online/dataflow/cmtuser/OnlineRelease/MyOnline/cmt/setup.${CMTCONFIG}.vars +cd ${FARMCONFIGROOT}/job; +##echo [ERROR] cd ${FARMCONFIGROOT}/job; +##cd /home/frankm/ONLINE/${ONLINE_VERSION}/Online/FarmConfig/job; + + + + +echo "===========> from runTask.sh" + +if [ -r /etc/sysconfig/dim ]; then + . /etc/sysconfig/dim + export DIM_DNS_NODE=`echo $DIM_DNS_NODE | tr a-z A-Z` +fi +if [ -z $DIM_DNS_NODE ]; then + echo DIM_DNS_NODE undefined and /etc/sysconfig/dim not readable + # exit 1 +fi; +# +export STATIC_OPTS=../options +export DYNAMIC_OPTS=/group/online/dataflow/options/${PARTITION_NAME} +export DATAINTERFACE=`python /group/online/dataflow/scripts/getDataInterface.py` +export ONLINETASKS=/group/online/dataflow/templates; +export INFO_OPTIONS=${DYNAMIC_OPTS}/${PARTITION_NAME}_Info.opts; +export SUBFARM_OPTIONS=${DYNAMIC_OPTS}/${PARTITION_NAME}_${DIM_DNS_NODE}_HLT.opts; +# +# +# +echo "===========>Executing preamble.sh" +. ./preamble.sh; +#. ./${TASK_TYPE}.sh; diff --git a/Online/FarmConfig/job/makeData.py b/Online/FarmConfig/job/makeData.py new file mode 100755 index 000000000..ccd9924d2 --- /dev/null +++ b/Online/FarmConfig/job/makeData.py @@ -0,0 +1,12 @@ +from builtins import range +import os + +try: + os.mkdir('/tmp/overflow') +except: + pass + +for i in range(200): + cmd = 'ln -s /home/frankm/data/Run_0134444_20121216-150116.hltf0122.MEP /tmp/overflow/Run_0134444_20121216-15%04d.hltf0122.MEP'%(i,) + os.system(cmd) + diff --git a/Online/FarmConfig/job/preamble.sh b/Online/FarmConfig/job/preamble.sh new file mode 100755 index 000000000..528d00270 --- /dev/null +++ b/Online/FarmConfig/job/preamble.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# +export NODENAME=`python3 -c "print ('$HOST'.split('.')[0])"` +# +dataflow_monitoring_options() +{ echo "-opts=/group/online/dataflow/options/${PARTITION_NAME}/MONITORING/${UTGID}.opts"; } +# +dataflow_task() +{ + arg_1=${1}; + shift; + echo "exec -a ${UTGID} genRunner.exe libDataflow.so dataflow_run_task -msg=fifo -mon=Dataflow_DIMMonitoring -class=${arg_1} $*"; +} +# +gaudi_task() +{ + arg_1=${1}; + shift; + echo "exec -a ${UTGID} genPython.exe `which gaudirun.py` ${arg_1} --application=OnlineApplication $*"; +} +# +gaudi_event_task() +{ + arg_1=${1}; + shift; + echo "exec -a ${UTGID} genPython.exe `which gaudirun.py` ${arg_1} --application=Online::OnlineEventApp $*"; +} diff --git a/Online/FarmConfig/job/runStandalone.sh b/Online/FarmConfig/job/runStandalone.sh new file mode 100755 index 000000000..1f1b98ff9 --- /dev/null +++ b/Online/FarmConfig/job/runStandalone.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# ========================================================================= +# +# Generic farm task startup script +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +# +utgid="P_$$"; +logfifo=; +partition=; +runinfo=; +task_type=; +task_info=; +task_count=; +task_auto=; +task_debug=; +start_logger=; +startup_script="/group/online/dataflow/scripts/runFarmTask.sh"; +# +usage() { + echo " Usage: $0 -arg [-arg]"; + echo " Passed arguments: $*"; + echo " "; + echo " Standalone script to mimic the online envirnent for HLT-farm tasks."; + echo " "; + echo " "; + echo " At least one of these 2 arguments must be supplied:"; + echo " -partition <name> Partition name to detemina the run-info data file"; + echo " -runinfo <path> Path to run-info file to determine the partition."; + echo " Process steering arguments:"; + echo " * -type <name> Set Task type (selects job file and options from FarmConfig."; + echo " -auto Set Task to auto startup. Must be supported by script!"; + echo " -debug Add -debug flag to image startup."; + echo " Optional arguments to be passed to the process instance:"; + echo " * -logfifo <path> Path to output- and error logger fifo."; + echo " * -utgid <name> Process UTGID. Default=${utgid}."; + echo " -taskinfo <path> Path to the architecture files."; + echo " -count <number> Set NBOFSLAVES."; + echo " "; + echo " (*) => These options are mandatory for default dataflow tasks."; + #echo " partition:'$partition' runinfo:'$runinfo' logfifo:'$logfifo' "; + exit 13; # EACCES +} +# +# Parse script arguments +# +parse_args() { + all_args="$*"; + while [[ "$1" == -* ]]; do + a1=`echo $1 | tr A-Z a-z`; + case ${a1} in + -auto) + task_auto="-auto"; + ;; + -debug) + task_debug="-debug"; + ;; + -partition) + partition="$2"; + shift; + ;; + -runinfo) + runinfo="$2"; + shift; + ;; + -logfifo) + logfifo="$2"; + shift; + ;; + -logger) + start_logger="YES"; + ;; + -utgid) + utgid="$2"; + shift; + ;; + -type) + task_type="$2"; + shift; + ;; + -count) + task_count="$2"; + shift; + ;; + -taskinfo) + task_info="$2"; + shift; + ;; + -script) + startup_script="$2"; + shift; + ;; + *) + usage $all_args; + ;; + esac + shift; + done; + if test -z "$partition" -a -z "$runinfo"; then + echo "Neither partition name nor runinfo file specified!"; + usage $*; + fi; + if test -z "$logfifo"; then + echo "No -logfifo argument given!"; + usage $*; + fi; + if test -z "$task_type"; then + echo "No -type argument given!"; + usage $*; + fi; +} +# +run_it() { + alias errlog='xterm -sl 20000 -ls -132 -geometry 230x50 -title logViewer@${DIM_DNS_NODE} -e /opt/FMC/bin/logViewer -l 2 -S ' + echo "+ ------------------------------------------------------------------+"; + echo "| Starting LHCb online task executor.... |"; + echo "+ ------------------------------------------------------------------+"; + echo "| UTGID: $utgid"; + echo "| Runinfo: $runinfo"; + echo "| Output logger: $logfifo"; + echo "| Task type: $task_type"; + echo "| Number of instances: $task_count"; + echo "| Start error logger to see output from task:"; + echo "| xterm -sl 10000 -ls -132 -geometry 230x50 -e /opt/FMC/bin/logViewer -l 2 -S -m `hostname -s` -N ${DIM_DNS_NODE} &"; + echo "+ ------------------------------------------------------------------+"; + echo "| Command string: UTGID=$utgid ${startup_script} $* "; + echo "+ ------------------------------------------------------------------+"; + if test -n "${start_logger}"; then + xterm -sl 20000 -ls -132 \ + -geometry 250x50 \ + -title logViewer@${DIM_DNS_NODE} \ + -e /opt/FMC/bin/logViewer \ + -l 2 -S -m `hostname -s` -N ${DIM_DNS_NODE} & + fi; + export UTGID=$utgid; + source ${startup_script} -logfifo=${logfifo} $*; +} +# Parse argument list +parse_args $*; +# +if test ! -f $runinfo; then + echo "The runinfo file for partition $partition : $runinfo does not exist."; + usage $*; +fi; +if test ! -e $logfifo; then + echo "The logfifo '$logfifo' for partition $partition : $runinfo does not exist."; + usage $*; +fi; +# +other_args=""; +if test -n "$task_count"; then + other_args="$other_args -count=$task_count"; +fi; +if test -n "$task_info"; then + other_args="$other_args -taskinfo=$task_info"; +fi; +if test -n "$task_auto"; then + other_args="$other_args -auto=YES"; +fi; +if test -n "$task_debug"; then + other_args="$other_args -debug=YES"; +fi; +# +# +# +if test -n "$partition"; then + runinfo=/group/online/dataflow/options/${partition}/HLT/OnlineEnvBase.py; + run_it -type=$task_type -runinfo=$runinfo $other_args; +elif test -n "$runinfo"; then + run_it -type=$task_type -runinfo=$runinfo $other_args; +fi; diff --git a/Online/FarmConfig/job/runTask.sh b/Online/FarmConfig/job/runTask.sh new file mode 100755 index 000000000..13272d8fa --- /dev/null +++ b/Online/FarmConfig/job/runTask.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# ========================================================================= +# +# Default script to start any task on the HLT farm. +# +# Author M.Frank +# Version: 1.0 +# Date: 20/05/2013 +# +# ========================================================================= +# +if test -z "${DIM_DNS_NODE}"; then + if [ -r /etc/sysconfig/dim ]; then + . /etc/sysconfig/dim + export DIM_DNS_NODE=`echo $DIM_DNS_NODE | tr a-z A-Z` + fi + if [ -z $DIM_DNS_NODE ]; then + echo DIM_DNS_NODE undefined and /etc/sysconfig/dim not readable + # exit 1 + fi; +fi; +if test -z "${HOST}"; then + export HOST="${DIM_HOST_NODE}"; +fi; +# +export CMTCONFIG=x86_64_v2-centos7-gcc10-do0; +. /group/online/dataflow/cmtuser/OnlineRelease/setup.${CMTCONFIG}.vars; +# +cd $FARMCONFIGROOT/job; +# +export SUBFARM=`echo ${DIM_DNS_NODE} | tr a-z A-Z`; +export STATIC_OPTS=${FARMCONFIGROOT}/options; +export DYNAMIC_OPTS=/group/online/dataflow/options/${PARTITION_NAME}; +if test -z "${DATAINTERFACE}"; then + DATAINTERFACE=`python /group/online/dataflow/scripts/getDataInterface.py`; +fi; +export DATAINTERFACE; +# +export PREAMBLE_OPTS=${FARMCONFIGROOT}/options/Empty.opts; +export ONLINETASKS=/group/online/dataflow/templates; +export INFO_OPTIONS=${DYNAMIC_OPTS}/OnlineEnv.opts; +export MBM_SETUP_OPTIONS=${DYNAMIC_OPTS}/MBM_setup.opts; +export PYTHONPATH=${DYNAMIC_OPTS}:${PYTHONPATH}; +export MONITORING_DISTBOX=MON0101; +# +. ./preamble.sh; +# +# echo "[ERROR] INFO_OPTIONS=${INFO_OPTIONS}"; +# +PRINT_COMMAND_LINE=; ####YES; +execute() +{ + if test -n "${PRINT_COMMAND_LINE}"; then + echo "${UTGID} [INFO] INFO_OPTIONS: ${INFO_OPTIONS}"; + echo "${UTGID} [INFO] MBM_SETUP_OPTIONS: ${MBM_SETUP_OPTIONS}"; + echo "${UTGID} [INFO] $*"; + fi; + $*; +} +if test -f "${OPTIONS}"; then + execute `dataflow_task ${CLASS}` -opts=${OPTIONS} ${AUTO_STARTUP} ${DEBUG_STARTUP}; +elif test -f ./${TASK_TYPE}.sh; then + execute . ./${TASK_TYPE}.sh $*; + # +elif test -f ./${PARTITION_NAME}${TASK_TYPE}.sh; then + execute . ./${PARTITION_NAME}${TASK_TYPE}.sh; + # +elif test -f ${SMICONTROLLERROOT}/scripts/${TASK_TYPE}.sh; then + cd ${SMICONTROLLERROOT}/scripts; + execute . ${SMICONTROLLERROOT}/scripts/${TASK_TYPE}.sh; + # +elif test -f "${STATIC_OPTS}/${TASK_TYPE}.opts"; then + execute `dataflow_task ${CLASS}` -opts=${STATIC_OPTS}/${TASK_TYPE}.opts ${AUTO_STARTUP} ${DEBUG_STARTUP}; + # +elif test -f "${STATIC_OPTS}/${TASK_TYPE}.py"; then + execute `gaudi_task ${STATIC_OPTS}/${TASK_TYPE}.py`; + # +elif test -n "`echo ${UTGID} | grep TestEvent`"; then + execute `gaudi_event_task ${FARMCONFIGROOT}/job/PassThrough.py`; + # +elif test -f ./${PARTITION_NAME}DefaultTask.sh; then + execute . ./${PARTITION_NAME}DefaultTask.sh; + # +else + echo "ERROR Running default dummy task "; + cd ${SMICONTROLLERROOT}/scripts; + execute exec -a ${UTGID} genPython.exe ${SMICONTROLLERROOT}/scripts/DummyTask.py -utgid ${UTGID} -partition 103 -print ${OUTPUT_LEVEL}; +fi; diff --git a/Online/FarmConfig/job/startGDB.sh b/Online/FarmConfig/job/startGDB.sh new file mode 100755 index 000000000..b1eebb2f1 --- /dev/null +++ b/Online/FarmConfig/job/startGDB.sh @@ -0,0 +1,108 @@ +#!/bin/bash +sleep 10; + +/home/frankm/bin/debug2 --pid ${1} <<EOF>/tmp/gdb.${1}.log +b Thread.cpp:345 +cont +bt +p t +p *t +cont +bt +p t +p *t +cont +bt +p t +p *t +cont +bt +p t +p *t +cont +bt +p t +p *t +cont +bt +p t +p *t +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +p thread +p *thread +info thr +thread apply all where +cont +bt +info thr +thread apply all where +cont +bt +info thr +thread apply all where + +detach +quit +y +EOF + + diff --git a/Online/FarmConfig/old/EmptyList.xml b/Online/FarmConfig/old/EmptyList.xml new file mode 100755 index 000000000..8e45910fe --- /dev/null +++ b/Online/FarmConfig/old/EmptyList.xml @@ -0,0 +1,2 @@ +<tasks_inventory> +</tasks_inventory> diff --git a/Online/FarmConfig/old/MBM_setup.opts b/Online/FarmConfig/old/MBM_setup.opts new file mode 100755 index 000000000..942453985 --- /dev/null +++ b/Online/FarmConfig/old/MBM_setup.opts @@ -0,0 +1,19 @@ +OnlineEnv.MBM_setup = "-s=100000 -e=1000 -u=40 -b=17 -f -i=Events -c -s=40000 -e=150 -u=8 -b=17 -f -i=Overflow -c -s=30000 -e=150 -u=36 -f -i=Send -c -s=8000 -e=10 -u=10 -b=17 -f -i=Recv -c"; +OnlineEnv.PartitionBuffers = true; +// +// +OnlineEnv.MEPRx_Output = "Events"; +OnlineEnv.MEPRx_Buffers = {"Events"}; +// +// +OnlineEnv.DiskWR_Input = "Send"; +OnlineEnv.DiskWR_Buffers = {"Send"}; +// +// +OnlineEnv.PassAll_Input = "Events"; +OnlineEnv.PassAll_Output = "Send"; +OnlineEnv.PassAll_Buffers = {"Events", "Send"}; +// +// +OnlineEnv.Receiver_Output = "Recv"; +OnlineEnv.Receiver_Buffers = {"Recv"}; diff --git a/Online/FarmConfig/old/OnlineEnvironment.opts b/Online/FarmConfig/old/OnlineEnvironment.opts new file mode 100755 index 000000000..65acdd4b5 --- /dev/null +++ b/Online/FarmConfig/old/OnlineEnvironment.opts @@ -0,0 +1,7 @@ +#pragma print off +OnlineEnv.PartitionID = 333; +OnlineEnv.PartitionName = "LHCb"; +OnlineEnv.OutputLevel = 4; +OnlineEnv.DeferredRuns = {"*"}; +OnlineEnv.passThroughDelay = 0; +OnlineEnv.AcceptRate = 0.00001; diff --git a/Online/FarmConfig/old/PLUS04.opts b/Online/FarmConfig/old/PLUS04.opts new file mode 100755 index 000000000..7e611863d --- /dev/null +++ b/Online/FarmConfig/old/PLUS04.opts @@ -0,0 +1,5 @@ +// Auto generated options for partition:LHCb activity:EOF_CALIB Wed May 15 17:20:03 2013 +// Number of subfarms:10 +// +// ---------------- Data sending information for sub-farm:HLTB07 +OnlineEnv.Target = "PLUS04::LHCb_PLUS04_Receiver_0"; diff --git a/Online/FarmConfig/old/Tasklist.xml b/Online/FarmConfig/old/Tasklist.xml new file mode 100755 index 000000000..3ab43a00c --- /dev/null +++ b/Online/FarmConfig/old/Tasklist.xml @@ -0,0 +1,81 @@ +<tasks_inventory> + + <!-- The task definition: command-line, arguments --> + <!-- and all FMC startup parameters --> + <task name="MEPInit" user="online" group="onliners"> + <command>runFarmTask.sh</command> + <argument name="-type" value="${NAME}"/> + <argument name="-runinfo" value="${RUNINFO}"/> + <argument name="-partition" value="${PARTITION}"/> + <fmcparam name="utgid" value="${PARTITION}_${NODE}_${NAME}_${INSTANCE}"/> + <fmcparam name="wd" value="/home/frankm/cmtuser/Online_v4r68/Online/ControllerTests/scripts"/> + <fmcparam name="stdout" value="/run/fmc/logSrv.fifo"/> + <fmcparam name="stderr" value="/run/fmc/logSrv.fifo"/> + <timeout action="Any" value="5"/> + <timeout action="load" value="10"/> + <timeout action="configure" value="15"/> + <timeout action="start" value="5"/> + <timeout action="stop" value="5"/> + <timeout action="reset" value="5"/> + <timeout action="unload" value="2"/> + </task> + + <task name="MEPRx" user="online" group="onliners"> + <command>runFarmTask.sh</command> + <argument name="-type" value="${NAME}"/> + <argument name="-runinfo" value="${RUNINFO}"/> + <argument name="-partition" value="${PARTITION}"/> + <fmcparam name="utgid" value="${PARTITION}_${NODE}_${NAME}_${INSTANCE}"/> + <fmcparam name="wd" value="/home/frankm/cmtuser/Online_v4r68/Online/ControllerTests/scripts"/> + <fmcparam name="stdout" value="/run/fmc/logSrv.fifo"/> + <fmcparam name="stderr" value="/run/fmc/logSrv.fifo"/> + <ioparam name="output" value="Events"/> + <timeout action="Any" value="5"/> + <timeout action="load" value="10"/> + </task> + + <task name="DiskWR" user="online" group="onliners"> + <command>runFarmTask.sh</command> + <argument name="-type" value="${NAME}"/> + <argument name="-runinfo" value="${RUNINFO}"/> + <argument name="-partition" value="${PARTITION}"/> + <fmcparam name="utgid" value="${PARTITION}_${NODE}_${NAME}_${INSTANCE}"/> + <fmcparam name="wd" value="/home/frankm/cmtuser/Online_v4r68/Online/ControllerTests/scripts"/> + <fmcparam name="stdout" value="/run/fmc/logSrv.fifo"/> + <fmcparam name="stderr" value="/run/fmc/logSrv.fifo"/> + <ioparam name="input" value="Send"/> + <timeout action="Any" value="5"/> + <timeout action="load" value="10"/> + </task> + + <task name="Receiver" user="online" group="onliners"> + <command>runFarmTask.sh</command> + <argument name="-type" value="${NAME}"/> + <argument name="-runinfo" value="${RUNINFO}"/> + <argument name="-partition" value="${PARTITION}"/> + <fmcparam name="utgid" value="${PARTITION}_${NODE}_${NAME}_${INSTANCE}"/> + <fmcparam name="wd" value="/home/frankm/cmtuser/Online_v4r68/Online/ControllerTests/scripts"/> + <fmcparam name="stdout" value="/run/fmc/logSrv.fifo"/> + <fmcparam name="stderr" value="/run/fmc/logSrv.fifo"/> + <ioparam name="input" value="Send"/> + <timeout action="Any" value="5"/> + <timeout action="load" value="10"/> + </task> + + <task name="PassAll" user="online" group="onliners" instances="NUMBER_OF_INSTANCES"> + <command>runFarmTask.sh</command> + <argument name="-type" value="${NAME}"/> + <argument name="-runinfo" value="${RUNINFO}"/> + <argument name="-partition" value="${PARTITION}"/> + <fmcparam name="utgid" value="${PARTITION}_${NODE}_${NAME}_${INSTANCE}"/> + <fmcparam name="wd" value="/home/frankm/cmtuser/Online_v4r68/Online/ControllerTests/scripts"/> + <fmcparam name="stdout" value="/run/fmc/logSrv.fifo"/> + <fmcparam name="stderr" value="/run/fmc/logSrv.fifo"/> + <ioparam name="input" value="Events"/> + <ioparam name="output" value="Send"/> + <timeout action="Any" value="1"/> + <timeout action="load" value="1"/> + <timeout action="configure" value="1"/> + </task> + +</tasks_inventory> diff --git a/Online/FarmConfig/options/AligDrv.opts b/Online/FarmConfig/options/AligDrv.opts new file mode 100755 index 000000000..4fcda753e --- /dev/null +++ b/Online/FarmConfig/options/AligDrv.opts @@ -0,0 +1,23 @@ +// Job options file. Simple Online monitoring example +//============================================================== +#include "$INFO_OPTIONS" + +ApplicationMgr.ExtSvc += {"IncidentSvc" }; +ApplicationMgr.EventLoop = "LHCb::OnlineRunable/EmptyEventLoop"; +ApplicationMgr.Runable = "LHCb::AlignDrv/AlignDrv"; +ApplicationMgr.HistogramPersistency = "NONE"; +ApplicationMgr.EvtSel = "NONE"; +Runable.Wait = 1; // 1 of running as daemon +MessageSvc.fifoPath = "$LOGFIFO"; +MessageSvc.OutputLevel = 5; //@OnlineEnv.OutputLevel; +HistogramPersistencySvc.Warnings = false; + +MonitorSvc.CounterUpdateInterval = -1; + +AlignDrv.PartitionName = @OnlineEnv.PartitionName; +AlignDrv.FitterClass = "AlignOnlineIterator"; +AlignDrv.FitterName = "AlIterator"; +AlignDrv.AlIterator.PartitionName = @OnlineEnv.PartitionName; +AlignDrv.AlIterator.ASDDir = "/group/online/alignment/EscherOut"; +AlignDrv.AlIterator.ASDFilePattern = "_Escher.out"; +AlignDrv.AlIterator.OutputLevel =2; \ No newline at end of file diff --git a/Online/FarmConfig/options/AligWrk.opts b/Online/FarmConfig/options/AligWrk.opts new file mode 100755 index 000000000..4ba07dcdb --- /dev/null +++ b/Online/FarmConfig/options/AligWrk.opts @@ -0,0 +1,26 @@ +// Job options file. Simple Online monitoring example +//============================================================== +#include "$INFO_OPTIONS" + +ApplicationMgr.ExtSvc += { + "MonitorSvc", + "IncidentSvc" + }; +ApplicationMgr.EventLoop = "LHCb::OnlineRunable/EmptyEventLoop"; +ApplicationMgr.Runable = "LHCb::AlignWork/aaa"; +ApplicationMgr.HistogramPersistency = "NONE"; +ApplicationMgr.EvtSel = "NONE"; +Runable.Wait = 1; // 1 of running as daemon +MessageSvc.fifoPath = "$LOGFIFO"; +MessageSvc.OutputLevel = 5; //@OnlineEnv.OutputLevel; + +HistogramPersistencySvc.Warnings = false; +MonitorSvc.CounterUpdateInterval = -1; + +aaa.PartitionName = @OnlineEnv.PartitionName; +aaa.FitterFunktionClass = "LHCb::FitterFcn"; +aaa.FitterFunktionName = "bbb"; +aaa.PartitionName = @OnlineEnv.PartitionName; +aaa.bbb.DataFileName = "/home/beat/aligdata.dat"; +aaa.bbb.ParameterFileName = "/home/beat/aligparams.dat"; +aaa.bbb.PartitionName = @OnlineEnv.PartitionName; diff --git a/Online/FarmConfig/options/AlignReader.opts b/Online/FarmConfig/options/AlignReader.opts new file mode 100755 index 000000000..1c1adc2f6 --- /dev/null +++ b/Online/FarmConfig/options/AlignReader.opts @@ -0,0 +1,31 @@ +// MSF: 04/12/2016: NEW Dataflow task type ! +#pragma print off +#include "$INFO_OPTIONS" +#include "$NODE_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIGROOT/options/Monitoring.opts" + +Manager.Services = {"Dataflow_MBMClient/MEPManager", + "Dataflow_HltReader/Reader", + "Dataflow_RunableWrapper/Wrap" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "Reader"; +Reader.Buffer = @OnlineEnv.AlignReader_Output; +Reader.BrokenHosts = ""; +Reader.Directories = {"$AlignDir"}; +Reader.AllowedRuns = {"*"}; +Reader.DeleteFiles = false; +Reader.SaveRest = true; +Reader.FilePrefix = "Run_"; +Reader.PauseSleep = 5; // Optional wait time until 'Output' event queue is empty +Reader.InitialSleep = 1; +Reader.MaxPauseWait = 1; +Reader.GoService = "";//"$GO_SERVICE_NAME"; +Reader.CheckedBuffers = @OnlineEnv.PassThrough_Buffers; +// +MEPManager.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.PartitionID = @OnlineEnv.PartitionID; +MEPManager.Buffers = @OnlineEnv.AlignReader_Buffers; +Logger.OutputLevel = @OnlineEnv.OutputLevel; diff --git a/Online/FarmConfig/options/AlignWriter.opts b/Online/FarmConfig/options/AlignWriter.opts new file mode 100755 index 000000000..a584ab52e --- /dev/null +++ b/Online/FarmConfig/options/AlignWriter.opts @@ -0,0 +1,142 @@ +// MSF: 04/12/2016: NEW Dataflow task type ! +#pragma print off +//------------- Default Writer options: ------------------------------------------ +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "../options/Monitoring.opts" + +Manager.Services = {"Dataflow_MBMClient/MBM", + "Dataflow_FileWriter/AlignDataWriter_Tracker", + "Dataflow_FileWriter/AlignDataWriter_Velo", + "Dataflow_FileWriter/AlignDataWriter_Rich", + "Dataflow_FileWriter/AlignDataWriter_Muon", + "Dataflow_FileWriter/AlignDataWriter_Calo", + "Dataflow_FileWriter/AlignDataWriter_BWDivision", + "Dataflow_FileWriter/AlignDataWriter_HLTTiming", + "Dataflow_FileWriterMgr/WrManager", + "Dataflow_RunableWrapper/Wrap", + "Dataflow_UI/UI" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "WrManager"; +// +MBM.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MBM.PartitionName = @OnlineEnv.PartitionName; +MBM.PartitionID = @OnlineEnv.PartitionID; +MBM.Buffers = @OnlineEnv.AlignWriter_Buffers; +// +WrManager.Input = @OnlineEnv.AlignWriter_Input; +WrManager.Processors += { "AlignDataWriter_Tracker"}; +WrManager.Processors += { "AlignDataWriter_Velo"}; +WrManager.Processors += { "AlignDataWriter_Rich"}; +WrManager.Processors += { "AlignDataWriter_Muon"}; +WrManager.Processors += { "AlignDataWriter_Calo"}; +WrManager.Processors += { "AlignDataWriter_BWDivision"}; +WrManager.Processors += { "AlignDataWriter_HLTTiming"}; +Param.FileSizeLimit = 1000; +// +Logger.OutputLevel = @OnlineEnv.OutputLevel; +Monitoring.CounterUpdateInterval = 3; +// +AlignDataWriter_Tracker.SizeLimit = @Param.FileSizeLimit; +// +// Requirements for Physics +// +AlignDataWriter_Tracker.Requirements = { +"EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; +AlignDataWriter_Tracker.FilePrefix = "/Alignment/Tracker/Run_"; +AlignDataWriter_Tracker.MaxEvents = 1000; +AlignDataWriter_Tracker.DIMSteering = 1; +AlignDataWriter_Tracker.PartitionName = @OnlineEnv.PartitionName; +AlignDataWriter_Tracker.DeviceList = {"/localdisk"}; + +AlignDataWriter_Rich.SizeLimit = @Param.FileSizeLimit; +AlignDataWriter_Rich.PartitionName = @OnlineEnv.PartitionName; +// +// Requirements for Physics +// +AlignDataWriter_Rich.DIMSteering = 1; +AlignDataWriter_Rich.Requirements = { +"EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; +AlignDataWriter_Rich.FilePrefix = "/Alignment/Rich/Run_"; +AlignDataWriter_Rich.MaxEvents = 1000; +AlignDataWriter_Rich.DeviceList = {"/localdisk"}; +AlignDataWriter_Rich.ExitOnError = false; +AlignDataWriter_Velo.SizeLimit = @Param.FileSizeLimit; +AlignDataWriter_Velo.PartitionName = @OnlineEnv.PartitionName; +AlignDataWriter_Velo.DIMSteering = 1; +// +// Requirements for Physics +// +AlignDataWriter_Velo.Requirements = { +"EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +,"EvType=2;TriggerMask=0x0,0x00000020,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=0.01" +}; +AlignDataWriter_Velo.FilePrefix = "/Alignment/Velo/Run_"; +AlignDataWriter_Velo.MaxEvents = 1000; +AlignDataWriter_Velo.DeviceList = {"/localdisk"}; + +AlignDataWriter_Muon.SizeLimit = @Param.FileSizeLimit; +AlignDataWriter_Muon.DIMSteering = 1; +AlignDataWriter_Muon.PartitionName = @OnlineEnv.PartitionName; +// +// Requirements for Physics +// +AlignDataWriter_Muon.Requirements = { +"EvType=2;TriggerMask=0x0,0x01000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; +AlignDataWriter_Muon.FilePrefix = "/Alignment/Muon/Run_"; +AlignDataWriter_Muon.MaxEvents = 1000; +AlignDataWriter_Muon.DIMSteering = 1; +AlignDataWriter_Muon.PartitionName = @OnlineEnv.PartitionName; +AlignDataWriter_Muon.DeviceList = {"/localdisk"}; + +AlignDataWriter_Calo.SizeLimit = @Param.FileSizeLimit; +AlignDataWriter_Calo.DIMSteering = 1; +AlignDataWriter_Calo.PartitionName = @OnlineEnv.PartitionName; +// +// Requirements for Physics +// +AlignDataWriter_Calo.Requirements = { +"EvType=2;TriggerMask=0x0,0x810000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; +AlignDataWriter_Calo.FilePrefix = "/Alignment/Calo/Run_"; +AlignDataWriter_Calo.MaxEvents = 1000; +AlignDataWriter_Calo.DIMSteering = 1; +AlignDataWriter_Calo.PartitionName = @OnlineEnv.PartitionName; +AlignDataWriter_Calo.DeviceList = {"/localdisk"}; +AlignDataWriter_Calo.ExitOnError = false; +AlignDataWriter_BWDivision.SizeLimit = @Param.FileSizeLimit; +AlignDataWriter_BWDivision.DIMSteering = 1; +AlignDataWriter_BWDivision.PartitionName = @OnlineEnv.PartitionName; +// +// Requirements for Physics +// +AlignDataWriter_BWDivision.Requirements = { +"EvType=2;TriggerMask=0x0,0x10000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; +AlignDataWriter_BWDivision.FilePrefix = "/Alignment/BWDivision/Run_"; +AlignDataWriter_BWDivision.MaxEvents = 1000; +AlignDataWriter_BWDivision.DIMSteering = 1; +AlignDataWriter_BWDivision.PartitionName = @OnlineEnv.PartitionName; +AlignDataWriter_BWDivision.DeviceList = {"/localdisk"}; +// +// +// +// +AlignDataWriter_HLTTiming.SizeLimit = @Param.FileSizeLimit; +AlignDataWriter_HLTTiming.DIMSteering = 1; +AlignDataWriter_HLTTiming.PartitionName = @OnlineEnv.PartitionName; +// +// Requirements for Physics +// +AlignDataWriter_HLTTiming.Requirements = { +"EvType=2;TriggerMask=0x0,0x80,0x0,0x0;VetoMask=0x10000,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; +AlignDataWriter_HLTTiming.FilePrefix = "/Alignment/HLTTiming/Run_"; +AlignDataWriter_HLTTiming.MaxEvents = 100; +AlignDataWriter_HLTTiming.DIMSteering = 0; +AlignDataWriter_HLTTiming.PartitionName = @OnlineEnv.PartitionName; +AlignDataWriter_HLTTiming.DeviceList = {"/localdisk"}; diff --git a/Online/FarmConfig/options/BusyPub.opts b/Online/FarmConfig/options/BusyPub.opts new file mode 100755 index 000000000..043151094 --- /dev/null +++ b/Online/FarmConfig/options/BusyPub.opts @@ -0,0 +1,80 @@ +// Job options file. Simple Online monitoring example +//============================================================== +ApplicationMgr.ExtSvc += { + "BusyPub" + }; +ApplicationMgr.ExtSvc += { + "BusyPub/LHCbPub" + }; + +ApplicationMgr.ExtSvc += { + "MoorePub/Moore1s" + }; +ApplicationMgr.ExtSvc += { + "MoorePub/Moore2s" + }; +ApplicationMgr.ExtSvc += { + "CntrPub/HLT2Output" + }; +ApplicationMgr.EventLoop = "LHCb::OnlineRunable/EmptyEventLoop"; +ApplicationMgr.Runable = "LHCb::OnlineRunable/Runable"; +ApplicationMgr.HistogramPersistency = "NONE"; +ApplicationMgr.EvtSel = "NONE"; +Runable.Wait = 3; // 1 of running as daemon +MessageSvc.OutputLevel = 3; //@OnlineEnv.OutputLevel; + +//MessageSvc.fifoPath = "$LOGFIFO"; +HistogramPersistencySvc.Warnings = false; + + + +BusyPub.MyName = "GEN_X_BusyPub"; +//BusyPub.PartitionName = "GEN"; +BusyPub.PartitionName = "LHCb"; +BusyPub.TaskPattern = "MON_GEN_HLT02_BusyMon"; +BusyPub.ServicePattern = "MON_GEN_Busy_00/Counter/"; +BusyPub.AdderClass = "Counter"; +BusyPub.InDNS = "mona08"; +BusyPub.TrendingOn = false; +BusyPub.OutDNS = "mona08"; +BusyPub.ForcePartition = "LHCb"; +BusyPub.GlobalPublisher = true; + +LHCbPub.MyName = "<part>_X_BusyPub"; +LHCbPub.PartitionName = "LHCb"; +LHCbPub.TaskPattern = "MON_<part>_HLT02_PartAdder_(.*)"; +LHCbPub.ServicePattern = "MON_<part>_Busy_00/Counter/"; +LHCbPub.AdderClass = "Counter"; +LHCbPub.InDNS = "mona08"; +LHCbPub.TrendingOn = false; +LHCbPub.OutDNS = "mona08"; + +Moore1s.MyName = "<part>_X_Moore1s"; +Moore1s.PartitionName = "LHCb"; +Moore1s.TaskPattern = "MON_GEN_HLT02_BusyMon"; +Moore1s.ServicePattern = "MON_GEN_Moore1_00/Counter/"; +Moore1s.AdderClass = "Counter"; +Moore1s.TrendName = "Moore1s"; +Moore1s.InDNS = "mona08"; +Moore1s.OutDNS = "mona08"; +Moore1s.TrendingOn = false; + +Moore2s.MyName = "<part>_X_Moore2s"; +Moore2s.PartitionName = "LHCb"; +Moore2s.TaskPattern = "MON_GEN_HLT02_BusyMon"; +Moore2s.ServicePattern = "MON_GEN_Moore2_00/Counter/"; +Moore2s.AdderClass = "Counter"; +Moore2s.TrendName = "Moore2s"; +Moore2s.InDNS = "mona08"; +Moore2s.OutDNS = "mona08"; +Moore2s.TrendingOn = false; + +HLT2Output.MyName = "<part>_X_HLT2Sender"; +HLT2Output.PartitionName = "LHCb2"; +HLT2Output.TaskPattern = "MON_GEN_HLT02_BusyMon"; +HLT2Output.ServicePattern = "MON_GEN_HLT2Sender_00/Counter/"; +HLT2Output.AdderClass = "Counter"; +HLT2Output.InDNS = "mona08"; +HLT2Output.OutDNS = "mona08"; +HLT2Output.CounterPattern = "SND/EventsOut"; +HLT2Output.ServiceInfix = "aaaaa"; diff --git a/Online/FarmConfig/options/CCESCAN.prescaler-requirements b/Online/FarmConfig/options/CCESCAN.prescaler-requirements new file mode 100755 index 000000000..815d52c76 --- /dev/null +++ b/Online/FarmConfig/options/CCESCAN.prescaler-requirements @@ -0,0 +1,3 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=20.0" +}; diff --git a/Online/FarmConfig/options/COLLISION-LEAD.prescaler-requirements b/Online/FarmConfig/options/COLLISION-LEAD.prescaler-requirements new file mode 100755 index 000000000..1a8d021e6 --- /dev/null +++ b/Online/FarmConfig/options/COLLISION-LEAD.prescaler-requirements @@ -0,0 +1,12 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=1.0;RATELIMIT=2.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0;RATELIMIT=1.0", +"Name=Herschel;EvType=2;TriggerMask=0x0,0x4020000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Express;EvType=2;TriggerMask=0x0,0x10,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Tell1Error;EvType=2;TriggerMask=0x0,0x2000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/COLLISION-VDM.prescaler-requirements b/Online/FarmConfig/options/COLLISION-VDM.prescaler-requirements new file mode 100755 index 000000000..b40ed2801 --- /dev/null +++ b/Online/FarmConfig/options/COLLISION-VDM.prescaler-requirements @@ -0,0 +1,12 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=1.0;RATELIMIT=2.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0;RATELIMIT=1.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0;RATELIMIT=1.0", +"Name=Herschel;EvType=2;TriggerMask=0x0,0x20000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Express;EvType=2;TriggerMask=0x0,0x10,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Tell1Error;EvType=2;TriggerMask=0x0,0x2000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/COLLISION-pHe.prescaler-requirements b/Online/FarmConfig/options/COLLISION-pHe.prescaler-requirements new file mode 100755 index 000000000..b40ed2801 --- /dev/null +++ b/Online/FarmConfig/options/COLLISION-pHe.prescaler-requirements @@ -0,0 +1,12 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=1.0;RATELIMIT=2.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0;RATELIMIT=1.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0;RATELIMIT=1.0", +"Name=Herschel;EvType=2;TriggerMask=0x0,0x20000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Express;EvType=2;TriggerMask=0x0,0x10,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Tell1Error;EvType=2;TriggerMask=0x0,0x2000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/COLLISION-pNe.prescaler-requirements b/Online/FarmConfig/options/COLLISION-pNe.prescaler-requirements new file mode 100755 index 000000000..b40ed2801 --- /dev/null +++ b/Online/FarmConfig/options/COLLISION-pNe.prescaler-requirements @@ -0,0 +1,12 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=1.0;RATELIMIT=2.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0;RATELIMIT=1.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0;RATELIMIT=1.0", +"Name=Herschel;EvType=2;TriggerMask=0x0,0x20000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Express;EvType=2;TriggerMask=0x0,0x10,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Tell1Error;EvType=2;TriggerMask=0x0,0x2000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/Collision-HiMu.prescaler-requirements b/Online/FarmConfig/options/Collision-HiMu.prescaler-requirements new file mode 100644 index 000000000..5db4e3e68 --- /dev/null +++ b/Online/FarmConfig/options/Collision-HiMu.prescaler-requirements @@ -0,0 +1,12 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=1.0;RATELIMIT=2.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0;RATELIMIT=1.0", +"Name=Herschel;EvType=2;TriggerMask=0x0,0x20000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Express;EvType=2;TriggerMask=0x0,0x10,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Tell1Error;EvType=2;TriggerMask=0x0,0x2000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/Default.prescaler-requirements b/Online/FarmConfig/options/Default.prescaler-requirements new file mode 100755 index 000000000..1a8d021e6 --- /dev/null +++ b/Online/FarmConfig/options/Default.prescaler-requirements @@ -0,0 +1,12 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=1.0;RATELIMIT=2.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0;RATELIMIT=1.0", +"Name=Herschel;EvType=2;TriggerMask=0x0,0x4020000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Express;EvType=2;TriggerMask=0x0,0x10,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0", +"Name=Tell1Error;EvType=2;TriggerMask=0x0,0x2000000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/EBMBM.opts b/Online/FarmConfig/options/EBMBM.opts new file mode 100644 index 000000000..4b273e267 --- /dev/null +++ b/Online/FarmConfig/options/EBMBM.opts @@ -0,0 +1,9 @@ +#pragma print off +#include "$INFO_OPTIONS" +//#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIG_OPTIONS/Logging.opts" +Manager.Setup = {"Dataflow_MBMServer/MEPManager"}; +Manager.Services = {"Dataflow_UI/UI"}; +MEPManager.PartitionBuffers = true; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.InitFlags = "-s=5000000 -e=150 -u=20 -b=12 -t=1 -n=0 -f -i=Events_0 -c -s=5000000 -e=150 -u=20 -b=12 -t=1 -n=1 -f -i=Events_1 -c -s=500000 -e=150 -u=5 -b=12 -t=1 -f -i=Output -c"; diff --git a/Online/FarmConfig/options/EBReader.opts b/Online/FarmConfig/options/EBReader.opts new file mode 100644 index 000000000..2782c8303 --- /dev/null +++ b/Online/FarmConfig/options/EBReader.opts @@ -0,0 +1,66 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +#include "$FARMCONFIGROOT/options/Monitoring.opts" +Monitoring.CounterUpdateInterval = 3; +// +Manager.Services = {"Dataflow_MBMClient/MEPManager", + "Dataflow_DiskReader/Reader", +// "Dataflow_StorageReader/Reader", + "Dataflow_RunableWrapper/Wrap", + "Dataflow_UI/UI" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "Reader"; +Task.HavePause = true; +// +Reader.Buffer = "$MBM_OUTPUT_BUFFER"; +Reader.BrokenHosts = ""; +Reader.Directories = {"/group/online/dataflow/cmtuser/data/mdf" + ,"/group/online/dataflow/cmtuser/data/mep" + ,"/group/online/dataflow/cmtuser/data/tae" + }; +//Reader.Directories = { "/daqarea1/fest/mep"}; +Reader.Directories = { "/daqarea1/fest/202110/mdf/30000000"}; +Reader.FilePrefix = "00"; +Reader.Directories = { "/hlt2/objects/CALO/0000221573"}; +Reader.FilePrefix = "Run_00"; +// +Reader.AllowedRuns = {"*"}; +Reader.MuDelay = 0; +Reader.DeleteFiles = false; +Reader.SaveRest = false; +Reader.PauseSleep = 2; // Optional wait time until 'Output' event queue is empty +Reader.InitialSleep = 0; +Reader.MaxPauseWait = 1; +Reader.GoService = ""; +Reader.Rescan = 1; +Reader.RequireConsumers = 0; +Reader.MMapFiles = 0; +Reader.ReuseFile = 0; +Reader.PackingFactor = 2000; +Reader.AllocationSizekB = 20000; +Reader.PatchOdin = 5000000; +Reader.RunNumberService = "$RUN_NUMBER_SERVICE"; +// +MEPManager.PartitionBuffers = true; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.PartitionID = @OnlineEnv.PartitionID; +MEPManager.Buffers = {"$MBM_OUTPUT_BUFFER"}; + +/* +Reader.PartitionName = "LHCb"; +Reader.Directories = {""}; +Reader.FilePrefix = "file:/daqarea1/objects/nfs_data/${PARTITION}/HLT1/${RUN1000}/${RUN}/Run_"; +Reader.AllowedRuns = {"72908"}; +Reader.DataType = "posix"; +Reader.Server = "XXEB09.lbdaq.cern.ch:8000"; + + +Reader.DataType = "network"; +Reader.Server = "devbbdb01.lbdaq.cern.ch:4242"; +Reader.FDBVersion = 1; +Reader.PartitionName = "FEST"; +Reader.FilePrefix = "${PARTITION}/${RUN}/"; +Reader.AllowedRuns = { "219677","219679","219680","219681" }; +*/ diff --git a/Online/FarmConfig/options/EBSender.opts b/Online/FarmConfig/options/EBSender.opts new file mode 100755 index 000000000..1d6a30b8e --- /dev/null +++ b/Online/FarmConfig/options/EBSender.opts @@ -0,0 +1,39 @@ +#pragma print off +//------------- Default sender options: ------------------------------------------ +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +#include "$FARMCONFIGROOT/options/Monitoring.opts" +Monitoring.CounterUpdateInterval = 3; +Logger.OutputLevel = @OnlineEnv.OutputLevel; + +Manager.Services = {"Dataflow_MBMClient/MBM", + "Dataflow_MBMSelector/EventSelector", + "Dataflow_UI/UI" +}; +//Manager.Algorithms = {"Dataflow_RoutingBitsPrescaler/Prescaler", +// "Dataflow_AsioSender/Sender" +//}; +// +Manager.Runable = "EventSelector"; +Manager.EnableAlgorithms = @OnlineEnv.HasMonitoring; +// +MBM.Buffers = {"Output"}; +MBM.PartitionID = @OnlineEnv.PartitionID; +MBM.PartitionName = @OnlineEnv.PartitionName; +MBM.PartitionBuffers = @OnlineEnv.PartitionBuffers; +// +EventSelector.Input = "Output"; +EventSelector.REQ1 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=USER;Frequency=PERC;Perc=50.0"; +//EventSelector.REQ1 = "$EVENTSELECTOR_REQ1"; +// +Sender.DataSink = "$SENDER_TARGET"; +Sender.Delay = 0; +Sender.PauseOnError = true; +// +//#include "$PRESCALER_REQUIREMENTS" +//Manager.Algorithms = {"Dataflow_ComponentContainer/SEQ"}; +//SEQ.Components = {"Dataflow_RoutingBitsPrescaler/Prescaler", "Dataflow_AsioSender/Sender"}; +//SEQ.Mode_AND = true; +// +Manager.Algorithms = {"Dataflow_AsioSender/Sender"}; diff --git a/Online/FarmConfig/options/EBStorage.opts b/Online/FarmConfig/options/EBStorage.opts new file mode 100644 index 000000000..22fcea2a5 --- /dev/null +++ b/Online/FarmConfig/options/EBStorage.opts @@ -0,0 +1,31 @@ +#include "$FARMCONFIGROOT/options/StorageWriter.opts" +Monitoring.CounterUpdateInterval = 3; +// +MBM.ConnectWhen = "initialize"; +//EventProc.DelayCancel = 15; +// +Writer.Server = "XXEB09.lbdaq.cern.ch:8000"; +Writer.Server = "devbbdb01.lbdaq.cern.ch:4242"; +Writer.FDBVersion = 1; +EventProc.REQ2 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0"; +// +// Write using client server +Writer.MaxFileSizeMB = -1; // Only valid for posix writing +Writer.NumBuffers = 2; +Writer.NumThreads = 1; +Writer.BufferSizeMB = 1024; +Writer.Stream = "Full"; +Writer.FileName = "/objects/data/HLT1/${PARTITION}/${NODE}/${RUN}/Run_${RUN}_${TIME}_${SEQ}.mdf"; +Writer.FileName = "/objects/${PARTITION}/${RUN}/Run_${RUN}_${TIME}_${NODE}_${SEQ}.mdf"; +// +/* +// NFS writing +Writer.IdleTimeout = 30; +Writer.HaveFileDB = 2; +Writer.NumThreads = 2; +Writer.NumBuffers = 3; +Writer.MaxFileSizeMB = 4000; +Writer.BufferSizeMB = 32; +Writer.FileName = "file:/daqarea1/objects/nfs_data/${PARTITION}/${RUN}/Run_${RUN}_${NODE}_${TIME}_${SEQ}.mdf"; +Writer.OutputType = "POSIX"; +*/ diff --git a/Online/FarmConfig/options/EBStorageNFS.opts b/Online/FarmConfig/options/EBStorageNFS.opts new file mode 100644 index 000000000..ab836ba8b --- /dev/null +++ b/Online/FarmConfig/options/EBStorageNFS.opts @@ -0,0 +1,18 @@ +#include "$FARMCONFIGROOT/options/StorageWriter.opts" +Monitoring.CounterUpdateInterval = 3; +MBM.ConnectWhen = "initialize"; +// +Writer.Server = "XXEB09.lbdaq.cern.ch:8010"; +// Writer.Server = "devbbdb01.lbdaq.cern.ch:4242"; +Writer.FDBVersion = 0; +EventProc.REQ2 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0"; +// +// NFS writing +Writer.IdleTimeout = 180; +Writer.HaveFileDB = 0; +Writer.NumThreads = 2; +Writer.NumBuffers = 4; +Writer.MaxFileSizeMB = 4100; +Writer.BufferSizeMB = 64; +Writer.FileName = "/hlt2/objects/${PARTITION}/${RUN}/Run_${RUN}_${TIME}_${NODE}.mdf"; +Writer.OutputType = "POSIX"; diff --git a/Online/FarmConfig/options/Empty.opts b/Online/FarmConfig/options/Empty.opts new file mode 100755 index 000000000..e69de29bb diff --git a/Online/FarmConfig/options/HLT2MBM.opts b/Online/FarmConfig/options/HLT2MBM.opts new file mode 100644 index 000000000..7388e7aba --- /dev/null +++ b/Online/FarmConfig/options/HLT2MBM.opts @@ -0,0 +1,12 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +//OnlineEnv.MBM_setup = "-s=1000000 -e=50 -u=30 -b=18 -t=1 -y -i=Events -f -c -s=100000 -e=50 -u=15 -b=12 -t=1 -y -i=Output -f -c"; +// +Manager.Setup = {"Dataflow_MBMServer/MEPManager"}; +Manager.Services = {"Dataflow_UI/UI"}; +// +MEPManager.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.InitFlags = @OnlineEnv.MBM_setup; diff --git a/Online/FarmConfig/options/HLT2Reader.opts b/Online/FarmConfig/options/HLT2Reader.opts new file mode 100644 index 000000000..254b4799c --- /dev/null +++ b/Online/FarmConfig/options/HLT2Reader.opts @@ -0,0 +1,62 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +#include "$FARMCONFIGROOT/options/Monitoring.opts" +Monitoring.CounterUpdateInterval = 3; +// +Manager.Services = {"Dataflow_MBMClient/MEPManager", +// "Dataflow_BurstReader/Reader", + "Dataflow_StorageReader/Reader", + "Dataflow_RunableWrapper/Wrap", + "Dataflow_UI/UI" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "Reader"; +Task.HavePause = true; +// +MEPManager.PartitionBuffers = true; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.PartitionID = @OnlineEnv.PartitionID; +MEPManager.Buffers = {"Events"};//@OnlineEnv.HLT2Reader_Buffers; +MEPManager.InhibitCancel = true; +// +Reader.Buffer = "Events";//@OnlineEnv.Hlt2Reader_Output; +Reader.BrokenHosts = ""; +Reader.Directories = {"/daqarea1/fest/202110/mdf/30000000"}; +Reader.FilePrefix = "00146082"; + +// +Reader.AllowedRuns = {"*"}; +Reader.MuDelay = 0; +Reader.DeleteFiles = false; +Reader.SaveRest = false; +Reader.PauseSleep = 2; // Optional wait time until 'Output' event queue is empty +Reader.InitialSleep = 0; +Reader.MaxPauseWait = 1; +Reader.GoService = ""; +Reader.Rescan = 1; +Reader.RequireConsumers = 0; +Reader.MMapFiles = 0; +Reader.ReuseFile = 0; +Reader.PackingFactor = 100; +Reader.AllocationSizekB = 20000; +Reader.PatchOdin = 0; // 0 = no patching +/* +Reader.PartitionName = "FEST"; +Reader.Directories = {""}; +Reader.FilePrefix = "/daqarea1/objects/nfs_data/${PARTITION}/${RUN}/Run_${RUN}"; +Reader.DataType = "posix"; +Reader.Server = "XXEB09.lbdaq.cern.ch:8000"; +*/ +// +Reader.DataType = "network"; +Reader.Server = "devbbdb01.lbdaq.cern.ch:4242"; +Reader.FDBVersion = 1; +Reader.PartitionName = "FEST"; +Reader.FilePrefix = "${PARTITION}/${RUN}/"; +Reader.AllowedRuns = { "219728", "219729" +// "219799", "219800", "219810", "219811", "219812", "219813", "219816", "219817", "219818", "219819", "219820" +}; +Reader.NumThreads = 2; +Reader.NumBuffers = 3; diff --git a/Online/FarmConfig/options/HLT2Writer.opts b/Online/FarmConfig/options/HLT2Writer.opts new file mode 100644 index 000000000..392a920af --- /dev/null +++ b/Online/FarmConfig/options/HLT2Writer.opts @@ -0,0 +1,31 @@ +#pragma print off +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIGROOT/options/StorageWriter.opts" +Monitoring.CounterUpdateInterval = 20; + +MBM.Buffers = @OnlineEnv.HLT2Writer_Buffers; +EventProc.Input = @OnlineEnv.HLT2Writer_Input; + +Writer.BufferSizeMB = 4000; +Writer.MaxFileSizeMB = -1; // Only valid for posix writing +Writer.NumBuffers = 4; +Writer.NumThreads = 3; +Writer.Stream = "Full"; +Writer.Server = "XXEB09.lbdaq.cern.ch:8000"; +Writer.FileName = "/objects/data/HLT2/${PARTITION}/${STREAM}/${RUN1000}/${RUN}/Run_${RUN}_${NODE}_${TIME}_${PID}_${SEQ}.mdf"; +// +EventProc.REQ2 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0"; +// +// NFS writing +Writer.PartitionName = "FEST"; +Writer.ThreadFileQueues = false; +Writer.IdleTimeout = 120; +Writer.NumThreads = 2; +Writer.NumBuffers = 3; +Writer.MaxFileSizeMB = 4000; +Writer.BufferSizeMB = 32; +Writer.HaveFileDB = 2; +Writer.FDBVersion = 0; +Writer.Server = "XXEB09.lbdaq.cern.ch:8010"; +Writer.FileName = "/hlt2/HLT2/${PARTITION}/${RUN}/Run_${RUN}_${NODE}_${TIME}_${SEQ}.mdf"; +Writer.OutputType = "POSIX"; diff --git a/Online/FarmConfig/options/HLT2WriterPosix.opts b/Online/FarmConfig/options/HLT2WriterPosix.opts new file mode 100644 index 000000000..25c7b88f4 --- /dev/null +++ b/Online/FarmConfig/options/HLT2WriterPosix.opts @@ -0,0 +1,8 @@ +#include "$FARMCONFIGROOT/options/StorageWriter.opts" +Writer.MaxFileSizeMB = 4000; +Writer.NumBuffers = 6; +Writer.NumThreads = 4; +Writer.Server = "XXEB09.lbdaq.cern.ch:8000"; +Writer.FileName = "/objects/data/HLT2/${PARTITION}/${STREAM}/${RUN1000}/${RUN}/Run_${RUN}_${NODE}_${TIME}_${PID}_${SEQ}.mdf"; +// +EventProc.REQ2 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=20.0"; diff --git a/Online/FarmConfig/options/Hlt2Reader.opts b/Online/FarmConfig/options/Hlt2Reader.opts new file mode 100755 index 000000000..a8ddf0c02 --- /dev/null +++ b/Online/FarmConfig/options/Hlt2Reader.opts @@ -0,0 +1,49 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +#include "$FARMCONFIGROOT/options/Monitoring.opts" +// +Manager.Services = {"Dataflow_MBMClient/MBM", + "Dataflow_BurstReader/Reader", + "Dataflow_RunableWrapper/Wrap", + "Dataflow_UI/UI" + }; +Manager.Runable = "Wrap"; +Wrap.Callable = "Reader"; +Task.HavePause = true; +// +Reader.Buffer = "Events"; +Reader.Buffer = @OnlineEnv.Hlt2Reader_Output; +Reader.BrokenHosts = ""; +Reader.Directories = {"/daqarea1/objects/data/TEST/0006718000/0006718861"}; +Reader.FilePrefix = "Run_"; +Reader.Directories = {"/group/online/dataflow/cmtuser/data/mdf"}; +Reader.FilePrefix = "000"; +Reader.Directories = {"/hlt2/data/hlt2_in/LHCb2", "/hlt2/data/HLT2/LHCb2"}; +Reader.Directories = {"/hlt2/data/hlt2_in/LHCb2"}; +Reader.Directories = {"/localdisk1/hlt1"}; +Reader.FilePrefix = "Run_"; +Reader.ScanRecursive = true; + +Reader.AllowedRuns = @OnlineEnv.DeferredRuns; +Reader.MuDelay = 0; +Reader.DeleteFiles = false; +Reader.SaveRest = false; +Reader.PauseSleep = 2; // Optional wait time until 'Output' event queue is empty +Reader.InitialSleep = 0; +Reader.MaxPauseWait = 1; +//Reader.GoService = "$GO_SERVICE_NAME"; +Reader.GoService = ""; +Reader.Rescan = 1; +Reader.RequireConsumers = 0; +Reader.MMapFiles = 0; +Reader.ReuseFile = 0; +Reader.PackingFactor = 100; +Reader.AllocationSizekB = 10000; +// +MBM.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MBM.PartitionName = @OnlineEnv.PartitionName; +MBM.PartitionID = @OnlineEnv.PartitionID; +MBM.Buffers = @OnlineEnv.Hlt2Reader_Buffers; + diff --git a/Online/FarmConfig/options/Logging.opts b/Online/FarmConfig/options/Logging.opts new file mode 100644 index 000000000..20f73ea1d --- /dev/null +++ b/Online/FarmConfig/options/Logging.opts @@ -0,0 +1,5 @@ +// +Logger.OutputLevel = @OnlineEnv.OutputLevel; +Logger.Format = "%-8LEVEL %-24SOURCE"; +Logger.LogPath = "$LOGFIFO"; +Logger.LogDeviceType = "RTL::Logger::LogDevice"; diff --git a/Online/FarmConfig/options/MonAdder.opts b/Online/FarmConfig/options/MonAdder.opts new file mode 100755 index 000000000..5ab37fda1 --- /dev/null +++ b/Online/FarmConfig/options/MonAdder.opts @@ -0,0 +1,29 @@ +#include "$INFO_OPTIONS" + +ApplicationMgr.ExtSvc += {"MonitorSvc","AdderSvc/BusyAdder"}; + +ApplicationMgr.EventLoop = "LHCb::OnlineRunable/EmptyEventLoop"; +ApplicationMgr.Runable = "LHCb::OnlineRunable/Runable"; +ApplicationMgr.HistogramPersistency = "NONE"; +ApplicationMgr.EvtSel = "NONE"; + +Runable.Wait = 3; // 1 of running as daemon (Class1 task) + +MessageSvc.fifoPath = "$LOGFIFO"; +MessageSvc.OutputLevel = @OnlineEnv.OutputLevel; +MonitorSvc.OutputLevel = @OnlineEnv.OutputLevel; +HistogramPersistencySvc.Warnings = false; +BusySvc.BogusMips = 0.0; +MonitorSvc.CounterUpdateInterval = 5; + +ApplicationMgr.ExtSvc += {"AdderSvc/MEPInitCountAdder"}; + +MEPInitCountAdder.PartitionName = @OnlineEnv.PartitionName; +MEPInitCountAdder.MyName = "<part>_<node>_"+tsk; +MEPInitCountAdder.TaskPattern = "<part>_mona08[0-9][2-9]_"+tsk+"_00"; +MEPInitCountAdder.ServicePattern = "MON_<part>_mona08[0-9][2-9]_"+tsk"+"_00"/Counter/"; +MEPInitCountAdder.ReceiveTimeout = 6; +MEPInitCountAdder.AdderClass = "Counter"; +MEPInitCountAdder.InDNS = "mona08"; +MEPInitCountAdder.OutDNS = "mona08"; + diff --git a/Online/FarmConfig/options/Monitoring.opts b/Online/FarmConfig/options/Monitoring.opts new file mode 100755 index 000000000..b62bc0857 --- /dev/null +++ b/Online/FarmConfig/options/Monitoring.opts @@ -0,0 +1,6 @@ +// +Monitoring.PartitionName = @OnlineEnv.PartitionName; +Monitoring.UniqueServiceNames = 1; +Monitoring.ExpandCounterServices = 1; +Monitoring.ExpandNameInfix = "<proc>/"; +Monitoring.CounterUpdateInterval = 5; diff --git a/Online/FarmConfig/options/OnlineStreams.opts b/Online/FarmConfig/options/OnlineStreams.opts new file mode 100644 index 000000000..92f76fe19 --- /dev/null +++ b/Online/FarmConfig/options/OnlineStreams.opts @@ -0,0 +1,324 @@ +// ------------------------------------------------------------------------------------- +// Calibration stream executing in the calibration farm +// ------------------------------------------------------------------------------------- +OnlineStreams.Calib = { +"TEST_MARKUS_WRITER/CALIB": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "2000", + "mask": "0x0,0x0,0x4000000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// VALO Calibration stream +// ------------------------------------------------------------------------------------- +OnlineStreams.CaloCalib = { +"TEST_MARKUS_WRITER/CALOCALIB": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "2000", + "mask": "0x0,0x810000,0x0,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// FULL stream (Full) +// ------------------------------------------------------------------------------------- +OnlineStreams.Full = { +"TEST_MARKUS_WRITER/FULL": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "4000", + "mask": "0x0,0x0,0x800000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// BEAMGAS stream (BeamGas) +// ------------------------------------------------------------------------------------- +OnlineStreams.BeamGas = { +"TEST_MARKUS_WRITER/BEAMGAS": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "4000", + "mask": "0x0,0x0,0x400000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// EXPRESS stream (Express) +// ------------------------------------------------------------------------------------- +OnlineStreams.Express = { +"TEST_MARKUS_WRITER/EXPRESS": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "bufferDepth": "0", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferSize": "4000", + "mask": "0x0,0x10,0x0,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// HLTONE stream (HltOne) +// ------------------------------------------------------------------------------------- +OnlineStreams.HltOne = { +"TEST_MARKUS_WRITER/HLTONE": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "4000", + "mask": "0x0,0x0,0x0,0x4", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// LOWMULT stream (LowMult) +// ------------------------------------------------------------------------------------- +OnlineStreams.LowMult = { +"TEST_MARKUS_WRITER/LOWMULT": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x100000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// LUMI stream (Lumi) +// ------------------------------------------------------------------------------------- +OnlineStreams.Lumi = { +"TEST_MARKUS_WRITER/LUMI": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x40000000,0x0", + "veto": "0x0,0x0,0x0,0xB00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// MICROB stream (MicroB) +// ------------------------------------------------------------------------------------- +OnlineStreams.MicroB = { +"TEST_MARKUS_WRITER/MICROB": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x40000000,0x0", + "veto": "0x0,0x0,0x0,0xB00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// NOBIAS stream (NoBias) +// ------------------------------------------------------------------------------------- +OnlineStreams.NoBias = { +"TEST_MARKUS_WRITER/NOBIAS": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x8000000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// PARK stream (Park) +// ------------------------------------------------------------------------------------- +OnlineStreams.Park = { +"TEST_MARKUS_WRITER/PARK": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x2000000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// RICH/EXPRESS stream (Rich) +// ------------------------------------------------------------------------------------- +OnlineStreams.Rich = { +"TEST_MARKUS_WRITER/EXPRESS": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x400000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// SMOGPHY stream (SmogPhy) +// ------------------------------------------------------------------------------------- +OnlineStreams.SmogPhy = { +"TEST_MARKUS_WRITER/SMOGPHY": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x20000000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// TURFULL stream (TurFull) = TURBORAW +// ------------------------------------------------------------------------------------- +OnlineStreams.TurFull = { +"TEST_MARKUS_WRITER/TURFULL": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "500", + "mask": "0x0,0x0,0x200000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; + +// ------------------------------------------------------------------------------------- +// TURBO stream (Turbo) +// ------------------------------------------------------------------------------------- +OnlineStreams.Turbo = { +"TEST_MARKUS_WRITER/TURBO": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "bufferDepth": "0", + "bufferSize": "1000", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "mask": "0x0,0x0,0x1000000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// TURBORAW stream (TurboRaw) = TURFULL +// ------------------------------------------------------------------------------------- +OnlineStreams.Turbo = { +"TEST_MARKUS_WRITER/TURBORAW": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "bufferDepth": "0", + "bufferSize": "1000", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "mask": "0x0,0x0,0x200000,0x0", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; +// ------------------------------------------------------------------------------------- +// Events stream +// ------------------------------------------------------------------------------------- +OnlineStreams.Events = { +"TEST_MARKUS_WRITER/FULL": + { "fileSizeMB": "5000", + "deviceType": "writerd", + "retireTimeout": "5", + "precloseTimeout": "3", + "closeTimeout": "500", + "bufferDepth": "0", + "bufferSize": "4000", + "mask": "0x0,0x0,0x0,0x1", + "veto": "0x0,0x0,0x0,0xFFFFFF00", + "frequency": "100", + "multiplicity": "1", + "enabled": "1" + } +}; diff --git a/Online/FarmConfig/options/PartAdderStatic.opts b/Online/FarmConfig/options/PartAdderStatic.opts new file mode 100755 index 000000000..2d4ff97dd --- /dev/null +++ b/Online/FarmConfig/options/PartAdderStatic.opts @@ -0,0 +1,11 @@ +ApplicationMgr.ExtSvc += {"AdderSvc/Moore2CountAdder"}; + + +Moore2CountAdder.PartitionName = @OnlineEnv.PartitionName; +Moore2CountAdder.MyName = "<part>_Moore2_00"; +Moore2CountAdder.TaskPattern = "<part>_HLT[a-z][0-9][0-9]_SubFarmAdder_(.*)"; +Moore2CountAdder.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_Moore2/Counter/"; +Moore2CountAdder.AdderClass = "Counter"; +Moore2CountAdder.ReceiveTimeout = 14; +Moore2CountAdder.InDNS = "hlt01"; +Moore2CountAdder.OutDNS = "mona08"; diff --git a/Online/FarmConfig/options/RCV.opts b/Online/FarmConfig/options/RCV.opts new file mode 100755 index 000000000..42bbe438b --- /dev/null +++ b/Online/FarmConfig/options/RCV.opts @@ -0,0 +1,17 @@ +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$STATIC_OPTS/SvcMapping.opts" +#include "$STATIC_OPTS/Monitoring.opts" +ApplicationMgr.HistogramPersistency = "NONE"; +ApplicationMgr.EvtSel = "NONE"; +ApplicationMgr.Runable = "LHCb::OnlineRunable/Runable"; +Runable.Wait = 3; // noop +ApplicationMgr.ExtSvc += { "ReceiverSvc" }; +MEPManager.PartitionID = @OnlineEnv.PartitionID; +MEPManager.PartitionName = @OnlineEnv.PartitionName; +MEPManager.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MEPManager.Buffers = @OnlineEnv.Receiver_Buffers; +ReceiverSvc.Buffer = @OnlineEnv.Receiver_Output; +ReceiverSvc.RoutingMask = 1; +ReceiverSvc.VetoMask = 65535; // 0xffff +#include "$STATIC_OPTS/MessageSvc.opts" diff --git a/Online/FarmConfig/options/SMOG.prescaler-requirements b/Online/FarmConfig/options/SMOG.prescaler-requirements new file mode 100755 index 000000000..abef5098a --- /dev/null +++ b/Online/FarmConfig/options/SMOG.prescaler-requirements @@ -0,0 +1,9 @@ +Prescaler.Requirements = { +"Name=All;EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=1.0", +"Name=Tracker;EvType=2;TriggerMask=0x0,0x00200000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0", +"Name=Rich;EvType=2;TriggerMask=0x0,0x00400000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0", +"Name=Velo;EvType=2;TriggerMask=0x0,0x00000008,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=1.0", +"Name=Muon;EvType=2;TriggerMask=0x0,0x00000400,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=10.0", +"Name=Calo;EvType=2;TriggerMask=0x0,0x18000,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=1.0", +"Name=VClose;EvType=2;TriggerMask=0x0,0x100,0x0,0x0;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0" +}; diff --git a/Online/FarmConfig/options/Sender.opts b/Online/FarmConfig/options/Sender.opts new file mode 100755 index 000000000..2b713f972 --- /dev/null +++ b/Online/FarmConfig/options/Sender.opts @@ -0,0 +1,22 @@ +// MSF: 04/12/2016: NEW Dataflow task type ! +#pragma print off +//------------- Default sender options: ------------------------------------------ +#include "$INFO_OPTIONS" +#include "$MBM_SETUP_OPTIONS" +#include "$SUBFARM_OPTIONS" +#include "../options/Monitoring.opts" + +Manager.Services = {"Dataflow_MBMClient/MBM","Dataflow_MBMSelector/EventProc","Dataflow_UI/UI"}; +Manager.Algorithms = {"Dataflow_AsioSender/Sender"}; +Manager.Runable = "EventProc"; +Logger.OutputLevel = @OnlineEnv.OutputLevel; +MBM.PartitionBuffers = @OnlineEnv.PartitionBuffers; +MBM.PartitionName = @OnlineEnv.PartitionName; +MBM.PartitionID = @OnlineEnv.PartitionID; +MBM.Buffers = @OnlineEnv.Sender_Buffers; +Sender.Delay = 0; +Sender.PauseOnError = true; +Sender.DataSink = @OnlineEnv.Target; +EventProc.Input = @OnlineEnv.Sender_Input; +EventProc.REQ1 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0"; +Monitoring.CounterUpdateInterval = 5; diff --git a/Online/FarmConfig/options/StorageReader.opts b/Online/FarmConfig/options/StorageReader.opts new file mode 100644 index 000000000..b0a95267d --- /dev/null +++ b/Online/FarmConfig/options/StorageReader.opts @@ -0,0 +1,36 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +#include "$FARMCONFIGROOT/options/Monitoring.opts" +// +Manager.Services = {"Dataflow_MBMClient/MBM", + "Dataflow_StorageReader/Reader", + "Dataflow_RunableWrapper/Wrap" + }; +// +Manager.Runable = "Wrap"; +Wrap.Callable = "Reader"; +// +Reader.PartitionName = @OnlineEnv.PartitionName; +Reader.RunType = @OnlineEnv.RunType; +Reader.Stream = "HLT1"; +Reader.AllowedRuns = { "*" }; +Reader.DeleteFiles = false; +Reader.SaveRest = false; +Reader.FilePrefix = "/objects/data/${PARTITION}/${RUN1000}"; +Reader.FilePrefix = "/objects/data/${PARTITION}"; +Reader.PartitionName = @OnlineEnv.PartitionName; +Reader.PauseSleep = 1; +Reader.InitialSleep = 1; +Reader.MaxPauseWait = 1; +Reader.RequireConsumers = 0; +Reader.PackingFactor = 40; +Reader.Buffer = "Events"; +Reader.Server = "XXEB09.lbdaq.cern.ch:8000"; +// +MBM.PartitionBuffers = true; +MBM.PartitionName = @OnlineEnv.PartitionName; +MBM.PartitionID = @OnlineEnv.PartitionID; +MBM.Buffers = { "Events" }; +// +Logger.OutputLevel = @OnlineEnv.OutputLevel; diff --git a/Online/FarmConfig/options/StorageWriter.opts b/Online/FarmConfig/options/StorageWriter.opts new file mode 100644 index 000000000..6ab1a357c --- /dev/null +++ b/Online/FarmConfig/options/StorageWriter.opts @@ -0,0 +1,47 @@ +#pragma print off +#include "$INFO_OPTIONS" +#include "$FARMCONFIGROOT/options/Logging.opts" +#include "$FARMCONFIGROOT/options/Monitoring.opts" + +Logger.OutputLevel = @OnlineEnv.OutputLevel; +Monitoring.CounterUpdateInterval = 5; +Monitoring.DimUpdateInterval = 20; +// +Manager.Services = {"Dataflow_MBMClient/MBM", + "Dataflow_MBMSelector/EventProc", + "Dataflow_RunableWrapper/Wrap" + }; +Manager.Algorithms = {"Dataflow_EmptyProcessor/Empty"}; +Manager.Runable = "Wrap"; +Wrap.Callable = "EventProc"; +// +EventProc.REQ1 = "EvType=1;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0"; +EventProc.REQ2 = "EvType=2;TriggerMask=0xffffffff,0xffffffff,0xffffffff,0xffffffff;VetoMask=0,0,0,0;MaskType=ANY;UserType=VIP;Frequency=PERC;Perc=100.0"; +EventProc.Input = "Output"; +EventProc.DelayStop = 5; +// +// +OnlineEnv.PartitionBuffers = true; +MBM.PartitionBuffers = true; +MBM.PartitionName = @OnlineEnv.PartitionName; +MBM.PartitionID = @OnlineEnv.PartitionID; +MBM.Buffers = {"Output"}; +// +// +Manager.Algorithms = {"Dataflow_StorageWriter/Writer"}; +Writer.PartitionName = @OnlineEnv.PartitionName; +Writer.RunType = @OnlineEnv.RunType; +Writer.Stream = "HLT1"; +Writer.FileName = "/objects/data/${PARTITION}/${STREAM}/${RUN1000}/${RUN}/Run_${RUN}_${NODE}_${TIME}_${PID}_${SEQ}.mdf"; +Writer.Server = "XXEB09.lbdaq.cern.ch:8000"; +Writer.BufferSizeMB = 2000; +Writer.MinFileSizeMB = 10; +Writer.WriteErrorRetry = 100000; +Writer.WriteErrorSleep = 3000; +Writer.PollTimeout = 100000; // micro-seconds +Writer.NumBuffers = 2; +Writer.NumThreads = 1; +Writer.CancelTimeout = 100; // seconds +Writer.ForceMDF = true; +Writer.OutputType = "NETWORK"; +// diff --git a/Online/FarmConfig/options/TopBsyAdder.opts b/Online/FarmConfig/options/TopBsyAdder.opts new file mode 100755 index 000000000..659490ba1 --- /dev/null +++ b/Online/FarmConfig/options/TopBsyAdder.opts @@ -0,0 +1,68 @@ +ApplicationMgr.ExtSvc += {"MonitorSvc"}; +ApplicationMgr.EventLoop = "LHCb::OnlineRunable/EmptyEventLoop"; +ApplicationMgr.Runable = "LHCb::OnlineRunable/Runable"; +ApplicationMgr.HistogramPersistency = "NONE"; +ApplicationMgr.EvtSel = "NONE"; + +Runable.Wait = 3; // 1 of running as daemon (Class1 task) + +MessageSvc.fifoPath = "$LOGFIFO"; +MessageSvc.OutputLevel = 3; +MonitorSvc.OutputLevel = 3; +HistogramPersistencySvc.Warnings = false; +MonitorSvc.CounterUpdateInterval = 5; +ApplicationMgr.ExtSvc += {"AdderSvc/BusyAdder"}; +ApplicationMgr.ExtSvc += {"AdderSvc/Moore1CountAdder"}; +ApplicationMgr.ExtSvc += {"AdderSvc/PassThroughCountAdder"}; +ApplicationMgr.ExtSvc += {"AdderSvc/Moore2CountAdder"}; +ApplicationMgr.ExtSvc += {"AdderSvc/HLT2SenderAdder"}; + +BusyAdder.MyName = "<part>_Busy_00"; +BusyAdder.PartitionName = "GEN"; +BusyAdder.TaskPattern = "<part>_hlt[a-z][0-9][0-9]_BusyMon"; +BusyAdder.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_BusyMon/Counter/"; +BusyAdder.AdderClass = "Counter"; +BusyAdder.ReceiveTimeout = 10; +BusyAdder.InDns = "hlt01"; +BusyAdder.OutDns = "mona08"; +BusyAdder.Test=true; + +Moore1CountAdder.PartitionName = "GEN"; +Moore1CountAdder.MyName = "<part>_Moore1_00"; +Moore1CountAdder.TaskPattern = "<part>_HLT[a-z][0-9][0-9]_BusyMon"; +Moore1CountAdder.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_Moore1/Counter/"; +Moore1CountAdder.AdderClass = "Counter"; +Moore1CountAdder.ReceiveTimeout = 15; +Moore1CountAdder.InDNS = "hlt01"; +Moore1CountAdder.OutDNS = "mona08"; +Moore1CountAdder.Test = true; + +PassThroughCountAdder.PartitionName = "GEN"; +PassThroughCountAdder.MyName = "<part>_PassThrough_00"; +PassThroughCountAdder.TaskPattern = "<part>_HLT[a-z][0-9][0-9]_BusyMon"; +PassThroughCountAdder.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_PassThrough/Counter/"; +PassThroughCountAdder.AdderClass = "Counter"; +PassThroughCountAdder.ReceiveTimeout = 15; +PassThroughCountAdder.InDNS = "hlt01"; +PassThroughCountAdder.OutDNS = "mona08"; +PassThroughCountAdder.Test = true; + +Moore2CountAdder.PartitionName = "GEN"; +Moore2CountAdder.MyName = "<part>_Moore2_00"; +Moore2CountAdder.TaskPattern = "<part>_HLT[a-z][0-9][0-9]_BusyMon"; +Moore2CountAdder.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_Moore2/Counter/"; +Moore2CountAdder.AdderClass = "Counter"; +Moore2CountAdder.ReceiveTimeout = 15; +Moore2CountAdder.InDNS = "hlt01"; +Moore2CountAdder.OutDNS = "mona08"; +Moore2CountAdder.Test = true; + +HLT2SenderAdder.PartitionName = "GEN"; +HLT2SenderAdder.MyName = "<part>_HLT2Sender_00"; +HLT2SenderAdder.TaskPattern = "<part>_HLT[a-z][0-9][0-9]_BusyMon"; +HLT2SenderAdder.ServicePattern = "MON_<part>_hlt[a-z][0-9][0-9]_HLT2Sender/Counter/"; +HLT2SenderAdder.AdderClass = "Counter"; +HLT2SenderAdder.ReceiveTimeout = 15; +HLT2SenderAdder.InDNS = "hlt01"; +HLT2SenderAdder.OutDNS = "mona08"; +HLT2SenderAdder.Test = true; -- GitLab From 23f889ea57cf9b14ed530d664475ecc6fbab48a2 Mon Sep 17 00:00:00 2001 From: Flavio Pisani <flavio.pisani@cern.ch> Date: Tue, 1 Feb 2022 17:17:13 +0100 Subject: [PATCH 4/4] latest bt fixes --- Online/EventBuilding/EventBuilding/BU.hpp | 4 + Online/EventBuilding/EventBuilding/RU.hpp | 1 + .../include/buffer_interface.hpp | 2 + .../EventBuilding/include/pcie40_reader.hpp | 21 ++- .../include/pcie40_reader_error.hpp | 1 + Online/EventBuilding/src/BU.cpp | 136 ++++++++++++----- Online/EventBuilding/src/RU.cpp | 58 ++++++- Online/EventBuilding/src/pcie40_reader.cpp | 143 +++++++++++++----- .../EventBuilding/src/pcie40_reader_error.cpp | 1 + 9 files changed, 287 insertions(+), 80 deletions(-) diff --git a/Online/EventBuilding/EventBuilding/BU.hpp b/Online/EventBuilding/EventBuilding/BU.hpp index 705446e4d..7b01bb887 100644 --- a/Online/EventBuilding/EventBuilding/BU.hpp +++ b/Online/EventBuilding/EventBuilding/BU.hpp @@ -96,6 +96,8 @@ namespace EB { std::vector<EB::src_id_type> _src_ids; std::vector<EB::src_id_type> _sorted_src_ids; + std::vector<std::string> _src_names; + std::map<EB::src_id_type, std::string> _src_id_names_maps; std::vector<size_t> _src_id_idx_to_ru_src_idx; std::vector<size_t> _ru_src_idx_to_src_id_idx; @@ -104,9 +106,11 @@ namespace EB { int check_buffer(); int config_buffer(); int sort_src_ids(); + int map_src_id_names(); int init_shift(); int receive_sizes(); int receive_src_ids(); + int receive_src_names(); int linear_shift(); int receive_MFPs(const std::vector<int>& shift_off_it); int get_next_MEP_space(); diff --git a/Online/EventBuilding/EventBuilding/RU.hpp b/Online/EventBuilding/EventBuilding/RU.hpp index 7a20777a6..471c58f0c 100644 --- a/Online/EventBuilding/EventBuilding/RU.hpp +++ b/Online/EventBuilding/EventBuilding/RU.hpp @@ -114,6 +114,7 @@ namespace EB { int send_sizes(); int init_dummy_src_ids(); int send_src_ids(); + int send_src_names(); int load_mfps(); // preload a set on 0 sized NULL MFPs int load_empty(); diff --git a/Online/EventBuilding/include/buffer_interface.hpp b/Online/EventBuilding/include/buffer_interface.hpp index 079f42acc..1c31f9b05 100644 --- a/Online/EventBuilding/include/buffer_interface.hpp +++ b/Online/EventBuilding/include/buffer_interface.hpp @@ -78,6 +78,7 @@ namespace EB { virtual void flush() = 0; // The src id should be set by an external device or in the constructor of the derived class virtual int get_src_id() const = 0; + virtual const std::string get_name() const {return "no_name" ; } }; template<class T> @@ -126,6 +127,7 @@ namespace EB { virtual void write_discard() = 0; // The src id should be set by an external device or in the constructor of the derived class virtual int get_src_id() const = 0; + virtual const std::string get_name() const {return "no_name" ; } }; } // namespace EB diff --git a/Online/EventBuilding/include/pcie40_reader.hpp b/Online/EventBuilding/include/pcie40_reader.hpp index d62e4c65a..7df717234 100644 --- a/Online/EventBuilding/include/pcie40_reader.hpp +++ b/Online/EventBuilding/include/pcie40_reader.hpp @@ -19,6 +19,16 @@ namespace EB { // alignments are expressed as a power of 2 constexpr int default_PCIe40_alignment = 12; // 4096 B constexpr int default_PCIe40_frag_alignment = 5; // 32 B + constexpr int default_PCIe40_frag_thr = 32; + constexpr int default_PCIe40_packing_factor = 3000; + // max number of character in the PCIe40 name + constexpr int PCIe40_name_length = 8; + // minimum str length to sto a PCIe40 name including the str terminator + constexpr int PCIe40_name_str_length = PCIe40_name_length + 1; + // max number of character in the PCIe40 unique name including stream + constexpr int PCIe40_unique_name_length = PCIe40_name_length + 2; + // minimum str length to sto a PCIe40 unique name including the str terminator + constexpr int PCIe40_unique_name_str_length = PCIe40_unique_name_length + 1; class PCIe40_reader { public: @@ -27,13 +37,13 @@ namespace EB { int id, int stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN, bool enable_MFP = true, - int packing_factor = 3000); + int packing_factor = default_PCIe40_packing_factor); PCIe40_reader( const std::string& name, int stream = P40_DAQ_STREAM::P40_DAQ_STREAM_MAIN, bool enable_MFP = true, - int packing_factor = 3000); + int packing_factor = default_PCIe40_packing_factor); PCIe40_reader(const PCIe40_reader& other) = delete; PCIe40_reader(PCIe40_reader&& other); @@ -46,10 +56,14 @@ namespace EB { std::error_code open(const std::string& name); std::error_code set_packing_factor(int packing_factor); + std::error_code set_fragment_threshold(int frag_thr); std::error_code enable_MFP_stream(); std::error_code disable_MFP_stream(); + std::error_code configure_MFP(int packing_factor); + std::error_code configure_fragment(int frag_thr = default_PCIe40_frag_thr); + // Resets the the cards and flush the buffer std::error_code reset(); @@ -148,6 +162,9 @@ namespace EB { std::vector<std::tuple<void*, size_t>> get_full_buffer() override; + // TODO this should be override + const std::string get_name() const override; + protected: PCIe40_reader _pcie40_reader; Circular_buffer_reader<EB::MFP, Shared_ptr_buffer_backend> _internal_buffer_reader; diff --git a/Online/EventBuilding/include/pcie40_reader_error.hpp b/Online/EventBuilding/include/pcie40_reader_error.hpp index e41efe6a9..2fdf65a89 100644 --- a/Online/EventBuilding/include/pcie40_reader_error.hpp +++ b/Online/EventBuilding/include/pcie40_reader_error.hpp @@ -25,6 +25,7 @@ namespace EB { LOGIC_RESET, CORRUPTED_DATA, INVALID_PACKING_FACTOR, + INVALID_FRAGMENT_THRESHOLD, INTERNAL_BUFFER_FULL, INTERNAL_BUFFER_FULL_FLUSH, }; diff --git a/Online/EventBuilding/src/BU.cpp b/Online/EventBuilding/src/BU.cpp index 01dbc9306..a384be143 100644 --- a/Online/EventBuilding/src/BU.cpp +++ b/Online/EventBuilding/src/BU.cpp @@ -1,4 +1,5 @@ #include "EventBuilding/BU.hpp" +#include "pcie40_reader.hpp" #include "shmem_buffer_writer.hpp" #include "MEP_injector.hpp" #include "dummy_mep_buffer_writer.hpp" @@ -127,7 +128,18 @@ int EB::BU::start() if (ret_val != DF_SUCCESS) { return ret_val; } - _ibComm->ibDeregMRs(); // clear memory regions + + // exchange src_names + ret_val = receive_src_names(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } + + // exchange src_names + ret_val = map_src_id_names(); + if (ret_val != DF_SUCCESS) { + return ret_val; + } ret_val = sort_src_ids(); if (ret_val != DF_SUCCESS) { @@ -343,6 +355,17 @@ int EB::BU::sort_src_ids() return ret_val; } +int EB::BU::map_src_id_names() +{ + int ret_val = DF_SUCCESS; + _src_id_names_maps.clear(); + for (int k = 0; k < _src_ids.size(); k++) { + _src_id_names_maps[_src_ids[k]] = _src_names[k]; + } + + return ret_val; +} + int EB::BU::config_buffer() { int ret_val = DF_SUCCESS; @@ -525,9 +548,36 @@ int EB::BU::run() // At the end of the run there is no MEP to check if (!_end_of_run) { - int n_events = (_curr_MEP->at(0))->header.n_banks; - _DF_events_in += n_events; - if (_curr_MEP->is_valid()) { + if (_incomplete) { + _incomplete_MEP_count++; + // The number of events can only be calculated for valid MEPs + _DF_events_err += 1; + _recv_buff->write_discard(); + } else if (!_curr_MEP->is_valid()) { + // TODO check what to do, should this be fatal? Do we discard the data (how?) + logger.error() << "CORRUPTED MEP received: "; + if (!_curr_MEP->is_magic_valid()) { + logger.error() << " corrupted header" << std::flush; + } else { + // logger.error() << _curr_MEP->print() << std::flush; + logger.error() << "Inconsistent EV ids " << std::flush; + int k = 0; + for (auto it = _curr_MEP->begin(); it != _curr_MEP->end(); it++) { + auto src_id = it->header.src_id; + logger.error() << "fragnum " << k << " magic: " << it->is_header_valid() << " source: " << src_id << "/" + << _src_id_names_maps[src_id] << " ev ID: " << it->header.ev_id << std::flush; + k++; + } + logger.error() << std::flush; + } + _recv_buff->write_discard(); + _corrupted_MEP_count++; + // The number of events can only be calculated for valid MEPs + _DF_events_err += 1; + } else { + int n_events = (_curr_MEP->at(0))->header.n_banks; + _DF_events_in += n_events; + // debug print if (logger.is_active(Online::PrintLevel::DEBUG)) { logger.debug() << "active MEP\n"; if (logger.is_active(Online::PrintLevel::VERBOSE)) { @@ -539,49 +589,21 @@ int EB::BU::run() logger.debug() << std::flush; } + // debug write to file if (_write_to_file[_my_idx] && (_n_meps_written_to_file < _n_meps_to_file)) { // TODO add error checking _file_writer.write(_curr_MEP); _n_meps_written_to_file++; } + // update counters if (_discarted) { - // TODO check what to do with discarted _DF counters _discarted_MEP_count++; - } else if (_incomplete) { - _incomplete_MEP_count++; - _DF_events_err += n_events; - _recv_buff->write_discard(); - _curr_MEP = NULL; } else { _DF_events_out += n_events; _MEP_count++; _snd_bytes += _curr_MEP->bytes(); } - } else { - // TODO check what to do, should this be fatal? Do we discard the data (how?) - logger.error() << "CORRUPTED MEP received: "; - if (!_curr_MEP->is_magic_valid()) { - logger.error() << " corrupted header" << std::flush; - } else { - // logger.error() << _curr_MEP->print() << std::flush; - logger.error() << "Inconsistent EV ids " << std::flush; - int k = 0; - for (auto it = _curr_MEP->begin(); it != _curr_MEP->end(); it++) { - logger.error() << "fragnum " << k << " magic: " << it->is_header_valid() << " source: " << it->header.src_id - << " ev ID: " << it->header.ev_id << std::flush; - k++; - } - logger.error() << std::flush; - } - - _recv_buff->write_discard(); - _curr_MEP = NULL; - - _corrupted_MEP_count++; - _DF_events_err += n_events; - // TODO check if this is the correct behaviour - // fireIncident("DAQ_ERROR"); } // Ack all the buffers // after write complete _curr_MEP is not valid @@ -694,7 +716,7 @@ int EB::BU::receive_sizes() _incomplete = true; logger.error() << "Incomplete event! No data received from the following sources: "; for (const auto& src : no_data_src_ids) { - logger.error() << src << " "; + logger.error() << src << "/" << _src_id_names_maps[src] << " "; _incomplete_MEP_srcs[src]++; } @@ -752,6 +774,46 @@ int EB::BU::receive_src_ids() } logger.debug() << std::flush; } + + _ibComm->ibDeregMRs(); // clear memory regions + + return ret_val; +} + +int EB::BU::receive_src_names() +{ + _src_names.resize(_prefix_n_sources_per_ru.back()); + auto tmp_buffer = new char[_src_names.size()][PCIe40_unique_name_str_length]; + _ibComm->addMR((char*) tmp_buffer, _src_names.size() * PCIe40_unique_name_str_length); + int ret_val = _ibComm->ibGatherBlockV( + reinterpret_cast<char*>(tmp_buffer), + _n_sources_per_ru.data(), + _prefix_n_sources_per_ru.data(), + PCIe40_unique_name_str_length, + _ru_ranks); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " size ibGatherBlockV failed " << ret_val << std::flush; + return ret_val; + } + + for (int k = 0; k < _src_names.size(); k++) { + _src_names[k] = tmp_buffer[k]; + logger.debug() << "buffer name : " << _src_names[k] << std::endl; + } + + logger.debug() << "src names written " << _src_names.size() << ": " << std::flush; + + if (logger.is_active(Online::PrintLevel::DEBUG)) { + for (const auto& name : _src_names) { + logger.debug() << name << " "; + } + logger.debug() << std::flush; + } + + delete tmp_buffer; + + _ibComm->ibDeregMRs(); // clear memory regions + return ret_val; } @@ -854,6 +916,10 @@ int EB::BU::get_next_MEP_space() int EB::BU::build_MEP_header() { + // DBG memset + if (logger.is_active(Online::PrintLevel::DEBUG)) { + memset(_curr_MEP, 0xeb, _full_size_words * EB::MEP_WORD_SIZE); + } // set magic _curr_MEP->set_magic_valid(); _curr_MEP->header.n_MFPs = _data_offset_words.size(); diff --git a/Online/EventBuilding/src/RU.cpp b/Online/EventBuilding/src/RU.cpp index 38dffd20f..b23b14529 100644 --- a/Online/EventBuilding/src/RU.cpp +++ b/Online/EventBuilding/src/RU.cpp @@ -4,6 +4,7 @@ #include <numeric> #include <stdexcept> #include <sstream> +#include <cstring> #include <chrono> #include "MFP_preloader.hpp" #include "RTL/rtl.h" @@ -225,8 +226,15 @@ int EB::RU::start() } // exchange srcids ret_val = send_src_ids(); - if (ret_val != DF_SUCCESS) return ret_val; - _ibComm->ibDeregMRs(); // clear memory regions + if (ret_val != DF_SUCCESS) { + return ret_val; + }; + + // exchange srcnames + ret_val = send_src_names(); + if (ret_val != DF_SUCCESS) { + return ret_val; + }; for (auto& buf : _buffers) { auto buflist = buf->get_full_buffer(); @@ -618,6 +626,40 @@ int EB::RU::send_src_ids() logger.error() << __FUNCTION__ << " src id broadcast failed" << std::flush; return ret_val; } + + _ibComm->ibDeregMRs(); // clear memory regions + return ret_val; +} + +int EB::RU::send_src_names() +{ + int ret_val = DF_SUCCESS; + // TODO check memory allocation + auto tmp_buffer = new char[_n_sources_per_ru[_my_idx]][PCIe40_unique_name_str_length]; + for (int k = 0; k < _buffers.size(); k++) { + std::strncpy(tmp_buffer[k], _buffers[k]->get_name().c_str(), PCIe40_unique_name_str_length); + // strncpy doesn't ensure a null terminated string adding terminator + tmp_buffer[k][PCIe40_unique_name_str_length - 1] = '\0'; + logger.debug() << "buffer name : " << tmp_buffer[k] << std::endl; + } + logger.debug() << "send buffer names " << _buffers.size() << std::flush; + // register mr + ret_val = _ibComm->addMR(reinterpret_cast<char*>(tmp_buffer), _buffers.size() * PCIe40_unique_name_str_length); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " unable to add memory region ptr " << reinterpret_cast<void*>(tmp_buffer) + << " size " << _buffers.size() * PCIe40_unique_name_str_length << std::flush; + return ret_val; + } + + ret_val = _ibComm->ibBroadcastV( + reinterpret_cast<char*>(tmp_buffer), _buffers.size(), PCIe40_unique_name_str_length, _bu_ranks); + if (ret_val != DF_SUCCESS) { + logger.error() << __FUNCTION__ << " src id broadcast failed" << std::flush; + return ret_val; + } + + _ibComm->ibDeregMRs(); // clear memory regions + delete tmp_buffer; return ret_val; } @@ -690,7 +732,7 @@ int EB::RU::send_MFPs(int shift_off) ret_val = comm_err; } // k=0 first source is taken into account to the event flow - if (selected_MFPs[shift_idx] != 0) { + if (selected_MFPs[shift_idx] != nullptr) { _DF_events_out += reinterpret_cast<const EB::MFP*>(selected_MFPs[shift_idx])->header.n_banks; } @@ -731,7 +773,13 @@ int EB::RU::load_mfps() // usleep(1); if (idle_timer.get_elapsed_time_s() > 5) { logger.warning() << __FUNCTION__ << " Time " << idle_timer.get_elapsed_time_s() << " no data from buffer " - << src << " src ID " << _buffers[src]->get_src_id() << std::flush; + << src << " src ID " << _buffers[src]->get_src_id(); + // FIXME only PCIe40s have name + if ((_buffer_type[_my_idx] == PCIe40_frag_buffer) || (_buffer_type[_my_idx] == PCIe40_MFP_buffer)) { + logger.warning() << " Tell40 name " << _buffers[src]->get_name() << std::flush; + } else { + logger.warning() << std::flush; + } idle_timer.reset(); } } else if (next_MFP->is_end_run() && !_received_data[src]) { @@ -800,7 +848,7 @@ int EB::RU::load_mfps() // All the missing slots are filled up with zero-sized MFPs for (int k = dst; k < _bu_ranks.size(); k++) { - int idx = dst * _buffers.size() + src; + int idx = k * _buffers.size() + src; selected_MFPs[idx] = NULL; sizes[idx] = 0; } diff --git a/Online/EventBuilding/src/pcie40_reader.cpp b/Online/EventBuilding/src/pcie40_reader.cpp index b417ec9f8..99ba4f696 100644 --- a/Online/EventBuilding/src/pcie40_reader.cpp +++ b/Online/EventBuilding/src/pcie40_reader.cpp @@ -18,18 +18,12 @@ EB::PCIe40_reader::PCIe40_reader(int id, int stream, bool enable_MFP, int packin } if (enable_MFP) { - err_val = set_packing_factor(packing_factor); + err_val = configure_MFP(packing_factor); if (err_val) { throw std::system_error(err_val, std::to_string(id)); } - - err_val = enable_MFP_stream(); - if (err_val) { - throw std::system_error(err_val, std::to_string(id)); - } - } else { - err_val = disable_MFP_stream(); + err_val = configure_fragment(); if (err_val) { throw std::system_error(err_val, std::to_string(id)); } @@ -46,18 +40,12 @@ EB::PCIe40_reader::PCIe40_reader(const std::string& name, int stream, bool enabl } if (enable_MFP) { - err_val = set_packing_factor(packing_factor); + err_val = configure_MFP(packing_factor); if (err_val) { throw std::system_error(err_val, name); } - - err_val = enable_MFP_stream(); - if (err_val) { - throw std::system_error(err_val, name); - } - } else { - err_val = disable_MFP_stream(); + err_val = configure_fragment(); if (err_val) { throw std::system_error(err_val, name); } @@ -211,10 +199,9 @@ std::error_code EB::PCIe40_reader::open(int id) _internal_read_off = _device_read_off; _requested_size = 0; - // TODO check with Paolo if there is a constant defined somewhere - char name[16]; + char name[PCIe40_unique_name_str_length]; - if (p40_id_get_name(_id_fd, name, sizeof(name)) != 0) { + if (p40_id_get_name_unique(_id_fd, name, sizeof(name)) != 0) { err_code = PCIe40_errors::GET_NAME; close(); return err_code; @@ -247,6 +234,25 @@ std::error_code EB::PCIe40_reader::set_packing_factor(int packing_factor) return err_code; } +std::error_code EB::PCIe40_reader::set_fragment_threshold(int frag_thr) +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + int ret_code = p40_ctrl_set_trunc_thres(_ctrl_fd, static_cast<P40_DAQ_STREAM>(_stream), frag_thr); + if (ret_code != 0) { + // TODO add error code + + err_code = PCIe40_errors::INVALID_FRAGMENT_THRESHOLD; + return err_code; + } + + return err_code; +} + std::error_code EB::PCIe40_reader::enable_MFP_stream() { std::error_code err_code{}; @@ -281,6 +287,48 @@ std::error_code EB::PCIe40_reader::disable_MFP_stream() return err_code; } +std::error_code EB::PCIe40_reader::configure_MFP(int packing_factor) +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + err_code = enable_MFP_stream(); + if (err_code) { + return err_code; + } + + err_code = set_packing_factor(packing_factor); + if (err_code) { + return err_code; + } + + return err_code; +} + +std::error_code EB::PCIe40_reader::configure_fragment(int frag_thr) +{ + std::error_code err_code{}; + if (!is_open()) { + err_code = PCIe40_errors::DEVICE_NOT_OPEN; + return err_code; + } + + err_code = disable_MFP_stream(); + if (err_code) { + return err_code; + } + + err_code = set_fragment_threshold(frag_thr); + if (err_code) { + return err_code; + } + + return err_code; +} + std::error_code EB::PCIe40_reader::reset() { std::error_code err_code{}; @@ -372,17 +420,17 @@ std::vector<std::tuple<void*, size_t>> EB::PCIe40_MFP_reader::get_full_buffer() // TODO check if something special is needed for fragments template<> -pcie40_hdr_frg_nometa* EB::PCIe40_reader::extract_element() +pcie40_frg_hdr* EB::PCIe40_reader::extract_element() { - pcie40_hdr_frg_nometa* ret_val = NULL; + pcie40_frg_hdr* ret_val = NULL; if (!is_open()) { - throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + throw std::system_error(PCIe40_errors::DEVICE_NOT_OPEN); } size_t size; - if (_available_data >= sizeof(pcie40_hdr_frg_nometa)) { - ret_val = reinterpret_cast<pcie40_hdr_frg_nometa*>(reinterpret_cast<uintptr_t>(_buffer) + _internal_read_off); + if (_available_data >= sizeof(pcie40_frg_hdr)) { + ret_val = reinterpret_cast<pcie40_frg_hdr*>(reinterpret_cast<uintptr_t>(_buffer) + _internal_read_off); if (ret_val->ghdr.is_invalid()) { - throw std::error_code(PCIe40_errors::CORRUPTED_DATA); + throw std::system_error(PCIe40_errors::CORRUPTED_DATA); } size = ret_val->bytes(); @@ -403,13 +451,13 @@ EB::MFP* EB::PCIe40_reader::extract_element() { EB::MFP* ret_val = NULL; if (!is_open()) { - throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + throw std::system_error(PCIe40_errors::DEVICE_NOT_OPEN); } size_t size; if (_available_data >= sizeof(EB::MFP)) { ret_val = reinterpret_cast<EB::MFP*>(reinterpret_cast<uintptr_t>(_buffer) + _internal_read_off); if (!ret_val->is_valid()) { - throw std::error_code(PCIe40_errors::CORRUPTED_DATA); + throw std::system_error(PCIe40_errors::CORRUPTED_DATA); } size = ret_val->bytes(); @@ -454,17 +502,17 @@ void EB::PCIe40_reader::update_usage() void EB::PCIe40_reader::ack_read() { if (!is_open()) { - throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + throw std::system_error(PCIe40_errors::DEVICE_NOT_OPEN); } if (p40_stream_free_host_buf_bytes(_stream_fd, _requested_size) < 0) { - throw std::error_code(PCIe40_errors::HOST_FREE_BUFF); + throw std::system_error(PCIe40_errors::HOST_FREE_BUFF); } std::error_code err_code = update_device_ptr(); if (err_code) { - throw err_code; + throw std::system_error(err_code); } _internal_read_off = _device_read_off; @@ -488,7 +536,14 @@ EB::MFP* EB::PCIe40_MFP_reader::try_get_element() void EB::PCIe40_MFP_reader::read_complete() { ack_read(); } -void EB::PCIe40_MFP_reader::flush() { reset(); } +void EB::PCIe40_MFP_reader::flush() +{ + std::error_code err_code; + err_code = reset(); + if (err_code) { + throw std::system_error(err_code); + } +} int EB::PCIe40_MFP_reader::get_src_id() const { return _src_id; } @@ -545,7 +600,7 @@ void EB::PCIe40_frag_reader::set_n_frags(int n_frags) _type_list.reserve(_packing_factor); _size_list.reserve(_packing_factor); } else { - throw std::error_code(PCIe40_errors::INVALID_PACKING_FACTOR); + throw std::system_error(PCIe40_errors::INVALID_PACKING_FACTOR); } } @@ -554,7 +609,7 @@ int EB::PCIe40_frag_reader::get_n_frags() const { return _packing_factor; } EB::MFP* EB::PCIe40_frag_reader::try_get_element() { if (!_pcie40_reader.is_open()) { - throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + throw std::system_error(PCIe40_errors::DEVICE_NOT_OPEN); } _pcie40_reader.update_usage(); @@ -570,7 +625,7 @@ EB::MFP* EB::PCIe40_frag_reader::try_get_element() if ((mfp_err == PCIe40_errors::INTERNAL_BUFFER_FULL) || (mfp_err == PCIe40_errors::INTERNAL_BUFFER_FULL_FLUSH)) { return NULL; } else { - throw mfp_err; + throw std::system_error(mfp_err); } } @@ -583,11 +638,11 @@ EB::MFP* EB::PCIe40_frag_reader::try_get_element() void EB::PCIe40_frag_reader::scan_frag_list() { if (!_pcie40_reader.is_open()) { - throw std::error_code(PCIe40_errors::DEVICE_NOT_OPEN); + throw std::system_error(PCIe40_errors::DEVICE_NOT_OPEN); } while (_frag_list.size() < _packing_factor) { - pcie40_hdr_frg_nometa* next_frag = _pcie40_reader.extract_element<pcie40_hdr_frg_nometa>(); + pcie40_frg_hdr* next_frag = _pcie40_reader.extract_element<pcie40_frg_hdr>(); // no more data into the device buffer if (next_frag == NULL) { _flush = false; @@ -609,6 +664,11 @@ void EB::PCIe40_frag_reader::scan_frag_list() // we strip off the fragment header size_t header_offset = sizeof(next_frag->le_evid) + sizeof(next_frag->ghdr); + if (next_frag->bytes() < header_offset) { + // Corrupted fragment we don't strip the header + // TODO check if this should throw an exception + header_offset = 0; + } _frag_list.emplace_back(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(next_frag) + header_offset)); _size_list.emplace_back(next_frag->bytes() - header_offset); _type_list.emplace_back(next_frag->ghdr.type()); @@ -692,7 +752,12 @@ void EB::PCIe40_frag_reader::read_complete() { _internal_buffer_reader.read_comp void EB::PCIe40_frag_reader::flush() { // TODO check retrun value of reset - _pcie40_reader.reset(); + std::error_code err_code; + err_code = _pcie40_reader.reset(); + if (err_code) { + throw std::system_error(err_code); + } + _internal_buffer_reader.flush(); } @@ -701,4 +766,6 @@ int EB::PCIe40_frag_reader::get_src_id() const { return _pcie40_reader._src_id; std::vector<std::tuple<void*, size_t>> EB::PCIe40_frag_reader::get_full_buffer() { return _internal_buffer_reader.get_full_buffer(); -} \ No newline at end of file +} + +const std::string EB::PCIe40_frag_reader::get_name() const { return _pcie40_reader.get_name(); } \ No newline at end of file diff --git a/Online/EventBuilding/src/pcie40_reader_error.cpp b/Online/EventBuilding/src/pcie40_reader_error.cpp index 8b271c3ec..ebfb0bcf5 100644 --- a/Online/EventBuilding/src/pcie40_reader_error.cpp +++ b/Online/EventBuilding/src/pcie40_reader_error.cpp @@ -31,6 +31,7 @@ namespace { case EB::PCIe40_errors::LOGIC_RESET: return "Unable to perform a logic reset"; case EB::PCIe40_errors::CORRUPTED_DATA: return "Corrupted data in the stream"; case EB::PCIe40_errors::INVALID_PACKING_FACTOR: return "Invalid packing factor"; + case EB::PCIe40_errors::INVALID_FRAGMENT_THRESHOLD: return "Invalid fragment threshold"; case EB::PCIe40_errors::INTERNAL_BUFFER_FULL: return "Internal buffer full on data write"; case EB::PCIe40_errors::INTERNAL_BUFFER_FULL_FLUSH: return "Internal buffer full on flush"; default: return "Undefined error"; -- GitLab