diff --git a/dox/dev_guides/debug/debug.md b/dox/dev_guides/debug/debug.md index ceed13b10c..1f43b8f4f1 100644 --- a/dox/dev_guides/debug/debug.md +++ b/dox/dev_guides/debug/debug.md @@ -269,4 +269,21 @@ Handle_TCollection_HAsciiString { } ~~~~~ -In Visual Studio 2012 and later, visualizers can be put in a separate file in subdirectory *Visualizers*. See file *occt.natvis* for example. \ No newline at end of file +In Visual Studio 2012 and later, visualizers can be put in a separate file in subdirectory *Visualizers*. See file *occt.natvis* for example. + +@section occt_debug_perf Performance measurement tools + +It is recommended to use specialized performance analysis tools to profile OCCT and application code. +However, when such tools are not available or cannot be used for some reason, tools provided by OCD package can be used: see low-level C functions and macros defined OSD_PerfMeter.h, and OSD_PerfMeter class. + +This tool maintains an array of 100 global performance counters that can be started and stopped independently. +Adding performance counter to a function of interest allows to get statistics on number of calls and total execution time of the function. +In C++ code, this can be achieved by creating local variable OSD_PerfMeter in each block of code to be measured. +In C or Fortran code, use functions perf_start_meter and perf_stop_meter to start and stop the counter. +Note that this instrumentation is intended to be removed when profiling is completed. +Macros provided in OSD_PerfMeter.h can be used to keep instrumentation code permanently, but enable it only when macro PERF_ENABLE_METERS is defined. +Each counter has its name shown when the collected statistics are printed. + +In DRAW, use command dperf to prints all performance statistics. + +Note that performance counters are not thread-safe. diff --git a/src/Draw/Draw_BasicCommands.cxx b/src/Draw/Draw_BasicCommands.cxx index 6499309bcd..500718a7c3 100644 --- a/src/Draw/Draw_BasicCommands.cxx +++ b/src/Draw/Draw_BasicCommands.cxx @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef _WIN32 @@ -721,6 +722,21 @@ static int dmeminfo (Draw_Interpretor& theDI, return 0; } +//============================================================================== +//function : dperf +//purpose : +//============================================================================== + +static int dperf (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec) +{ + // reset if argument is provided and it is not '0' + int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0); + char buffer[25600]; + perf_sprint_all_meters (buffer, 25600 - 1, reset); + theDI << buffer; + return 0; +} + //============================================================================== //function : dtracelevel //purpose : @@ -843,6 +859,8 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands) "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]" " : memory counters for this process", __FILE__, dmeminfo, g); + theCommands.Add("dperf","dperf [reset] -- show performance counters, reset if argument is provided", + __FILE__,dperf,g); // Logging commands; note that their names are hard-coded in the code // of Draw_Interpretor, thus should not be changed without update of that code! diff --git a/src/OSD/OSD_PerfMeter.cxx b/src/OSD/OSD_PerfMeter.cxx index 498f1b9cbd..3c0fbe6058 100644 --- a/src/OSD/OSD_PerfMeter.cxx +++ b/src/OSD/OSD_PerfMeter.cxx @@ -218,18 +218,36 @@ int perf_get_meter (const char * const MeterName, Function : perf_print_all_meters Purpose : Prints on stdout the cumulated time and the number of enters for each meter in MeterTable; - resets all meters -Output : none -Returns : none + resets all meters if reset is non-null ======================================================================*/ -void perf_print_all_meters (void) +void perf_print_all_meters (int reset) { + char buffer[MAX_METERS * 256]; + perf_sprint_all_meters (buffer, MAX_METERS * 256, reset); + printf ("%s", buffer); +} + +/*====================================================================== +Function : perf_print_all_meters +Purpose : Prints to string buffer the cumulated time and the number of + enters for each meter in MeterTable; + resets all meters if reset is non-null +======================================================================*/ +void perf_sprint_all_meters (char *buffer, int length, int reset) +{ + char string[256]; + int i; for (i=0; inb_enter) { - printf (" Perf meter results :" - " enters seconds \xe6sec/enter\n"); + int n = sprintf (string, " Perf meter results : enters seconds sec/enter\n"); + if (n < length) + { + memcpy (buffer, string, n); + buffer += n; + length -= n; + } break; } } @@ -240,18 +258,29 @@ void perf_print_all_meters (void) if (ptc && ptc->nb_enter) { const double secs = ptc->cumul_time; + int n = 0; if (ptc->start_time) - printf ("Warning : meter %s has not been stopped\n", ptc->name); + n = sprintf (string, "Warning : meter %42s has not been stopped\n", ptc->name); - printf ("%-42s : %7d %8.2f %10.2f\n", - ptc->name, ptc->nb_enter, secs, - (secs>0. ? 1000000 * secs/ptc->nb_enter : 0.)); + n += sprintf (string + n, "%-42s : %7d %8.2f %10.2f\n", + ptc->name, ptc->nb_enter, secs, + (secs>0. ? 1000000 * secs/ptc->nb_enter : 0.)); + if (n < length) + { + memcpy (buffer, string, n); + buffer += n; + length -= n; + } - ptc->cumul_time = 0; - ptc->start_time = 0; - ptc->nb_enter = 0; + if (reset) + { + ptc->cumul_time = 0; + ptc->start_time = 0; + ptc->nb_enter = 0; + } } } + *buffer = '\0'; } /*====================================================================== @@ -261,17 +290,7 @@ Returns : none ======================================================================*/ void perf_close_meter (const char * const MeterName) { - const int ic = find_meter (MeterName); - if (ic >= 0 && MeterTable[ic].nb_enter) { - t_TimeCounter * const ptc = &MeterTable[ic]; - if (ptc->start_time) - printf (" ===> Warning : meter %s has not been stopped\n", ptc->name); - printf (" ===> [%s] : %d enters, %9.3f seconds\n", - ptc->name, ptc->nb_enter, ptc->cumul_time); - ptc->cumul_time = 0; - ptc->start_time = 0; - ptc->nb_enter = 0; - } + perf_close_imeter (find_meter (MeterName)); } /*====================================================================== @@ -311,7 +330,7 @@ void perf_destroy_all_meters (void) void perf_print_and_destroy (void) { - perf_print_all_meters (); + perf_print_all_meters (0); perf_destroy_all_meters (); } diff --git a/src/OSD/OSD_PerfMeter.h b/src/OSD/OSD_PerfMeter.h index a2a228d9b5..d7feb91b70 100644 --- a/src/OSD/OSD_PerfMeter.h +++ b/src/OSD/OSD_PerfMeter.h @@ -65,8 +65,8 @@ * @def PERF_PRINT_ALL * Prints all existing meters which have been entered at least once and resets them. */ -#define PERF_PRINT_ALL { \ - perf_print_all_meters(); \ +#define PERF_PRINT_ALL() { \ + perf_print_all_meters(1); \ } #else @@ -74,7 +74,7 @@ #define PERF_START_METER(_m_name) #define PERF_STOP_METER(_m_name) #define PERF_CLOSE_METER(_m_name) - #define PERF_PRINT_ALL + #define PERF_PRINT_ALL() #endif /** @@ -143,9 +143,18 @@ Standard_EXPORTEXTERNC void perf_close_imeter (const int theMeterId); /** * Prints on stdout the cumulated time and the number of enters for each alive meter which have the number of enters > 0. + * Resets all meters if reset is non-null. + */ +Standard_EXPORTEXTERNC void perf_print_all_meters (int reset); + +/** + * Prints to supplied string buffer the cumulated time and the number of enters + * for each alive meter with the number of enters > 0. + * If buffer length is not sufficient, data of some meters may be lost. + * It is recommended to reserve 256 bytes per meter, 25600 bytes should fit all. * Resets all meters. */ -Standard_EXPORTEXTERNC void perf_print_all_meters (void); +Standard_EXPORTEXTERNC void perf_sprint_all_meters (char *buffer, int length, int reset); /** * Deletes all meters and frees memory. @@ -154,7 +163,7 @@ Standard_EXPORTEXTERNC void perf_destroy_all_meters (void); /** * ATTENTION!!! - * This func calls both perf_print_all_meters() and perf_destroy_all_meters() + * This func calls perf_print_all_meters() and perf_destroy_all_meters() * and is called automatically at the end of a program via system call atexit(). */ Standard_EXPORTEXTERNC void perf_print_and_destroy (void); diff --git a/src/QANCollection/QANCollection_Perf.cxx b/src/QANCollection/QANCollection_Perf.cxx index c00d33ce32..a0fec09dfb 100644 --- a/src/QANCollection/QANCollection_Perf.cxx +++ b/src/QANCollection/QANCollection_Perf.cxx @@ -89,8 +89,16 @@ DEFINE_SEQUENCE(QANCollection_SequencePerf,QANCollection_BaseColPerf,ItemType) DEFINE_HSEQUENCE(QANCollection_HSequencePerf,QANCollection_SequencePerf) IMPLEMENT_HSEQUENCE(QANCollection_HSequencePerf) +static void printAllMeters (Draw_Interpretor& theDI) +{ + char buffer[25600]; + perf_sprint_all_meters (buffer, 25600 - 1, 1); + theDI << buffer; +} + // ===================== Test perform of Array1 type ========================== -static void CompArray1 (const Standard_Integer theRep, +static void CompArray1 (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -169,11 +177,12 @@ static void CompArray1 (const Standard_Integer theRep, ////////////////////////////////aTOper.Stop(); PERF_STOP_METER("TCollection_Array1 operator=") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of Array2 type ========================== -static void CompArray2 (const Standard_Integer theRep, +static void CompArray2 (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j,k; @@ -256,11 +265,12 @@ static void CompArray2 (const Standard_Integer theRep, ////////////////////////////////aTOper.Stop(); PERF_STOP_METER("TCollection_Array2 operator=") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of List type ========================== -static void CompList (const Standard_Integer theRep, +static void CompList (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -327,11 +337,12 @@ static void CompList (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_List clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of Sequence type ========================== -static void CompSequence (const Standard_Integer theRep, +static void CompSequence (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -420,11 +431,12 @@ static void CompSequence (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_Sequence clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of Map type ========================== -static void CompMap (const Standard_Integer theRep, +static void CompMap (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -513,11 +525,12 @@ static void CompMap (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_Map clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of DataMap type ========================== -static void CompDataMap (const Standard_Integer theRep, +static void CompDataMap (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -608,11 +621,12 @@ static void CompDataMap (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_DataMap clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of DoubleMap type ========================== -static void CompDoubleMap (const Standard_Integer theRep, +static void CompDoubleMap (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -718,14 +732,15 @@ static void CompDoubleMap (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_DoubleMap clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); if (iFail1 || iFail2) cout << "Warning : N map failed " << iFail1 << " times, T map - " << iFail2 << endl; } // ===================== Test perform of IndexedMap type ========================== -static void CompIndexedMap (const Standard_Integer theRep, +static void CompIndexedMap (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -815,11 +830,12 @@ static void CompIndexedMap (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_IndexedMap clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of IndexedDataMap type ========================== -static void CompIndexedDataMap (const Standard_Integer theRep, +static void CompIndexedDataMap (Draw_Interpretor& theDI, + const Standard_Integer theRep, const Standard_Integer theSize) { Standard_Integer i,j; @@ -911,11 +927,13 @@ static void CompIndexedDataMap (const Standard_Integer theRep, ////////////////////////////////aTClea.Stop(); PERF_STOP_METER("TCollection_IndexedDataMap clearing") } - PERF_PRINT_ALL + printAllMeters(theDI); } // ===================== Test perform of SparseArray type ========================== -static void CompSparseArray (const Standard_Integer theRep, const Standard_Integer theSize) +static void CompSparseArray (Draw_Interpretor& theDI, + const Standard_Integer theRep, + const Standard_Integer theSize) { Standard_Integer i,j; for (i=0; i MySequence; const Standard_Integer REPEAT = 100; -void printAllMeters () +static void printAllMeters (Draw_Interpretor& theDI) { - PERF_PRINT_ALL + char buffer[25600]; + perf_sprint_all_meters (buffer, 25600 - 1, 1); + theDI << buffer; } static void createArray (TColgp_Array1OfPnt& anArrPnt) @@ -132,7 +134,7 @@ static void assignArray (MyArray1& aDest, const MyArray1& aSrc) } } -static void checkArray (const Standard_Boolean isNewColl) +static void checkArray (Draw_Interpretor& theDI, const Standard_Boolean isNewColl) { if (isNewColl) { MyArray1 anArrPnt (1, 100000), anArrPnt1 (1, 100000); @@ -144,10 +146,11 @@ static void checkArray (const Standard_Boolean isNewColl) createArray (anArrPnt); assignArray (anArrPnt1, anArrPnt); } - printAllMeters (); + printAllMeters (theDI); } -static void checkSequence (const Standard_Boolean isNewColl, +static void checkSequence (Draw_Interpretor& theDI, + const Standard_Boolean isNewColl, const Standard_Boolean isIncr) { if (isNewColl) { @@ -165,7 +168,7 @@ static void checkSequence (const Standard_Boolean isNewColl, createSequence (aSeqPnt); assignSequence (aSeqPnt1, aSeqPnt); } - printAllMeters (); + printAllMeters (theDI); } //======================================================================= @@ -183,7 +186,7 @@ static Standard_Integer QANColCheckArray1(Draw_Interpretor& di, Standard_Integer if (argc > 1) { if (strcmp (argv[1], "-n") == 0) isNewColl = Standard_True; } - checkArray (isNewColl); + checkArray (di, isNewColl); return 0; } @@ -207,7 +210,7 @@ static Standard_Integer QANColCheckSequence(Draw_Interpretor& di, Standard_Integ isIncr = Standard_True; } } - checkSequence (isNewColl, isIncr); + checkSequence (di, isNewColl, isIncr); return 0; } diff --git a/src/QANCollection/QANCollection_Stl.cxx b/src/QANCollection/QANCollection_Stl.cxx index 248e8f9199..3c1332bae4 100644 --- a/src/QANCollection/QANCollection_Stl.cxx +++ b/src/QANCollection/QANCollection_Stl.cxx @@ -947,7 +947,7 @@ static Standard_Integer QANTestStlIterators ( //purpose : //======================================================================= template -void TestPerformanceRandomIterator() +void TestPerformanceRandomIterator(Draw_Interpretor& di) { OSD_Timer aTimer; @@ -986,12 +986,12 @@ void TestPerformanceRandomIterator() Standard_Real aOccTime = aTimer.ElapsedTime(); - std::cout << aSize << "\t" << aStlTime << "\t" << - aOccTime << "\t" << aOccTime / aStlTime << std::endl; + di << aSize << "\t" << aStlTime << "\t" << + aOccTime << "\t" << aOccTime / aStlTime << "\n"; // check that result is the same if ( ! std::equal (aVector->begin(), aVector->end(), aCollec->begin()) ) - std::cout << "Error: sequences are not the same at the end!" << std::endl; + di << "Error: sequences are not the same at the end!" << "\n"; delete aVector; delete aCollec; @@ -1003,7 +1003,7 @@ void TestPerformanceRandomIterator() //purpose : //======================================================================= template -void TestPerformanceForwardIterator() +void TestPerformanceForwardIterator(Draw_Interpretor& di) { OSD_Timer aTimer; @@ -1038,12 +1038,12 @@ void TestPerformanceForwardIterator() Standard_Real aOccTime = aTimer.ElapsedTime(); - std::cout << aSize << "\t" << aStlTime << "\t" << - aOccTime << "\t" << aOccTime / aStlTime << std::endl; + di << aSize << "\t" << aStlTime << "\t" << + aOccTime << "\t" << aOccTime / aStlTime << "\n"; // check that result is the same if ( ! std::equal (aVector->begin(), aVector->end(), aCollec->begin()) ) - std::cout << "Error: sequences are not the same at the end!" << std::endl; + di << "Error: sequences are not the same at the end!" << "\n"; delete aVector; delete aCollec; @@ -1055,7 +1055,7 @@ void TestPerformanceForwardIterator() //purpose : //======================================================================= template -void TestPerformanceBidirIterator() +void TestPerformanceBidirIterator(Draw_Interpretor& di) { OSD_Timer aTimer; @@ -1090,12 +1090,12 @@ void TestPerformanceBidirIterator() Standard_Real aOccTime = aTimer.ElapsedTime(); - std::cout << aSize << "\t" << aStlTime << "\t" << - aOccTime << "\t" << aOccTime / aStlTime << std::endl; + di << aSize << "\t" << aStlTime << "\t" << + aOccTime << "\t" << aOccTime / aStlTime << "\n"; // check that result is the same if ( ! std::equal (aVector->begin(), aVector->end(), aCollec->begin()) ) - std::cout << "Error: sequences are not the same at the end!" << std::endl; + di << "Error: sequences are not the same at the end!" << "\n"; delete aVector; delete aCollec; @@ -1107,7 +1107,7 @@ void TestPerformanceBidirIterator() //purpose : //======================================================================= template -void TestPerformanceMapAccess() +void TestPerformanceMapAccess(Draw_Interpretor& di) { OSD_Timer aTimer; @@ -1166,8 +1166,8 @@ void TestPerformanceMapAccess() if (aResult) { - std::cout << aSize << "\t" << aStlTime << "\t" << - aOccTime << "\t" << (aStlTime > 1e-16 ? aOccTime / aStlTime : -1) << std::endl; + di << aSize << "\t" << aStlTime << "\t" << + aOccTime << "\t" << (aStlTime > 1e-16 ? aOccTime / aStlTime : -1) << "\n"; } delete aCollec; @@ -1178,42 +1178,37 @@ void TestPerformanceMapAccess() //function : QANTestNCollectionPerformance //purpose : //======================================================================= -static Standard_Integer QANTestNCollectionPerformance ( - Draw_Interpretor& /*theInterpretor*/, Standard_Integer, const char**) +static Standard_Integer QANTestNCollectionPerformance (Draw_Interpretor& di, Standard_Integer, const char**) { - std::cout.precision (8); + di << "Testing performance (Size | STL time | OCCT time | STL/OCCT boost)" << "\n"; - std::cout << "Testing performance (Size | STL time | OCCT time | STL/OCCT boost)\n"; + di << "\n" << "std::vector vs NCollection_Array1 (sort):" << "\n\n"; + TestPerformanceRandomIterator, std::vector >(di); + + di << "\n" << "std::vector vs NCollection_Vector (sort):" << "\n\n"; + TestPerformanceRandomIterator, std::vector >(di); + + di << "\n" << "std::vector vs NCollection_Array1 (replace):" << "\n\n"; + TestPerformanceForwardIterator, std::vector >(di); + + di << "\n" << "std::vector vs NCollection_Vector (replace):" << "\n\n"; + TestPerformanceForwardIterator, std::vector >(di); - std::cout << std::endl << "std::vector vs NCollection_Array1 (sort):\n" << std::endl; - TestPerformanceRandomIterator, std::vector >(); + di << "\n" << "std::list vs NCollection_List (replace):" << "\n\n"; + TestPerformanceForwardIterator, std::list >(di); - std::cout << std::endl << "std::vector vs NCollection_Vector (sort):\n" << std::endl; - TestPerformanceRandomIterator, std::vector >(); + di << "\n" << "std::list vs NCollection_Sequence (replace):" << "\n\n"; + TestPerformanceForwardIterator, std::list >(di); - std::cout << std::endl << "std::vector vs NCollection_Array1 (replace):\n" << std::endl; - TestPerformanceForwardIterator, std::vector >(); + di << "\n" << "std::list vs NCollection_Sequence (reverse):" << "\n\n"; + TestPerformanceBidirIterator, std::list >(di); - std::cout << std::endl << "std::vector vs NCollection_Vector (replace):\n" << std::endl; - TestPerformanceForwardIterator, std::vector >(); - - std::cout << std::endl << "std::list vs NCollection_List (replace):\n" << std::endl; - TestPerformanceForwardIterator, std::list >(); - - std::cout << std::endl << "std::list vs NCollection_Sequence (replace):\n" << std::endl; - TestPerformanceForwardIterator, std::list >(); - - std::cout << std::endl << "std::list vs NCollection_Sequence (reverse):\n" << std::endl; - TestPerformanceBidirIterator, std::list >(); - - std::cout << std::endl << "std::set vs NCollection_Map (search):\n" << std::endl; - TestPerformanceMapAccess, int>(); - - std::cout << std::endl << "std::set vs NCollection_IndexedMap (search):\n" << std::endl; - TestPerformanceMapAccess, int>(); - - std::cout.unsetf (std::ios::floatfield); + di << "\n" << "std::set vs NCollection_Map (search):" << "\n\n"; + TestPerformanceMapAccess, int>(di); + di << "\n" << "std::set vs NCollection_IndexedMap (search):" << "\n\n"; + TestPerformanceMapAccess, int>(di); + return 0; } diff --git a/tests/perf/grids.list b/tests/perf/grids.list index e2ad5b9f47..a99041f3bd 100644 --- a/tests/perf/grids.list +++ b/tests/perf/grids.list @@ -16,3 +16,4 @@ 016 single_object_wireframe 017 bspline 018 bop +019 ncollection diff --git a/tests/perf/ncollection/A1 b/tests/perf/ncollection/A1 new file mode 100644 index 0000000000..f7a8f290e9 --- /dev/null +++ b/tests/perf/ncollection/A1 @@ -0,0 +1,52 @@ +cpulimit 5000 +pload QAcommands + +set info [QANTestNCollectionPerformance] + +set values {} +set keys {} +unset -nocomplain std_cl occt_cl diff_cl +foreach line [split $info "\n"] { + if { [regexp {(std::.*)} $line] } { + lappend keys $line + if {[info exists std_cl] && [info exists occt_cl] && [info exists diff_cl]} { + lappend values "$diff_cl" + } + } + regexp {\s*[-0-9*.+eE]+\s+([-0-9*.+eE]+)\s+([-0-9*.+eE]+)\s+([-0-9*.+eE]+)} $line dump std_cl occt_cl diff_cl +} +lappend values "$diff_cl" + +if { [string compare $tcl_platform(platform) "windows"] != 0 } { + set check_values { 1.2363286058767904 + 1.9537414143534 + 1.2596260162601621 + 2.8737043746844462 + 1.2133020329576465 + 1.2164522569168656 + 1.2495457282327385 + 0.10352433841051313 + 0.45175659293697572 + } +} else { + set check_values { 1.383409071179103 + 5.1472531605899908 + 1.35719377028335395 + 5.5309830187022213 + 1.18734859347377246 + 1.18885181806915312 + 1.4285334583511072 + 0.20619280354776386 + 0.05983563611646603 + } +} +set index 0 +foreach key $keys { + set value [lindex $values $index] + if { $value > [lindex $check_values $index] } { + puts "Error: performance of $key become worse" + } else { + puts "OK: performance of $key is OK" + } + incr index +}