From 6041118c738d3e725ee4aee3fb1432d0a37a5a50 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 30 Jun 2021 11:45:52 -0400 Subject: [PATCH 01/17] Improve speed of bowtie-build sanity checking --- multikey_qsort.h | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/multikey_qsort.h b/multikey_qsort.h index 81ce6296..4b4f2d90 100644 --- a/multikey_qsort.h +++ b/multikey_qsort.h @@ -1,6 +1,7 @@ #ifndef MULTIKEY_QSORT_H_ #define MULTIKEY_QSORT_H_ +#include #include #include "alphabet.h" @@ -292,26 +293,38 @@ bool assertPartitionedSuf2( #endif /** - * Assert that the seqan::String s of suffix offsets into seqan::String - * 'host' is a seemingly legitimate suffix-offset list (at this time, - * we just check that it doesn't list any suffix twice). + * Assert that string s of suffix offsets into string 'host' is a seemingly + * legitimate suffix-offset list (at this time, we just check that it doesn't + * list any suffix twice). */ + static inline void sanityCheckInputSufs(TIndexOffU *s, size_t slen) { assert_gt(slen, 0); - for(size_t i = 0; i < slen; i++) { - // Actually, it's convenient to allow the caller to provide - // suffix offsets thare are off the end of the host string. - // See, e.g., build() in diff_sample.cpp. - //assert_lt(s[i], length(host)); - for(size_t j = i+1; j < slen; j++) { - assert_neq(s[i], s[j]); + // Try keeping the running time <1min + if (slen > 4096) { + TIndexOffU *s_copy = new TIndexOffU[slen]; + assert(s_copy != NULL); + std::copy(s, s + slen, s_copy); + std::sort(s_copy, s_copy + slen); + for (size_t i = 0; i < slen - 1; i++) + assert_neq(s_copy[i], s_copy[i + 1]); + delete[] s_copy; + } else { + for(size_t i = 0; i < slen; i++) { + // Actually, it's convenient to allow the caller to provide + // suffix offsets thare are off the end of the host string. + // See, e.g., build() in diff_sample.cpp. + //assert_lt(s[i], length(host)); + for(size_t j = i+1; j < slen; j++) { + assert_neq(s[i], s[j]); + } } } } /** - * Assert that the seqan::String s of suffix offsets into seqan::String - * 'host' really are in lexicographical order up to depth 'upto'. + * Assert that the string s of suffix offsets into 'host' really are in + * lexicographical order up to depth 'upto'. */ template void sanityCheckOrderedSufs(const T& host, From b4d6ed899851e3d54015dcda55dde97edbc73e81 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 30 Jun 2021 11:47:55 -0400 Subject: [PATCH 02/17] Fix issue that may cause deadlocks when using MCS lock with many threads --- bt2_locks.cpp | 20 ++++++++--------- bt2_locks.h | 26 ++++++++++++---------- threading.h | 60 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/bt2_locks.cpp b/bt2_locks.cpp index 293718f6..b39af237 100644 --- a/bt2_locks.cpp +++ b/bt2_locks.cpp @@ -1,21 +1,21 @@ -#include "bt2_locks.h" - #if (__cplusplus >= 201103L) -void mcs_lock::lock() { +#include "bt2_locks.h" + +void mcs_lock::lock(mcs_node &node) { node.next = nullptr; - node.unlocked = false; - mcs_node *pred = q.exchange(&node, std::memory_order_release); + mcs_node *pred = q.exchange(&node, std::memory_order_acq_rel); if (pred) { - pred->next = &node; + node.unlocked = false; + pred->next.store(&node, std::memory_order_release); spin_while_eq(node.unlocked, false); } node.unlocked.load(std::memory_order_acquire); } -void mcs_lock::unlock() { - if (!node.next) { +void mcs_lock::unlock(mcs_node &node) { + if (!node.next.load(std::memory_order_acquire)) { mcs_node *node_ptr = &node; if (q.compare_exchange_strong(node_ptr, (mcs_node *)nullptr, @@ -23,10 +23,9 @@ void mcs_lock::unlock() { return; spin_while_eq(node.next, (mcs_node *)nullptr); } - node.next->unlocked.store(true, std::memory_order_release); + node.next.load(std::memory_order_acquire)->unlocked.store(true, std::memory_order_release); } -thread_local mcs_lock::mcs_node mcs_lock::node; void spin_lock::lock() { cpu_backoff backoff; @@ -37,4 +36,5 @@ void spin_lock::lock() { void spin_lock::unlock() { flag.clear(std::memory_order_release); } + #endif diff --git a/bt2_locks.h b/bt2_locks.h index b956ea4e..85584152 100644 --- a/bt2_locks.h +++ b/bt2_locks.h @@ -12,13 +12,17 @@ class cpu_backoff { public: cpu_backoff(): count(1) {} - void pause() { + inline void pause() { if (count <= LOOPS_BEFORE_YIELD) { for (int32_t i = 0; i < count; i++) { #ifdef __aarch64__ __asm__ __volatile__("yield" ::: "memory"); -#else +#elif __ppc__ + __asm__ __volatile__("or 27,27,27" ::: "memory"); +#elif __x86_64__ __asm__ __volatile__("pause;"); +#else + // do nothing #endif } count *= 2; @@ -44,27 +48,27 @@ class mcs_lock { public: mcs_lock(): q(nullptr) {} struct mcs_node { - mcs_node *next; + std::atomic next; std::atomic_bool unlocked; }; - void lock(); - void unlock(); - typedef mcs_node* mcs_node_ptr; + void lock(mcs_node &node); + void unlock(mcs_node &node); + typedef std::atomic mcs_node_ptr; private: - void spin_while_eq(const volatile mcs_node_ptr& value, mcs_node *expected) { + void spin_while_eq(const volatile mcs_node_ptr& value, const volatile mcs_node *expected) { cpu_backoff backoff; - while (value == expected) + while (value.load(std::memory_order_acquire) == expected) backoff.pause(); } - void spin_while_eq(const volatile std::atomic_bool& value, bool expected) { + void spin_while_eq(const volatile std::atomic_bool& value, const volatile bool expected) { cpu_backoff backoff; while (value.load(std::memory_order_acquire) == expected) backoff.pause(); } std::atomic q; - static thread_local mcs_node node; }; -#endif + +#endif // if (__cplusplus >= 201103L) #endif // __MCS_LOCK_H__ diff --git a/threading.h b/threading.h index 3cd9e198..f727fa12 100644 --- a/threading.h +++ b/threading.h @@ -19,13 +19,17 @@ #ifdef NO_SPINLOCK # if (__cplusplus >= 201103L) # ifdef WITH_QUEUELOCK - #include "bt2_locks.h" -# define MUTEX_T mcs_lock +# include "bt2_locks.h" +# define MUTEX_T mcs_lock # else -# define MUTEX_T std::mutex +# define MUTEX_T std::mutex # endif # else -# define MUTEX_T tthread::mutex +# ifdef WITH_QUEUELOCK +# error "QUEUELOCK requires C++11 or newer." +# else +# define MUTEX_T tthread::mutex +# endif # endif #else # if (__cplusplus >= 201103L) @@ -57,24 +61,56 @@ struct thread_tracking_pair { /** * Wrap a lock; obtain lock upon construction, release upon destruction. */ +// class ThreadSafe { +// public: + +// ThreadSafe(MUTEX_T* ptr_mutex) : +// ptr_mutex_(ptr_mutex) +// { +// assert(ptr_mutex_ != NULL); +// ptr_mutex_->lock(); +// } + +// ~ThreadSafe() { +// ptr_mutex_->unlock(); +// } + +// private: +// MUTEX_T *ptr_mutex_; +// }; class ThreadSafe { public: - ThreadSafe(MUTEX_T* ptr_mutex) : - ptr_mutex_(ptr_mutex) - { - assert(ptr_mutex_ != NULL); - ptr_mutex_->lock(); - } + ThreadSafe(MUTEX_T *mutex) : +#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK + node_{}, +#endif + mutex_(mutex) { +#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK + mutex_->lock(node_); +#else + mutex_->lock(); +#endif + + } ~ThreadSafe() { - ptr_mutex_->unlock(); +#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK + mutex_->unlock(node_); +#else + mutex_->unlock(); +#endif } private: - MUTEX_T *ptr_mutex_; + +#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK + MUTEX_T::mcs_node node_; +#endif + MUTEX_T *mutex_; }; + #if defined(_TTHREAD_WIN32_) #define SLEEP(x) Sleep(x) #else From a8441a5abf9be175fb1033ead8a3d453a3a5efae Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 30 Jun 2021 11:48:52 -0400 Subject: [PATCH 03/17] Fix compiler warnings --- shmem.h | 3 ++- util.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/shmem.h b/shmem.h index 19d2e764..c4cc79bc 100644 --- a/shmem.h +++ b/shmem.h @@ -10,6 +10,7 @@ #ifdef BOWTIE_SHARED_MEM +#include #include #include #include @@ -102,7 +103,7 @@ bool allocSharedMem(std::string fname, cerr << "shmctl returned " << ret << " for IPC_STAT and errno is " << errno << endl; throw 1; } - if(ds.shm_segsz != shmemLen) { + if((size_t)ds.shm_segsz != shmemLen) { cerr << "Warning: shared-memory chunk's segment size (" << ds.shm_segsz << ") doesn't match expected size (" << shmemLen << ")" << endl << "Deleting old shared memory block and trying again." << endl; diff --git a/util.h b/util.h index d126c565..a5b6a268 100644 --- a/util.h +++ b/util.h @@ -47,7 +47,7 @@ char* itoa10(const T& value, char* result) { // Only apply negative sign for base 10 if(std::numeric_limits::is_signed) { // Avoid compiler warning in cases where T is unsigned - if (value <= 0 && value != 0) *out++ = '-'; + if (value < 0) *out++ = '-'; } std::reverse( result, out ); *out = 0; // terminator From 2b0caf191f7e5c75c93a5ff3054f4437c48b9baa Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 30 Jun 2021 11:49:26 -0400 Subject: [PATCH 04/17] Various Makefile improvements --- Makefile | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 9b85f72a..df5bf657 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ bindir = $(prefix)/bin ARCH = $(shell uname -m) INC = $(if $(RELEASE_BUILD),-I$(CURDIR)/.include) -I third_party -LIBS = $(LDFLAGS) $(if $(RELEASE_BUILD),-L$(CURDIR)/.lib) -lz +LIBS = $(LDFLAGS) $(if $(RELEASE_BUILD),-L$(CURDIR)/.lib) -lz -lpthread HEADERS = $(wildcard *.h) BOWTIE_MM = 1 BOWTIE_SHARED_MEM = 1 @@ -65,25 +65,9 @@ SHMEM_DEF = ifeq (1,$(BOWTIE_SHARED_MEM)) SHMEM_DEF = -DBOWTIE_SHARED_MEM endif -PTHREAD_PKG = -PTHREAD_LIB = -PTHREAD_DEF = ifeq (1,$(MINGW)) - PTHREAD_LIB = override EXTRA_FLAGS += -static-libgcc -static-libstdc++ -else - PTHREAD_LIB = -lpthread -endif - -ifeq (1,$(NO_SPINLOCK)) - override EXTRA_FLAGS += -DNO_SPINLOCK -endif - - -LIBS += $(PTHREAD_LIB) -ifeq (1, $(WITH_TBBMALLOC)) - LIBS += -ltbbmalloc endif POPCNT_CAPABILITY ?= 1 @@ -113,15 +97,14 @@ ifeq (1,$(WITH_THREAD_PROFILING)) endif OTHER_CPPS = ccnt_lut.cpp ref_read.cpp alphabet.cpp shmem.cpp \ - edit.cpp ebwt.cpp + edit.cpp ebwt.cpp bt2_locks.cpp -ifneq (1, $(NO_SPINLOCK)) - OTHER_CPPS += bt2_locks.cpp +ifeq (1,$(WITH_QUEUELOCK)) + override EXTRA_FLAGS += -DWITH_QUEUELOCK=1 -DNO_SPINLOCK endif -ifeq (1,$(WITH_QUEUELOCK)) - OTHER_CPPS += bt2_locks.cpp - override EXTRA_FLAGS += -DWITH_QUEUELOCK=1 +ifeq (1, $(NO_SPINLOCK)) + EXTRA_FLAGS += -DNO_SPINLOCK endif ifeq (1,$(WITH_FINE_TIMER)) @@ -232,9 +215,9 @@ DEFS=-fno-strict-aliasing \ $(MM_DEF) \ $(SHMEM_DEF) -ALL_FLAGS = $(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS) -DEBUG_DEFS = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(ALL_FLAGS)\"" -RELEASE_DEFS = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(ALL_FLAGS)\"" +# ALL_FLAGS = "$(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS)" +DEBUG_DEFS = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS)\"" +RELEASE_DEFS = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS)\"" # # bowtie-build targets From 58e89f2f7933425065bee9bafe9b9fee40006c58 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 30 Jun 2021 11:50:56 -0400 Subject: [PATCH 05/17] Add workflow for running simple tests --- .github/workflows/simple_tests.yml | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/simple_tests.yml diff --git a/.github/workflows/simple_tests.yml b/.github/workflows/simple_tests.yml new file mode 100644 index 00000000..67535308 --- /dev/null +++ b/.github/workflows/simple_tests.yml @@ -0,0 +1,54 @@ +name: Run bowtie simple tests on Ubuntu and MacOS +on: + push: + branches: + - 'bug_fixes' + - 'master' + paths: + - '**.c' + - '**.h' + - '**.cpp' + - 'bowtie' + - 'bowtie-build' + - 'bowtie-inspect' + - 'Makefile' + - 'scripts/test/**' + pull_request: + branches: + - 'master' + paths: + - '**.c' + - '**.h' + - '**.cpp' + - 'bowtie' + - 'bowtie-build' + - 'bowtie-inspect' + - 'Makefile' + - 'scripts/test/**' +jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Install zlib development files + run: | + sudo apt-get update + sudo apt-get install zlib1g-dev + linux: + runs-on: ubuntu-latest + needs: setup + steps: + - uses: actions/checkout@v2 + - name: Run simple tests + run: | + make allall + make simple-test + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Run simple tests + run: | + make allall + make simple-test From e0881bfa61e754c2abaa78dcbd96151336834f44 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 30 Jun 2021 11:51:37 -0400 Subject: [PATCH 06/17] Remove X86_64 architectures from TravisCI test matrix --- .travis.yml | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3829181a..78b1c4b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,45 +7,6 @@ branches: - bug_fixes matrix: include: - # Linux (gcc4.9) - - os: linux - language: python - python: "3.4" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.9 - - zlib1g-dev - env: - - CC=gcc-4.9 - - CXX=g++-4.9 - # Linux (gcc8) - - os: linux - language: python - python: "3.8" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-8 - - zlib1g-dev - env: - - CC=gcc-8 - - CXX=g++-8 - - CXXFLAGS="-fuse-ld=gold" - # MacOS - - os: osx - osx_image: xcode11.2 - compiler: clang - env: - - CC=clang - - CXX=clang++ - - NPROC="$(sysctl -n hw.activecpu)" - before_install: - - brew unlink python@2 # ARM 64-bit - os: linux arch: arm64 From 7c4356fba9a719563673c27555838c9fc2451d2e Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Thu, 22 Jul 2021 10:44:07 -0400 Subject: [PATCH 07/17] Fix issue which caused -M to produce an incorrect alignment summary #125 --- hit.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hit.h b/hit.h index 90ecd7e3..6cdba0e7 100644 --- a/hit.h +++ b/hit.h @@ -288,16 +288,21 @@ class HitSink { numMaxed += ptNumMaxed_[i]; } - uint64_t tot = numAligned + numUnaligned + numMaxed; + uint64_t tot = numAligned + numUnaligned; + if (!sampleMax_) + tot += numMaxed; double alPct = 0.0, unalPct = 0.0, maxPct = 0.0; if(tot > 0) { - alPct = 100.0 * (double)(numAligned + numMaxed) / (double)tot; + if (sampleMax_) + alPct = 100.0 * (double)(numAligned) / (double)tot; + else + alPct = 100.0 * (double)(numAligned + numMaxed) / (double)tot; unalPct = 100.0 * (double)numUnaligned / (double)tot; maxPct = 100.0 * (double)numMaxed / (double)tot; } cerr << "# reads processed: " << tot << endl; cerr << "# reads with at least one alignment: " - << numAligned + numMaxed << " (" << fixed << setprecision(2) + << numAligned + (sampleMax_ ? 0 : numMaxed) << " (" << fixed << setprecision(2) << alPct << "%)" << endl; cerr << "# reads that failed to align: " << numUnaligned << " (" << fixed << setprecision(2) From 5368b991d5d176861de09b54e770b1933d994b1f Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Thu, 2 Sep 2021 14:58:11 -0400 Subject: [PATCH 08/17] Fix an overflow issue that would corrupt the index created by bowtie-build #124 --- ebwt.h | 80 +++++++++++++++++++++++++++---------------------------- mem_ids.h | 35 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 41 deletions(-) create mode 100644 mem_ids.h diff --git a/ebwt.h b/ebwt.h index 9204cb22..ba48a7cf 100644 --- a/ebwt.h +++ b/ebwt.h @@ -36,6 +36,7 @@ #include "threading.h" #include "timer.h" #include "word_io.h" +#include "mem_ids.h" #ifdef POPCNT_CAPABILITY #include "processor_support.h" @@ -206,7 +207,7 @@ class EbwtParams { uint32_t sideSz() const { return _sideSz; } uint32_t sideBwtSz() const { return _sideBwtSz; } uint32_t sideBwtLen() const { return _sideBwtLen; } - uint32_t numSidePairs() const { return _numSidePairs; } /* check */ + TIndexOffU numSidePairs() const { return _numSidePairs; } /* check */ TIndexOffU numSides() const { return _numSides; } TIndexOffU numLines() const { return _numLines; } TIndexOffU ebwtTotLen() const { return _ebwtTotLen; } @@ -310,7 +311,7 @@ class EbwtParams { uint32_t _sideSz; uint32_t _sideBwtSz; uint32_t _sideBwtLen; - uint32_t _numSidePairs; + TIndexOffU _numSidePairs; TIndexOffU _numSides; TIndexOffU _numLines; TIndexOffU _ebwtTotLen; @@ -754,17 +755,17 @@ class Ebwt { dcv <<= 1; TIndexOffU sz = (TIndexOffU)DifferenceCoverSample::simulateAllocs(s, dcv >> 1); if(nthreads > 1) sz *= (nthreads + 1); - AutoArray tmp(sz); + AutoArray tmp(sz, EBWT_CAT); dcv >>= 1; // Likewise with the KarkkainenBlockwiseSA sz = (TIndexOffU)KarkkainenBlockwiseSA::simulateAllocs(s, bmax); - AutoArray tmp2(sz); + AutoArray tmp2(sz, EBWT_CAT); // Now throw in the 'ftab' and 'isaSample' structures // that we'll eventually allocate in buildToDisk - AutoArray ftab(_eh._ftabLen * 2); + AutoArray ftab(_eh._ftabLen * 2, EBWT_CAT); AutoArray side(_eh._sideSz); // Grab another 20 MB out of caution - AutoArray extra(20*1024*1024); + AutoArray extra(20*1024*1024, EBWT_CAT); // If we made it here without throwing bad_alloc, then we // passed the memory-usage stress test VMSG(" Passed! Constructing with these parameters: --bmax " << bmax << " --dcv " << dcv); @@ -3996,13 +3997,14 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, assert(sa.suffixItrIsReset()); // assert_leq((int)ValueSize::VALUE, 4); - TIndexOffU len = eh._len; - TIndexOffU ftabLen = eh._ftabLen; - TIndexOffU sideSz = eh._sideSz; - TIndexOffU ebwtTotSz = eh._ebwtTotSz; - TIndexOffU fchr[] = {0, 0, 0, 0, 0}; - TIndexOffU* ftab = NULL; - TIndexOffU zOff = OFF_MASK; + TIndexOffU len = eh._len; + TIndexOffU ftabLen = eh._ftabLen; + TIndexOffU sideSz = eh._sideSz; + TIndexOffU ebwtTotSz = eh._ebwtTotSz; + TIndexOffU fchr[] = {0, 0, 0, 0, 0}; + EList ftab(EBWT_CAT); + TIndexOffU zOff = OFF_MASK; + // Save # of occurrences of each character as we walk along the bwt TIndexOffU occ[4] = {0, 0, 0, 0}; @@ -4013,42 +4015,42 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, // The absorbed rows represent suffixes shorter than the ftabChars // cutoff. uint8_t absorbCnt = 0; - uint8_t *absorbFtab; + EList absorbFtab(EBWT_CAT); + try { VMSG_NL("Allocating ftab, absorbFtab"); - ftab = new TIndexOffU[ftabLen]; - memset(ftab, 0, OFF_SIZE * ftabLen); - absorbFtab = new uint8_t[ftabLen]; - memset(absorbFtab, 0, ftabLen); + ftab.resize(ftabLen); + ftab.fillZero(); + absorbFtab.resize(ftabLen); + absorbFtab.fillZero(); + } catch(bad_alloc &e) { cerr << "Out of memory allocating ftab[] or absorbFtab[] " << "in Ebwt::buildToDisk() at " << __FILE__ << ":" << __LINE__ << endl; throw e; } - assert(ftab != NULL); - assert(absorbFtab != NULL); // Allocate the side buffer; holds a single side as its being // constructed and then written to disk. Reused across all sides. #ifdef SIXTY4_FORMAT - uint64_t *ebwtSide = NULL; + EList ebwtSide(EBWT_CAT); #else - uint8_t *ebwtSide = NULL; + EList ebwtSide(EBWT_CAT); #endif try { #ifdef SIXTY4_FORMAT - ebwtSide = new uint64_t[sideSz >> 3]; + ebwtSide.resize(sideSz >> 3); #else - ebwtSide = new uint8_t[sideSz]; + ebwtSide.resize(sideSz); #endif + } catch(bad_alloc &e) { cerr << "Out of memory allocating ebwtSide[] in " << "Ebwt::buildToDisk() at " << __FILE__ << ":" << __LINE__ << endl; throw e; } - assert(ebwtSide != NULL); // Allocate a buffer to hold the ISA sample, which we accumulate in // the loop and then output at the end. We can't write output the @@ -4244,7 +4246,7 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, // Write 'G' and 'T' assert_leq(occSave[0], occ[2]); assert_leq(occSave[1], occ[3]); - TIndexOffU *u32side = reinterpret_cast(ebwtSide); + TIndexOffU *u32side = reinterpret_cast(ebwtSide.ptr()); side += sideSz; assert_leq(side, eh._ebwtTotSz); #ifdef BOWTIE_64BIT_INDEX @@ -4255,14 +4257,14 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, u32side[(sideSz >> 2)-1] = endianizeU(occSave[1], this->toBe()); #endif // Write forward side to primary file - out1.write((const char *)ebwtSide, sideSz); + out1.write((const char *)ebwtSide.ptr(), sideSz); } else if (sideCur == -1) { // Backward side boundary assert_eq(0, si % eh._sideBwtLen); sideCur = 0; assert(!fw); fw = true; // Write 'A' and 'C' - TIndexOffU *u32side = reinterpret_cast(ebwtSide); + TIndexOffU *u32side = reinterpret_cast(ebwtSide.ptr()); side += sideSz; assert_leq(side, eh._ebwtTotSz); #ifdef BOWTIE_64BIT_INDEX @@ -4275,11 +4277,10 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, occSave[0] = occ[2]; // save 'G' count occSave[1] = occ[3]; // save 'T' count // Write backward side to primary file - out1.write((const char *)ebwtSide, sideSz); + out1.write((const char *)ebwtSide.ptr(), sideSz); } } VMSG_NL("Exited Ebwt loop"); - assert(ftab != NULL); assert_neq(zOff, OFF_MASK); if(absorbCnt > 0) { // Absorb any trailing, as-yet-unabsorbed short suffixes into @@ -4331,20 +4332,20 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, } assert_leq(eftabLen, (TIndexOffU)eh._ftabChars*2); eftabLen = eh._ftabChars*2; - TIndexOffU *eftab = NULL; + EList eftab(EBWT_CAT); try { - eftab = new TIndexOffU[eftabLen]; - memset(eftab, 0, OFF_SIZE * eftabLen); + eftab.resize(eftabLen); + eftab.fillZero(); } catch(bad_alloc &e) { cerr << "Out of memory allocating eftab[] " << "in Ebwt::buildToDisk() at " << __FILE__ << ":" << __LINE__ << endl; throw e; } - assert(eftab != NULL); + TIndexOffU eftabCur = 0; for(TIndexOffU i = 1; i < ftabLen; i++) { - TIndexOffU lo = ftab[i] + Ebwt::ftabHi(ftab, eftab, len, ftabLen, eftabLen, i-1); + TIndexOffU lo = ftab[i] + Ebwt::ftabHi(ftab.ptr(), eftab.ptr(), len, ftabLen, eftabLen, i-1); if(absorbFtab[i] > 0) { // Skip a number of short pattern indicated by absorbFtab[i] TIndexOffU hi = lo + absorbFtab[i]; @@ -4352,13 +4353,13 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, eftab[eftabCur*2] = lo; eftab[eftabCur*2+1] = hi; ftab[i] = (eftabCur++) ^ OFF_MASK; // insert pointer into eftab - assert_eq(lo, Ebwt::ftabLo(ftab, eftab, len, ftabLen, eftabLen, i)); - assert_eq(hi, Ebwt::ftabHi(ftab, eftab, len, ftabLen, eftabLen, i)); + assert_eq(lo, Ebwt::ftabLo(ftab.ptr(), eftab.ptr(), len, ftabLen, eftabLen, i)); + assert_eq(hi, Ebwt::ftabHi(ftab.ptr(), eftab.ptr(), len, ftabLen, eftabLen, i)); } else { ftab[i] = lo; } } - assert_eq(Ebwt::ftabHi(ftab, eftab, len, ftabLen, eftabLen, ftabLen-1), len+1); + assert_eq(Ebwt::ftabHi(ftab.ptr(), eftab.ptr(), len, ftabLen, eftabLen, ftabLen-1), len+1); // Write ftab to primary file for(TIndexOffU i = 0; i < ftabLen; i++) { writeU(out1, ftab[i], this->toBe()); @@ -4379,9 +4380,6 @@ void Ebwt::buildToDisk(InorderBlockwiseSA& sa, } delete[] isaSample; } - delete[] ftab; - delete[] eftab; - delete[] absorbFtab; // Note: if you'd like to sanity-check the Ebwt, you'll have to // read it back into memory first! diff --git a/mem_ids.h b/mem_ids.h new file mode 100644 index 00000000..352817be --- /dev/null +++ b/mem_ids.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011, Ben Langmead + * + * This file is part of Bowtie 2. + * + * Bowtie 2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Bowtie 2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bowtie 2. If not, see . + */ + +// For holding index data +#define EBWT_CAT ((int) 1) +// For holding index-building data +#define EBWTB_CAT ((int) 2) +// For holding cache data +#define CA_CAT ((int) 3) +// For holding group-walk-left bookkeeping data +#define GW_CAT ((int) 4) +// For holding alignment bookkeeping data +#define AL_CAT ((int) 5) +// For holding dynamic programming bookkeeping data +#define DP_CAT ((int) 6) +// For holding alignment results and other hit objects +#define RES_CAT ((int) 7) +#define MISC_CAT ((int) 9) +#define DEBUG_CAT ((int)10) From f3f5630303aa70660925e9574064476bbf6b9184 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 8 Sep 2021 15:09:27 -0400 Subject: [PATCH 09/17] Fix build issues when compiling with C++98 standard or earlier. --- Makefile | 10 ++++++---- threading.h | 8 ++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index df5bf657..42c44762 100644 --- a/Makefile +++ b/Makefile @@ -100,11 +100,13 @@ OTHER_CPPS = ccnt_lut.cpp ref_read.cpp alphabet.cpp shmem.cpp \ edit.cpp ebwt.cpp bt2_locks.cpp ifeq (1,$(WITH_QUEUELOCK)) - override EXTRA_FLAGS += -DWITH_QUEUELOCK=1 -DNO_SPINLOCK + NO_SPINLOCK = 1 + override EXTRA_FLAGS += -DWITH_QUEUELOCK endif -ifeq (1, $(NO_SPINLOCK)) - EXTRA_FLAGS += -DNO_SPINLOCK +ifeq (1,$(NO_SPINLOCK)) +$(info $(NO_SPINLOCK)) + override EXTRA_FLAGS += -DNO_SPINLOCK endif ifeq (1,$(WITH_FINE_TIMER)) @@ -215,7 +217,7 @@ DEFS=-fno-strict-aliasing \ $(MM_DEF) \ $(SHMEM_DEF) -# ALL_FLAGS = "$(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS)" +ALL_FLAGS = $(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS) DEBUG_DEFS = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS)\"" RELEASE_DEFS = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(EXTRA_FLAGS) $(CFLAGS) $(CXXFLAGS)\"" diff --git a/threading.h b/threading.h index f727fa12..e8b42315 100644 --- a/threading.h +++ b/threading.h @@ -82,11 +82,11 @@ class ThreadSafe { public: ThreadSafe(MUTEX_T *mutex) : -#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK +#if (__cplusplus >= 201103L && defined(NO_SPINLOCK) && defined(WITH_QUEUELOCK)) node_{}, #endif mutex_(mutex) { -#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK +#if (__cplusplus >= 201103L && defined(NO_SPINLOCK) && defined(WITH_QUEUELOCK)) mutex_->lock(node_); #else mutex_->lock(); @@ -95,7 +95,7 @@ class ThreadSafe { } ~ThreadSafe() { -#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK +#if (__cplusplus >= 201103L && defined(NO_SPINLOCK) && defined(WITH_QUEUELOCK)) mutex_->unlock(node_); #else mutex_->unlock(); @@ -104,7 +104,7 @@ class ThreadSafe { private: -#if __cplusplus >= 201103L && NO_SPINLOCK && WITH_QUEUELOCK +#if (__cplusplus >= 201103L && defined(NO_SPINLOCK) && defined(WITH_QUEUELOCK)) MUTEX_T::mcs_node node_; #endif MUTEX_T *mutex_; From 965fd6e0afb26d3bfce7f35f947790c8d7ad8f69 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 8 Sep 2021 15:11:21 -0400 Subject: [PATCH 10/17] Fix an issue causing bowtie to output incorrect XM:i value for certain reads #127 --- hit.h | 1 - 1 file changed, 1 deletion(-) diff --git a/hit.h b/hit.h index 6cdba0e7..82e9eb4d 100644 --- a/hit.h +++ b/hit.h @@ -775,7 +775,6 @@ class HitSinkPerThread { if(paired) { xms /= 2; } - xms++; _sink.reportHits(NULL, &_bufferedHits, 0, _bufferedHits.size(), threadId_, mapq, xms, true, p); _sink.dumpAlign(p); From 6b798ca14f16b2097c9b667331c5c73a5f93f135 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Wed, 8 Sep 2021 15:46:34 -0400 Subject: [PATCH 11/17] Fix compiler warning --- ebwt_search_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebwt_search_util.h b/ebwt_search_util.h index b1a847b5..2abc1061 100644 --- a/ebwt_search_util.h +++ b/ebwt_search_util.h @@ -34,7 +34,7 @@ struct QueryMutation { * into the spillover list, a non-tail entry in the spillover list, or * a tail entry in the spillover list. */ -typedef union { +typedef union PartialAlignment { struct { uint64_t pos0 : 16; // mismatched pos 1 uint64_t pos1 : 16; // mismatched pos 2 From c73d48533e16164785b55d3b0109707ef3220040 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Mon, 13 Sep 2021 09:36:06 -0400 Subject: [PATCH 12/17] Add workflow for running random tests triggered by commits to master --- .github/workflows/random_tests.yml | 53 ++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/random_tests.yml diff --git a/.github/workflows/random_tests.yml b/.github/workflows/random_tests.yml new file mode 100644 index 00000000..6361e602 --- /dev/null +++ b/.github/workflows/random_tests.yml @@ -0,0 +1,53 @@ +name: Run bowtie random tests for all commits to master on Ubuntu and MacOS +on: + push: + branches: + - 'master' + paths: + - '**.c' + - '**.h' + - '**.cpp' + - 'bowtie' + - 'bowtie-build' + - 'bowtie-inspect' + - 'Makefile' + - 'scripts/test/**' + pull_request: + branches: + - 'master' + paths: + - '**.c' + - '**.h' + - '**.cpp' + - 'bowtie' + - 'bowtie-build' + - 'bowtie-inspect' + - 'Makefile' + - 'scripts/test/**' +jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Install zlib development files + run: | + sudo apt-get update + sudo apt-get install zlib1g-dev + linux: + runs-on: ubuntu-latest + needs: setup + steps: + - uses: actions/checkout@v2 + - name: Run random tests + run: | + make allall + make random-test + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Run random tests + run: | + make allall + make random-test From 7207fb493d76d42db824fb07a27fc8edef487b9a Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Mon, 13 Sep 2021 09:49:00 -0400 Subject: [PATCH 13/17] Remove outdated cpuid.h --- third_party/cpuid.h | 187 -------------------------------------------- 1 file changed, 187 deletions(-) delete mode 100644 third_party/cpuid.h diff --git a/third_party/cpuid.h b/third_party/cpuid.h deleted file mode 100644 index 6a9688f6..00000000 --- a/third_party/cpuid.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. - * - * This file is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 3, or (at your option) any - * later version. - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * Under Section 7 of GPL version 3, you are granted additional - * permissions described in the GCC Runtime Library Exception, version - * 3.1, as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License and - * a copy of the GCC Runtime Library Exception along with this program; - * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - * . - */ - -/* %ecx */ -#define bit_SSE3 (1 << 0) -#define bit_PCLMUL (1 << 1) -#define bit_SSSE3 (1 << 9) -#define bit_FMA (1 << 12) -#define bit_CMPXCHG16B (1 << 13) -#define bit_SSE4_1 (1 << 19) -#define bit_SSE4_2 (1 << 20) -#define bit_MOVBE (1 << 22) -#define bit_POPCNT (1 << 23) -#define bit_AES (1 << 25) -#define bit_XSAVE (1 << 26) -#define bit_OSXSAVE (1 << 27) -#define bit_AVX (1 << 28) -#define bit_F16C (1 << 29) -#define bit_RDRND (1 << 30) - -/* %edx */ -#define bit_CMPXCHG8B (1 << 8) -#define bit_CMOV (1 << 15) -#define bit_MMX (1 << 23) -#define bit_FXSAVE (1 << 24) -#define bit_SSE (1 << 25) -#define bit_SSE2 (1 << 26) - -/* Extended Features */ -/* %ecx */ -#define bit_LAHF_LM (1 << 0) -#define bit_ABM (1 << 5) -#define bit_SSE4a (1 << 6) -#define bit_XOP (1 << 11) -#define bit_LWP (1 << 15) -#define bit_FMA4 (1 << 16) -#define bit_TBM (1 << 21) - -/* %edx */ -#define bit_LM (1 << 29) -#define bit_3DNOWP (1 << 30) -#define bit_3DNOW (1 << 31) - -/* Extended Features (%eax == 7) */ -#define bit_FSGSBASE (1 << 0) -#define bit_BMI (1 << 3) - -#if defined(__i386__) && defined(__PIC__) -/* %ebx may be the PIC register. */ -#if __GNUC__ >= 3 -#define __cpuid(level, a, b, c, d) \ - __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchg{l}\t{%%}ebx, %1\n\t" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - -#define __cpuid_count(level, count, a, b, c, d) \ - __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchg{l}\t{%%}ebx, %1\n\t" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ - : "0" (level), "2" (count)) -#else -/* Host GCCs older than 3.0 weren't supporting Intel asm syntax - nor alternatives in i386 code. */ -#define __cpuid(level, a, b, c, d) \ - __asm__ ("xchgl\t%%ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchgl\t%%ebx, %1\n\t" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - -#define __cpuid_count(level, count, a, b, c, d) \ - __asm__ ("xchgl\t%%ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchgl\t%%ebx, %1\n\t" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ - : "0" (level), "2" (count)) -#endif -#else -#define __cpuid(level, a, b, c, d) \ - __asm__ ("cpuid\n\t" \ - : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - -#define __cpuid_count(level, count, a, b, c, d) \ - __asm__ ("cpuid\n\t" \ - : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ - : "0" (level), "2" (count)) -#endif - -/* Return highest supported input value for cpuid instruction. ext can - be either 0x0 or 0x8000000 to return highest supported value for - basic or extended cpuid information. Function returns 0 if cpuid - is not supported or whatever cpuid returns in eax register. If sig - pointer is non-null, then first four bytes of the signature - (as found in ebx register) are returned in location pointed by sig. */ - -static __inline unsigned int -__get_cpuid_max (unsigned int __ext, unsigned int *__sig) -{ - unsigned int __eax, __ebx, __ecx, __edx; - -#ifndef __x86_64__ -#if __GNUC__ >= 3 - /* See if we can use cpuid. On AMD64 we always can. */ - __asm__ ("pushf{l|d}\n\t" - "pushf{l|d}\n\t" - "pop{l}\t%0\n\t" - "mov{l}\t{%0, %1|%1, %0}\n\t" - "xor{l}\t{%2, %0|%0, %2}\n\t" - "push{l}\t%0\n\t" - "popf{l|d}\n\t" - "pushf{l|d}\n\t" - "pop{l}\t%0\n\t" - "popf{l|d}\n\t" - : "=&r" (__eax), "=&r" (__ebx) - : "i" (0x00200000)); -#else -/* Host GCCs older than 3.0 weren't supporting Intel asm syntax - nor alternatives in i386 code. */ - __asm__ ("pushfl\n\t" - "pushfl\n\t" - "popl\t%0\n\t" - "movl\t%0, %1\n\t" - "xorl\t%2, %0\n\t" - "pushl\t%0\n\t" - "popfl\n\t" - "pushfl\n\t" - "popl\t%0\n\t" - "popfl\n\t" - : "=&r" (__eax), "=&r" (__ebx) - : "i" (0x00200000)); -#endif - - if (!((__eax ^ __ebx) & 0x00200000)) - return 0; -#endif - - /* Host supports cpuid. Return highest supported cpuid input value. */ - __cpuid (__ext, __eax, __ebx, __ecx, __edx); - - if (__sig) - *__sig = __ebx; - - return __eax; -} - -/* Return cpuid data for requested cpuid level, as found in returned - eax, ebx, ecx and edx registers. The function checks if cpuid is - supported and returns 1 for valid cpuid information or 0 for - unsupported cpuid level. All pointers are required to be non-null. */ - -static __inline int -__get_cpuid (unsigned int __level, - unsigned int *__eax, unsigned int *__ebx, - unsigned int *__ecx, unsigned int *__edx) -{ - unsigned int __ext = __level & 0x80000000; - - if (__get_cpuid_max (__ext, 0) < __level) - return 0; - - __cpuid (__level, *__eax, *__ebx, *__ecx, *__edx); - return 1; -} From 8564c9bb0c0b6ace41287cc631e6ddbb0d8d2743 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Mon, 13 Sep 2021 09:49:49 -0400 Subject: [PATCH 14/17] Remove duplicate third_party includes --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 42c44762..996e68f2 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,6 @@ ifeq (aarch64,$(shell uname -m)) endif ifeq (1, $(POPCNT_CAPABILITY)) override EXTRA_FLAGS += -DPOPCNT_CAPABILITY - INC += -I third_party endif PREFETCH_LOCALITY = 2 From 6933de2975e1963e55f3acf7d32ec0e21d56731a Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Mon, 13 Sep 2021 19:27:45 -0400 Subject: [PATCH 15/17] Update path to ar binary and remove c++98 standard requirement --- scripts/bowtie-hbb.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/bowtie-hbb.sh b/scripts/bowtie-hbb.sh index 0909049c..6ad9385f 100755 --- a/scripts/bowtie-hbb.sh +++ b/scripts/bowtie-hbb.sh @@ -45,7 +45,7 @@ fi source /hbb_exe_gc_hardened/activate mkdir /mybin -echo 'res=`echo $@ | sed "s/-L.*$//"`; echo $res; echo $res; /opt/rh/devtoolset-7/root/usr/bin/ar $res;' > /mybin/ar +echo 'res=`echo $@ | sed "s/-L.*$//"`; /opt/rh/devtoolset-8/root/usr/bin/ar $res;' > /mybin/ar chmod +x /mybin/ar && export PATH=/mybin:$PATH # make static-libs @@ -54,7 +54,7 @@ chmod +x /mybin/ar && export PATH=/mybin:$PATH # exit 1 # fi -make bowtie-bin.zip RELEASE_BUILD=1 EXTRA_FLAGS="--std=c++98" +make bowtie-bin.zip RELEASE_BUILD=1 if [ $? -ne 0 ] ; then echo "Unable to create bowtie package" exit 1 From 29772a4766f6476d2d10534827cbd23471066d15 Mon Sep 17 00:00:00 2001 From: Rone Charles Date: Mon, 13 Sep 2021 19:56:11 -0400 Subject: [PATCH 16/17] Update documentation in preparation for release 1.3.1 --- NEWS | 14 +++++++++++++- VERSION | 2 +- doc/website/manual.ssi | 2 +- doc/website/recent_news.ssi | 8 ++++++++ doc/website/rhsidebar.ssi | 4 ++-- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index f6337728..22a301c9 100644 --- a/NEWS +++ b/NEWS @@ -5,7 +5,7 @@ Bowtie NEWS Bowtie is now available for download. 0.9.0 is the first version to be released under the OSI Artistic License (see `LICENSE') and freely -available to the public for download. The current version is 1.3.0. +available to the public for download. The current version is 1.3.1. Reporting Issues ================ @@ -23,6 +23,18 @@ Keep up with our releases on the GitHub releases page: Version Release History ======================= +Version 1.3.1 - Sep 13, 2021 + + * Fixed an overflow issue in `bowtie-build` that would sometimes + yield corrupt "large" (64-bit) indexes; the resulting index + would sometimes cause `bowtie` to hang. Note: `bowtie2-build` + does not have this issue. + * Fixed an issue in `bowtie` causing XM:i SAM optional field to + sometimes be off by 1 when using the `-m/-M` flags. + * Fixed an issue that would sometimes cause deadlocks in `bowtie` + when running multithreaded. + * Fixed an issue causing build errors when compiling against + a pre-C++11 standard. Version 1.3.0 - Jul 22, 2020 diff --git a/VERSION b/VERSION index f0bb29e7..3a3cd8cc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.0 +1.3.1 diff --git a/doc/website/manual.ssi b/doc/website/manual.ssi index 0fbee603..9956793a 100644 --- a/doc/website/manual.ssi +++ b/doc/website/manual.ssi @@ -1,5 +1,5 @@

Table of Contents

-

Bowtie 1.3.0

+

Bowtie 1.3.1