KiCad PCB EDA Suite
Loading...
Searching...
No Matches
trace_capture.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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "trace_capture.h"
21
22#include <cmath>
23#include <cstdio>
24
25
27 m_prev( wxLog::GetActiveTarget() )
28{
29}
30
31
33{
34 m_providerMs.clear();
35 m_totalMs = 0.0;
36}
37
38
44static bool extractMs( const wxString& aMsg, double& aMs )
45{
46 int tookPos = aMsg.Find( wxT( " took " ) );
47
48 if( tookPos == wxNOT_FOUND )
49 return false;
50
51 wxString tail = aMsg.Mid( tookPos + 6 );
52
53 if( !tail.EndsWith( wxT( " ms" ) ) )
54 return false;
55
56 wxString number = tail.Left( tail.length() - 3 );
57
58 return number.ToCDouble( &aMs );
59}
60
61
62bool DRC_PROFILE_LOG::ParseLine( const wxString& aMsg )
63{
64 // The active wxLog target receives the fully formatted record, which may carry a
65 // timestamp and a "Trace: (KICAD_DRC_PROFILE) " prefix ahead of the engine text. Anchor
66 // on the known substrings rather than the start of the line so the prefix is tolerated.
67 int provPos = aMsg.Find( wxT( "DRC provider '" ) );
68
69 if( provPos != wxNOT_FOUND )
70 {
71 wxString rest = aMsg.Mid( provPos + 14 );
72 int quote = rest.Find( '\'' );
73
74 if( quote == wxNOT_FOUND )
75 return false;
76
77 wxString name = rest.Left( quote );
78 double ms = 0.0;
79
80 if( !extractMs( aMsg, ms ) )
81 return false;
82
83 m_providerMs[name] += ms;
84
85 return true;
86 }
87
88 int totalPos = aMsg.Find( wxT( "DRC took " ) );
89
90 if( totalPos != wxNOT_FOUND )
91 {
92 wxString tail = aMsg.Mid( totalPos + 9 );
93
94 if( !tail.EndsWith( wxT( " ms" ) ) )
95 return false;
96
97 wxString number = tail.Left( tail.length() - 3 );
98 double ms = 0.0;
99
100 if( !number.ToCDouble( &ms ) )
101 return false;
102
103 m_totalMs = ms;
104
105 return true;
106 }
107
108 return false;
109}
110
111
112void DRC_PROFILE_LOG::DoLogTextAtLevel( wxLogLevel aLevel, const wxString& aMsg )
113{
114 ParseLine( aMsg );
115
116 if( m_prev && m_prev != this )
117 m_prev->LogTextAtLevel( aLevel, aMsg );
118}
119
120
122{
123 DRC_PROFILE_LOG parser;
124
125 const wxString lines[] = {
126 wxT( "DRC provider 'courtyard_overlap' took 12.345 ms" ),
127 wxT( "DRC provider 'matched length' took 0.500 ms" ),
128 wxT( "DRC took 42.000 ms" )
129 };
130
131 for( const wxString& line : lines )
132 {
133 if( !parser.ParseLine( line ) )
134 {
135 std::printf( "selftest FAIL: unparsed line: %s\n", static_cast<const char*>( line.utf8_str() ) );
136 return 1;
137 }
138 }
139
140 int rv = 0;
141
142 auto checkProvider = [&]( const wxString& aName, double aExpected )
143 {
144 auto it = parser.ProviderMs().find( aName );
145
146 if( it == parser.ProviderMs().end() || std::fabs( it->second - aExpected ) > 1e-9 )
147 {
148 std::printf( "selftest FAIL: provider '%s' expected %.3f got %.3f\n",
149 static_cast<const char*>( aName.utf8_str() ), aExpected,
150 it == parser.ProviderMs().end() ? -1.0 : it->second );
151 rv = 1;
152 }
153 };
154
155 checkProvider( wxT( "courtyard_overlap" ), 12.345 );
156 checkProvider( wxT( "matched length" ), 0.500 );
157
158 if( std::fabs( parser.TotalMs() - 42.000 ) > 1e-9 )
159 {
160 std::printf( "selftest FAIL: total expected 42.000 got %.3f\n", parser.TotalMs() );
161 rv = 1;
162 }
163
164 if( parser.ProviderMs().size() != 2 )
165 {
166 std::printf( "selftest FAIL: expected 2 providers got %zu\n", parser.ProviderMs().size() );
167 rv = 1;
168 }
169
170 if( rv == 0 )
171 std::printf( "selftest PASS\n" );
172
173 return rv;
174}
const char * name
wxLog chain target that scrapes the engine's "KICAD_DRC_PROFILE" trace channel.
const std::map< wxString, double > & ProviderMs() const
void DoLogTextAtLevel(wxLogLevel aLevel, const wxString &aMsg) override
double TotalMs() const
bool ParseLine(const wxString &aMsg)
Parse a single trace message into the maps.
std::map< wxString, double > m_providerMs
int RunTraceCaptureSelftest()
Run the three fixed self-test lines through a fresh parser and confirm the parsed provider map and to...
static bool extractMs(const wxString &aMsg, double &aMs)
Pull the millisecond value out of a "... took <ms> ms" tail.