Function perf_sprint_all_meters added in OSD_PerfMeter.h to allow printing to string buffer rather than stdout. Macro PERF_PRINT_ALL converted to functional form.
Command dperf added in DRAW to print and conditionally reset all meters.
Description of these tools is added in Debug Hints.
Modified output of command QANTestNCollectionPerformance.
Added test case perf/ncollection/A1
Modified ratio of performance to check all platforms
Small correction of test-case for Windows platform
}
~~~~~
-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.
#include <OSD_Chronometer.hxx>
#include <OSD.hxx>
#include <OSD_Exception_CTRL_BREAK.hxx>
+#include <OSD_PerfMeter.h>
#ifdef _WIN32
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 :
"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!
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; i<nb_meters; i++) {
const t_TimeCounter * const ptc = &MeterTable[i];
if (ptc && ptc->nb_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;
}
}
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);
-
- printf ("%-42s : %7d %8.2f %10.2f\n",
- ptc->name, ptc->nb_enter, secs,
- (secs>0. ? 1000000 * secs/ptc->nb_enter : 0.));
-
- ptc->cumul_time = 0;
- ptc->start_time = 0;
- ptc->nb_enter = 0;
+ n = sprintf (string, "Warning : meter %42s has not been stopped\n", ptc->name);
+
+ 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;
+ }
+
+ if (reset)
+ {
+ ptc->cumul_time = 0;
+ ptc->start_time = 0;
+ ptc->nb_enter = 0;
+ }
}
}
+ *buffer = '\0';
}
/*======================================================================
======================================================================*/
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));
}
/*======================================================================
void perf_print_and_destroy (void)
{
- perf_print_all_meters ();
+ perf_print_all_meters (0);
perf_destroy_all_meters ();
}
* @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
#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
/**
/**
* 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.
/**
* 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);
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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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;
////////////////////////////////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<theRep; i++)
}
- PERF_PRINT_ALL
+ printAllMeters(theDI);
}
//=======================================================================
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompArray1(Repeat,Size);
+ CompArray1 (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompArray2(Repeat,Size);
+ CompArray2 (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompList(Repeat,Size);
+ CompList (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompSequence(Repeat,Size);
+ CompSequence (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompMap(Repeat,Size);
+ CompMap (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompDataMap(Repeat,Size);
+ CompDataMap (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompDoubleMap(Repeat,Size);
+ CompDoubleMap (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompIndexedMap(Repeat,Size);
+ CompIndexedMap (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompIndexedDataMap(Repeat,Size);
+ CompIndexedDataMap (di, Repeat, Size);
return 0;
}
if ( CheckArguments(di, argc, argv, Repeat, Size) ) {
return 1;
}
- CompSparseArray(Repeat,Size);
+ CompSparseArray (di, Repeat, Size);
return 0;
}
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)
}
}
-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);
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) {
createSequence (aSeqPnt);
assignSequence (aSeqPnt1, aSeqPnt);
}
- printAllMeters ();
+ printAllMeters (theDI);
}
//=======================================================================
if (argc > 1) {
if (strcmp (argv[1], "-n") == 0) isNewColl = Standard_True;
}
- checkArray (isNewColl);
+ checkArray (di, isNewColl);
return 0;
}
isIncr = Standard_True;
}
}
- checkSequence (isNewColl, isIncr);
+ checkSequence (di, isNewColl, isIncr);
return 0;
}
//purpose :
//=======================================================================
template<class CollectionType, class StlType>
-void TestPerformanceRandomIterator()
+void TestPerformanceRandomIterator(Draw_Interpretor& di)
{
OSD_Timer aTimer;
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;
//purpose :
//=======================================================================
template<class CollectionType, class StlType>
-void TestPerformanceForwardIterator()
+void TestPerformanceForwardIterator(Draw_Interpretor& di)
{
OSD_Timer aTimer;
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;
//purpose :
//=======================================================================
template<class CollectionType, class StlType>
-void TestPerformanceBidirIterator()
+void TestPerformanceBidirIterator(Draw_Interpretor& di)
{
OSD_Timer aTimer;
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;
//purpose :
//=======================================================================
template<class CollectionType, class T>
-void TestPerformanceMapAccess()
+void TestPerformanceMapAccess(Draw_Interpretor& di)
{
OSD_Timer aTimer;
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;
//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";
-
- std::cout << std::endl << "std::vector vs NCollection_Array1 (sort):\n" << std::endl;
- TestPerformanceRandomIterator<NCollection_Array1<double>, std::vector<double> >();
-
- std::cout << std::endl << "std::vector vs NCollection_Vector (sort):\n" << std::endl;
- TestPerformanceRandomIterator<NCollection_Vector<double>, std::vector<double> >();
-
- std::cout << std::endl << "std::vector vs NCollection_Array1 (replace):\n" << std::endl;
- TestPerformanceForwardIterator<NCollection_Array1<double>, std::vector<double> >();
-
- std::cout << std::endl << "std::vector vs NCollection_Vector (replace):\n" << std::endl;
- TestPerformanceForwardIterator<NCollection_Vector<double>, std::vector<double> >();
-
- std::cout << std::endl << "std::list vs NCollection_List (replace):\n" << std::endl;
- TestPerformanceForwardIterator<NCollection_List<double>, std::list<double> >();
-
- std::cout << std::endl << "std::list vs NCollection_Sequence (replace):\n" << std::endl;
- TestPerformanceForwardIterator<NCollection_Sequence<double>, std::list<double> >();
+ di << "\n" << "std::vector vs NCollection_Array1 (sort):" << "\n\n";
+ TestPerformanceRandomIterator<NCollection_Array1<double>, std::vector<double> >(di);
+
+ di << "\n" << "std::vector vs NCollection_Vector (sort):" << "\n\n";
+ TestPerformanceRandomIterator<NCollection_Vector<double>, std::vector<double> >(di);
+
+ di << "\n" << "std::vector vs NCollection_Array1 (replace):" << "\n\n";
+ TestPerformanceForwardIterator<NCollection_Array1<double>, std::vector<double> >(di);
+
+ di << "\n" << "std::vector vs NCollection_Vector (replace):" << "\n\n";
+ TestPerformanceForwardIterator<NCollection_Vector<double>, std::vector<double> >(di);
- std::cout << std::endl << "std::list vs NCollection_Sequence (reverse):\n" << std::endl;
- TestPerformanceBidirIterator<NCollection_Sequence<double>, std::list<double> >();
+ di << "\n" << "std::list vs NCollection_List (replace):" << "\n\n";
+ TestPerformanceForwardIterator<NCollection_List<double>, std::list<double> >(di);
- std::cout << std::endl << "std::set vs NCollection_Map (search):\n" << std::endl;
- TestPerformanceMapAccess<NCollection_Map<int>, int>();
+ di << "\n" << "std::list vs NCollection_Sequence (replace):" << "\n\n";
+ TestPerformanceForwardIterator<NCollection_Sequence<double>, std::list<double> >(di);
- std::cout << std::endl << "std::set vs NCollection_IndexedMap (search):\n" << std::endl;
- TestPerformanceMapAccess<NCollection_IndexedMap<int>, int>();
+ di << "\n" << "std::list vs NCollection_Sequence (reverse):" << "\n\n";
+ TestPerformanceBidirIterator<NCollection_Sequence<double>, std::list<double> >(di);
- std::cout.unsetf (std::ios::floatfield);
+ di << "\n" << "std::set vs NCollection_Map (search):" << "\n\n";
+ TestPerformanceMapAccess<NCollection_Map<int>, int>(di);
+ di << "\n" << "std::set vs NCollection_IndexedMap (search):" << "\n\n";
+ TestPerformanceMapAccess<NCollection_IndexedMap<int>, int>(di);
+
return 0;
}
016 single_object_wireframe
017 bspline
018 bop
+019 ncollection
--- /dev/null
+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
+}