From 6986566efe5bfb40477e6b6b55eed712e595477a Mon Sep 17 00:00:00 2001 From: bha Date: Mon, 26 Feb 2024 14:12:51 +0100 Subject: [PATCH] add license for 3rd party, add ibofloggerfactory, add 3rd part queue but do not use it, update bofprofiler --- Dependencies.cmake | 10 + .../ConcurrentQueue.Cameron.Desrochers.txt | 65 ++++ dependency.license/Date.Howard.Hinnant.txt | 33 ++ dependency.license/Fmt.Victor.Zverovich.txt | 29 ++ dependency.license/Google.Test.Google.txt | 30 ++ .../JsonCpp.Baptiste.Lepilleur.txt | 57 ++++ .../LightweightSemaphore.Jeff.Preshing.txt | 20 ++ .../LineNoise.Salvatore.Sanfilippo.txt | 123 +++++++ .../ReaderWriterQueue.Cameron.Desrochers.txt | 31 ++ dependency.license/SpdLog.Gabime.txt | 27 ++ lib/CMakeLists.txt | 7 +- lib/include/bofstd/bofcircularbuffer.h | 28 +- lib/include/bofstd/bofmpmcqueue.h | 101 ++++++ lib/include/bofstd/bofperformance.h | 6 +- lib/include/bofstd/bofspscqueue.h | 100 ++++++ lib/include/bofstd/bofstatistics.h | 134 +++++--- lib/include/bofstd/ibofloggerfactory.h | 306 +++++++++++++++++ lib/src/bofperformance.cpp | 37 +- lib/src/bofstd.cpp | 1 + lib/src/bofsystem.cpp | 7 +- tests/CMakeLists.txt | 2 + tests/src/main.cpp | 27 +- tests/src/ut_circularbuffer.cpp | 188 ++++++++++- tests/src/ut_logger.cpp | 317 ++++++++++++++++++ tests/src/ut_mpmcqueue.cpp | 140 ++++++++ tests/src/ut_spscqueue.cpp | 139 ++++++++ 26 files changed, 1892 insertions(+), 73 deletions(-) create mode 100644 dependency.license/ConcurrentQueue.Cameron.Desrochers.txt create mode 100644 dependency.license/Date.Howard.Hinnant.txt create mode 100644 dependency.license/Fmt.Victor.Zverovich.txt create mode 100644 dependency.license/Google.Test.Google.txt create mode 100644 dependency.license/JsonCpp.Baptiste.Lepilleur.txt create mode 100644 dependency.license/LightweightSemaphore.Jeff.Preshing.txt create mode 100644 dependency.license/LineNoise.Salvatore.Sanfilippo.txt create mode 100644 dependency.license/ReaderWriterQueue.Cameron.Desrochers.txt create mode 100644 dependency.license/SpdLog.Gabime.txt create mode 100644 lib/include/bofstd/bofmpmcqueue.h create mode 100644 lib/include/bofstd/bofspscqueue.h create mode 100644 lib/include/bofstd/ibofloggerfactory.h create mode 100644 tests/src/ut_mpmcqueue.cpp create mode 100644 tests/src/ut_spscqueue.cpp diff --git a/Dependencies.cmake b/Dependencies.cmake index 08633a0..0a1285c 100644 --- a/Dependencies.cmake +++ b/Dependencies.cmake @@ -45,3 +45,13 @@ endif() find_package_dependency(fmt REQUIRED) find_package_dependency(date REQUIRED) +#if you want to use readerwriterqueue or concurrentqueue add the following to vcpkg.json +# {"name": "readerwriterqueue"}, +# {"name": "concurrentqueue"} +#and activate +# include/bofstd/bofspscqueue.h +# include/bofstd/bofmpmcqueue.h +#in lib CMakeLists.txt +# src/ut_spscqueue.cpp +# src/ut_mpmcqueue.cpp +#in tests CMakeLists.txt \ No newline at end of file diff --git a/dependency.license/ConcurrentQueue.Cameron.Desrochers.txt b/dependency.license/ConcurrentQueue.Cameron.Desrochers.txt new file mode 100644 index 0000000..e03908f --- /dev/null +++ b/dependency.license/ConcurrentQueue.Cameron.Desrochers.txt @@ -0,0 +1,65 @@ +https://github.com/cameron314/concurrentqueue +===>NOT CURRENTLY USED + +This license file applies to everything in this repository except that which +is explicitly annotated as being written by other authors, i.e. the Boost +queue (included in the benchmarks for comparison), Intel's TBB library (ditto), +dlib::pipe (ditto), +the CDSChecker tool (used for verification), the Relacy model checker (ditto), +and Jeff Preshing's semaphore implementation (used in the blocking queue) which +has a zlib license (embedded in lightweightsempahore.h). + +--- + +Simplified BSD License: + +Copyright (c) 2013-2016, Cameron Desrochers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + +I have also chosen to dual-license under the Boost Software License as an alternative to +the Simplified BSD license above: + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/dependency.license/Date.Howard.Hinnant.txt b/dependency.license/Date.Howard.Hinnant.txt new file mode 100644 index 0000000..25e7e86 --- /dev/null +++ b/dependency.license/Date.Howard.Hinnant.txt @@ -0,0 +1,33 @@ +https://github.com/HowardHinnant/date + +The source code in this project is released using the MIT License. There is no +global license for the project because each file is licensed individually with +different author names and/or dates. + +If you contribute to this project, please add your name to the license of each +file you modify. If you have already contributed to this project and forgot to +add your name to the license, please feel free to submit a new P/R to add your +name to the license in each file you modified. + +For convenience, here is a copy of the MIT license found in each file except +without author names or dates: + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/dependency.license/Fmt.Victor.Zverovich.txt b/dependency.license/Fmt.Victor.Zverovich.txt new file mode 100644 index 0000000..d1e28d7 --- /dev/null +++ b/dependency.license/Fmt.Victor.Zverovich.txt @@ -0,0 +1,29 @@ +https://github.com/fmtlib/fmt + +Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. \ No newline at end of file diff --git a/dependency.license/Google.Test.Google.txt b/dependency.license/Google.Test.Google.txt new file mode 100644 index 0000000..2a0df3d --- /dev/null +++ b/dependency.license/Google.Test.Google.txt @@ -0,0 +1,30 @@ +https://github.com/google/googletest + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/dependency.license/JsonCpp.Baptiste.Lepilleur.txt b/dependency.license/JsonCpp.Baptiste.Lepilleur.txt new file mode 100644 index 0000000..33119f8 --- /dev/null +++ b/dependency.license/JsonCpp.Baptiste.Lepilleur.txt @@ -0,0 +1,57 @@ +https://github.com/open-source-parsers/jsoncpp + +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. \ No newline at end of file diff --git a/dependency.license/LightweightSemaphore.Jeff.Preshing.txt b/dependency.license/LightweightSemaphore.Jeff.Preshing.txt new file mode 100644 index 0000000..820fc9a --- /dev/null +++ b/dependency.license/LightweightSemaphore.Jeff.Preshing.txt @@ -0,0 +1,20 @@ +https://github.com/preshing/cpp11-on-multicore/tree/master +===>NOT CURRENTLY USED + +Copyright (c) 2015 Jeff Preshing + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/dependency.license/LineNoise.Salvatore.Sanfilippo.txt b/dependency.license/LineNoise.Salvatore.Sanfilippo.txt new file mode 100644 index 0000000..b30e45e --- /dev/null +++ b/dependency.license/LineNoise.Salvatore.Sanfilippo.txt @@ -0,0 +1,123 @@ +https://github.com/yhirose/cpp-linenoise/blob/master/linenoise.hpp + +/* + * linenoise.hpp -- Multi-platform C++ header-only linenoise library. + * + * All credits and commendations have to go to the authors of the + * following excellent libraries. + * + * - linenoise.h and linenoise.c (https://github.com/antirez/linenoise) + * - ANSI.c (https://github.com/adoxa/ansicon) + * - Win32_ANSI.h and Win32_ANSI.c (https://github.com/MSOpenTech/redis) + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2015 yhirose + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* linenoise.h -- guerrilla line editing library against the idea that a + * line editing lib needs to be 20,000 lines of C code. + * + * See linenoise.c for more information. + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2010, Salvatore Sanfilippo + * Copyright (c) 2010, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ANSI.c - ANSI escape sequence console driver. + * + * Copyright (C) 2005-2014 Jason Hood + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the author be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Jason Hood + * jadoxa@yahoo.com.au + */ + +/* + * Win32_ANSI.h and Win32_ANSI.c + * + * Derived from ANSI.c by Jason Hood, from his ansicon project (https://github.com/adoxa/ansicon), with modifications. + * + * Copyright (c), Microsoft Open Technologies, Inc. + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/dependency.license/ReaderWriterQueue.Cameron.Desrochers.txt b/dependency.license/ReaderWriterQueue.Cameron.Desrochers.txt new file mode 100644 index 0000000..971882f --- /dev/null +++ b/dependency.license/ReaderWriterQueue.Cameron.Desrochers.txt @@ -0,0 +1,31 @@ +https://github.com/cameron314/readerwriterqueue +===>NOT CURRENTLY USED + +This license applies to all the code in this repository except that written by third +parties, namely the files in benchmarks/ext, which have their own licenses, and Jeff +Preshing's semaphore implementation (used in the blocking queues) which has a zlib +license (embedded in atomicops.h). + +Simplified BSD License: + +Copyright (c) 2013-2021, Cameron Desrochers +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/dependency.license/SpdLog.Gabime.txt b/dependency.license/SpdLog.Gabime.txt new file mode 100644 index 0000000..d48c57b --- /dev/null +++ b/dependency.license/SpdLog.Gabime.txt @@ -0,0 +1,27 @@ +https://github.com/gabime/spdlog + +The MIT License (MIT) + +Copyright (c) 2016 Gabi Melman. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-- NOTE: Third party dependency used by this software -- +This software depends on the fmt lib (MIT License), +and users must comply to its license: https://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a169f29..60ec8a4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -59,6 +59,8 @@ set(CONIO_SHELL_FILES ) set(CONTAINER_FILES +# include/bofstd/bofspscqueue.h +# include/bofstd/bofmpmcqueue.h include/bofstd/bofcircularbuffer.h include/bofstd/bofstringcircularbuffer.h src/bofstringcircularbuffer.cpp @@ -166,6 +168,7 @@ set(LOG_FILES src/boflogchannel_spdlog.cpp include/bofstd/boflogsink_spdlog.h src/boflogsink_spdlog.cpp + include/bofstd/ibofloggerfactory.h include/bofstd/boflogger.h src/boflogger.cpp ) @@ -209,6 +212,8 @@ set(SOCKIO_FILES ) set(SYSTEM_FILES + include/bofstd/bofsystem.h + src/bofsystem.cpp include/bofstd/bofscopeguard.h include/bofstd/bofgraph.h include/bofstd/bofstring.h @@ -233,8 +238,6 @@ set(SYSTEM_FILES set(THREADING_FILES include/bofstd/bofthread.h src/bofthread.cpp - include/bofstd/bofsystem.h - src/bofsystem.cpp include/bofstd/bofprocess.h src/bofprocess.cpp diff --git a/lib/include/bofstd/bofcircularbuffer.h b/lib/include/bofstd/bofcircularbuffer.h index fa09d97..ebba863 100644 --- a/lib/include/bofstd/bofcircularbuffer.h +++ b/lib/include/bofstd/bofcircularbuffer.h @@ -164,6 +164,7 @@ struct BOF_CIRCULAR_BUFFER_PARAM MultiThreadAware_B = false; NbMaxElement_U32 = 0; pData = nullptr; + Overwrite_B = false; Blocking_B = false; PopLockMode_B = false; } @@ -463,21 +464,29 @@ DataType *BofCircularBuffer::GetInternalDataBuffer() const return mpData_T; } + template BOFERR BofCircularBuffer::Push(const DataType *_pData, uint32_t _BlockingTimeouItInMs_U32, uint32_t *_pIndexOf_U32, DataType **_ppStorage_X) { BOFERR Rts_E = BOF_ERR_EINVAL; - + //First call is slower ??? + //static uint32_t S_Test_U32 = 0; + //static uint32_t S_Index_U32 = 0; + //static uint64_t S_pTiming_U64[2][16]; if (_pData) { RetryPush: + //S_Index_U32 = 0; + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount(); Rts_E = ((mCircularBufferParam_X.Blocking_B) && (_BlockingTimeouItInMs_U32)) ? Bof_WaitForEvent(mCanWriteEvent_X, _BlockingTimeouItInMs_U32, 0) : BOF_ERR_NO_ERROR; // printf("@@%d@--->PushIn %s nb %d/%d pop %d push %d islock %d block %d blockto %d err %s\n", BOF::Bof_GetMsTickCount(),mCanReadEvent_X.Name_S.c_str(), mNbElementInBuffer_U32, mNbElementLockedInBuffer_U32, mPopIndex_U32, mPushIndex_U32, // mpLock_U8[mPushIndex_U32], mCircularBufferParam_X.Blocking_B, _BlockingTimeouItInMs_U32, Bof_ErrorCode(Rts_E)); - if (Rts_E == BOF_ERR_NO_ERROR) { + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; BOF_CIRCULAR_BUFFER_LOCK(Rts_E); + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; + if (Rts_E == BOF_ERR_NO_ERROR) { // Buffer is dimensioned to contains a an integer number of "_pData"->there is no read/write pointer clipping during an "atomic" push or pop @@ -493,6 +502,8 @@ BOFERR BofCircularBuffer::Push(const DataType *_pData, uint32_t _Block { *_ppStorage_X = &mpData_T[mPushIndex_U32]; } + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; + mpData_T[mPushIndex_U32] = *_pData; BOF_ASSERT(mPushIndex_U32 < mCircularBufferParam_X.NbMaxElement_U32); mPushIndex_U32++; @@ -519,6 +530,7 @@ BOFERR BofCircularBuffer::Push(const DataType *_pData, uint32_t _Block { mLevelMax_U32 = mNbElementInBuffer_U32; } + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; Rts_E = BOF_ERR_NO_ERROR; } @@ -538,6 +550,7 @@ BOFERR BofCircularBuffer::Push(const DataType *_pData, uint32_t _Block { if (Rts_E == BOF_ERR_NO_ERROR) { + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; Rts_E = SignalReadWrite(); } else @@ -552,11 +565,20 @@ BOFERR BofCircularBuffer::Push(const DataType *_pData, uint32_t _Block } } } + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; BOF_CIRCULAR_BUFFER_UNLOCK(); + //S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; } } } - + /* + S_pTiming_U64[S_Test_U32][S_Index_U32++] = BOF::Bof_GetNsTickCount() - S_pTiming_U64[S_Test_U32][0]; + S_Test_U32++; + if (S_Test_U32 > 1) + { + S_Test_U32 = 1; + } + */ return Rts_E; } diff --git a/lib/include/bofstd/bofmpmcqueue.h b/lib/include/bofstd/bofmpmcqueue.h new file mode 100644 index 0000000..1ec04c5 --- /dev/null +++ b/lib/include/bofstd/bofmpmcqueue.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020-2040, Onbings. All rights reserved. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + * PURPOSE. + * + * This module defines routines for creating and managing a multiple producer-multiple consumer queue + * It is based on ythe well known cameron314/concurrentqueue https://github.com/cameron314/concurrentqueue + * + * History: + * + * V 1.00 May 26 2020 BHA : Initial release + */ +#pragma once + +#include +//#include +#include + +BEGIN_BOF_NAMESPACE() +struct BOF_MPMC_QUEUE_PARAM +{ + uint32_t NbMaxElement_U32; /*! Specifies the maximum number of element inside the queue*/ + + BOF_MPMC_QUEUE_PARAM() + { + Reset(); + } + + void Reset() + { + NbMaxElement_U32 = 0; + } +}; + +template +class BofMpMcQueue +{ +private: + BOF_MPMC_QUEUE_PARAM mMpMcQueueParam_X; + std::unique_ptr> mpuMpMcQueue = nullptr; + +public: + BofMpMcQueue(const BOF_MPMC_QUEUE_PARAM &_rMpMcQueueParam_X) + { + mMpMcQueueParam_X = _rMpMcQueueParam_X; + mpuMpMcQueue = std::make_unique>(mMpMcQueueParam_X.NbMaxElement_U32); + } + virtual ~BofMpMcQueue() + { + + } + BOFERR Push(const DataType &_rData, uint32_t _TimeoutInMs_U32) + { + BOFERR Rts_E = BOF_ERR_FULL; + if (mpuMpMcQueue->try_enqueue(std::move(_rData))) //, _TimeoutInMs_U32 * 1000)) + { + Rts_E = BOF_ERR_NO_ERROR; + } + return Rts_E; + } + BOFERR Pop(DataType &_rData, uint32_t _TimeoutInMs_U32) + { + BOFERR Rts_E = BOF_ERR_EMPTY; + if (mpuMpMcQueue->wait_dequeue_timed(_rData, _TimeoutInMs_U32 * 1000)) + { + Rts_E = BOF_ERR_NO_ERROR; + } + return Rts_E; + } +}; +END_BOF_NAMESPACE() + +/* +# Allocates more memory if necessary +enqueue(item) : bool +enqueue(prod_token, item) : bool +enqueue_bulk(item_first, count) : bool +enqueue_bulk(prod_token, item_first, count) : bool + +# Fails if not enough memory to enqueue +try_enqueue(item) : bool +try_enqueue(prod_token, item) : bool +try_enqueue_bulk(item_first, count) : bool +try_enqueue_bulk(prod_token, item_first, count) : bool + +# Attempts to dequeue from the queue (never allocates) +try_dequeue(item&) : bool +try_dequeue(cons_token, item&) : bool +try_dequeue_bulk(item_first, max) : size_t +try_dequeue_bulk(cons_token, item_first, max) : size_t + +# If you happen to know which producer you want to dequeue from +try_dequeue_from_producer(prod_token, item&) : bool +try_dequeue_bulk_from_producer(prod_token, item_first, max) : size_t + +# A not-necessarily-accurate count of the total number of elements +size_approx() : size_t +*/ \ No newline at end of file diff --git a/lib/include/bofstd/bofperformance.h b/lib/include/bofstd/bofperformance.h index 3f7a881..7dfeb1b 100644 --- a/lib/include/bofstd/bofperformance.h +++ b/lib/include/bofstd/bofperformance.h @@ -377,9 +377,9 @@ class BOFSTD_EXPORT BofProfiler virtual ~BofProfiler(); void EnterBench(uint32_t _ItemId_U32); - void LeaveBench(uint32_t _ItemId_U32); + void LeaveBench(bool _IgnoreFirstSample_B, uint32_t _ItemId_U32); - bool SetStats(uint32_t _ItemId_U32, uint64_t _Value_U64); + bool SetStats(bool _IgnoreFirstSample_B, uint32_t _ItemId_U32, uint64_t _Value_U64); bool GetStats(uint32_t _ItemId_U32, BOF_STAT_VARIABLE *_pStats_X); void ResetStats(uint32_t _ItemId_U32); @@ -393,7 +393,7 @@ class BOFSTD_EXPORT BofProfiler uint64_t GetLast(uint32_t _ItemId_U32); uint64_t GetLockCount(uint32_t _ItemId_U32); uint64_t GetNbSample(uint32_t _ItemId_U32); - + uint32_t GetLastMax(uint32_t _ItemId_U32, BOF_STAT_MAX *_pLastMax_X); uint32_t GetNbItemInProfiler(); protected: diff --git a/lib/include/bofstd/bofspscqueue.h b/lib/include/bofstd/bofspscqueue.h new file mode 100644 index 0000000..561e8d8 --- /dev/null +++ b/lib/include/bofstd/bofspscqueue.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020-2040, Onbings. All rights reserved. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + * PURPOSE. + * + * This module defines routines for creating and managing a single producer-single consumer queue + * It is based on ythe well known cameron314/concurrentqueue https://github.com/cameron314/concurrentqueue + * + * History: + * + * V 1.00 May 26 2020 BHA : Initial release + */ +#pragma once + +#include +#include + +BEGIN_BOF_NAMESPACE() +struct BOF_SPSC_QUEUE_PARAM +{ + uint32_t NbMaxElement_U32; /*! Specifies the maximum number of element inside the queue*/ + + BOF_SPSC_QUEUE_PARAM() + { + Reset(); + } + + void Reset() + { + NbMaxElement_U32 = 0; + } +}; + +template +class BofSpScQueue +{ +private: + BOF_SPSC_QUEUE_PARAM mSpScQueueParam_X; + std::unique_ptr> mpuSpScQueue=nullptr; + +public: + BofSpScQueue(const BOF_SPSC_QUEUE_PARAM &_rSpScQueueParam_X) + { + mSpScQueueParam_X = _rSpScQueueParam_X; + mpuSpScQueue = std::make_unique>(mSpScQueueParam_X.NbMaxElement_U32); + } + virtual ~BofSpScQueue() + { + + } + BOFERR Push(const DataType &_rData, uint32_t _TimeoutInMs_U32) + { + BOFERR Rts_E = BOF_ERR_FULL; + if (mpuSpScQueue->wait_enqueue_timed(std::move(_rData), _TimeoutInMs_U32 * 1000)) + { + Rts_E = BOF_ERR_NO_ERROR; + } + return Rts_E; + } + BOFERR Pop(DataType &_rData, uint32_t _TimeoutInMs_U32) + { + BOFERR Rts_E = BOF_ERR_EMPTY; + if (mpuSpScQueue->wait_dequeue_timed(_rData, _TimeoutInMs_U32 * 1000)) + { + Rts_E = BOF_ERR_NO_ERROR; + } + return Rts_E; + } +}; +END_BOF_NAMESPACE() + +/* +# Allocates more memory if necessary +enqueue(item) : bool +enqueue(prod_token, item) : bool +enqueue_bulk(item_first, count) : bool +enqueue_bulk(prod_token, item_first, count) : bool + +# Fails if not enough memory to enqueue +try_enqueue(item) : bool +try_enqueue(prod_token, item) : bool +try_enqueue_bulk(item_first, count) : bool +try_enqueue_bulk(prod_token, item_first, count) : bool + +# Attempts to dequeue from the queue (never allocates) +try_dequeue(item&) : bool +try_dequeue(cons_token, item&) : bool +try_dequeue_bulk(item_first, max) : size_t +try_dequeue_bulk(cons_token, item_first, max) : size_t + +# If you happen to know which producer you want to dequeue from +try_dequeue_from_producer(prod_token, item&) : bool +try_dequeue_bulk_from_producer(prod_token, item_first, max) : size_t + +# A not-necessarily-accurate count of the total number of elements +size_approx() : size_t +*/ \ No newline at end of file diff --git a/lib/include/bofstd/bofstatistics.h b/lib/include/bofstd/bofstatistics.h index b6043ed..14e6424 100644 --- a/lib/include/bofstd/bofstatistics.h +++ b/lib/include/bofstd/bofstatistics.h @@ -27,22 +27,25 @@ BEGIN_BOF_NAMESPACE() -#define BOF_SET_NEW_STAT_MIN(newval, themin) \ - { \ - if ((newval) < (themin)) \ - { \ - (themin) = (newval); \ - } \ +template +struct BOF_STAT_MAX +{ + uint64_t MaxIndex_U64; + T Max; + BOF_STAT_MAX() + { + Reset(); } -#define BOF_SET_NEW_STAT_MAX(newval, themax) \ - { \ - if ((newval) > (themax)) \ - { \ - (themax) = (newval); \ - } \ + void Reset() + { + MaxIndex_U64 = 0xFFFFFFFF; + Max = std::numeric_limits::min(); } +}; -template struct BOF_STAT_VARIABLE +constexpr uint32_t BOF_STAT_KEEP_LAST_NB_MAX_VAL = 16; +template +struct BOF_STAT_VARIABLE { T Crt; /*! Crt value */ T Min; /*! Minimum value */ @@ -51,6 +54,8 @@ template struct BOF_STAT_VARIABLE T MeanAcc; /*! Accumulator needed for computing the mean */ uint64_t LockCount_U64; /*! +1 for each call to EnterBench -1 for each LeaveBench */ uint64_t NbSample_U64; /*! Number of items accumulated */ + uint32_t NbMax_U32; + BOF_STAT_MAX pMax_X[BOF_STAT_KEEP_LAST_NB_MAX_VAL]; BOF_STAT_VARIABLE() { Reset(); @@ -58,13 +63,19 @@ template struct BOF_STAT_VARIABLE void Reset() { + uint32_t i_U32; Crt = 0; - Min = std::numeric_limits::max();; - Max = std::numeric_limits::min();; + Min = std::numeric_limits::max(); + Max = std::numeric_limits::min(); Mean = 0; MeanAcc = 0; LockCount_U64 = 0; NbSample_U64 = 0; + NbMax_U32 = 0; + for (i_U32 = 0; i_U32 < BOF_STAT_KEEP_LAST_NB_MAX_VAL; i_U32++) + { + pMax_X[i_U32].Reset(); + } } }; @@ -81,7 +92,8 @@ Nothing Remarks Aucune */ -template BOFERR Bof_ResetStatVar(BOF_STAT_VARIABLE &_rStatVar_X) +template +BOFERR Bof_ResetStatVar(BOF_STAT_VARIABLE &_rStatVar_X) { BOFERR Rts_E; @@ -108,7 +120,8 @@ Nothing Remarks Aucune */ -template BOFERR Bof_UpdateStatVar(BOF_STAT_VARIABLE &_rStatVar_X, T _Val) +template +BOFERR Bof_UpdateStatVar(bool _IgnoreFirstSample_B, BOF_STAT_VARIABLE &_rStatVar_X, T _Val) { BOFERR Rts_E; @@ -117,15 +130,33 @@ template BOFERR Bof_UpdateStatVar(BOF_STAT_VARIABLE &_rStatVar_X _rStatVar_X.Crt = _Val; if (_rStatVar_X.NbSample_U64 == 0) { - _rStatVar_X.Min = _Val; - _rStatVar_X.Max = _Val; + if (!_IgnoreFirstSample_B) + { + _rStatVar_X.Min = _Val; + _rStatVar_X.Max = _Val; + _rStatVar_X.pMax_X[0].MaxIndex_U64 = 0; + _rStatVar_X.pMax_X[0].Max = _Val; + _rStatVar_X.NbMax_U32 = 1; + } } else { - BOF_SET_NEW_STAT_MIN(_rStatVar_X.Crt, _rStatVar_X.Min); - BOF_SET_NEW_STAT_MAX(_rStatVar_X.Crt, _rStatVar_X.Max); + if (_rStatVar_X.Crt < _rStatVar_X.Min) + { + _rStatVar_X.Min = _rStatVar_X.Crt; + } + if (_rStatVar_X.Crt > _rStatVar_X.Max) + { + _rStatVar_X.Max = _rStatVar_X.Crt; + if (_rStatVar_X.NbMax_U32 < BOF_STAT_KEEP_LAST_NB_MAX_VAL) + { + _rStatVar_X.pMax_X[_rStatVar_X.NbMax_U32].MaxIndex_U64 = _rStatVar_X.NbSample_U64; + _rStatVar_X.pMax_X[_rStatVar_X.NbMax_U32].Max = _rStatVar_X.Crt; + _rStatVar_X.NbMax_U32++; + } + } } - Bof_UpdateStatMean(_rStatVar_X); + Bof_UpdateStatMean(_IgnoreFirstSample_B, _rStatVar_X); return Rts_E; } @@ -142,40 +173,51 @@ Nothing Remarks Aucune */ -template BOFERR Bof_UpdateStatMean(BOF_STAT_VARIABLE &_rStatVar_X) +template +BOFERR Bof_UpdateStatMean(bool _IgnoreFirstSample_B, BOF_STAT_VARIABLE &_rStatVar_X) { - BOFERR Rts_E; + BOFERR Rts_E = BOF_ERR_NO_ERROR; T TempAccumulator; bool RollOver_B; - Rts_E = BOF_ERR_EMPTY; - //if (_rStatVar_X.Crt != 0) + // printf("InNb %zd Crt %zd Mean %zd MeanAcc %zd\n", _rStatVar_X.NbSample_U64, _rStatVar_X.Crt, _rStatVar_X.Mean, _rStatVar_X.MeanAcc); + if (_IgnoreFirstSample_B) { - Rts_E = BOF_ERR_NO_ERROR; - - // On accumule la valeur dans une variable temporaire - TempAccumulator = _rStatVar_X.MeanAcc + _rStatVar_X.Crt; - // Il n'y aura pas de "roll-over" - RollOver_B = (TempAccumulator < _rStatVar_X.MeanAcc); - if (!RollOver_B) + if (_rStatVar_X.NbSample_U64 == 0) { - _rStatVar_X.MeanAcc = TempAccumulator; - _rStatVar_X.NbSample_U64++; - RollOver_B = (_rStatVar_X.NbSample_U64 == 0); + _rStatVar_X.NbSample_U64 = 1; + _rStatVar_X.MeanAcc = 0; + return Rts_E; } - if (RollOver_B) + if (_rStatVar_X.NbSample_U64 == 1) { - // Si on ajoute cette valeur on va provoquer - // un "roll-over" de notre accumulateur - // On relance l'accumulateur a la valeur de la moyenne actuelle - _rStatVar_X.MeanAcc = _rStatVar_X.Mean; - _rStatVar_X.NbSample_U64 = 1; + _rStatVar_X.MeanAcc = _rStatVar_X.Crt; } - - BOF_ASSERT(_rStatVar_X.NbSample_U64 != 0); - // On met a jour la moyenne - _rStatVar_X.Mean = static_cast((_rStatVar_X.MeanAcc / _rStatVar_X.NbSample_U64)); } + // On accumule la valeur dans une variable temporaire + TempAccumulator = _rStatVar_X.MeanAcc + _rStatVar_X.Crt; + // Il n'y aura pas de "roll-over" + RollOver_B = (TempAccumulator < _rStatVar_X.MeanAcc); + if (!RollOver_B) + { + _rStatVar_X.MeanAcc = TempAccumulator; + _rStatVar_X.NbSample_U64++; + RollOver_B = (_rStatVar_X.NbSample_U64 == 0); + } + if (RollOver_B) + { + // Si on ajoute cette valeur on va provoquer + // un "roll-over" de notre accumulateur + // On relance l'accumulateur a la valeur de la moyenne actuelle + _rStatVar_X.MeanAcc = _rStatVar_X.Mean; + _rStatVar_X.NbSample_U64 = 1; + } + + BOF_ASSERT(_rStatVar_X.NbSample_U64 != 0); + // On met a jour la moyenne + _rStatVar_X.Mean = static_cast((_rStatVar_X.MeanAcc / _rStatVar_X.NbSample_U64)); + + // printf("OutNb %zd Crt %zd Mean %zd MeanAcc %zd\n", _rStatVar_X.NbSample_U64, _rStatVar_X.Crt, _rStatVar_X.Mean, _rStatVar_X.MeanAcc); return Rts_E; } END_BOF_NAMESPACE() \ No newline at end of file diff --git a/lib/include/bofstd/ibofloggerfactory.h b/lib/include/bofstd/ibofloggerfactory.h new file mode 100644 index 0000000..9644efe --- /dev/null +++ b/lib/include/bofstd/ibofloggerfactory.h @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2024-2044, EVS Broadcast Equipment S.A. All rights reserved. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + * PURPOSE. + * + * This module define the different logger interfaces + * + * Author: Bernard HARMEL: b.harmel@evs.com + * + * History: + * V 1.00 Feb 19 2024 BHA : Initial release + */ +#pragma once +#include + +BEGIN_BOF_NAMESPACE() + +class IBofLogger +{ +public: + enum LogSeverity : uint32_t + { + LOG_SEVERITY_FORCE = 0, + LOG_SEVERITY_ERROR, + LOG_SEVERITY_WARNING, + LOG_SEVERITY_INFO, + LOG_SEVERITY_VERBOSE, + LOG_SEVERITY_DEBUG, + LOG_SEVERITY_MAX + }; + + IBofLogger() = default; + virtual ~IBofLogger() = default; + virtual void V_Log(LogSeverity _SeverityLevel_E, const char *_pLogMessage_c, ...) = 0; + inline bool SetLogSeverityLevel(LogSeverity _SeverityLevel_E) + { + bool Rts_B = false; + if (_SeverityLevel_E < LOG_SEVERITY_MAX) + { + mLogSeverityLevel_E = _SeverityLevel_E; + Rts_B = true; + } + return Rts_B; + } + inline LogSeverity GetLogSeverityLevel() const + { + return mLogSeverityLevel_E; + } + // For ut + inline bool GetLogStat(uint32_t &_rNbLogOut_U32, uint32_t &_rNbLogRejected_U32) const + { + _rNbLogOut_U32 = mNbLogOut_U32; + _rNbLogRejected_U32 = mNbLogRejected_U32; + return true; + } + uint32_t mNbLogOut_U32 = 0; + uint32_t mNbLogRejected_U32 = 0; + +private: + LogSeverity mLogSeverityLevel_E = LogSeverity::LOG_SEVERITY_MAX; +}; + +class IBofLoggerFactory +{ +public: + virtual ~IBofLoggerFactory() = default; + virtual std::shared_ptr V_Create(const uint32_t _ChannelIndex_U32, const uint32_t _MaxChannelIndex_U32, const std::string &_rChannelName_S) = 0; + virtual bool V_SetLogSeverityLevel(const uint32_t _ChannelIndex_U32, IBofLogger::LogSeverity _SeverityLevel_E) = 0; + virtual IBofLogger::LogSeverity V_GetLogSeverityLevel(const uint32_t _ChannelIndex_U32) const = 0; + virtual bool V_GetLogStat(const uint32_t _ChannelIndex_U32, uint32_t &_rNbLogOut_U32, uint32_t &_rNbLogRejected_U32) const = 0; +}; + +struct BOF_LOGGER_FACTORY_STORAGE +{ + uint32_t NbMaxChannel_U32; + std::vector> LoggerCollection; + BOF_LOGGER_FACTORY_STORAGE(uint32_t _NbMaxChannel_U32) + { + NbMaxChannel_U32 = _NbMaxChannel_U32; + Reset(); + } + void Reset() + { + uint32_t i_U32; + LoggerCollection.clear(); + LoggerCollection.reserve(NbMaxChannel_U32); + for (i_U32 = 0; i_U32 < NbMaxChannel_U32; i_U32++) + { + LoggerCollection.push_back(nullptr); + } + } +}; +// #define MY_LOGGER TheBhaLogger +// BOF_LOGGER_DEFINE_STORAGE(MY_LOGGER, LOGGER_CHANNEL_MAX); +//==>define BOF::BOF_LOGGER_FACTORY_STORAGE GL_LoggerStorage_TheBhaLogger(LOGGER_CHANNEL_MAX) +#define BOF_LOGGER_STORAGE_NAME(name) GL_LoggerStorage_##name +#define BOF_LOGGER_DEFINE_STORAGE(name, nbmaxchannel) BOF::BOF_LOGGER_FACTORY_STORAGE BOF_LOGGER_STORAGE_NAME(name)(nbmaxchannel) + +#define BOF_LOGGER_FACTORY_ADD(name, logger, channel, sts) \ + if (channel < BOF_LOGGER_STORAGE_NAME(name).NbMaxChannel_U32) \ + { \ + BOF_LOGGER_STORAGE_NAME(name).LoggerCollection[channel] = logger; \ + sts = true; \ + } \ + else \ + { \ + sts = false; \ + } + +// The first if could be replaced by assert...???... +#define BOF_LOGGER_LOG(name, channel, level, format, ...) \ + if (channel < BOF_LOGGER_STORAGE_NAME(name).NbMaxChannel_U32) \ + { \ + if (BOF_LOGGER_STORAGE_NAME(name).LoggerCollection[channel]) \ + { \ + if (level <= BOF_LOGGER_STORAGE_NAME(name).LoggerCollection[channel]->GetLogSeverityLevel()) \ + { \ + BOF_LOGGER_STORAGE_NAME(name).LoggerCollection[channel]->V_Log(level, format, __VA_ARGS__); \ + BOF_LOGGER_STORAGE_NAME(name).LoggerCollection[channel]->mNbLogOut_U32++; \ + } \ + else \ + { \ + BOF_LOGGER_STORAGE_NAME(name).LoggerCollection[channel]->mNbLogRejected_U32++; \ + } \ + } \ + } + +#ifdef BOF_LOGGER_FACTORY_DISABLE +#define BOF_LOG_FORCE(name, channel, format, ...) +#define BOF_LOG_ERROR(name, channel, format, ...) +#define BOF_LOG_WARNING(name, channel, format, ...) +#define BOF_LOG_INFO(name, channel, format, ...) +#define BOF_LOG_VERBOSE(name, channel, format, ...) +#define BOF_LOG_DEBUG(name, channel, format, ...) +#else +#define BOF_LOG_FORCE(name, channel, format, ...) BOF_LOGGER_LOG(name, channel, BOF::IBofLogger::LOG_SEVERITY_FORCE, format, __VA_ARGS__) +#define BOF_LOG_ERROR(name, channel, format, ...) BOF_LOGGER_LOG(name, channel, BOF::IBofLogger::LOG_SEVERITY_ERROR, format, __VA_ARGS__) +#define BOF_LOG_WARNING(name, channel, format, ...) BOF_LOGGER_LOG(name, channel, BOF::IBofLogger::LOG_SEVERITY_WARNING, format, __VA_ARGS__) +#define BOF_LOG_INFO(name, channel, format, ...) BOF_LOGGER_LOG(name, channel, BOF::IBofLogger::LOG_SEVERITY_INFO, format, __VA_ARGS__) +#define BOF_LOG_VERBOSE(name, channel, format, ...) BOF_LOGGER_LOG(name, channel, BOF::IBofLogger::LOG_SEVERITY_VERBOSE, format, __VA_ARGS__) +#define BOF_LOG_DEBUG(name, channel, format, ...) BOF_LOGGER_LOG(name, channel, BOF::IBofLogger::LOG_SEVERITY_DEBUG, format, __VA_ARGS__) +#endif +END_BOF_NAMESPACE() + +//Usage example: +#if 0 +enum LOGGER_CHANNEL : uint32_t +{ + LOGGER_CHANNEL_INIT = 0, + LOGGER_CHANNEL_CODEC, + LOGGER_CHANNEL_DMA, + LOGGER_CHANNEL_MAX +}; + +class Logger : public BOF::IBofLogger +{ +public: + Logger(const uint32_t _ChannelIndex_U32, const std::string &_rChannelName_S) + : BOF::IBofLogger() + { + char pLogFile_c[256]; + + mChannelIndex_U32 = _ChannelIndex_U32; + mChannelName_S = _rChannelName_S; + + sprintf(pLogFile_c, "%s_%03d.log", _rChannelName_S.c_str(), mChannelIndex_U32); + mpLogFile_X = fopen(pLogFile_c, "w+"); + } + virtual ~Logger() + { + if (mpLogFile_X) + { + fclose(mpLogFile_X); + mpLogFile_X = nullptr; + } + } + void V_Log(LogSeverity _SeverityLevel_E, const char *_pLogMessage_c, ...) override + { + char pLog_c[0x1000]; + va_list VaList_X; + + va_start(VaList_X, _pLogMessage_c); + vsnprintf(pLog_c, sizeof(pLog_c), _pLogMessage_c, VaList_X); + va_end(VaList_X); + + pLog_c[sizeof(pLog_c) - 1] = 0; + printf("Channel[%d][%s]->%s", mChannelIndex_U32, mChannelName_S.c_str(), pLog_c); + fwrite(pLog_c, strlen(pLog_c), 1, mpLogFile_X); + } + +private: + uint32_t mChannelIndex_U32 = 0; + std::string mChannelName_S; + FILE *mpLogFile_X = nullptr; +}; + +class LoggerFactory : public BOF::IBofLoggerFactory +{ +public: + LoggerFactory() = default; + virtual ~LoggerFactory() = default; + + std::shared_ptr V_Create(const uint32_t _ChannelIndex_U32, const uint32_t _MaxChannelIndex_U32, const std::string &_rChannelName_S) override + { + std::shared_ptr psRts = nullptr; + uint32_t i_U32; + + if (_ChannelIndex_U32 < _MaxChannelIndex_U32) + { + if (mLoggerCollection.size() != _MaxChannelIndex_U32) + { + mLoggerCollection.clear(); + for (i_U32 = 0; i_U32 < _MaxChannelIndex_U32; i_U32++) + { + mLoggerCollection.push_back(nullptr); + } + } + psRts = std::make_shared(_ChannelIndex_U32, _rChannelName_S); + mLoggerCollection[_ChannelIndex_U32] = psRts; + } + return psRts; + } + bool V_SetLogSeverityLevel(const uint32_t _ChannelIndex_U32, BOF::IBofLogger::LogSeverity _SeverityLevel_E) override + { + bool Rts_B = false; + + if (_ChannelIndex_U32 < mLoggerCollection.size()) + { + if (mLoggerCollection[_ChannelIndex_U32]) + { + Rts_B = mLoggerCollection[_ChannelIndex_U32]->SetLogSeverityLevel(_SeverityLevel_E); + } + } + return Rts_B; + } + BOF::IBofLogger::LogSeverity V_GetLogSeverityLevel(const uint32_t _ChannelIndex_U32) const override + { + BOF::IBofLogger::LogSeverity Rts_E = BOF::IBofLogger::LogSeverity::LOG_SEVERITY_MAX; + + if (_ChannelIndex_U32 < mLoggerCollection.size()) + { + if (mLoggerCollection[_ChannelIndex_U32]) + { + Rts_E = mLoggerCollection[_ChannelIndex_U32]->GetLogSeverityLevel(); + } + } + return Rts_E; + } + bool V_GetLogStat(const uint32_t _ChannelIndex_U32, uint32_t &_rNbLogOut_U32, uint32_t &_rNbLogRejected_U32) const override + { + bool Rts_B = false; + + _rNbLogOut_U32 = 0; + _rNbLogRejected_U32 = 0; + if (_ChannelIndex_U32 < mLoggerCollection.size()) + { + if (mLoggerCollection[_ChannelIndex_U32]) + { + Rts_B = mLoggerCollection[_ChannelIndex_U32]->GetLogStat(_rNbLogOut_U32, _rNbLogRejected_U32); + } + } + return Rts_B; + } + +private: + std::vector> mLoggerCollection; +}; + +#define WLOG(channel, ...) BOF_LOG_WARNING(MY_LOGGER, channel, __VA_ARGS__); +#define MY_LOGGER TheBhaLogger +BOF_LOGGER_DEFINE_STORAGE(MY_LOGGER, LOGGER_CHANNEL_MAX); +bool LoggerInit(std::shared_ptr _psLoggerFactory) +{ + bool Rts_B = false; + std::shared_ptr psLogger; + + if (_psLoggerFactory) + { + psLogger = _psLoggerFactory->V_Create(LOGGER_CHANNEL_INIT, LOGGER_CHANNEL_MAX, "INIT"); + BOF_LOGGER_FACTORY_ADD(MY_LOGGER, psLogger, LOGGER_CHANNEL_INIT, Rts_B); + + psLogger = _psLoggerFactory->V_Create(LOGGER_CHANNEL_CODEC, LOGGER_CHANNEL_MAX, "CODEC"); + BOF_LOGGER_FACTORY_ADD(MY_LOGGER, psLogger, LOGGER_CHANNEL_CODEC, Rts_B); + + psLogger = _psLoggerFactory->V_Create(LOGGER_CHANNEL_DMA, LOGGER_CHANNEL_MAX, "DMA"); + BOF_LOGGER_FACTORY_ADD(MY_LOGGER, psLogger, LOGGER_CHANNEL_DMA, Rts_B); + } + BOF_LOG_WARNING(MY_LOGGER, LOGGER_CHANNEL_INIT, "Log me Rts %d Ptr %p\n", Rts_B, psLogger.get()); + + return Rts_B; +} + + + std::shared_ptr psLoggerFactory = std::make_shared(); + LoggerInit(psLoggerFactory); + psLoggerFactory->V_SetLogSeverityLevel(LOGGER_CHANNEL_INIT, BOF::IBofLogger::LOG_SEVERITY_DEBUG); + psLoggerFactory->V_SetLogSeverityLevel(LOGGER_CHANNEL_CODEC, BOF::IBofLogger::LOG_SEVERITY_DEBUG); + psLoggerFactory->V_SetLogSeverityLevel(LOGGER_CHANNEL_DMA, BOF::IBofLogger::LOG_SEVERITY_DEBUG); + WLOG(LOGGER_CHANNEL_INIT, "Warning from init:\nPwd %s\nRunning BofStd V %s on %s under %s\n", Cwd_S.c_str(), StdParam_X.Version_S.c_str(), StdParam_X.ComputerName_S.c_str(), StdParam_X.OsName_S.c_str()); + WLOG(LOGGER_CHANNEL_CODEC, "Warning from codec\n"); + WLOG(LOGGER_CHANNEL_DMA, "Warning from dma\n"); + +#endif \ No newline at end of file diff --git a/lib/src/bofperformance.cpp b/lib/src/bofperformance.cpp index e43c143..72016b0 100644 --- a/lib/src/bofperformance.cpp +++ b/lib/src/bofperformance.cpp @@ -148,7 +148,7 @@ void BofProfiler::EnterBench(uint32_t _ItemId_U32) See also Nothing */ -void BofProfiler::LeaveBench(uint32_t _ItemId_U32) +void BofProfiler::LeaveBench(bool _IgnoreFirstSample_B, uint32_t _ItemId_U32) { uint64_t Ticks1_U64; uint64_t Ticks2_U64; @@ -170,7 +170,7 @@ void BofProfiler::LeaveBench(uint32_t _ItemId_U32) mpStats_X[_ItemId_U32].Crt = (uint64_t)(Ticks2_U64 < Ticks1_U64 ? (uint64_t)-1 : 0) + Ticks2_U64 - Ticks1_U64; - Bof_UpdateStatVar(mpStats_X[_ItemId_U32], mpStats_X[_ItemId_U32].Crt); + Bof_UpdateStatVar(_IgnoreFirstSample_B, mpStats_X[_ItemId_U32], mpStats_X[_ItemId_U32].Crt); } } } @@ -242,7 +242,7 @@ bool BofProfiler::GetStats(uint32_t _ItemId_U32, BOF_STAT_VARIABLE *_p See also Nothing */ -bool BofProfiler::SetStats(uint32_t _ItemId_U32, uint64_t _Value_U64) +bool BofProfiler::SetStats(bool _IgnoreFirstSample_B, uint32_t _ItemId_U32, uint64_t _Value_U64) { bool Rts_B = false; @@ -254,7 +254,7 @@ bool BofProfiler::SetStats(uint32_t _ItemId_U32, uint64_t _Value_U64) } else { - Bof_UpdateStatVar(mpStats_X[_ItemId_U32], _Value_U64); + Bof_UpdateStatVar(_IgnoreFirstSample_B, mpStats_X[_ItemId_U32], _Value_U64); } Rts_B = true; } @@ -458,6 +458,35 @@ uint64_t BofProfiler::GetNbSample(uint32_t _ItemId_U32) return Rts_U64; } +uint32_t BofProfiler::GetLastMax(uint32_t _ItemId_U32, BOF_STAT_MAX *_pLastMax_X) +{ + uint32_t Rts_U32 = 0, i_U32; + BOF_STAT_VARIABLE Stats_X; + + if (_ItemId_U32 < mNbItems_U32) + { + if (mProfilerType_E == BOF_PROFILER_TYPE::BOF_PROFILER_TYPE_OS_AWARE) + { + } + else + { + if (GetStats(_ItemId_U32, &Stats_X)) + { + Rts_U32 = Stats_X.NbMax_U32; + if (_pLastMax_X) + { + for (i_U32 = 0; i_U32 < Rts_U32; i_U32++) + { + _pLastMax_X[i_U32].Max = Stats_X.pMax_X[i_U32].Max; + _pLastMax_X[i_U32].MaxIndex_U64 = Stats_X.pMax_X[i_U32].MaxIndex_U64; + } + } + } + } + } + + return Rts_U32; +} /*! Description This function converts ticks to the specified unit value diff --git a/lib/src/bofstd.cpp b/lib/src/bofstd.cpp index ddba41d..3d70e8b 100644 --- a/lib/src/bofstd.cpp +++ b/lib/src/bofstd.cpp @@ -81,6 +81,7 @@ cmake -DCMAKE_TOOLCHAIN_FILE=/home/bha/pro/github/vcpkg/scripts/buildsystems/vcp #include #include #include + #if defined(__EMSCRIPTEN__) #include #endif diff --git a/lib/src/bofsystem.cpp b/lib/src/bofsystem.cpp index 2583638..e2e944a 100644 --- a/lib/src/bofsystem.cpp +++ b/lib/src/bofsystem.cpp @@ -849,13 +849,12 @@ BOFERR Bof_CreateMutex(const std::string &_rName_S, bool _Recursive_B, bool _Pri { // https://sakhnik.com/2017/07/16/custom-mutex.html + pthread_mutexattr_t Attributes_X; // Destroy the underlying mutex - // NO ::pthread_mutex_destroy(_rMtx_X.Mtx.native_handle()); - // NO ::pthread_mutex_destroy(_rMtx_X.RecursiveMtx.native_handle()); + ::pthread_mutex_destroy(_rMtx_X.Mtx.native_handle()); + ::pthread_mutex_destroy(_rMtx_X.RecursiveMtx.native_handle()); // Create mutex attribute with desired protocol - pthread_mutexattr_t Attributes_X; - pthread_mutexattr_init(&Attributes_X); pthread_mutexattr_setprotocol(&Attributes_X, PTHREAD_PRIO_INHERIT); ::pthread_mutex_init(_rMtx_X.Mtx.native_handle(), &Attributes_X); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 87cd90a..6688114 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -63,6 +63,8 @@ set(CONIO_SHELL_FILES set(CONTAINER_FILES src/ut_narytreekv.cpp +# src/ut_spscqueue.cpp +# src/ut_mpmcqueue.cpp src/ut_circularbuffer.cpp src/ut_rawcircularbuffer.cpp src/ut_stringcircularbuffer.cpp diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 0a4a60f..0948cd1 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -1,6 +1,7 @@ #include -#include #include +#include +//#include #include "../include/gtestrunner.h" @@ -21,8 +22,6 @@ #include #endif -USE_BOF_NAMESPACE() - BOFERR AppBofAssertCallback(const std::string &_rFile_S, uint32_t _Line_U32, const std::string &_rMasg_S) { printf("Assert in %s line %d Msg %s\n", _rFile_S.c_str(), _Line_U32, _rMasg_S.c_str()); @@ -37,16 +36,15 @@ int main(int argc, char *argv[]) #else int Rts_i; BOFERR Sts_E; - BOFSTDPARAM StdParam_X; + BOF::BOFSTDPARAM StdParam_X; std::string HelpString_S, Cwd_S; StdParam_X.AssertInRelease_B = true; StdParam_X.AssertCallback = AppBofAssertCallback; Sts_E = Bof_Initialize(StdParam_X); BOF_ASSERT(Sts_E == BOF_ERR_NO_ERROR); - Bof_GetCurrentDirectory(Cwd_S); + BOF::Bof_GetCurrentDirectory(Cwd_S); printf("\nPwd %s\nRunning BofStd V %s on %s under %s\n", Cwd_S.c_str(), StdParam_X.Version_S.c_str(), StdParam_X.ComputerName_S.c_str(), StdParam_X.OsName_S.c_str()); - /* BOF::BofLogger &rBofLog = BOF::BofLogger::S_Instance(); BOF::BOF_LOGGER_PARAM LoggerParam_X; @@ -126,7 +124,11 @@ int main(int argc, char *argv[]) // "Threading_Test.*:BofThreadPool_Test.*:Timecode_Test.*:Uart_Test.*:Uri_Test.*"; //::testing::GTEST_FLAG(filter) = "DateTime_Test.StringDateTime:SocketTcp_Test.TcpClientTest:DateTime_Test.ValidateDateTime:SocketOs_Test.SocketAddress"; - //::testing::GTEST_FLAG(filter) = "Logger_Test.*"; + // ::testing::GTEST_FLAG(filter) = "Logger_Test.*:ut_logger_ibofloggerfactory.*"; +// ::testing::GTEST_FLAG(filter) = "ut_logger_ibofloggerfactory.*"; +// ::testing::GTEST_FLAG(filter) = "ut_spsc.*:ut_mpmc.*:CircularBuffer_Test.Perf"; + //::testing::GTEST_FLAG(filter) = "CircularBuffer_Test.PerfThread"; + //::testing::GTEST_FLAG(filter) = "XmlParser_Test.*:JsonParser_Test.*:JsonWriter_Test.*:Pipe_Test.*"; //::testing::GTEST_FLAG(filter) = "JsonParser_Test.*:XmlWriter_Test.*"; //::testing::GTEST_FLAG(filter) = "CmdLineParser_Test.*:Uri_Test.*"; @@ -136,13 +138,20 @@ int main(int argc, char *argv[]) //::testing::GTEST_FLAG(filter) = "RawCircularBuffer_Test.*:CircularBuffer_Test.*:RawCircularBufferInSlotMode_Test.*"; //::testing::GTEST_FLAG(filter) = "BofThreadPool_Test.*:BofThread_Test.*"; //::testing::GTEST_FLAG(filter) = "Graph_Test.*:ScopedGuard_Test.*"; -// ::testing::GTEST_FLAG(filter) = "RawCircularBufferAlwaysContiguous_Test.*:RawCircularBuffer_Test.*:RawCircularBufferInSlotMode_Test.*"; + // ::testing::GTEST_FLAG(filter) = "RawCircularBufferAlwaysContiguous_Test.*:RawCircularBuffer_Test.*:RawCircularBufferInSlotMode_Test.*"; // std::string CrtDir_S; // BOF::Bof_GetCurrentDirectory(CrtDir_S); // printf("-CrtDir_S->%s\n", CrtDir_S.c_str()); + + // BHALOG("! Rts_i=%d nb %d p %p !\n", 0, 7, nullptr); + + // LOG_INFO(MY_LOGGER, 0, "! Rts_i=%d nb %d p %p !\n", Rts_i, _Argc_i, _pArgv_c); + // LOG_WARNING(MY_LOGGER, 0, "! This will not be logged !\n"); + // LOG_ERROR(MY_LOGGER, 0, "! This will not be logged !\n"); + Rts_i = RUN_ALL_TESTS(); - Sts_E = Bof_Shutdown(); + Sts_E = BOF::Bof_Shutdown(); BOF_ASSERT(Sts_E == BOF_ERR_NO_ERROR); #if defined(NDEBUG) // We are in Release compil diff --git a/tests/src/ut_circularbuffer.cpp b/tests/src/ut_circularbuffer.cpp index ab9fde7..c51dd1b 100644 --- a/tests/src/ut_circularbuffer.cpp +++ b/tests/src/ut_circularbuffer.cpp @@ -18,10 +18,10 @@ * * V 1.00 vendredi 30 mai 2014 16:51:15 b.harmel : Initial release */ +#include "gtestrunner.h" #include #include - -#include "gtestrunner.h" +#include #include #include @@ -600,3 +600,187 @@ TEST(CircularBuffer_Test, StdString) BOF_SAFE_DELETE(pReplyCollection); } +struct QUEUE_ITEM +{ + uint32_t Val_U32; + uint8_t *pData_U8; + float pFloat_f[8]; + std::string Val_S; + + QUEUE_ITEM() + { + Reset(); + } + void Reset() + { + uint32_t i_U32; + + Val_U32 = 0; + pData_U8 = nullptr; + for (i_U32 = 0; i_U32 < BOF_NB_ELEM_IN_ARRAY(pFloat_f); i_U32++) + { + pFloat_f[i_U32] = 0; + } + Val_S = ""; + } +}; +TEST(CircularBuffer_Test, Perf) +{ + uint32_t i_U32, j_U32, Index_U32; + uint8_t pData_U8[0x1000]; + BOF::BOF_CIRCULAR_BUFFER_PARAM CbParam_X; + QUEUE_ITEM Item_X; + constexpr bool IGNORE_FIRST_SAMPLE = true; + constexpr uint32_t NB_QUEUE_OP = 100; + CbParam_X.Blocking_B = true; + CbParam_X.MultiThreadAware_B = true; + CbParam_X.NbMaxElement_U32 = NB_QUEUE_OP; + BOF::BofCircularBuffer Cb(CbParam_X); + BOF::BofProfiler Profiler(BOF::BOF_PROFILER_TYPE::BOF_PROFILER_TYPE_NORMAL, 2); + + memset(pData_U8, 0, sizeof(pData_U8)); + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Val_U32 = i_U32; + Item_X.pData_U8 = &pData_U8[Index_U32]; + pData_U8[Index_U32] = 'A' + (i_U32 % 26); + for (j_U32 = 0; j_U32 < BOF_NB_ELEM_IN_ARRAY(Item_X.pFloat_f); j_U32++) + { + Item_X.pFloat_f[j_U32] = i_U32 * j_U32; + } + Item_X.Val_S = BOF::Bof_Random(false, (i_U32 * 16) + j_U32, 'A', 'Z'); + Profiler.EnterBench(0); + EXPECT_EQ(Cb.Push(&Item_X, 1000, nullptr, nullptr), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, 0); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + printf("%zd Push Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(0), Profiler.GetMin(0), Profiler.GetMean(0), Profiler.GetMax(0), Profiler.GetLockCount(0)); + + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Reset(); + Profiler.EnterBench(1); + EXPECT_EQ(Cb.Pop(&Item_X, 1000, nullptr, nullptr), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, 1); + + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + EXPECT_NE(Cb.Pop(&Item_X, 1000, nullptr, nullptr), BOF_ERR_NO_ERROR); + printf("%zd Pop Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(1), Profiler.GetMin(1), Profiler.GetMean(1), Profiler.GetMax(1), Profiler.GetLockCount(1)); +} + +TEST(CircularBuffer_Test, PerfThread) +{ + constexpr bool IGNORE_FIRST_SAMPLE = true; + constexpr uint32_t NB_QUEUE_OP = 100; + constexpr uint32_t NB_QUEUE_PRODUCER_CONSUMER = 8; + uint8_t pData_U8[0x1000]; + BOF::BOF_CIRCULAR_BUFFER_PARAM CbParam_X; + CbParam_X.Blocking_B = true; + CbParam_X.MultiThreadAware_B = true; + CbParam_X.NbMaxElement_U32 = (NB_QUEUE_PRODUCER_CONSUMER * NB_QUEUE_OP); + BOF::BofCircularBuffer Cb(CbParam_X); + BOF::BofProfiler Profiler(BOF::BOF_PROFILER_TYPE::BOF_PROFILER_TYPE_NORMAL, NB_QUEUE_PRODUCER_CONSUMER + NB_QUEUE_PRODUCER_CONSUMER); + std::thread pThread[NB_QUEUE_PRODUCER_CONSUMER + NB_QUEUE_PRODUCER_CONSUMER]; + uint32_t i_U32, j_U32, Index_U32, pDequeued_U32[NB_QUEUE_PRODUCER_CONSUMER * NB_QUEUE_OP], NbLastMax_U32; + BOF_STAT_MAX pLastMax_X[BOF_STAT_KEEP_LAST_NB_MAX_VAL]; + static bool S_AllThreadReady_B = false; + + memset(pDequeued_U32, 0, sizeof(pDequeued_U32)); + // Producers + for (i_U32 = 0; i_U32 < NB_QUEUE_PRODUCER_CONSUMER; i_U32++) + { + pThread[i_U32] = std::thread([&](uint32_t _Id_U32) { + QUEUE_ITEM Item_X; + uint32_t j_U32=0; + + while (!S_AllThreadReady_B) + { + BOF::Bof_MsSleep(1); + } + for (j_U32 = 0; j_U32 < NB_QUEUE_OP; j_U32++) + { + Item_X.Val_U32 = (_Id_U32 * NB_QUEUE_OP) + j_U32; + // printf("Thread %d push %d\n", _Id_U32, Item_X.Val_U32); + Profiler.EnterBench(_Id_U32); + EXPECT_EQ(Cb.Push(&Item_X, 1000, nullptr, nullptr), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, _Id_U32); + } + }, + i_U32); + } + // Consumers + for (i_U32 = NB_QUEUE_PRODUCER_CONSUMER; i_U32 < (NB_QUEUE_PRODUCER_CONSUMER + NB_QUEUE_PRODUCER_CONSUMER); i_U32++) + { + pThread[i_U32] = std::thread([&](uint32_t _Id_U32) { + QUEUE_ITEM Item_X; + uint32_t j_U32 = 0; + + while (!S_AllThreadReady_B) + { + BOF::Bof_MsSleep(1); + } + for (j_U32 = NB_QUEUE_OP; j_U32 < (NB_QUEUE_OP + NB_QUEUE_OP); j_U32++) + { + Profiler.EnterBench(_Id_U32); + EXPECT_EQ(Cb.Pop(&Item_X, 1000, nullptr, nullptr), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, _Id_U32); + // printf("Thread %d pop %d\n", _Id_U32, Item_X.Val_U32); + + ++pDequeued_U32[Item_X.Val_U32]; + } + }, + i_U32); + } + S_AllThreadReady_B = true; + // Wait for all pThread + for (i_U32 = 0; i_U32 < BOF_NB_ELEM_IN_ARRAY(pThread); i_U32++) + { + pThread[i_U32].join(); + } + + // Collect any leftovers (could be some if e.g. consumers finish before producers) + QUEUE_ITEM Item_X; + while (Cb.Pop(&Item_X, 1000, nullptr, nullptr) == BOF_ERR_NO_ERROR) + { + ++pDequeued_U32[Item_X.Val_U32]; + } + + // Make sure everything went in and came back out! + for (i_U32 = 0; i_U32 < BOF_NB_ELEM_IN_ARRAY(pDequeued_U32); i_U32++) + { + EXPECT_EQ(pDequeued_U32[i_U32], 1); + } + printf("---PUSH--------------------------\n"); + for (i_U32 = 0; i_U32 < NB_QUEUE_PRODUCER_CONSUMER; i_U32++) + { + NbLastMax_U32 = Profiler.GetLastMax(i_U32, pLastMax_X); + printf("NbOp %zd NbMax %d Push[%d] Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(i_U32), NbLastMax_U32, i_U32, Profiler.GetMin(i_U32), Profiler.GetMean(i_U32), Profiler.GetMax(i_U32), Profiler.GetLockCount(i_U32)); + EXPECT_EQ(Profiler.GetNbSample(i_U32), NB_QUEUE_OP); + for (j_U32 = 0; j_U32 < NbLastMax_U32; j_U32++) + { + printf(" Index %zd Max %zd\n", pLastMax_X[j_U32].MaxIndex_U64, pLastMax_X[j_U32].Max); + } + } + printf("---POP---------------------------\n"); + for (i_U32 = NB_QUEUE_PRODUCER_CONSUMER; i_U32 < (NB_QUEUE_PRODUCER_CONSUMER + NB_QUEUE_PRODUCER_CONSUMER); i_U32++) + { + NbLastMax_U32 = Profiler.GetLastMax(i_U32, pLastMax_X); + printf("NbOp %zd NbMax %d Pop[%d] Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(i_U32), NbLastMax_U32, i_U32, Profiler.GetMin(i_U32), Profiler.GetMean(i_U32), Profiler.GetMax(i_U32), Profiler.GetLockCount(i_U32)); + EXPECT_EQ(Profiler.GetNbSample(i_U32), NB_QUEUE_OP); + for (j_U32 = 0; j_U32 < NbLastMax_U32; j_U32++) + { + printf(" Index %zd Max %zd\n", pLastMax_X[j_U32].MaxIndex_U64, pLastMax_X[j_U32].Max); + } + } +} \ No newline at end of file diff --git a/tests/src/ut_logger.cpp b/tests/src/ut_logger.cpp index 2516f1a..605d8ed 100644 --- a/tests/src/ut_logger.cpp +++ b/tests/src/ut_logger.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "gtestrunner.h" @@ -273,6 +274,322 @@ TEST_F(Logger_Test, LoggerInit) #endif } + + + + //*** External lib code ********************************************************************* +BOF_LOGGER_DEFINE_STORAGE(MyExternalSingleChannelLibLogger,1); +void MyExternalSingleChannelLibInit(std::shared_ptr _psLoggerFactory) +{ + uint32_t ChannelIndex_U32=0; + bool Sts_B; + std::shared_ptr psSingleChannelLogger; + + psSingleChannelLogger = _psLoggerFactory->V_Create(ChannelIndex_U32, 1, "SNG"); + EXPECT_FALSE(psSingleChannelLogger == nullptr); + BOF_LOGGER_FACTORY_ADD(MyExternalSingleChannelLibLogger, psSingleChannelLogger, ChannelIndex_U32, Sts_B); + EXPECT_TRUE(Sts_B); + + ChannelIndex_U32++; + psSingleChannelLogger = _psLoggerFactory->V_Create(ChannelIndex_U32, 1, "SNG"); + EXPECT_TRUE(psSingleChannelLogger == nullptr); + BOF_LOGGER_FACTORY_ADD(MyExternalSingleChannelLibLogger, psSingleChannelLogger, ChannelIndex_U32, Sts_B); + EXPECT_FALSE(Sts_B); +} +void MyExternalSingleChannelLibCode(std::shared_ptr _psLoggerFactory) +{ + uint32_t ChannelIndex_U32 = 0, NbLogOut_U32, NbLogRejected_U32; + + EXPECT_FALSE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32 + 1, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 0); + EXPECT_EQ(NbLogRejected_U32, 0); + BOF_LOG_FORCE(MyExternalSingleChannelLibLogger, ChannelIndex_U32 + 1, "! This will not be logged !\n"); + EXPECT_FALSE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32 + 1, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 0); + EXPECT_EQ(NbLogRejected_U32, 0); + + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 0); + EXPECT_EQ(NbLogRejected_U32, 0); + BOF_LOG_FORCE(MyExternalSingleChannelLibLogger, ChannelIndex_U32, "This will be logged\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 1); + EXPECT_EQ(NbLogRejected_U32, 0); + + BOF_LOG_INFO(MyExternalSingleChannelLibLogger, ChannelIndex_U32, "! This will not be logged !\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 1); + EXPECT_EQ(NbLogRejected_U32, 1); + + BOF_LOG_WARNING(MyExternalSingleChannelLibLogger, ChannelIndex_U32, "This will be logged\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 2); + EXPECT_EQ(NbLogRejected_U32, 1); + + BOF_LOG_ERROR(MyExternalSingleChannelLibLogger, ChannelIndex_U32, "This will be logged\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(ChannelIndex_U32, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 3); + EXPECT_EQ(NbLogRejected_U32, 1); +} +/* +#define WLOG(channel, ...) BOF_LOG_WARNING(MY_LOGGER, channel, __VA_ARGS__); +#define MY_LOGGER TheBhaLogger +BOF_LOGGER_DEFINE_STORAGE(MY_LOGGER, LOGGER_CHANNEL_MAX); +*/ +constexpr uint32_t MAX_MULTI_CHANNEL = 3; +#define WLOG(channel, ...) BOF_LOG_WARNING(MY_UT_LOGGER, channel, __VA_ARGS__); +#define MY_UT_LOGGER TheUtLogger +BOF_LOGGER_DEFINE_STORAGE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL); +void MyExternalMultipleChannelLibInit(std::shared_ptr _psLoggerFactory) +{ + bool Sts_B; + std::shared_ptr psMultiChannelLogger; + if (_psLoggerFactory) + { + psMultiChannelLogger = _psLoggerFactory->V_Create(MAX_MULTI_CHANNEL, MAX_MULTI_CHANNEL, "MLT"); + EXPECT_TRUE(psMultiChannelLogger == nullptr); + BOF_LOGGER_FACTORY_ADD(MyExternalMultipleChannelLibLogger, psMultiChannelLogger, MAX_MULTI_CHANNEL, Sts_B); + EXPECT_FALSE(Sts_B); + + psMultiChannelLogger = _psLoggerFactory->V_Create(MAX_MULTI_CHANNEL - 1, MAX_MULTI_CHANNEL, "DMA"); + EXPECT_FALSE(psMultiChannelLogger == nullptr); + BOF_LOGGER_FACTORY_ADD(MyExternalMultipleChannelLibLogger, psMultiChannelLogger, MAX_MULTI_CHANNEL - 1, Sts_B); + EXPECT_TRUE(Sts_B); + + psMultiChannelLogger = _psLoggerFactory->V_Create(0, MAX_MULTI_CHANNEL, "REC"); + EXPECT_FALSE(psMultiChannelLogger == nullptr); + BOF_LOGGER_FACTORY_ADD(MyExternalMultipleChannelLibLogger, psMultiChannelLogger, 0, Sts_B); + EXPECT_TRUE(Sts_B); + + /* Let a nullptr in the collection + psMultiChannelLogger = _psLoggerFactory->V_Create(1, MAX_MULTI_CHANNEL, "PLY"); + EXPECT_FALSE(psMultiChannelLogger == nullptr); + BOF_LOGGER_FACTORY_ADD(MyExternalMultipleChannelLibLogger, psMultiChannelLogger, 1, Sts_B); + EXPECT_TRUE(Sts_B); + */ + } +} +void MyExternalMultipleChannelLibCode(std::shared_ptr _psLoggerFactory) +{ + uint32_t NbLogOut_U32, NbLogRejected_U32; + + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL, "! This will not be logged !\n"); + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, 0, "This will be logged\n"); + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); //Let a nullptr in the collection + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL-1, "This will be logged\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(0, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 1); + EXPECT_EQ(NbLogRejected_U32, 0); + EXPECT_FALSE(_psLoggerFactory->V_GetLogStat(1, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 0); + EXPECT_EQ(NbLogRejected_U32, 0); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(MAX_MULTI_CHANNEL - 1, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 1); + EXPECT_EQ(NbLogRejected_U32, 0); + + BOF_LOG_INFO(MyExternalMultipleChannelLibLogger, 0, "! This will not be logged !\n"); + BOF_LOG_WARNING(MyExternalMultipleChannelLibLogger, 0, "This will be logged\n"); + BOF_LOG_ERROR(MyExternalMultipleChannelLibLogger, 0, "This will be logged\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(0, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 3); + EXPECT_EQ(NbLogRejected_U32, 1); + + BOF_LOG_INFO(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); //Let a nullptr in the collection + BOF_LOG_WARNING(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); + BOF_LOG_ERROR(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); + EXPECT_FALSE(_psLoggerFactory->V_GetLogStat(1, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 0); + EXPECT_EQ(NbLogRejected_U32, 0); + + BOF_LOG_VERBOSE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "! This will not be logged !\n"); + BOF_LOG_INFO(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "This will be logged\n"); + BOF_LOG_ERROR(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "This will be logged\n"); + EXPECT_TRUE(_psLoggerFactory->V_GetLogStat(MAX_MULTI_CHANNEL - 1, NbLogOut_U32, NbLogRejected_U32)); + EXPECT_EQ(NbLogOut_U32, 3); + EXPECT_EQ(NbLogRejected_U32, 1); +} +void MyExternalMultipleNullptrChannelLibCode() +{ + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL, "! This will not be logged !\n"); + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, 0, "! This will not be logged !\n"); + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); //Let a nullptr in the collection + BOF_LOG_FORCE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "! This will not be logged !\n"); + + BOF_LOG_INFO(MyExternalMultipleChannelLibLogger, 0, "! This will not be logged !\n"); + BOF_LOG_WARNING(MyExternalMultipleChannelLibLogger, 0, "! This will not be logged !\n"); + BOF_LOG_ERROR(MyExternalMultipleChannelLibLogger, 0, "! This will not be logged !\n"); + + BOF_LOG_INFO(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); //Let a nullptr in the collection + BOF_LOG_WARNING(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); + BOF_LOG_ERROR(MyExternalMultipleChannelLibLogger, 1, "! This will not be logged !\n"); + + BOF_LOG_VERBOSE(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "! This will not be logged !\n"); + BOF_LOG_INFO(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "! This will not be logged !\n"); + BOF_LOG_ERROR(MyExternalMultipleChannelLibLogger, MAX_MULTI_CHANNEL - 1, "! This will not be logged !\n"); +} + +//*** Caller/User of the external lib ******************************************************** +class MyUtLogger :public BOF::IBofLogger +{ +public: + MyUtLogger(const uint32_t _ChannelIndex_U32, const std::string &_rChannelName_S) + { + char pLogFile_c[256]; + + mChannelIndex_U32 = _ChannelIndex_U32; + mChannelName_S = _rChannelName_S; + + sprintf(pLogFile_c, "%s_%03d.log", _rChannelName_S.c_str(), mChannelIndex_U32); + mpLogFile_X = fopen(pLogFile_c,"w+"); + } + ~MyUtLogger() + { + if (mpLogFile_X) + { + fclose(mpLogFile_X); + mpLogFile_X = nullptr; + } + } + void V_Log(LogSeverity _SeverityLevel_E, const char *_pLogMessage_c, ...) override + { + char pLog_c[0x1000]; + va_list VaList_X; + + va_start(VaList_X, _pLogMessage_c); + vsnprintf(pLog_c, sizeof(pLog_c), _pLogMessage_c, VaList_X); + va_end(VaList_X); + + pLog_c[sizeof(pLog_c) - 1] = 0; + printf("Sev %d Channel[%d][%s]->%s", _SeverityLevel_E, mChannelIndex_U32, mChannelName_S.c_str(), pLog_c); + fwrite(pLog_c, strlen(pLog_c), 1, mpLogFile_X); + } +private: + uint32_t mChannelIndex_U32 = 0; + std::string mChannelName_S; + FILE *mpLogFile_X = nullptr; +}; + +class MyUtLoggerFactory:public BOF::IBofLoggerFactory +{ +public: + std::shared_ptr V_Create(const uint32_t _ChannelIndex_U32, const uint32_t _MaxChannelIndex_U32, const std::string &_rChannelName_S) override + { + std::shared_ptr psRts = nullptr; + uint32_t i_U32; + + if (_ChannelIndex_U32 < _MaxChannelIndex_U32) + { + if (mLoggerCollection.size() != _MaxChannelIndex_U32) + { + mLoggerCollection.clear(); + for (i_U32 = 0; i_U32 < _MaxChannelIndex_U32; i_U32++) + { + mLoggerCollection.push_back(nullptr); + } + } + psRts = std::make_shared(_ChannelIndex_U32, _rChannelName_S); + mLoggerCollection[_ChannelIndex_U32]=psRts; + } + return psRts; + } + bool V_SetLogSeverityLevel(const uint32_t _ChannelIndex_U32, BOF::IBofLogger::LogSeverity _SeverityLevel_E) override + { + bool Rts_B = false; + + if (_ChannelIndex_U32 < mLoggerCollection.size()) + { + if (mLoggerCollection[_ChannelIndex_U32]) + { + Rts_B = mLoggerCollection[_ChannelIndex_U32]->SetLogSeverityLevel(_SeverityLevel_E); + } + } + return Rts_B; + } + BOF::IBofLogger::LogSeverity V_GetLogSeverityLevel(const uint32_t _ChannelIndex_U32) const override + { + BOF::IBofLogger::LogSeverity Rts_E = BOF::IBofLogger::LogSeverity::LOG_SEVERITY_MAX; + if (_ChannelIndex_U32 < mLoggerCollection.size()) + { + if (mLoggerCollection[_ChannelIndex_U32]) + { + Rts_E = mLoggerCollection[_ChannelIndex_U32]->GetLogSeverityLevel(); + } + } + return Rts_E; + } + bool V_GetLogStat(const uint32_t _ChannelIndex_U32, uint32_t &_rNbLogOut_U32, uint32_t &_rNbLogRejected_U32) const override + { + bool Rts_B = false; + + _rNbLogOut_U32 = 0; + _rNbLogRejected_U32 = 0; + if (_ChannelIndex_U32 < mLoggerCollection.size()) + { + if (mLoggerCollection[_ChannelIndex_U32]) + { + Rts_B = mLoggerCollection[_ChannelIndex_U32]->GetLogStat(_rNbLogOut_U32, _rNbLogRejected_U32); + } + } + return Rts_B; + } + +private: + std::vector> mLoggerCollection; +}; +//*** Caller/User of the external lib ******************************************************** +//*** Unit Test ****************************************************************************** +TEST(ut_logger_ibofloggerfactory, InjectNullptr) +{ + MyExternalMultipleChannelLibInit(nullptr); + + MyExternalMultipleNullptrChannelLibCode(); +} + +TEST(ut_logger_ibofloggerfactory, SingleChannel) +{ + std::shared_ptr psSingleChannelLogger=std::make_shared(); + MyExternalSingleChannelLibInit(psSingleChannelLogger); + + EXPECT_EQ(psSingleChannelLogger->V_GetLogSeverityLevel(0), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_MAX); + EXPECT_TRUE(psSingleChannelLogger->V_SetLogSeverityLevel(0, BOF::IBofLogger::LogSeverity::LOG_SEVERITY_WARNING)); + EXPECT_EQ(psSingleChannelLogger->V_GetLogSeverityLevel(0), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_WARNING); + + MyExternalSingleChannelLibCode(psSingleChannelLogger); +} + +TEST(ut_logger_ibofloggerfactory, MultipleChannel) +{ + std::shared_ptr psMultipleChannelLogger = std::make_shared(); + MyExternalMultipleChannelLibInit(psMultipleChannelLogger); + + EXPECT_EQ(psMultipleChannelLogger->V_GetLogSeverityLevel(0), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_MAX); + EXPECT_TRUE(psMultipleChannelLogger->V_SetLogSeverityLevel(0, BOF::IBofLogger::LogSeverity::LOG_SEVERITY_WARNING)); + EXPECT_EQ(psMultipleChannelLogger->V_GetLogSeverityLevel(0), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_WARNING); + + EXPECT_EQ(psMultipleChannelLogger->V_GetLogSeverityLevel(MAX_MULTI_CHANNEL - 1), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_MAX); + EXPECT_TRUE(psMultipleChannelLogger->V_SetLogSeverityLevel(MAX_MULTI_CHANNEL - 1, BOF::IBofLogger::LogSeverity::LOG_SEVERITY_INFO)); + EXPECT_EQ(psMultipleChannelLogger->V_GetLogSeverityLevel(MAX_MULTI_CHANNEL - 1), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_INFO); + + EXPECT_EQ(psMultipleChannelLogger->V_GetLogSeverityLevel(0), BOF::IBofLogger::LogSeverity::LOG_SEVERITY_WARNING); + + MyExternalMultipleChannelLibCode(psMultipleChannelLogger); +} + + + + + + + + + + + + + + + + #if 0 TEST_F(Logger_Test, LoggerFile) { diff --git a/tests/src/ut_mpmcqueue.cpp b/tests/src/ut_mpmcqueue.cpp new file mode 100644 index 0000000..533d923 --- /dev/null +++ b/tests/src/ut_mpmcqueue.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020-2040, Onbings. All rights reserved. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + * PURPOSE. + * + * This module test a multiple producer-multiple consumer queue + * + * History: + * + * V 1.00 May 26 2020 BHA : Initial release + */ +#include +#include +#include +#include "gtestrunner.h" + +struct QUEUE_ITEM +{ + uint32_t Val_U32; + uint8_t *pData_U8; + float pFloat_f[8]; + std::string Val_S; + + QUEUE_ITEM() + { + Reset(); + } + void Reset() + { + uint32_t i_U32; + + Val_U32 = 0; + pData_U8 = nullptr; + for (i_U32 = 0; i_U32 < BOF_NB_ELEM_IN_ARRAY(pFloat_f); i_U32++) + { + pFloat_f[i_U32] = 0; + } + Val_S = ""; + } +}; +TEST(ut_mpmc, Basic) +{ + uint32_t i_U32, j_U32, Index_U32; + uint8_t pData_U8[0x1000]; + BOF::BOF_MPMC_QUEUE_PARAM MpMcQueueParam_X; + QUEUE_ITEM Item_X; + constexpr uint32_t NB_QUEUE_OP = 100; + MpMcQueueParam_X.NbMaxElement_U32 = NB_QUEUE_OP; + BOF::BofMpMcQueue MpMcQueue(MpMcQueueParam_X); + + memset(pData_U8, 0, sizeof(pData_U8)); + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Val_U32 = i_U32; + Item_X.pData_U8 = &pData_U8[Index_U32]; + pData_U8[Index_U32] = 'A' + (i_U32 % 26); + for (j_U32 = 0; j_U32 < BOF_NB_ELEM_IN_ARRAY(Item_X.pFloat_f); j_U32++) + { + Item_X.pFloat_f[j_U32] = i_U32*j_U32; + } + Item_X.Val_S = BOF::Bof_Random(false,(i_U32 *16) + j_U32, 'A','Z'); + EXPECT_EQ(MpMcQueue.Push(Item_X,1000), BOF_ERR_NO_ERROR); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Reset(); + EXPECT_EQ(MpMcQueue.Pop(Item_X,1000), BOF_ERR_NO_ERROR); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + EXPECT_NE(MpMcQueue.Pop(Item_X,1000), BOF_ERR_NO_ERROR); +} + + +TEST(ut_mpmc, Perf) +{ + uint32_t i_U32, j_U32, Index_U32; + uint8_t pData_U8[0x1000]; + BOF::BOF_MPMC_QUEUE_PARAM MpMcQueueParam_X; + QUEUE_ITEM Item_X; + constexpr uint32_t NB_QUEUE_OP = 100; + constexpr bool IGNORE_FIRST_SAMPLE = true; + MpMcQueueParam_X.NbMaxElement_U32 = NB_QUEUE_OP; + BOF::BofMpMcQueue MpMcQueue(MpMcQueueParam_X); + BOF::BofProfiler Profiler(BOF::BOF_PROFILER_TYPE::BOF_PROFILER_TYPE_NORMAL, 2); + + memset(pData_U8, 0, sizeof(pData_U8)); + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Val_U32 = i_U32; + Item_X.pData_U8 = &pData_U8[Index_U32]; + pData_U8[Index_U32] = 'A' + (i_U32 % 26); + for (j_U32 = 0; j_U32 < BOF_NB_ELEM_IN_ARRAY(Item_X.pFloat_f); j_U32++) + { + Item_X.pFloat_f[j_U32] = i_U32 * j_U32; + } + Item_X.Val_S = BOF::Bof_Random(false, (i_U32 * 16) + j_U32, 'A', 'Z'); + Profiler.EnterBench(0); + EXPECT_EQ(MpMcQueue.Push(Item_X, 1000), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, 0); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + printf("%zd Push Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(0), Profiler.GetMin(0), Profiler.GetMean(0), Profiler.GetMax(0), Profiler.GetLockCount(0)); + + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Reset(); + Profiler.EnterBench(1); + EXPECT_EQ(MpMcQueue.Pop(Item_X, 1000), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, 1); + + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + EXPECT_NE(MpMcQueue.Pop(Item_X, 1000), BOF_ERR_NO_ERROR); + printf("%zd Pop Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(1), Profiler.GetMin(1), Profiler.GetMean(1), Profiler.GetMax(1), Profiler.GetLockCount(1)); +} \ No newline at end of file diff --git a/tests/src/ut_spscqueue.cpp b/tests/src/ut_spscqueue.cpp new file mode 100644 index 0000000..4d0e479 --- /dev/null +++ b/tests/src/ut_spscqueue.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2020-2040, Onbings. All rights reserved. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + * PURPOSE. + * + * This module test a single producer-single consumer queue + * + * History: + * + * V 1.00 May 26 2020 BHA : Initial release + */ +#include +#include +#include +#include "gtestrunner.h" + +struct QUEUE_ITEM +{ + uint32_t Val_U32; + uint8_t *pData_U8; + float pFloat_f[8]; + std::string Val_S; + + QUEUE_ITEM() + { + Reset(); + } + void Reset() + { + uint32_t i_U32; + + Val_U32 = 0; + pData_U8 = nullptr; + for (i_U32 = 0; i_U32 < BOF_NB_ELEM_IN_ARRAY(pFloat_f); i_U32++) + { + pFloat_f[i_U32] = 0; + } + Val_S = ""; + } +}; +TEST(ut_spsc, Basic) +{ + uint32_t i_U32, j_U32, Index_U32; + uint8_t pData_U8[0x1000]; + BOF::BOF_SPSC_QUEUE_PARAM SpScQueueParam_X; + QUEUE_ITEM Item_X; + constexpr uint32_t NB_QUEUE_OP = 100; + SpScQueueParam_X.NbMaxElement_U32 = NB_QUEUE_OP; + BOF::BofSpScQueue SpScQueue(SpScQueueParam_X); + + memset(pData_U8, 0, sizeof(pData_U8)); + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Val_U32 = i_U32; + Item_X.pData_U8 = &pData_U8[Index_U32]; + pData_U8[Index_U32] = 'A' + (i_U32 % 26); + for (j_U32 = 0; j_U32 < BOF_NB_ELEM_IN_ARRAY(Item_X.pFloat_f); j_U32++) + { + Item_X.pFloat_f[j_U32] = i_U32*j_U32; + } + Item_X.Val_S = BOF::Bof_Random(false,(i_U32 *16) + j_U32, 'A','Z'); + EXPECT_EQ(SpScQueue.Push(Item_X,1000), BOF_ERR_NO_ERROR); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Reset(); + EXPECT_EQ(SpScQueue.Pop(Item_X,1000), BOF_ERR_NO_ERROR); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + EXPECT_NE(SpScQueue.Pop(Item_X,1000), BOF_ERR_NO_ERROR); +} + +TEST(ut_spsc, Perf) +{ + uint32_t i_U32, j_U32, Index_U32; + uint8_t pData_U8[0x1000]; + BOF::BOF_SPSC_QUEUE_PARAM SpScQueueParam_X; + QUEUE_ITEM Item_X; + constexpr bool IGNORE_FIRST_SAMPLE = true; + constexpr uint32_t NB_QUEUE_OP = 100; + SpScQueueParam_X.NbMaxElement_U32 = NB_QUEUE_OP; + BOF::BofSpScQueue SpScQueue(SpScQueueParam_X); + BOF::BofProfiler Profiler(BOF::BOF_PROFILER_TYPE::BOF_PROFILER_TYPE_NORMAL, 2); + + memset(pData_U8, 0, sizeof(pData_U8)); + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Val_U32 = i_U32; + Item_X.pData_U8 = &pData_U8[Index_U32]; + pData_U8[Index_U32] = 'A' + (i_U32 % 26); + for (j_U32 = 0; j_U32 < BOF_NB_ELEM_IN_ARRAY(Item_X.pFloat_f); j_U32++) + { + Item_X.pFloat_f[j_U32] = i_U32 * j_U32; + } + Item_X.Val_S = BOF::Bof_Random(false, (i_U32 * 16) + j_U32, 'A', 'Z'); + Profiler.EnterBench(0); + EXPECT_EQ(SpScQueue.Push(Item_X,1000), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, 0); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + printf("%zd Push Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(0), Profiler.GetMin(0), Profiler.GetMean(0), Profiler.GetMax(0), Profiler.GetLockCount(0)); + + Index_U32 = 0; + for (i_U32 = 0; i_U32 < NB_QUEUE_OP; i_U32++) + { + Item_X.Reset(); + Profiler.EnterBench(1); + EXPECT_EQ(SpScQueue.Pop(Item_X,1000), BOF_ERR_NO_ERROR); + Profiler.LeaveBench(IGNORE_FIRST_SAMPLE, 1); + Index_U32++; + if (Index_U32 > sizeof(pData_U8)) + { + Index_U32 = 0; + } + } + EXPECT_NE(SpScQueue.Pop(Item_X,1000), BOF_ERR_NO_ERROR); + printf("%zd Pop Min %zd Mean %zd Max %zd Lck %zd\n", Profiler.GetNbSample(1), Profiler.GetMin(1), Profiler.GetMean(1), Profiler.GetMax(1), Profiler.GetLockCount(1)); +} +