From e6b67dcdc2d50605092f5dfe50d8f2c130f00277 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Jun 2021 13:42:55 -0400 Subject: [PATCH 01/12] We cannot delete from the queue when capturing. Just do the waiting. Reduce severity of logs. Make more use of auto. Realise that no other iterators can be pointing into the queue. --- src/zm_packetqueue.cpp | 74 +++++++++--------------------------------- 1 file changed, 15 insertions(+), 59 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index b18fdc266..9d0168ab7 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -92,48 +92,9 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { Warning("You have set the max video packets in the queue to %u." " The queue is full. Either Analysis is not keeping up or" " your camera's keyframe interval is larger than this setting." - " We are dropping packets.", max_video_packet_count); - if (add_packet->keyframe) { - // Have a new keyframe, so delete everything - while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > max_video_packet_count)) { - std::shared_ptr zm_packet = *pktQueue.begin(); - ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); - if (!lp->trylock()) { - Debug(1, "Found locked packet when trying to free up video packets. Can't continue"); - delete lp; - break; - } - delete lp; - - for ( - std::list::iterator iterators_it = iterators.begin(); - iterators_it != iterators.end(); - ++iterators_it - ) { - packetqueue_iterator *iterator_it = *iterators_it; - // Have to check each iterator and make sure it doesn't point to the packet we are about to delete - if ( *(*iterator_it) == zm_packet ) { - Debug(1, "Bumping IT because it is at the front that we are deleting"); - ++(*iterators_it); - } - } // end foreach iterator - - pktQueue.pop_front(); - packet_counts[zm_packet->packet.stream_index] -= 1; - Debug(1, - "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu", - zm_packet->packet.stream_index, - zm_packet->image_index, - zm_packet->keyframe, - packet_counts[video_stream_id], - max_video_packet_count, - pktQueue.size()); - } // end while - } - } // end if too many video packets - if (max_video_packet_count > 0) { + , max_video_packet_count); while (packet_counts[video_stream_id] > max_video_packet_count) { - Error("Unable to free up older packets. Waiting."); + Debug(1, "Capture waiting for room in the queue."); condition.wait(lck); if (deleting or zm_terminate) return false; @@ -148,16 +109,13 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { packet_counts[add_packet->packet.stream_index]); for ( - std::list::iterator iterators_it = iterators.begin(); + auto iterators_it = iterators.begin(); iterators_it != iterators.end(); ++iterators_it ) { packetqueue_iterator *iterator_it = *iterators_it; if (*iterator_it == pktQueue.end()) { - Debug(4, "pointing it %p to back", iterator_it); --(*iterator_it); - } else { - Debug(4, "it %p not at end", iterator_it); } } // end foreach iterator } // end lock scope @@ -166,7 +124,7 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { condition.notify_all(); return true; -} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet) +} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet) void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { // Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one. @@ -240,8 +198,8 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { return; } - packetqueue_iterator it = pktQueue.begin(); - packetqueue_iterator next_front = pktQueue.begin(); + auto it = pktQueue.begin(); + auto next_front = pktQueue.begin(); // First packet is special because we know it is a video keyframe and only need to check for lock std::shared_ptr zm_packet = *it; @@ -249,18 +207,13 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { return; } - Debug(1, "trying lock on first packet"); ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); if (lp->trylock()) { int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking - Debug(1, "Have lock on first packet"); + Debug(4, "Have lock on first packet"); ++it; delete lp; - if (it == pktQueue.end()) { - Debug(1, "Hit end already"); - it = pktQueue.begin(); - } else { // Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that while (*it != add_packet) { zm_packet = *it; @@ -271,10 +224,14 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { } delete lp; - if (is_there_an_iterator_pointing_to_packet(zm_packet) and (pktQueue.begin() == next_front)) { - Warning("Found iterator at beginning of queue. Some thread isn't keeping up"); +#if 0 + // There are no threads that follow analysis thread. So there cannot be an it pointing here + if (is_there_an_iterator_pointing_to_packet(zm_packet)) { + if (pktQueue.begin() == next_front) + Warning("Found iterator at beginning of queue. Some thread isn't keeping up"); break; } +#endif if (zm_packet->packet.stream_index == video_stream_id) { if (zm_packet->keyframe) { @@ -282,15 +239,14 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { next_front = it; } ++video_packets_to_delete; - Debug(4, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d", - video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count); + Debug(4, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d", + video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count); if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) { break; } } ++it; } // end while - } } // end if first packet not locked Debug(1, "Resulting pointing at latest packet? %d, next front points to begin? %d", ( *it == add_packet ), From 3723e136b1f973f0a731c0a58d61b732b82eb81a Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 19:44:58 +0000 Subject: [PATCH 02/12] Initial benchmark exe --- src/CMakeLists.txt | 8 +++++ src/zmbenchmark.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 src/zmbenchmark.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f37ff0ab..80e09e9c3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -107,6 +107,7 @@ endif() add_executable(zmc zmc.cpp) add_executable(zms zms.cpp) add_executable(zmu zmu.cpp) +add_executable(zmbenchmark zmbenchmark.cpp) target_link_libraries(zmc PRIVATE @@ -129,6 +130,13 @@ target_link_libraries(zmu ${ZM_EXTRA_LIBS} ${CMAKE_DL_LIBS}) +target_link_libraries(zmbenchmark + PRIVATE + zm-core-interface + zm + ${ZM_EXTRA_LIBS} + ${CMAKE_DL_LIBS}) + # Generate man files for the binaries destined for the bin folder if(BUILD_MAN) foreach(CBINARY zmc zmu) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp new file mode 100644 index 000000000..a12462a50 --- /dev/null +++ b/src/zmbenchmark.cpp @@ -0,0 +1,76 @@ +// +// ZoneMinder Benchmark, $Date$, $Revision$ +// Copyright (C) 2001-2008 Philip Coombes +// +// 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 2 +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// + +#include +#include + +#include "zm_image.h" +#include "zm_zone.h" + + + +// +// Generate a greyscale image that simulates a delta that can be fed to +// Zone::CheckAlarms. +// +// Args: +// minVal: 0-255 value telling the minimum (random) value to initialize +// all the pixels to. +// maxVal: 0-255 value telling the maximum (random) value to initialize +// all the pixels to. +// width: The width of the new image. +// height: The height of the new image. +// +// Return: +// An image with all pixels initialized to values in the [minVal,maxVal] range. +// +std::shared_ptr GenerateDeltaImage( + int minVal, + int maxVal, + int width = 3840, + int height = 2160) { + // Create the image. + Image *image = new Image( + width, + height, + ZM_COLOUR_GRAY8, + ZM_SUBPIX_ORDER_NONE); + + const int range = maxVal - minVal + 1; + for (int y=0; y < height; y++) + { + uint8_t *row = (uint8_t*)image->Buffer(0, y); + for (int x=0; x < width; x++) + row[x] = (rand() * range) / RAND_MAX + minVal; + } + + return image; +} + + +int main(int argc, char *argv[]) { + srand(111); + + RunZoneBenchmark("0%% delta", GenerateDeltaImage(0, 0)); + RunZoneBenchmark("50%% delta", GenerateDeltaImage(0, 255)); + RunZoneBenchmark("100%% delta", GenerateDeltaImage(255, 255)); + + return 0; +} + From 305af08112fec3e0cdb047c6912cf01ee86a5305 Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 20:22:10 +0000 Subject: [PATCH 03/12] Added Monitor scaffolding and a skeleton benchmark for DetectMotion. --- src/zmbenchmark.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 6 deletions(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index a12462a50..dde4fa69a 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -20,11 +20,13 @@ #include #include +#include "zm_config.h" #include "zm_image.h" +#include "zm_monitor.h" +#include "zm_utils.h" #include "zm_zone.h" - // // Generate a greyscale image that simulates a delta that can be fed to // Zone::CheckAlarms. @@ -40,7 +42,7 @@ // Return: // An image with all pixels initialized to values in the [minVal,maxVal] range. // -std::shared_ptr GenerateDeltaImage( +std::shared_ptr GenerateRandomImage( int minVal, int maxVal, int width = 3840, @@ -60,16 +62,159 @@ std::shared_ptr GenerateDeltaImage( row[x] = (rand() * range) / RAND_MAX + minVal; } - return image; + return std::shared_ptr(image); +} + + +// +// This is used to help rig up tests of Monitor. +// +class TestMonitor : public Monitor +{ +public: + TestMonitor(int width, int height) { + cur_zone_id = 111; + + this->width = width; + this->height = height; + + // Create a dummy ref_image. + std::shared_ptr tempImage = GenerateRandomImage(0, 0, width, height); + ref_image = *tempImage.get(); + + shared_data = &temp_shared_data; + } + + // + // Add a new zone to this monitor. + // + // Args: + // checkMethod: This controls how this zone will actually do motion detection. + // + // p_filter_box: The size of the filter to use. + // + void AddZone(Zone::CheckMethod checkMethod, const Vector2 &p_filter_box=Vector2(5,5)) { + const int p_min_pixel_threshold = 50; + const int p_max_pixel_threshold = 255; + const int p_min_alarm_pixels = 1000; + const int p_max_alarm_pixels = 10000000; + + const int zone_id = cur_zone_id++; + const std::string zone_label = std::string("zone_") + std::to_string(zone_id); + const Zone::ZoneType zoneType = Zone::ZoneType::ACTIVE; + const Polygon poly({ + Vector2(0, 0), + Vector2(width-1, 0), + Vector2(width-1, height-1), + Vector2(0, height-1)}); + + Zone zone( + this, + zone_id, + zone_label.c_str(), + zoneType, + poly, + kRGBGreen, + Zone::CheckMethod::FILTERED_PIXELS, + p_min_pixel_threshold, + p_max_pixel_threshold, + p_min_alarm_pixels, + p_max_alarm_pixels, + p_filter_box + ); + zones.push_back(zone); + } + + void SetRefImage(const Image *image) { + ref_image = *image; + } + +private: + SharedData temp_shared_data; + int cur_zone_id; +}; + + + +class CounterInfo { +public: + CounterInfo( + const std::chrono::microseconds &in_timer, + const std::string &in_label) : + timer(in_timer), + label(in_label) + { + } + + const std::chrono::microseconds timer; + const std::string label; +}; + +// +// Print out a table of timing results. +// +// Args: +// counters: The list of counters to print out, and info about how to format it. +// +void PrintCounters(std::vector counters) { + for (const auto counter : counters) { + printf("%s: %lims\n", counter.label.c_str(), counter.timer.count()); + } +} + +// +// Run zone benchmarks on the given image. +// +// Args: +// label: A label to be printed before the output. +// +// image: The image to run the tests on. +// +void RunZoneBenchmark(const char *label, std::shared_ptr image) { + // Create a monitor to use for the benchmark. Give it 1 zone that uses + // a 5x5 filter. + TestMonitor testMonitor(image->Width(), image->Height()); + testMonitor.AddZone(Zone::CheckMethod::FILTERED_PIXELS, Vector2(5,5)); + + // Generate a black image to use as the reference image. + std::shared_ptr blackImage = GenerateRandomImage( + 0, 0, image->Width(), image->Height()); + testMonitor.SetRefImage(blackImage.get()); + + std::chrono::microseconds totalTimeTaken(0); + + // Run a series of passes over DetectMotion. + const int numPasses = 10; + for (int i=0; i < numPasses; i++) + { + printf("\r(%d / %d) ", i+1, numPasses); + fflush(stdout); + + Event::StringSet zoneSet; + testMonitor.DetectMotion(*image.get(), zoneSet); + } + + printf("\n"); + printf("------- %s -------\n", label); + PrintCounters({ + CounterInfo(totalTimeTaken, "Total zone benchmark time")}); } int main(int argc, char *argv[]) { srand(111); - RunZoneBenchmark("0%% delta", GenerateDeltaImage(0, 0)); - RunZoneBenchmark("50%% delta", GenerateDeltaImage(0, 255)); - RunZoneBenchmark("100%% delta", GenerateDeltaImage(255, 255)); + // Init global stuff that we need. + config.font_file_location = "../fonts/default.zmfnt"; + config.event_close_mode = "time"; + config.cpu_extensions = 1; + + // Detect SSE version. + HwCapsDetect(); + + RunZoneBenchmark("0%% delta", GenerateRandomImage(0, 0)); + RunZoneBenchmark("50%% delta", GenerateRandomImage(0, 255)); + RunZoneBenchmark("100%% delta", GenerateRandomImage(255, 255)); return 0; } From 9370cfe25c6be22e7505a6f38deb4559416f091c Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 21:12:46 +0000 Subject: [PATCH 04/12] Added TimeSegmentAdder class and got benchmark output looking ok. --- src/zm_time.h | 38 ++++++++++++++++++++++++++++++++++++++ src/zmbenchmark.cpp | 29 +++++++++++++++++------------ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/zm_time.h b/src/zm_time.h index f7574bbf7..ab2a8d000 100644 --- a/src/zm_time.h +++ b/src/zm_time.h @@ -83,4 +83,42 @@ Duration duration_cast(timeval const &tv) { } } +// +// This can be used for benchmarking. It will measure the time in between +// its constructor and destructor (or when you call Finish()) and add that +// duration to a microseconds clock. +// +class TimeSegmentAdder { +public: + TimeSegmentAdder(Microseconds &inTarget) : + target(inTarget), + startTime(std::chrono::steady_clock::now()), + finished(false) { + } + + ~TimeSegmentAdder() { + Finish(); + } + + // Call this to stop the timer and add the timed duration to `target`. + void Finish() { + if (!finished) { + const TimePoint endTime = std::chrono::steady_clock::now(); + target += (std::chrono::duration_cast(endTime - startTime)); + } + finished = true; + } + +private: + // This is where we will add our duration to. + Microseconds ⌖ + + // The time we started. + const TimePoint startTime; + + // True when it has finished timing. + bool finished; +}; + + #endif // ZM_TIME_H diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index dde4fa69a..90a2316b3 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -23,6 +23,7 @@ #include "zm_config.h" #include "zm_image.h" #include "zm_monitor.h" +#include "zm_time.h" #include "zm_utils.h" #include "zm_zone.h" @@ -67,7 +68,7 @@ std::shared_ptr GenerateRandomImage( // -// This is used to help rig up tests of Monitor. +// This is used to help rig up Monitor benchmarks. // class TestMonitor : public Monitor { @@ -139,14 +140,14 @@ private: class CounterInfo { public: CounterInfo( - const std::chrono::microseconds &in_timer, + const Microseconds in_timer, const std::string &in_label) : timer(in_timer), label(in_label) { } - const std::chrono::microseconds timer; + const Microseconds timer; const std::string label; }; @@ -158,7 +159,7 @@ public: // void PrintCounters(std::vector counters) { for (const auto counter : counters) { - printf("%s: %lims\n", counter.label.c_str(), counter.timer.count()); + printf("%s: %liµs\n", counter.label.c_str(), counter.timer.count()); } } @@ -181,23 +182,27 @@ void RunZoneBenchmark(const char *label, std::shared_ptr image) { 0, 0, image->Width(), image->Height()); testMonitor.SetRefImage(blackImage.get()); - std::chrono::microseconds totalTimeTaken(0); + Microseconds totalTimeTaken(0); + + printf("\n"); + printf("------- %s -------\n", label); // Run a series of passes over DetectMotion. const int numPasses = 10; for (int i=0; i < numPasses; i++) { - printf("\r(%d / %d) ", i+1, numPasses); + printf("\rPass %2d / %2d ", i+1, numPasses); fflush(stdout); + TimeSegmentAdder adder(totalTimeTaken); + Event::StringSet zoneSet; testMonitor.DetectMotion(*image.get(), zoneSet); } - printf("\n"); - printf("------- %s -------\n", label); + PrintCounters({ - CounterInfo(totalTimeTaken, "Total zone benchmark time")}); + CounterInfo(totalTimeTaken / numPasses, "Time per pass")}); } @@ -212,9 +217,9 @@ int main(int argc, char *argv[]) { // Detect SSE version. HwCapsDetect(); - RunZoneBenchmark("0%% delta", GenerateRandomImage(0, 0)); - RunZoneBenchmark("50%% delta", GenerateRandomImage(0, 255)); - RunZoneBenchmark("100%% delta", GenerateRandomImage(255, 255)); + RunZoneBenchmark("0% delta", GenerateRandomImage(0, 0)); + RunZoneBenchmark("50% delta", GenerateRandomImage(0, 255)); + RunZoneBenchmark("100% delta", GenerateRandomImage(255, 255)); return 0; } From e4542de6f2affd878060267057eee26a663f7404 Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 14:21:08 -0700 Subject: [PATCH 05/12] Fixed random image generation, and now it shows a proper (giant) perf difference between images that take longer for Zone's FILTERED_PIXELS detection to deal with. --- src/zmbenchmark.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index 90a2316b3..d194fc0a8 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -55,12 +55,16 @@ std::shared_ptr GenerateRandomImage( ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE); - const int range = maxVal - minVal + 1; + const int randMax = RAND_MAX; + const int range = maxVal - minVal; + for (int y=0; y < height; y++) { uint8_t *row = (uint8_t*)image->Buffer(0, y); - for (int x=0; x < width; x++) - row[x] = (rand() * range) / RAND_MAX + minVal; + for (int x=0; x < width; x++) { + uint64_t randVal = rand(); + row[x] = (uint8_t)((randVal * range) / randMax + minVal); + } } return std::shared_ptr(image); From 146ff1ac7aad48a2cedff972795dd1b5c2e31c3d Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 15:53:29 -0700 Subject: [PATCH 06/12] Print the benchmark results in a nicer table --- src/zmbenchmark.cpp | 171 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 29 deletions(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index d194fc0a8..b142879eb 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -17,6 +17,8 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // +#include +#include #include #include @@ -28,15 +30,87 @@ #include "zm_zone.h" +// +// This allows you to feed in a set of columns and timing rows, and print it +// out in a nice-looking table. +// +class TimingsTable { +public: + TimingsTable(const std::vector &inColumns) : columns(inColumns) {} + + void AddRow(const std::string &label, const std::vector &timings) { + assert(timings.size() == columns.size()); + Row row; + row.label = label; + row.timings = timings; + rows.push_back(row); + } + + void Print(const int columnPad = 5) { + // Figure out column widths. + std::vector widths(columns.size() + 1); + + // The first width is the max of the row labels. + auto result = std::max_element(rows.begin(), rows.end(), [](const Row &a, const Row &b) -> bool { return a.label.length() < b.label.length(); }); + widths[0] = result->label.length() + columnPad; + + // Calculate the rest of the column widths. + for (size_t i=0; i < columns.size(); i++) + widths[i+1] = columns[i].length() + columnPad; + + auto PrintColStr = [&](size_t icol, const std::string &str) { + printf("%s", str.c_str()); + PrintPadding(widths[icol] - str.length()); + }; + + // Print the header. + PrintColStr(0, ""); + for (size_t i=0; i < columns.size(); i++) { + PrintColStr(i+1, columns[i]); + } + printf("\n"); + + // Print the timings rows. + for (const auto &row : rows) { + PrintColStr(0, row.label); + + for (size_t i=0; i < row.timings.size(); i++) { + char num[128]; + sprintf(num, "%.2f", row.timings[i].count() / 1000.0); + PrintColStr(i+1, num); + } + + printf("\n"); + } + } + +private: + void PrintPadding(int count) { + std::string str(count, ' '); + printf("%s", str.c_str()); + } + + class Row { + public: + std::string label; + std::vector timings; + }; + + std::vector columns; + std::vector rows; +}; + + + // // Generate a greyscale image that simulates a delta that can be fed to -// Zone::CheckAlarms. +// Zone::CheckAlarms. This first creates a black image, and then it fills +// a box of a certain size inside the image with random data. This is to simulate +// a typical scene where most of the scene doesn't change except a specific region. // // Args: -// minVal: 0-255 value telling the minimum (random) value to initialize -// all the pixels to. -// maxVal: 0-255 value telling the maximum (random) value to initialize -// all the pixels to. +// changeBoxPercent: 0-100 value telling how large the box with random data should be. +// Set to 0 to leave the whole thing black. // width: The width of the new image. // height: The height of the new image. // @@ -44,10 +118,9 @@ // An image with all pixels initialized to values in the [minVal,maxVal] range. // std::shared_ptr GenerateRandomImage( - int minVal, - int maxVal, - int width = 3840, - int height = 2160) { + const int changeBoxPercent, + const int width = 3840, + const int height = 2160) { // Create the image. Image *image = new Image( width, @@ -55,15 +128,20 @@ std::shared_ptr GenerateRandomImage( ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE); - const int randMax = RAND_MAX; - const int range = maxVal - minVal; + // Set it to black initially. + memset((void*)image->Buffer(0, 0), 0, image->LineSize() * image->Height()); - for (int y=0; y < height; y++) + // Now randomize the pixels inside a box. + const int boxWidth = (width * changeBoxPercent) / 100; + const int boxHeight = (height * changeBoxPercent) / 100; + const int boxX = (int)((uint64_t)rand() * (width - boxWidth) / RAND_MAX); + const int boxY = (int)((uint64_t)rand() * (height - boxHeight) / RAND_MAX); + + for (int y=0; y < boxHeight; y++) { - uint8_t *row = (uint8_t*)image->Buffer(0, y); - for (int x=0; x < width; x++) { - uint64_t randVal = rand(); - row[x] = (uint8_t)((randVal * range) / randMax + minVal); + uint8_t *row = (uint8_t*)image->Buffer(boxX, boxY + y); + for (int x=0; x < boxWidth; x++) { + row[x] = (uint8_t)rand(); } } @@ -84,7 +162,7 @@ public: this->height = height; // Create a dummy ref_image. - std::shared_ptr tempImage = GenerateRandomImage(0, 0, width, height); + std::shared_ptr tempImage = GenerateRandomImage(0, width, height); ref_image = *tempImage.get(); shared_data = &temp_shared_data; @@ -174,28 +252,33 @@ void PrintCounters(std::vector counters) { // label: A label to be printed before the output. // // image: The image to run the tests on. +// +// p_filter_box: The size of the filter to use for alarm detection. +// +// Return: +// The average time taken for each DetectMotion call. // -void RunZoneBenchmark(const char *label, std::shared_ptr image) { +Microseconds RunDetectMotionBenchmark( + const std::string &label, + std::shared_ptr image, + const Vector2 &p_filter_box) { // Create a monitor to use for the benchmark. Give it 1 zone that uses // a 5x5 filter. TestMonitor testMonitor(image->Width(), image->Height()); - testMonitor.AddZone(Zone::CheckMethod::FILTERED_PIXELS, Vector2(5,5)); + testMonitor.AddZone(Zone::CheckMethod::FILTERED_PIXELS, p_filter_box); // Generate a black image to use as the reference image. std::shared_ptr blackImage = GenerateRandomImage( - 0, 0, image->Width(), image->Height()); + 0, image->Width(), image->Height()); testMonitor.SetRefImage(blackImage.get()); Microseconds totalTimeTaken(0); - printf("\n"); - printf("------- %s -------\n", label); - // Run a series of passes over DetectMotion. const int numPasses = 10; for (int i=0; i < numPasses; i++) { - printf("\rPass %2d / %2d ", i+1, numPasses); + printf("\r%s - pass %2d / %2d ", label.c_str(), i+1, numPasses); fflush(stdout); TimeSegmentAdder adder(totalTimeTaken); @@ -205,8 +288,27 @@ void RunZoneBenchmark(const char *label, std::shared_ptr image) { } printf("\n"); - PrintCounters({ - CounterInfo(totalTimeTaken / numPasses, "Time per pass")}); + return totalTimeTaken / numPasses; +} + + +void RunDetectMotionBenchmarks( + TimingsTable &table, + const std::vector &deltaBoxPercents, + const Vector2 &p_filter_box) { + std::vector timings; + + for (int percent : deltaBoxPercents) { + Microseconds timing = RunDetectMotionBenchmark( + std::string("DetectMotion: ") + std::to_string(p_filter_box.x_) + "x" + std::to_string(p_filter_box.y_) + " box, " + std::to_string(percent) + "% delta", + GenerateRandomImage(percent), + p_filter_box); + timings.push_back(timing); + } + + table.AddRow( + std::to_string(p_filter_box.x_) + "x" + std::to_string(p_filter_box.y_) + " filter", + timings); } @@ -220,11 +322,22 @@ int main(int argc, char *argv[]) { // Detect SSE version. HwCapsDetect(); + + // Setup the column titles for the TimingsTable we'll generate. + // Each column represents how large the box in the image is with delta pixels. + // Each row represents a different filter size. + const std::vector percents = {0, 10, 50, 100}; + std::vector columns(percents.size()); + std::transform(percents.begin(), percents.end(), columns.begin(), + [](const int percent) {return std::to_string(percent) + "% delta (ms)";}); + TimingsTable table(columns); - RunZoneBenchmark("0% delta", GenerateRandomImage(0, 0)); - RunZoneBenchmark("50% delta", GenerateRandomImage(0, 255)); - RunZoneBenchmark("100% delta", GenerateRandomImage(255, 255)); + std::vector filterSizes = {Vector2(3,3), Vector2(5,5), Vector2(13,13)}; + for (const auto filterSize : filterSizes) { + RunDetectMotionBenchmarks(table, percents, filterSize); + } + table.Print(); return 0; } From 2cf16eb49537b08f7e7f3f8a4b8c8cdae76ea461 Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 15:58:30 -0700 Subject: [PATCH 07/12] Removed some unused code and added more function comments --- src/zmbenchmark.cpp | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index b142879eb..b8a02ff69 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -38,6 +38,12 @@ class TimingsTable { public: TimingsTable(const std::vector &inColumns) : columns(inColumns) {} + // + // Add a row to the end of the table. + // + // Args: + // label: The name of the row (printed in the first column). + // timings: The values for all the other columns in this row. void AddRow(const std::string &label, const std::vector &timings) { assert(timings.size() == columns.size()); Row row; @@ -46,6 +52,12 @@ public: rows.push_back(row); } + // + // Print out the table. + // + // Args: + // columnPad: # characters between table columns + // void Print(const int columnPad = 5) { // Figure out column widths. std::vector widths(columns.size() + 1); @@ -219,32 +231,6 @@ private: -class CounterInfo { -public: - CounterInfo( - const Microseconds in_timer, - const std::string &in_label) : - timer(in_timer), - label(in_label) - { - } - - const Microseconds timer; - const std::string label; -}; - -// -// Print out a table of timing results. -// -// Args: -// counters: The list of counters to print out, and info about how to format it. -// -void PrintCounters(std::vector counters) { - for (const auto counter : counters) { - printf("%s: %liµs\n", counter.label.c_str(), counter.timer.count()); - } -} - // // Run zone benchmarks on the given image. // @@ -292,6 +278,19 @@ Microseconds RunDetectMotionBenchmark( } +// +// This runs a set of Monitor::DetectMotion benchmarks, one for each of the +// "delta box percents" that are passed in. This adds one row to the +// TimingsTable specified. +// +// Args: +// table: The table to add timings into. +// +// deltaBoxPercents: Each of these defines a box size in the delta images +// passed to DetectMotion (larger boxes make it slower, sometimes significantly so). +// +// p_filter_box: Defines the filter size used in DetectMotion. +// void RunDetectMotionBenchmarks( TimingsTable &table, const std::vector &deltaBoxPercents, From 814124251e3e4710ec411ff8e306e4346124382b Mon Sep 17 00:00:00 2001 From: Mike Dussault Date: Mon, 11 Oct 2021 23:57:20 +0000 Subject: [PATCH 08/12] Fixed a CodeQL complaint --- src/zmbenchmark.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index b8a02ff69..2c19d0b6f 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -141,7 +141,7 @@ std::shared_ptr GenerateRandomImage( ZM_SUBPIX_ORDER_NONE); // Set it to black initially. - memset((void*)image->Buffer(0, 0), 0, image->LineSize() * image->Height()); + memset((void*)image->Buffer(0, 0), 0, (size_t)image->LineSize() * (size_t)image->Height()); // Now randomize the pixels inside a box. const int boxWidth = (width * changeBoxPercent) / 100; From c6cac57fb1b3d4a3f891bd90c5f443b144c8c274 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Oct 2021 12:44:44 -0400 Subject: [PATCH 09/12] remove bogus wanring --- src/zm_packetqueue.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 77d9e9d87..8a393cf9c 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -154,7 +154,6 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { add_packet->packet.stream_index, video_stream_id, add_packet->keyframe, keep_keyframes, packet_counts[video_stream_id], pre_event_video_packet_count, ( *(pktQueue.begin()) != add_packet ) ); - Warning("Keyframe interval may be larger than MaxImageBufferCount and PreEventCount. Please increase MaxImageBufferCount"); return; } std::unique_lock lck(mutex); From 97b38bd4abe9fa7fcf69e6f68701f8a438aa6c25 Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Tue, 12 Oct 2021 18:53:31 +0200 Subject: [PATCH 10/12] Align changes with our codestyle See https://google.github.io/styleguide/cppguide.html for reference --- src/zm_time.h | 27 +++---- src/zmbenchmark.cpp | 190 ++++++++++++++++++++------------------------ 2 files changed, 100 insertions(+), 117 deletions(-) diff --git a/src/zm_time.h b/src/zm_time.h index ab2a8d000..d3d5b95c5 100644 --- a/src/zm_time.h +++ b/src/zm_time.h @@ -89,11 +89,11 @@ Duration duration_cast(timeval const &tv) { // duration to a microseconds clock. // class TimeSegmentAdder { -public: - TimeSegmentAdder(Microseconds &inTarget) : - target(inTarget), - startTime(std::chrono::steady_clock::now()), - finished(false) { + public: + TimeSegmentAdder(Microseconds &in_target) : + target_(in_target), + start_time_(std::chrono::steady_clock::now()), + finished_(false) { } ~TimeSegmentAdder() { @@ -102,23 +102,22 @@ public: // Call this to stop the timer and add the timed duration to `target`. void Finish() { - if (!finished) { - const TimePoint endTime = std::chrono::steady_clock::now(); - target += (std::chrono::duration_cast(endTime - startTime)); + if (!finished_) { + const TimePoint end_time = std::chrono::steady_clock::now(); + target_ += (std::chrono::duration_cast(end_time - start_time_)); } - finished = true; + finished_ = true; } -private: + private: // This is where we will add our duration to. - Microseconds ⌖ + Microseconds &target_; // The time we started. - const TimePoint startTime; + const TimePoint start_time_; // True when it has finished timing. - bool finished; + bool finished_; }; - #endif // ZM_TIME_H diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index 2c19d0b6f..2e9bd7678 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -18,9 +18,10 @@ // #include -#include +#include #include -#include +#include +#include #include "zm_config.h" #include "zm_image.h" @@ -29,14 +30,13 @@ #include "zm_utils.h" #include "zm_zone.h" - // // This allows you to feed in a set of columns and timing rows, and print it // out in a nice-looking table. // class TimingsTable { -public: - TimingsTable(const std::vector &inColumns) : columns(inColumns) {} + public: + explicit TimingsTable(std::vector in_columns) : columns_(std::move(in_columns)) {} // // Add a row to the end of the table. @@ -45,11 +45,11 @@ public: // label: The name of the row (printed in the first column). // timings: The values for all the other columns in this row. void AddRow(const std::string &label, const std::vector &timings) { - assert(timings.size() == columns.size()); + assert(timings.size() == columns_.size()); Row row; row.label = label; row.timings = timings; - rows.push_back(row); + rows_.push_back(row); } // @@ -58,17 +58,21 @@ public: // Args: // columnPad: # characters between table columns // - void Print(const int columnPad = 5) { + void Print(const int column_pad = 5) { // Figure out column widths. - std::vector widths(columns.size() + 1); + std::vector widths(columns_.size() + 1); // The first width is the max of the row labels. - auto result = std::max_element(rows.begin(), rows.end(), [](const Row &a, const Row &b) -> bool { return a.label.length() < b.label.length(); }); - widths[0] = result->label.length() + columnPad; + auto result = std::max_element(rows_.begin(), + rows_.end(), + [](const Row &a, const Row &b) -> bool { + return a.label.length() < b.label.length(); + }); + widths[0] = result->label.length() + column_pad; // Calculate the rest of the column widths. - for (size_t i=0; i < columns.size(); i++) - widths[i+1] = columns[i].length() + columnPad; + for (size_t i = 0 ; i < columns_.size() ; i++) + widths[i + 1] = columns_[i].length() + column_pad; auto PrintColStr = [&](size_t icol, const std::string &str) { printf("%s", str.c_str()); @@ -77,43 +81,40 @@ public: // Print the header. PrintColStr(0, ""); - for (size_t i=0; i < columns.size(); i++) { - PrintColStr(i+1, columns[i]); + for (size_t i = 0 ; i < columns_.size() ; i++) { + PrintColStr(i + 1, columns_[i]); } printf("\n"); // Print the timings rows. - for (const auto &row : rows) { + for (const Row &row : rows_) { PrintColStr(0, row.label); - for (size_t i=0; i < row.timings.size(); i++) { + for (size_t i = 0 ; i < row.timings.size() ; i++) { char num[128]; sprintf(num, "%.2f", row.timings[i].count() / 1000.0); - PrintColStr(i+1, num); + PrintColStr(i + 1, num); } printf("\n"); } } -private: - void PrintPadding(int count) { + private: + static void PrintPadding(int count) { std::string str(count, ' '); printf("%s", str.c_str()); } - class Row { - public: + struct Row { std::string label; std::vector timings; }; - std::vector columns; - std::vector rows; + std::vector columns_; + std::vector rows_; }; - - // // Generate a greyscale image that simulates a delta that can be fed to // Zone::CheckAlarms. This first creates a black image, and then it fills @@ -130,52 +131,43 @@ private: // An image with all pixels initialized to values in the [minVal,maxVal] range. // std::shared_ptr GenerateRandomImage( - const int changeBoxPercent, + const int change_box_percent, const int width = 3840, const int height = 2160) { // Create the image. - Image *image = new Image( - width, - height, - ZM_COLOUR_GRAY8, - ZM_SUBPIX_ORDER_NONE); + Image *image = new Image(width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE); // Set it to black initially. - memset((void*)image->Buffer(0, 0), 0, (size_t)image->LineSize() * (size_t)image->Height()); + memset((void *) image->Buffer(0, 0), 0, (size_t) image->LineSize() * (size_t) image->Height()); // Now randomize the pixels inside a box. - const int boxWidth = (width * changeBoxPercent) / 100; - const int boxHeight = (height * changeBoxPercent) / 100; - const int boxX = (int)((uint64_t)rand() * (width - boxWidth) / RAND_MAX); - const int boxY = (int)((uint64_t)rand() * (height - boxHeight) / RAND_MAX); + const int box_width = (width * change_box_percent) / 100; + const int box_height = (height * change_box_percent) / 100; + const int box_x = (int) ((uint64_t) rand() * (width - box_width) / RAND_MAX); + const int box_y = (int) ((uint64_t) rand() * (height - box_height) / RAND_MAX); - for (int y=0; y < boxHeight; y++) - { - uint8_t *row = (uint8_t*)image->Buffer(boxX, boxY + y); - for (int x=0; x < boxWidth; x++) { - row[x] = (uint8_t)rand(); + for (int y = 0 ; y < box_height ; y++) { + uint8_t *row = (uint8_t *) image->Buffer(box_x, box_y + y); + for (int x = 0 ; x < box_width ; x++) { + row[x] = (uint8_t) rand(); } } return std::shared_ptr(image); } - // // This is used to help rig up Monitor benchmarks. // -class TestMonitor : public Monitor -{ -public: - TestMonitor(int width, int height) { - cur_zone_id = 111; - +class TestMonitor : public Monitor { + public: + TestMonitor(int width, int height) : cur_zone_id(111) { this->width = width; this->height = height; // Create a dummy ref_image. std::shared_ptr tempImage = GenerateRandomImage(0, width, height); - ref_image = *tempImage.get(); + ref_image = *tempImage; shared_data = &temp_shared_data; } @@ -188,49 +180,44 @@ public: // // p_filter_box: The size of the filter to use. // - void AddZone(Zone::CheckMethod checkMethod, const Vector2 &p_filter_box=Vector2(5,5)) { - const int p_min_pixel_threshold = 50; - const int p_max_pixel_threshold = 255; - const int p_min_alarm_pixels = 1000; - const int p_max_alarm_pixels = 10000000; + void AddZone(Zone::CheckMethod checkMethod, const Vector2 &p_filter_box = Vector2(5, 5)) { + const int p_min_pixel_threshold = 50; + const int p_max_pixel_threshold = 255; + const int p_min_alarm_pixels = 1000; + const int p_max_alarm_pixels = 10000000; - const int zone_id = cur_zone_id++; - const std::string zone_label = std::string("zone_") + std::to_string(zone_id); - const Zone::ZoneType zoneType = Zone::ZoneType::ACTIVE; - const Polygon poly({ - Vector2(0, 0), - Vector2(width-1, 0), - Vector2(width-1, height-1), - Vector2(0, height-1)}); + const int zone_id = cur_zone_id++; + const std::string zone_label = std::string("zone_") + std::to_string(zone_id); + const Zone::ZoneType zone_type = Zone::ZoneType::ACTIVE; + const Polygon poly({Vector2(0, 0), + Vector2(width - 1, 0), + Vector2(width - 1, height - 1), + Vector2(0, height - 1)}); - Zone zone( - this, - zone_id, - zone_label.c_str(), - zoneType, - poly, - kRGBGreen, - Zone::CheckMethod::FILTERED_PIXELS, - p_min_pixel_threshold, - p_max_pixel_threshold, - p_min_alarm_pixels, - p_max_alarm_pixels, - p_filter_box - ); - zones.push_back(zone); + Zone zone(this, + zone_id, + zone_label.c_str(), + zone_type, + poly, + kRGBGreen, + Zone::CheckMethod::FILTERED_PIXELS, + p_min_pixel_threshold, + p_max_pixel_threshold, + p_min_alarm_pixels, + p_max_alarm_pixels, + p_filter_box); + zones.push_back(zone); } void SetRefImage(const Image *image) { ref_image = *image; } -private: + private: SharedData temp_shared_data; int cur_zone_id; }; - - // // Run zone benchmarks on the given image. // @@ -244,10 +231,9 @@ private: // Return: // The average time taken for each DetectMotion call. // -Microseconds RunDetectMotionBenchmark( - const std::string &label, - std::shared_ptr image, - const Vector2 &p_filter_box) { +Microseconds RunDetectMotionBenchmark(const std::string &label, + std::shared_ptr image, + const Vector2 &p_filter_box) { // Create a monitor to use for the benchmark. Give it 1 zone that uses // a 5x5 filter. TestMonitor testMonitor(image->Width(), image->Height()); @@ -255,29 +241,27 @@ Microseconds RunDetectMotionBenchmark( // Generate a black image to use as the reference image. std::shared_ptr blackImage = GenerateRandomImage( - 0, image->Width(), image->Height()); + 0, image->Width(), image->Height()); testMonitor.SetRefImage(blackImage.get()); Microseconds totalTimeTaken(0); // Run a series of passes over DetectMotion. const int numPasses = 10; - for (int i=0; i < numPasses; i++) - { - printf("\r%s - pass %2d / %2d ", label.c_str(), i+1, numPasses); + for (int i = 0 ; i < numPasses ; i++) { + printf("\r%s - pass %2d / %2d ", label.c_str(), i + 1, numPasses); fflush(stdout); TimeSegmentAdder adder(totalTimeTaken); Event::StringSet zoneSet; - testMonitor.DetectMotion(*image.get(), zoneSet); + testMonitor.DetectMotion(*image, zoneSet); } printf("\n"); return totalTimeTaken / numPasses; } - // // This runs a set of Monitor::DetectMotion benchmarks, one for each of the // "delta box percents" that are passed in. This adds one row to the @@ -293,45 +277,45 @@ Microseconds RunDetectMotionBenchmark( // void RunDetectMotionBenchmarks( TimingsTable &table, - const std::vector &deltaBoxPercents, + const std::vector &delta_box_percents, const Vector2 &p_filter_box) { std::vector timings; - for (int percent : deltaBoxPercents) { + for (int percent : delta_box_percents) { Microseconds timing = RunDetectMotionBenchmark( - std::string("DetectMotion: ") + std::to_string(p_filter_box.x_) + "x" + std::to_string(p_filter_box.y_) + " box, " + std::to_string(percent) + "% delta", - GenerateRandomImage(percent), - p_filter_box); + std::string("DetectMotion: ") + std::to_string(p_filter_box.x_) + "x" + std::to_string(p_filter_box.y_) + + " box, " + std::to_string(percent) + "% delta", + GenerateRandomImage(percent), + p_filter_box); timings.push_back(timing); } table.AddRow( - std::to_string(p_filter_box.x_) + "x" + std::to_string(p_filter_box.y_) + " filter", - timings); + std::to_string(p_filter_box.x_) + "x" + std::to_string(p_filter_box.y_) + " filter", + timings); } - int main(int argc, char *argv[]) { srand(111); // Init global stuff that we need. config.font_file_location = "../fonts/default.zmfnt"; config.event_close_mode = "time"; - config.cpu_extensions = 1; + config.cpu_extensions = true; // Detect SSE version. HwCapsDetect(); - + // Setup the column titles for the TimingsTable we'll generate. // Each column represents how large the box in the image is with delta pixels. // Each row represents a different filter size. const std::vector percents = {0, 10, 50, 100}; std::vector columns(percents.size()); std::transform(percents.begin(), percents.end(), columns.begin(), - [](const int percent) {return std::to_string(percent) + "% delta (ms)";}); + [](const int percent) { return std::to_string(percent) + "% delta (ms)"; }); TimingsTable table(columns); - std::vector filterSizes = {Vector2(3,3), Vector2(5,5), Vector2(13,13)}; + std::vector filterSizes = {Vector2(3, 3), Vector2(5, 5), Vector2(13, 13)}; for (const auto filterSize : filterSizes) { RunDetectMotionBenchmarks(table, percents, filterSize); } From c027b7a38d3637af69423a513b14f97c098ecd24 Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Tue, 12 Oct 2021 19:05:22 +0200 Subject: [PATCH 11/12] Fix some clang-tidy warnings --- src/zmbenchmark.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index 2e9bd7678..926e073a7 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -60,7 +60,7 @@ class TimingsTable { // void Print(const int column_pad = 5) { // Figure out column widths. - std::vector widths(columns_.size() + 1); + std::vector widths(columns_.size() + 1); // The first width is the max of the row labels. auto result = std::max_element(rows_.begin(), @@ -91,8 +91,7 @@ class TimingsTable { PrintColStr(0, row.label); for (size_t i = 0 ; i < row.timings.size() ; i++) { - char num[128]; - sprintf(num, "%.2f", row.timings[i].count() / 1000.0); + std::string num = stringtf("%.2f", std::chrono::duration_cast(row.timings[i]).count()); PrintColStr(i + 1, num); } @@ -101,7 +100,7 @@ class TimingsTable { } private: - static void PrintPadding(int count) { + static void PrintPadding(size_t count) { std::string str(count, ' '); printf("%s", str.c_str()); } @@ -232,7 +231,7 @@ class TestMonitor : public Monitor { // The average time taken for each DetectMotion call. // Microseconds RunDetectMotionBenchmark(const std::string &label, - std::shared_ptr image, + const std::shared_ptr& image, const Vector2 &p_filter_box) { // Create a monitor to use for the benchmark. Give it 1 zone that uses // a 5x5 filter. From cd45c6155519798d03111b4ebef806dd0aa6f9ff Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Tue, 12 Oct 2021 19:18:21 +0200 Subject: [PATCH 12/12] Use mt19937 as PRNG Reasons: It's faster than rand() and can be made thread-safe --- src/zmbenchmark.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/zmbenchmark.cpp b/src/zmbenchmark.cpp index 926e073a7..244094a54 100644 --- a/src/zmbenchmark.cpp +++ b/src/zmbenchmark.cpp @@ -19,8 +19,9 @@ #include #include -#include #include +#include +#include #include #include "zm_config.h" @@ -30,6 +31,8 @@ #include "zm_utils.h" #include "zm_zone.h" +static std::mt19937 mt_rand(111); + // // This allows you to feed in a set of columns and timing rows, and print it // out in a nice-looking table. @@ -142,13 +145,13 @@ std::shared_ptr GenerateRandomImage( // Now randomize the pixels inside a box. const int box_width = (width * change_box_percent) / 100; const int box_height = (height * change_box_percent) / 100; - const int box_x = (int) ((uint64_t) rand() * (width - box_width) / RAND_MAX); - const int box_y = (int) ((uint64_t) rand() * (height - box_height) / RAND_MAX); + const int box_x = (int) ((uint64_t) mt_rand() * (width - box_width) / RAND_MAX); + const int box_y = (int) ((uint64_t) mt_rand() * (height - box_height) / RAND_MAX); for (int y = 0 ; y < box_height ; y++) { uint8_t *row = (uint8_t *) image->Buffer(box_x, box_y + y); for (int x = 0 ; x < box_width ; x++) { - row[x] = (uint8_t) rand(); + row[x] = (uint8_t) mt_rand(); } } @@ -295,8 +298,6 @@ void RunDetectMotionBenchmarks( } int main(int argc, char *argv[]) { - srand(111); - // Init global stuff that we need. config.font_file_location = "../fonts/default.zmfnt"; config.event_close_mode = "time";