diff --git a/docs/Manual_Quickstart/Manual_Setup.md b/docs/Manual_Quickstart/Manual_Setup.md index 1df1b02cd..bce40ec37 100644 --- a/docs/Manual_Quickstart/Manual_Setup.md +++ b/docs/Manual_Quickstart/Manual_Setup.md @@ -44,6 +44,8 @@ If you have installed LLVM using the package manager, specifying this var Note: In case you want to use a specific Version of LLVM, it is possible to specify the `-DUSE_LLVM_VERSION=` flag. +Note: In case your application uses PThreads, please specify `-DDP_PTHREAD_COMPATIBILITY_MODE=1`. Note, however, that this can influence the runtime of the profiling. + Once the configuration process is successfully finished, compile the DiscoPoP libraries using `make`. All created shared objects will be stored in the build directory and can be found inside a folder named `libi/`. make diff --git a/rtlib/CMakeLists.txt b/rtlib/CMakeLists.txt index 4baeee671..ad5737dcc 100644 --- a/rtlib/CMakeLists.txt +++ b/rtlib/CMakeLists.txt @@ -26,6 +26,15 @@ set(CMAKE_CXX_FLAGS add_library(DiscoPoP_RT STATIC ${DiscoPoP_SOURCES}) + +# forward compiler flags +if(DEFINED DP_PTHREAD_COMPATIBILITY_MODE) + if(NOT ${DP_PTHREAD_COMPATIBILITY_MODE} EQUAL 0) + target_compile_definitions(DiscoPoP_RT PUBLIC DP_PTHREAD_COMPATIBILITY_MODE=${DP_PTHREAD_COMPATIBILITY_MODE}) + endif() + +endif() + install(TARGETS DiscoPoP_RT ARCHIVE DESTINATION lib) # compile simple-alias-detection diff --git a/rtlib/iFunctions.cpp b/rtlib/iFunctions.cpp index b7dce63a7..d3e7661ad 100755 --- a/rtlib/iFunctions.cpp +++ b/rtlib/iFunctions.cpp @@ -32,6 +32,11 @@ using namespace dputil; #define unpackLIDMetadata_getLoopIteration_1(lid) ((lid >> 40) & 0xFF) #define unpackLIDMetadata_getLoopIteration_2(lid) ((lid >> 32) & 0xFF) +// issue a warning if DP_PTHREAD_COMPATIBILITY_MODE is enabled +#ifdef DP_PTHREAD_COMPATIBILITY_MODE +# warning "DP_PTHREAD_COMPATIBILITY_MODE enabled! This may have negative implications on the profiling time." +#endif + bool DP_DEBUG = false; // debug flag bool USE_PERFECT = true; @@ -664,7 +669,11 @@ namespace __dp { #else void __dp_read(LID lid, ADDR addr, char *var) { #endif + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif + if (targetTerminated) { if (DP_DEBUG) { cout << "__dp_read() is not executed since target program has returned from main()." << endl; @@ -736,7 +745,10 @@ namespace __dp { #else void __dp_write(LID lid, ADDR addr, char *var) { #endif + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (targetTerminated) { if (DP_DEBUG) { cout << "__dp_write() is not executed since target program has returned from main()." << endl; @@ -808,7 +820,10 @@ namespace __dp { #else void __dp_decl(LID lid, ADDR addr, char *var) { #endif + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (targetTerminated) { if (DP_DEBUG) { cout << "__dp_write() is not executed since target program has returned from main()." << endl; @@ -876,7 +891,9 @@ namespace __dp { } void __dp_alloca(LID lid, char *var, ADDR startAddr, ADDR endAddr, int64_t numBytes, int64_t numElements) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif int64_t buffer = nextFreeMemoryRegionId; string allocId = to_string(buffer); nextFreeMemoryRegionId++; @@ -898,7 +915,9 @@ namespace __dp { } void __dp_new(LID lid, ADDR startAddr, ADDR endAddr, int64_t numBytes){ +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif // instrumentation function for new and malloc int64_t buffer = nextFreeMemoryRegionId; string allocId = to_string(buffer); @@ -928,7 +947,9 @@ namespace __dp { } void __dp_delete(LID lid, ADDR startAddr){ +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif // DO NOT DELETE MEMORY REGIONS AS THEY ARE STILL REQUIRED FOR LOGGING // TODO more efficient implementation @@ -948,35 +969,47 @@ namespace __dp { } void __dp_report_bb(int32_t bbIndex) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif bbList->insert(bbIndex); } void __dp_report_bb_pair(int32_t semaphore, int32_t bbIndex) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (semaphore) bbList->insert(bbIndex); } void __dp_finalize(LID lid) { - pthread_compatibility_mutex.lock(); +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + pthread_compatibility_mutex.lock(); +#endif if (targetTerminated) { if (DP_DEBUG) { cout << "__dp_finalize() has been called before. Doing nothing this time to avoid double free." << endl; } +#ifdef DP_PTHREAD_COMPATIBILITY_MODE pthread_compatibility_mutex.unlock(); +#endif return; } // release mutex so it can be re-aquired in the called __dp_func_exit +#ifdef DP_PTHREAD_COMPATIBILITY_MODE pthread_compatibility_mutex.unlock(); +#endif while (FuncStackLevel >= 0) { __dp_func_exit(lid, 1); } // use lock_guard here, since no other mutex-aquiring function is called +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif // Returning from main or exit from somewhere, clear up everything. assert(FuncStackLevel == -1 && "Program terminates without clearing function stack!"); @@ -1027,7 +1060,9 @@ namespace __dp { // hybrid analysis void __dp_add_bb_deps(char *depStringPtr) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif string depString(depStringPtr); regex r0("[^\\/]+"), r1("[^=]+"), r2("[^,]+"), r3("[0-9]+:[0-9]+"), r4("(INIT|(R|W)A(R|W)).*"); smatch res0, res1, res2, res3; @@ -1064,12 +1099,16 @@ namespace __dp { // End HA void __dp_call(LID lid) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif lastCallOrInvoke = lid; } void __dp_func_entry(LID lid, int32_t isStart) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (!dpInited) { // This part should be executed only once. readRuntimeInfo(); @@ -1158,7 +1197,9 @@ namespace __dp { } void __dp_func_exit(LID lid, int32_t isExit) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (targetTerminated) { if (DP_DEBUG) { cout << "Exiting function LID " << std::dec << decodeLID(lid); @@ -1215,7 +1256,9 @@ namespace __dp { } void __dp_loop_entry(LID lid, int32_t loopID) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (targetTerminated) { if (DP_DEBUG) { cout << "__dp_loop_entry() is not executed since target program has returned from main()." << endl; @@ -1264,7 +1307,9 @@ namespace __dp { } void __dp_loop_exit(LID lid, int32_t loopID) { +#ifdef DP_PTHREAD_COMPATIBILITY_MODE std::lock_guard guard(pthread_compatibility_mutex); +#endif if (targetTerminated) { if (DP_DEBUG) { cout << "__dp_loop_exit() is not executed since target program has returned from main()." << endl;