KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_group_save_perf.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
37
38#include <algorithm>
39#include <cstddef>
40#include <filesystem>
41#include <limits>
42#include <memory>
43#include <string>
44#include <vector>
45
47
48#include <board.h>
49#include <core/profile.h>
50#include <lset.h>
51#include <pcb_group.h>
52#include <pcb_shape.h>
55
56
57namespace
58{
59
69std::unique_ptr<BOARD> buildBoardWithGroups( std::size_t aGroupCount, std::size_t aTotalShapes )
70{
71 auto board = std::make_unique<BOARD>();
72 board->SetEnabledLayers( LSET::AllCuMask() | LSET::AllTechMask() );
73
74 std::vector<PCB_GROUP*> groups;
75 groups.reserve( aGroupCount );
76
77 for( std::size_t g = 0; g < aGroupCount; ++g )
78 {
79 PCB_GROUP* group = new PCB_GROUP( board.get() );
80 group->SetName( wxString::Format( wxT( "G%zu" ), g ) );
81 board->Add( group );
82 groups.push_back( group );
83 }
84
85 for( std::size_t i = 0; i < aTotalShapes; ++i )
86 {
87 PCB_SHAPE* shape = new PCB_SHAPE( board.get(), SHAPE_T::SEGMENT );
88 int x = static_cast<int>( i );
89 shape->SetStart( VECTOR2I( x, 0 ) );
90 shape->SetEnd( VECTOR2I( x + pcbIUScale.mmToIU( 1 ), 0 ) );
91 shape->SetLayer( F_SilkS );
92 shape->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.1 ), LINE_STYLE::SOLID ) );
93 board->Add( shape );
94
95 if( !groups.empty() )
96 groups[i % groups.size()]->AddItem( shape );
97 }
98
99 return board;
100}
101
102
109double saveBoardSeconds( const std::filesystem::path& aDir, std::size_t aGroupCount,
110 std::size_t aTotalShapes )
111{
112 auto board = buildBoardWithGroups( aGroupCount, aTotalShapes );
113
114 const std::filesystem::path savePath =
115 aDir / ( "groups" + std::to_string( aGroupCount ) + ".kicad_pcb" );
116
117 PROF_TIMER timer;
118 KI_TEST::DumpBoardToFile( *board, savePath.string() );
119 timer.Stop();
120
121 return timer.msecs() / 1000.0;
122}
123
124} // namespace
125
126
127BOOST_AUTO_TEST_SUITE( GroupSavePerformance )
128
129
130
141BOOST_AUTO_TEST_CASE( SaveScalesLinearlyWithGroupCount )
142{
143 constexpr std::size_t kTotalShapes = 5000;
144
145 KI_TEST::TEMPORARY_DIRECTORY tempDir( "group_save_perf", "" );
146
147 // Warm up the save path (allocators, formatter, disk cache) so the first
148 // measurement is not dominated by one-shot setup costs.
149 (void) saveBoardSeconds( tempDir.GetPath(), 10, 100 );
150
151 // Take the best of two runs per configuration so a scheduler stall during
152 // a single save cannot fail the test on a loaded CI machine.
153 auto bestSave =
154 [&]( std::size_t aGroupCount )
155 {
156 double best = std::numeric_limits<double>::infinity();
157
158 for( int run = 0; run < 2; ++run )
159 {
160 best = std::min( best, saveBoardSeconds( tempDir.GetPath(), aGroupCount,
161 kTotalShapes ) );
162 }
163
164 return best;
165 };
166
167 double t100 = bestSave( 100 );
168 double t5000 = bestSave( 5000 );
169
170 BOOST_TEST_MESSAGE( "Save time (s) 100 groups : " << t100 );
171 BOOST_TEST_MESSAGE( "Save time (s) 5000 groups : " << t5000 );
172
173 // Use a 5 ms floor so very fast runs do not produce huge ratios from
174 // measurement jitter.
175 const double floorSec = 0.005;
176 double ratio = t5000 / std::max( t100, floorSec );
177
178 BOOST_TEST_MESSAGE( "Ratio (5000 / 100): " << ratio );
179
180 // Linear scaling in the group count gives a small single-digit ratio here
181 // because the serialised output is dominated by the shared 5000 shapes.
182 // The unfixed O(Groups * BoardItems) code rescans the full item cache for
183 // each of the 5000 groups and lands far above this bound.
184 BOOST_CHECK_LT( ratio, 20.0 );
185}
186
187
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
General utilities for PCB file IO for QA programs.
A temporary directory that will be deleted when it goes out of scope.
const std::filesystem::path & GetPath() const
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition lset.cpp:672
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:49
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
A small class to help profiling.
Definition profile.h:46
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:86
double msecs(bool aSinceLast=false)
Definition profile.h:147
Simple container to manage line stroke parameters.
@ SEGMENT
Definition eda_shape.h:46
@ F_SilkS
Definition layer_ids.h:96
void DumpBoardToFile(BOARD &board, const std::string &aFilename)
Utility function to simply write a Board out to a file.
Class to handle a set of BOARD_ITEMs.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683