Loading plink2.cc +106 −88 File changed.Preview size limit exceeded, changes collapsed. Show changes plink2_base.h +12 −6 Original line number Diff line number Diff line Loading @@ -77,6 +77,12 @@ // valid input types, NOT counting VecW*. #if (__GNUC__ < 4) // may eventually add MSVC support to gain access to MKL on Windows, but can't // justify doing that before all major features are implemented. # error "gcc 4.x+ or clang equivalent required." #endif // The -Wshorten-64-to-32 diagnostic forces the code to be cluttered with // meaningless uintptr_t -> uint32_t static casts (number known to be < 2^32, // just stored in a uintptr_t because there's no speed penalty and we generally Loading @@ -91,7 +97,7 @@ // 10000 * major + 100 * minor + patch // Exception to CONSTI32, since we want the preprocessor to have access // to this value. Named with all caps as a consequence. #define PLINK2_BASE_VERNUM 600 #define PLINK2_BASE_VERNUM 601 #define _FILE_OFFSET_BITS 64 Loading Loading @@ -208,7 +214,7 @@ namespace plink2 { # define CSINLINE static inline # define CSINLINE2 static inline // _Static_assert() should work in gcc 4.6+ # if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 6) # if (__GNUC__ == 4) && (__GNUC_MINOR__ < 6) # if defined(__clang__) && defined(__has_feature) && defined(__has_extension) # if __has_feature(c_static_assert) || __has_extension(c_static_assert) # define static_assert _Static_assert Loading Loading @@ -568,7 +574,7 @@ HEADER_INLINE uint32_t bsrw(unsigned long ulii) { } # ifndef __LP64__ // needed to prevent GCC 6 build failure # if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 8) # if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) # if (__cplusplus < 201103L) && !defined(__APPLE__) # ifndef uintptr_t # define uintptr_t unsigned long Loading Loading @@ -607,7 +613,7 @@ HEADER_INLINE uint32_t bsrw(unsigned long ulii) { // without this, we get ridiculous warning spew... // not 100% sure this is the right cutoff, but this has been tested on 4.7 // and 4.8 build machines, so it plausibly is. # if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 8) && (__cplusplus < 201103L) # if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) && (__cplusplus < 201103L) # undef PRIuPTR # undef PRIdPTR # define PRIuPTR "lu" Loading Loading @@ -1810,7 +1816,7 @@ extern uintptr_t g_failed_alloc_attempt_size; // number is printed as well; see e.g. // https://stackoverflow.com/questions/15884793/how-to-get-the-name-or-file-and-line-of-caller-method #if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) #if (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) // putting this in the header file caused a bunch of gcc 4.4 strict-aliasing // warnings, while not doing so seems to inhibit some malloc-related compiler // optimizations, bleah Loading Loading @@ -2123,7 +2129,7 @@ HEADER_INLINE uint32_t VecIsAligned(const void* ptr) { HEADER_INLINE void VecAlignUp(void* pp) { uintptr_t addr = *S_CAST(uintptr_t*, pp); #if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) #if (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) // bleah, need to write this way to avoid gcc 4.4 strict-aliasing warning addr = RoundUpPow2(addr, kBytesPerVec); memcpy(pp, &addr, sizeof(intptr_t)); Loading plink2_bgzf.cc +1 −2 Original line number Diff line number Diff line Loading @@ -562,8 +562,7 @@ THREAD_FUNC_DECL BgzfCompressorThread(void* raw_arg) { BgzfCompressCommWithW** cwws = bgzfp->cwws; uintptr_t* next_job_idxp = bgzfp->next_job_idxp; while (1) { // make this depend on gcc version? const uint32_t slot_idx = __sync_fetch_and_add(next_job_idxp, 1) & slot_mask; const uint32_t slot_idx = __atomic_fetch_add(next_job_idxp, 1, __ATOMIC_ACQ_REL) & slot_mask; BgzfCompressCommWithP* cwp = cwps[slot_idx]; BgzfCompressCommWithW* cww = cwws[slot_idx]; #ifdef _WIN32 Loading plink2_bgzf.h +4 −3 Original line number Diff line number Diff line Loading @@ -178,12 +178,13 @@ void CleanupBgzfRawMtStream(BgzfRawMtDecompressStream* bgzfp); // threads), but that proved to be slightly slower than htslib's bgzf writer // in my testing; it didn't do a good enough job of managing the // split-between-production-and-compression core. // So I've switched to a more flexible thread pool using // __sync_fetch_and_add() to distribute compression jobs. // So I've switched to a more flexible thread pool using __atomic_fetch_add() // to distribute compression jobs. // - There's a dedicated writer thread which flushes the compression results. // I will look into adding direct support for this parallelization pattern to // plink2_thread; the benefit is small (~5%), but applies to a lot of // workloads. // workloads. It may also be worthwhile to implement some form of // work-stealing. // // I tried making this less granular (each job contains two blocks instead of // one) to see if there was still meaningful room for improvement re: reducing Loading plink2_cmdline.cc +10 −5 Original line number Diff line number Diff line Loading @@ -2456,8 +2456,7 @@ void DupflagHtableMakerMain(uint32_t tidx, uint32_t thread_ct, DupflagHtableMake for (uint32_t hashval = Hashceil(sptr, slen, id_htable_size); ; ) { uint32_t old_htable_entry = id_htable[hashval]; if (old_htable_entry == UINT32_MAX) { old_htable_entry = __sync_val_compare_and_swap(&(id_htable[hashval]), UINT32_MAX, item_uidx); if (old_htable_entry == UINT32_MAX) { if (ATOMIC_COMPARE_EXCHANGE_N_U32(&(id_htable[hashval]), &old_htable_entry, item_uidx, 0, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) { break; } } Loading Loading @@ -2505,10 +2504,16 @@ PglErr MakeDupflagHtable(const uintptr_t* subset_mask, const char* const* item_i DupflagHtableMaker ctx; { uint32_t thread_ct = item_ct / 65536; if (!thread_ct) { thread_ct = 1; } else { if (thread_ct > max_thread_ct) { thread_ct = max_thread_ct; } else if (!thread_ct) { thread_ct = 1; } // bugfix (26 Nov 2019): forgot to force this if (thread_ct > kMaxDupflagThreads) { thread_ct = kMaxDupflagThreads; } } if (unlikely(SetThreadCt0(thread_ct - 1, &tg))) { goto MakeDupflagHtable_ret_NOMEM; Loading Loading
plink2_base.h +12 −6 Original line number Diff line number Diff line Loading @@ -77,6 +77,12 @@ // valid input types, NOT counting VecW*. #if (__GNUC__ < 4) // may eventually add MSVC support to gain access to MKL on Windows, but can't // justify doing that before all major features are implemented. # error "gcc 4.x+ or clang equivalent required." #endif // The -Wshorten-64-to-32 diagnostic forces the code to be cluttered with // meaningless uintptr_t -> uint32_t static casts (number known to be < 2^32, // just stored in a uintptr_t because there's no speed penalty and we generally Loading @@ -91,7 +97,7 @@ // 10000 * major + 100 * minor + patch // Exception to CONSTI32, since we want the preprocessor to have access // to this value. Named with all caps as a consequence. #define PLINK2_BASE_VERNUM 600 #define PLINK2_BASE_VERNUM 601 #define _FILE_OFFSET_BITS 64 Loading Loading @@ -208,7 +214,7 @@ namespace plink2 { # define CSINLINE static inline # define CSINLINE2 static inline // _Static_assert() should work in gcc 4.6+ # if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 6) # if (__GNUC__ == 4) && (__GNUC_MINOR__ < 6) # if defined(__clang__) && defined(__has_feature) && defined(__has_extension) # if __has_feature(c_static_assert) || __has_extension(c_static_assert) # define static_assert _Static_assert Loading Loading @@ -568,7 +574,7 @@ HEADER_INLINE uint32_t bsrw(unsigned long ulii) { } # ifndef __LP64__ // needed to prevent GCC 6 build failure # if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 8) # if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) # if (__cplusplus < 201103L) && !defined(__APPLE__) # ifndef uintptr_t # define uintptr_t unsigned long Loading Loading @@ -607,7 +613,7 @@ HEADER_INLINE uint32_t bsrw(unsigned long ulii) { // without this, we get ridiculous warning spew... // not 100% sure this is the right cutoff, but this has been tested on 4.7 // and 4.8 build machines, so it plausibly is. # if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 8) && (__cplusplus < 201103L) # if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) && (__cplusplus < 201103L) # undef PRIuPTR # undef PRIdPTR # define PRIuPTR "lu" Loading Loading @@ -1810,7 +1816,7 @@ extern uintptr_t g_failed_alloc_attempt_size; // number is printed as well; see e.g. // https://stackoverflow.com/questions/15884793/how-to-get-the-name-or-file-and-line-of-caller-method #if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) #if (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) // putting this in the header file caused a bunch of gcc 4.4 strict-aliasing // warnings, while not doing so seems to inhibit some malloc-related compiler // optimizations, bleah Loading Loading @@ -2123,7 +2129,7 @@ HEADER_INLINE uint32_t VecIsAligned(const void* ptr) { HEADER_INLINE void VecAlignUp(void* pp) { uintptr_t addr = *S_CAST(uintptr_t*, pp); #if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) #if (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__APPLE__) // bleah, need to write this way to avoid gcc 4.4 strict-aliasing warning addr = RoundUpPow2(addr, kBytesPerVec); memcpy(pp, &addr, sizeof(intptr_t)); Loading
plink2_bgzf.cc +1 −2 Original line number Diff line number Diff line Loading @@ -562,8 +562,7 @@ THREAD_FUNC_DECL BgzfCompressorThread(void* raw_arg) { BgzfCompressCommWithW** cwws = bgzfp->cwws; uintptr_t* next_job_idxp = bgzfp->next_job_idxp; while (1) { // make this depend on gcc version? const uint32_t slot_idx = __sync_fetch_and_add(next_job_idxp, 1) & slot_mask; const uint32_t slot_idx = __atomic_fetch_add(next_job_idxp, 1, __ATOMIC_ACQ_REL) & slot_mask; BgzfCompressCommWithP* cwp = cwps[slot_idx]; BgzfCompressCommWithW* cww = cwws[slot_idx]; #ifdef _WIN32 Loading
plink2_bgzf.h +4 −3 Original line number Diff line number Diff line Loading @@ -178,12 +178,13 @@ void CleanupBgzfRawMtStream(BgzfRawMtDecompressStream* bgzfp); // threads), but that proved to be slightly slower than htslib's bgzf writer // in my testing; it didn't do a good enough job of managing the // split-between-production-and-compression core. // So I've switched to a more flexible thread pool using // __sync_fetch_and_add() to distribute compression jobs. // So I've switched to a more flexible thread pool using __atomic_fetch_add() // to distribute compression jobs. // - There's a dedicated writer thread which flushes the compression results. // I will look into adding direct support for this parallelization pattern to // plink2_thread; the benefit is small (~5%), but applies to a lot of // workloads. // workloads. It may also be worthwhile to implement some form of // work-stealing. // // I tried making this less granular (each job contains two blocks instead of // one) to see if there was still meaningful room for improvement re: reducing Loading
plink2_cmdline.cc +10 −5 Original line number Diff line number Diff line Loading @@ -2456,8 +2456,7 @@ void DupflagHtableMakerMain(uint32_t tidx, uint32_t thread_ct, DupflagHtableMake for (uint32_t hashval = Hashceil(sptr, slen, id_htable_size); ; ) { uint32_t old_htable_entry = id_htable[hashval]; if (old_htable_entry == UINT32_MAX) { old_htable_entry = __sync_val_compare_and_swap(&(id_htable[hashval]), UINT32_MAX, item_uidx); if (old_htable_entry == UINT32_MAX) { if (ATOMIC_COMPARE_EXCHANGE_N_U32(&(id_htable[hashval]), &old_htable_entry, item_uidx, 0, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) { break; } } Loading Loading @@ -2505,10 +2504,16 @@ PglErr MakeDupflagHtable(const uintptr_t* subset_mask, const char* const* item_i DupflagHtableMaker ctx; { uint32_t thread_ct = item_ct / 65536; if (!thread_ct) { thread_ct = 1; } else { if (thread_ct > max_thread_ct) { thread_ct = max_thread_ct; } else if (!thread_ct) { thread_ct = 1; } // bugfix (26 Nov 2019): forgot to force this if (thread_ct > kMaxDupflagThreads) { thread_ct = kMaxDupflagThreads; } } if (unlikely(SetThreadCt0(thread_ct - 1, &tg))) { goto MakeDupflagHtable_ret_NOMEM; Loading