4 * Copyright (c) 2003, 2004
7 * This material is provided "as is", with absolutely no warranty expressed
8 * or implied. Any use is at your own risk.
10 * Permission to use or copy this software for any purpose is hereby granted
11 * without fee, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
19 #if defined(_DEBUG) && _MSC_VER == 1500
20 # define _CRTDBG_MAP_ALLOC
26 #include "cppunit/cppunit_proxy.h"
27 #include "cppunit/file_reporter.h"
30 #include <cds/gc/hp.h>
31 #include <cds/gc/hrc.h>
32 #include <cds/gc/ptb.h>
33 #include <cds/urcu/general_instant.h>
34 #include <cds/urcu/general_buffered.h>
35 #include <cds/urcu/general_threaded.h>
36 #include <cds/urcu/signal_buffered.h>
37 #include <cds/urcu/signal_threaded.h>
38 #include <cds/os/topology.h>
44 #include <boost/date_time/posix_time/posix_time.hpp>
45 #include <boost/thread/mutex.hpp>
47 // Visual leak detector (see http://vld.codeplex.com/)
48 #if defined(CDS_USE_VLD) && CDS_COMPILER == CDS_COMPILER_MSVC
55 std::ostream& operator << (std::ostream& s, const cds::gc::hzp::GarbageCollector::InternalState& stat)
57 s << "\nHZP GC internal state:"
58 << "\n\t\tHP record allocated=" << stat.nHPRecAllocated
59 << "\n\t\tHP records used=" << stat.nHPRecUsed
60 << "\n\t\tTotal retired ptr count=" << stat.nTotalRetiredPtrCount
61 << "\n\t\tRetired ptr in free HP records=" << stat.nRetiredPtrInFreeHPRecs
63 << "\n\t\tHPRec allocations=" << stat.evcAllocHPRec
64 << "\n\t\tHPRec retire events=" << stat.evcRetireHPRec
65 << "\n\t\tnew HPRec allocations from heap=" << stat.evcAllocNewHPRec
66 << "\n\t\tHPRec deletions=" << stat.evcDeleteHPRec
67 << "\n\t\tScan calling=" << stat.evcScanCall
68 << "\n\t\tHelpScan calling=" << stat.evcHelpScanCall
69 << "\n\t\tScan calls from HelpScan=" << stat.evcScanFromHelpScan
70 << "\n\t\tretired objects deleting=" << stat.evcDeletedNode
71 << "\n\t\tguarded objects on Scan=" << stat.evcDeferredNode
77 std::ostream& operator << (std::ostream& s, const cds::gc::hrc::GarbageCollector::internal_state& stat)
79 s << "\nHRC GC internal state:"
80 << "\n\t\tHRC record allocated=" << stat.nHRCRecAllocated
81 << "\n\t\tHRC records used=" << stat.nHRCRecUsed
82 << "\n\t\tTotal retired ptr count=" << stat.nTotalRetiredPtrCount
83 << "\n\t\tRetired ptr in free HRC records=" << stat.nRetiredPtrInFreeHRCRecs
85 << "\n\t\tHRCrec allocations=" << stat.evcAllocHRCRec
86 << "\n\t\tHRCrec retire events=" << stat.evcRetireHRCRec
87 << "\n\t\tnew HRCrec allocations from heap=" << stat.evcAllocNewHRCRec
88 << "\n\t\tHRCrec deletions=" << stat.evcDeleteHRCRec
89 << "\n\t\tScan calling=" << stat.evcScanCall
90 << "\n\t\tHelpScan calling=" << stat.evcHelpScanCalls
91 << "\n\t\tCleanUpAll calling=" << stat.evcCleanUpAllCalls
92 << "\n\t\tretired objects deleting=" << stat.evcDeletedNode
93 << "\n\t\tguarded nodes on Scan=" << stat.evcScanGuarded
94 << "\n\t\tclaimed node on Scan=" << stat.evcScanClaimGuarded
96 << "\n\t\tnode constructed count=" << stat.evcNodeConstruct
97 << "\n\t\tnode destructed count=" << stat.evcNodeDestruct
104 namespace CppUnitMini
106 int TestCase::m_numErrors = 0;
107 int TestCase::m_numTests = 0;
108 std::vector<std::string> TestCase::m_arrStrings;
109 bool TestCase::m_bPrintGCState = false;
110 std::string TestCase::m_strTestDataDir(".");
111 Config TestCase::m_Cfg;
113 TestCase * TestCase::m_pCurTestCase = nullptr;
115 TestCase *TestCase::m_root = 0;
116 Reporter *TestCase::m_reporter = 0;
118 void TestCase::registerTestCase(TestCase *in_testCase) {
119 in_testCase->m_next = m_root;
120 m_root = in_testCase;
123 int TestCase::run(Reporter *in_reporter, const char *in_testName, bool invert)
125 TestCase::m_reporter = in_reporter;
130 TestCase *tmp = m_root;
132 m_pCurTestCase = tmp;
134 tmp->myRun(in_testName, invert);
135 } catch ( std::exception& ex ) {
136 in_reporter->message( "EXCEPTION: ");
137 in_reporter->message( ex.what() );
145 void TestCase::print_gc_state()
147 if ( m_bPrintGCState ) {
149 cds::gc::hzp::GarbageCollector::InternalState stat;
150 std::cout << cds::gc::hzp::GarbageCollector::instance().getInternalState( stat ) << std::endl;
154 cds::gc::hrc::GarbageCollector::internal_state stat;
155 std::cout << cds::gc::hrc::GarbageCollector::instance().getInternalState( stat ) << std::endl;
160 void Config::load( const char * fileName )
164 if ( !s.is_open() ) {
165 std::cerr << "WARNING: Cannot open test cfg file " << fileName
166 << "\n\tUse default settings"
171 std::cout << "Using test config file: " << fileName << std::endl;
175 TestCfg * pMap = nullptr;
177 s.getline( buf, sizeof(buf)/sizeof(buf[0]) );
180 while ( *pszStr != 0 && (*pszStr == ' ' || *pszStr == '\t' )) ++pszStr;
182 char * pszEnd = strchr( pszStr, 0 );
183 if ( pszEnd == pszStr ) // empty srtring
186 while ( pszEnd != pszStr && (*pszEnd ==' ' || *pszEnd=='\t' || *pszEnd=='\n' || *pszEnd=='\r' )) --pszEnd;
188 if ( pszStr == pszEnd ) // empty string
193 if ( *pszStr == '#' ) // comment
196 if ( *pszStr == '[' && *pszEnd == ']' ) { // chapter header
198 pMap = &( m_Cfg[ pszStr + 1 ] );
205 char * pszEq = strchr( pszStr, '=' );
208 if ( pszEq == pszStr )
212 while ( pszStr <= --pszEnd && (*pszEnd ==' ' || *pszEnd=='\t' || *pszEnd=='\n' || *pszEnd=='\r') );
214 if ( pszEnd <= pszStr )
217 pMap->m_Cfg[ pszStr ] = pszEq + 1;
222 std::vector<std::string> const & TestCase::getTestStrings()
224 if ( m_arrStrings.empty() ) {
225 std::string strTestDir = m_strTestDataDir;
229 std::cout << "Loading test data " << strTestDir << "/dictionary.txt..." << std::endl;
230 fDict.open( (strTestDir + "/dictionary.txt").c_str() );
231 if ( fDict.is_open() ) {
232 cds::OS::Timer timer;
234 fDict >> str ; // number of lines in file
236 // Assume that dictionary.txt does not contain doubles.
237 CppUnitMini::TestCase::m_arrStrings.reserve( atol(str.c_str()) );
238 while ( !fDict.eof() ) {
239 fDict.getline( bufLine, sizeof(bufLine)/sizeof(bufLine[0]) );
241 m_arrStrings.push_back( bufLine );
245 std::cout << " Duration=" << timer.duration() << " String count " << CppUnitMini::TestCase::m_arrStrings.size() << std::endl;
248 std::cout << " Failed, file not found" << std::endl;
255 static void usage(const char* name)
257 printf("Usage : %s [-t=<class>[::<test>]] [-x=<class>[::<test>]] [-f=<file>] [-m]\n", name);
258 printf("\t[-t=<class>[::<test>]] : test class or class::test to execute;\n");
259 printf("\t[-x=<class>[::<test>]] : test class or class::test to exclude from execution;\n");
260 printf("\t[-d=dir] : test data directory (default is .);\n");
261 printf("\t[-f=<file>] : output file");
262 //printf(";\n\t[-m] : monitor test execution, display time duration for each test\n");
263 printf("\t[-gc_state] : print gc state after each test\n");
264 printf("\t[-cfg=<file>] : config file name for tests\n");
267 int main(int argc, char** argv)
270 #ifdef CDS_MSVC_MEMORY_LEAKS_DETECTING_ENABLED
271 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
274 // CppUnit(mini) test launcher
275 // command line option syntax:
278 // -t=CLASS[::TEST] run the test class CLASS or member test CLASS::TEST
279 // -x=CLASS[::TEST] run all except the test class CLASS or member test CLASS::TEST
280 // -d=dir test data directory (default is .)
281 // -f=FILE save output in file FILE instead of stdout
282 // -m monitor test(s) execution
283 // -gc_state print GC state after test
284 const char *fileName = 0;
285 const char *testName = "";
286 const char *xtestName = "";
287 const char *testDataDir = ".";
288 const char *cfgFileName =
295 bool doMonitoring = false;
297 for (int i = 1; i < argc; ++i) {
298 if (argv[i][0] == '-') {
299 if (!strncmp(argv[i], "-t=", 3)) {
300 testName = argv[i]+3;
303 else if (!strncmp(argv[i], "-f=", 3)) {
304 fileName = argv[i]+3;
307 else if (!strncmp(argv[i], "-x=", 3)) {
308 xtestName = argv[i]+3;
311 else if (!strncmp(argv[i], "-d=", 3)) {
312 testDataDir = argv[i] + 3;
315 else if ( !strncmp(argv[i], "-m", 2)) {
319 else if (!strncmp(argv[i], "-gc_state", 9)) {
320 CppUnitMini::TestCase::m_bPrintGCState = true;
323 else if( !strncmp(argv[i], "-cfg=", 5)) {
324 cfgFileName = argv[i] + 5;
329 // invalid option, we display normal usage.
336 boost::posix_time::ptime cur( boost::posix_time::second_clock::local_time());
338 std::cout << "libcds version " << CDS_VERSION_STRING << "\n";
339 std::cout << "Test started " << cur << std::endl;
343 CppUnitMini::TestCase::m_strTestDataDir = testDataDir;
345 CppUnitMini::Reporter* reporter;
347 reporter = new CppUnitMini::FileReporter(fileName, doMonitoring);
349 reporter = new CppUnitMini::FileReporter(stdout, doMonitoring);
351 // Load config params
352 CppUnitMini::TestCase::m_Cfg.load( cfgFileName );
359 size_t nHazardPtrCount = 0;
361 CppUnitMini::TestCfg& cfg = CppUnitMini::TestCase::m_Cfg.get( "General" );
362 nHazardPtrCount = cfg.getULong( "hazard_pointer_count", 0 );
365 // Safe reclamation schemes
366 cds::gc::HP hzpGC( nHazardPtrCount );
367 cds::gc::HRC hrcGC( nHazardPtrCount );
371 typedef cds::urcu::gc< cds::urcu::general_instant<> > rcu_gpi;
374 typedef cds::urcu::gc< cds::urcu::general_buffered<> > rcu_gpb;
377 typedef cds::urcu::gc< cds::urcu::general_threaded<> > rcu_gpt;
380 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
381 typedef cds::urcu::gc< cds::urcu::signal_buffered<> > rcu_shb;
382 rcu_shb shbRCU( 256, SIGUSR1 );
384 typedef cds::urcu::gc< cds::urcu::signal_threaded<> > rcu_sht;
385 rcu_sht shtRCU( 256, SIGUSR2 );
391 << "System topology:\n"
392 << " Logical processor count: " << cds::OS::topology::processor_count() << "\n";
393 std::cout << std::endl;
397 CppUnitMini::TestCfg& cfg = CppUnitMini::TestCase::m_Cfg.get( "General" );
398 std::string strHZPScanStrategy = cfg.get( "HZP_scan_strategy", std::string("classic") );
399 if ( strHZPScanStrategy == "inplace" )
400 hzpGC.setScanType( cds::gc::hzp::inplace );
401 else if ( strHZPScanStrategy == "classic" )
402 hzpGC.setScanType( cds::gc::hzp::classic );
404 std::cout << "Error value of HZP_scan_strategy in General section of test config\n";
407 switch (hzpGC.getScanType()) {
408 case cds::gc::hzp::inplace:
409 std::cout << "Use in-place scan strategy for Hazard Pointer memory reclamation algorithm\n";
411 case cds::gc::hzp::classic:
412 std::cout << "Use classic scan strategy for Hazard Pointer memory reclamation algorithm\n";
415 std::cout << "ERROR: use unknown scan strategy for Hazard Pointer memory reclamation algorithm\n";
419 std::cout << " Hazard Pointer count: " << hzpGC.max_hazard_count() << "\n"
420 << " Max thread count for HP: " << hzpGC.max_thread_count() << "\n"
421 << "Retired HP array capacity: " << hzpGC.retired_array_capacity() << "\n";
424 if ( CppUnitMini::TestCase::m_bPrintGCState ) {
425 cds::gc::hzp::GarbageCollector::InternalState stat;
426 cds::gc::hzp::GarbageCollector::instance().getInternalState( stat );
428 std::cout << "HZP GC constants:"
429 << "\n\tHP count per thread=" << stat.nHPCount
430 << "\n\tMax thread count=" << stat.nMaxThreadCount
431 << "\n\tMax retired pointer count per thread=" << stat.nMaxRetiredPtrCount
432 << "\n\tHP record size in bytes=" << stat.nHPRecSize
433 << "\n" << std::endl;
436 if ( CppUnitMini::TestCase::m_bPrintGCState ) {
437 cds::gc::hrc::GarbageCollector::internal_state stat;
438 cds::gc::hrc::GarbageCollector::instance().getInternalState( stat );
440 std::cout << "HRC GC constants:"
441 << "\n\tHRC count per thread=" << stat.nHPCount
442 << "\n\tMax thread count=" << stat.nMaxThreadCount
443 << "\n\tMax retired pointer count per thread=" << stat.nMaxRetiredPtrCount
444 << "\n\tHRC record size in bytes=" << stat.nHRCRecSize
445 << "\n" << std::endl;
448 // Attach main thread to CDS GC
449 cds::threading::Manager::attachThread();
451 if (xtestName[0] != 0)
452 num_errors = CppUnitMini::TestCase::run(reporter, xtestName, true);
454 num_errors = CppUnitMini::TestCase::run(reporter, testName);
456 // Detach main thread from CDS GC
457 cds::threading::Manager::detachThread();
461 // Finalize CDS runtime
464 reporter->printSummary();
470 // See doc/README.intel for explanation about this code
471 #if defined (STLPORT) && defined (__ICL) && (__ICL >= 900) && \
472 (_STLP_MSVC_LIB < 1300) && defined (_STLP_USE_DYNAMIC_LIB)
473 # include <exception>
478 void _STLP_CALL unexpected() {
479 unexpected_handler hdl;
480 set_unexpected(hdl = set_unexpected((unexpected_handler)0));