// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause // .NAME Test speed of Observers. // .SECTION Description // Probe the speed of vtkObject::AddObserver, vtkObject::InvokeEvent and // vtkObject::RemoveObserver #include "vtkCollection.h" #include "vtkCommand.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkSmartPointer.h" #include "vtkTimerLog.h" #include #include #include // How many times the tests are run to average the elapsed time. static constexpr int STRESS_COUNT = 5; // Description: // Type of console outputs. // CDash writes perfs as for unit test regression // Csv writes perfs as series of 2D table for easy plotting in spreadsheet apps // Details writes more timing information enum VerboseType { None = 0x0, CDash = 0x1, Csv = 0x2, Details = 0x4 }; static constexpr int VERBOSE_MODE = CDash; //------------------------------------------------------------------------------ class vtkSimpleCommand : public vtkCommand { public: static vtkSimpleCommand* New() { return new vtkSimpleCommand(); } vtkTypeMacro(vtkSimpleCommand, vtkCommand); void Execute(vtkObject*, unsigned long, void*) override { vtkSimpleCommand::MTime.Modified(); } protected: static vtkTimeStamp MTime; }; vtkTimeStamp vtkSimpleCommand::MTime; //------------------------------------------------------------------------------ double TestStressInvoke(int observerCount, int eventCount, int invokeCount); //------------------------------------------------------------------------------ int TestObserversPerformance(int, char*[]) { bool res = true; int maxInvokeCount = 1000; int maxEventCount = 100; int maxObserverCount = 1000; for (int eventCount = 1; eventCount <= maxEventCount; eventCount *= 10) { if (VERBOSE_MODE & Csv) { std::cout << eventCount << " events:" << "\n" << ","; for (int observerCount = 1; observerCount <= maxObserverCount; observerCount *= 10) { std::cout << observerCount << ","; } std::cout << std::endl; } for (int invokeCount = 1; invokeCount <= maxInvokeCount; invokeCount *= 10) { if (VERBOSE_MODE & Csv) { std::cout << invokeCount << ","; } for (int observerCount = 1; observerCount <= maxObserverCount; observerCount *= 10) { double time = TestStressInvoke(observerCount, eventCount, invokeCount); if (VERBOSE_MODE & Csv) { std::cout << time << ","; } } if (VERBOSE_MODE & Csv) { std::cout << std::endl; } } } return res ? EXIT_SUCCESS : EXIT_FAILURE; } //------------------------------------------------------------------------------ double StressInvoke(const int observerCount, const int eventCount, const int invokeCount) { if (VERBOSE_MODE & Details) { std::cout << "StressInvoke " << invokeCount << " invokes " << "on " << eventCount << " events observed by " << observerCount / eventCount << " observers each." << std::endl; } vtkObject* volcano = vtkObject::New(); std::vector> observers; vtkNew totalTimer; vtkNew addTimer; vtkNew invokeTimer; vtkNew removeTimer; totalTimer->StartTimer(); addTimer->StartTimer(); for (int observerIDX = 0; observerIDX < observerCount; observerIDX += eventCount) { for (int event = 0; event < eventCount; ++event) { vtkNew observer; volcano->AddObserver(event + 1000, observer.GetPointer()); observers.emplace_back(observer.GetPointer()); } } addTimer->StopTimer(); invokeTimer->StartTimer(); for (int invoke = 0; invoke < invokeCount; invoke += eventCount) { for (int event = 0; event < eventCount; ++event) { volcano->InvokeEvent(event + 1000); } } invokeTimer->StopTimer(); removeTimer->StartTimer(); observers.clear(); volcano->Delete(); removeTimer->StopTimer(); totalTimer->StopTimer(); if (VERBOSE_MODE & Details) { std::cout << " Add: " << addTimer->GetElapsedTime() << " seconds" << "\n" << " Invoke: " << invokeTimer->GetElapsedTime() << " seconds" << "\n" << " Remove: " << removeTimer->GetElapsedTime() << " seconds" << "\n" << ">>>> Total: " << totalTimer->GetElapsedTime() << " seconds" << "\n"; } return totalTimer->GetElapsedTime(); } //------------------------------------------------------------------------------ double TestStressInvoke(int observerCount, int eventCount, int invokeCount) { double meanDuration = 0.0; for (int i = 0; i < STRESS_COUNT; ++i) { meanDuration += StressInvoke(observerCount, eventCount, invokeCount); } meanDuration /= STRESS_COUNT; if (VERBOSE_MODE == CDash) { std::cout << "" << meanDuration << "" << std::endl; } return meanDuration; }