diff --git a/Framework/Parallel/CMakeLists.txt b/Framework/Parallel/CMakeLists.txt index 4c78ef283fe0f86092dc889ce0a0c2768afc9f63..faeda7ba64d758c12ab9f9839854d03c36543c78 100644 --- a/Framework/Parallel/CMakeLists.txt +++ b/Framework/Parallel/CMakeLists.txt @@ -3,6 +3,7 @@ set ( SRC_FILES src/ExecutionMode.cpp src/IO/Chunker.cpp src/IO/EventLoader.cpp + src/IO/EventParser.cpp src/Request.cpp src/StorageMode.cpp src/ThreadingBackend.cpp diff --git a/Framework/Parallel/inc/MantidParallel/IO/EventParser.h b/Framework/Parallel/inc/MantidParallel/IO/EventParser.h index 0c28a8baeac863f7ed3ab32c0074fd60e1bd409f..dcd5bde8d02773f6aef2a6061b0a7fc2c66486ef 100644 --- a/Framework/Parallel/inc/MantidParallel/IO/EventParser.h +++ b/Framework/Parallel/inc/MantidParallel/IO/EventParser.h @@ -55,6 +55,20 @@ template <class TimeOffsetType> struct Event { TimeOffsetType tof; Types::Core::DateAndTime pulseTime; }; + +void MANTID_PARALLEL_DLL eventIdToGlobalSpectrumIndex(int32_t *event_id_start, + size_t count, + const int32_t bankOffset); + +template <class TimeOffsetType> +void redistributeDataMPI( + Communicator &comm, std::vector<Event<TimeOffsetType>> &result, + const std::vector<std::vector<Event<TimeOffsetType>>> &data); + +template <class TimeOffsetType> +void populateEventLists( + const std::vector<Event<TimeOffsetType>> &events, + std::vector<std::vector<Types::Event::TofEvent> *> &eventLists); } template <class IndexType, class TimeZeroType, class TimeOffsetType> @@ -79,15 +93,6 @@ public: const TimeOffsetType *eventTimeOffset, const Chunker::LoadRange &range); - void eventIdToGlobalSpectrumIndex(int32_t *event_id_start, size_t count, - size_t bankIndex) const; - - void populateEventList(const std::vector<Event> &events); - - const std::vector<std::vector<Event>> &rankData() const { - return m_allRankData; - } - void wait() const; private: @@ -142,24 +147,6 @@ void EventParser<IndexType, TimeZeroType, TimeOffsetType>::setPulseInformation( event_time_zero_offset); } -/** Transform event IDs to global spectrum numbers using the bankOffsets stored - * at object creation. - * - * The transformation is in-place to save memory bandwidth and modifies the - * range pointed to by `event_id_start`. - * @param event_id_start Starting position of chunk of data containing event - * IDs. - * @param count Number of items in data chunk - * @param bankIndex Index into the list of bank offsets. - */ -template <class IndexType, class TimeZeroType, class TimeOffsetType> -void EventParser<IndexType, TimeZeroType, TimeOffsetType>:: - eventIdToGlobalSpectrumIndex(int32_t *event_id_start, size_t count, - size_t bankIndex) const { - for (size_t i = 0; i < count; ++i) - event_id_start[i] -= m_bankOffsets[bankIndex]; -} - /** Extracts event information from the list of time offsets and global spectrum * indices using the event_index and event_time_offset tables provided from * file. These events are separated according to MPI ranks. @@ -191,6 +178,7 @@ void EventParser<IndexType, TimeZeroType, TimeOffsetType>:: } } +namespace detail { /** Uses MPI calls to redistribute chunks which must be processed on certain * ranks. * @param comm MPI communicator. @@ -200,9 +188,9 @@ void EventParser<IndexType, TimeZeroType, TimeOffsetType>:: */ template <class TimeOffsetType> void redistributeDataMPI( - Communicator &comm, std::vector<detail::Event<TimeOffsetType>> &result, - const std::vector<std::vector<detail::Event<TimeOffsetType>>> &data) { - using Event = detail::Event<TimeOffsetType>; + Communicator &comm, std::vector<Event<TimeOffsetType>> &result, + const std::vector<std::vector<Event<TimeOffsetType>>> &data) { + using Event = Event<TimeOffsetType>; if (comm.size() == 1) { result = data.front(); return; @@ -248,20 +236,21 @@ void redistributeDataMPI( /** Fills the workspace EventList with extracted events * @param events Events extracted from file according to mpi rank. */ -template <class IndexType, class TimeZeroType, class TimeOffsetType> -void EventParser<IndexType, TimeZeroType, TimeOffsetType>::populateEventList( - const std::vector<Event> &events) { +template <class TimeOffsetType> +void populateEventLists( + const std::vector<Event<TimeOffsetType>> &events, + std::vector<std::vector<Types::Event::TofEvent> *> &eventLists) { for (const auto &event : events) { - m_eventLists[event.index]->emplace_back(event.tof, event.pulseTime); + eventLists[event.index]->emplace_back(event.tof, event.pulseTime); // In general `index` is random so this loop suffers from frequent cache // misses (probably because the hardware prefetchers cannot keep up with the // number of different memory locations that are getting accessed). We // manually prefetch into L2 cache to reduce the amount of misses. - _mm_prefetch( - reinterpret_cast<char *>(&m_eventLists[event.index]->back() + 1), - _MM_HINT_T1); + _mm_prefetch(reinterpret_cast<char *>(&eventLists[event.index]->back() + 1), + _MM_HINT_T1); } } +} /** Accepts raw data from file which has been pre-treated and sorted into chunks * for parsing. The parser extracts event data from the provided buffers, @@ -292,16 +281,16 @@ void EventParser<IndexType, TimeZeroType, TimeOffsetType>::doParsing( int32_t *event_id_start, const TimeOffsetType *event_time_offset_start, const Chunker::LoadRange &range) { // change event_id_start in place - eventIdToGlobalSpectrumIndex(event_id_start, range.eventCount, - range.bankIndex); + detail::eventIdToGlobalSpectrumIndex(event_id_start, range.eventCount, + m_bankOffsets[range.bankIndex]); // event_id_start now contains globalSpectrumIndex extractEventsForRanks(m_allRankData, event_id_start, event_time_offset_start, range); - redistributeDataMPI(m_comm, m_thisRankData, m_allRankData); + detail::redistributeDataMPI(m_comm, m_thisRankData, m_allRankData); // TODO: accept something which translates from global to local spectrum index - populateEventList(m_thisRankData); + populateEventLists(m_thisRankData, m_eventLists); } template <class IndexType, class TimeZeroType, class TimeOffsetType> diff --git a/Framework/Parallel/src/IO/EventParser.cpp b/Framework/Parallel/src/IO/EventParser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70f00e1f5657edb6fb0e87a620fb0a2e888a6496 --- /dev/null +++ b/Framework/Parallel/src/IO/EventParser.cpp @@ -0,0 +1,27 @@ +#include "MantidParallel/IO/EventParser.h" + +namespace Mantid { +namespace Parallel { +namespace IO { +namespace detail { + +/** Transform event IDs to global spectrum numbers using the bankOffsets stored + * at object creation. + * + * The transformation is in-place to save memory bandwidth and modifies the + * range pointed to by `event_id_start`. + * @param event_id_start Starting position of chunk of data containing event + * IDs. + * @param count Number of items in data chunk + * @param bankOffset Offset to subtract from the array `event_id_start`. + */ +void eventIdToGlobalSpectrumIndex(int32_t *event_id_start, size_t count, + const int32_t bankOffset) { + for (size_t i = 0; i < count; ++i) + event_id_start[i] -= bankOffset; +} + +} // namespace detail +} // namespace IO +} // namespace Parallel +} // namespace Mantid diff --git a/Framework/Parallel/test/EventParserTest.h b/Framework/Parallel/test/EventParserTest.h index e51a47ef2d082d1082dd27e0cff10e74dd108ecd..1825ee53b4f4e3be3f637b976a6cd8dbf105c548 100644 --- a/Framework/Parallel/test/EventParserTest.h +++ b/Framework/Parallel/test/EventParserTest.h @@ -152,17 +152,11 @@ public: } void testConvertEventIDToGlobalSpectrumIndex() { - std::vector<std::vector<int>> rankGroups; std::vector<int32_t> bankOffsets{1000}; - std::vector<std::vector<TofEvent> *> eventLists(10); - - Parallel::Communicator comm; - EventParser<int64_t, int64_t, double> parser(comm, rankGroups, bankOffsets, - eventLists); - std::vector<int32_t> eventId{1001, 1002, 1004, 1004}; auto eventIdCopy = eventId; - parser.eventIdToGlobalSpectrumIndex(eventId.data(), eventId.size(), 0); + detail::eventIdToGlobalSpectrumIndex(eventId.data(), eventId.size(), + bankOffsets[0]); TS_ASSERT_EQUALS(eventId[0], eventIdCopy[0] - bankOffsets[0]); TS_ASSERT_EQUALS(eventId[1], eventIdCopy[1] - bankOffsets[0]); @@ -178,8 +172,8 @@ public: auto event_time_offset = gen.eventTimeOffset(0); auto range = gen.generateBasicRange(0); - parser->eventIdToGlobalSpectrumIndex(event_id.data() + range.eventOffset, - range.eventCount, range.bankIndex); + detail::eventIdToGlobalSpectrumIndex(event_id.data() + range.eventOffset, + range.eventCount, 1000); std::vector<std::vector<EventParser<int32_t, int64_t, int64_t>::Event>> rankData; // event_id now contains spectrum indices @@ -201,8 +195,8 @@ public: auto event_time_offset = gen.eventTimeOffset(0); auto range = Chunker::LoadRange{0, 5, 100}; - parser->eventIdToGlobalSpectrumIndex(event_id.data() + range.eventOffset, - range.eventCount, range.bankIndex); + detail::eventIdToGlobalSpectrumIndex(event_id.data() + range.eventOffset, + range.eventCount, 1000); std::vector<std::vector<EventParser<int32_t, int64_t, int64_t>::Event>> rankData; // event_id now contains spectrum indices @@ -355,6 +349,8 @@ public: } parser = gen.generateTestParser(); + for (auto &eventList : m_eventLists) + m_eventListPtrs.emplace_back(&eventList); } void testCompletePerformance() { @@ -373,8 +369,8 @@ public: gen.generateBasicRange(bank)); } - void testPopulateEventListPerformance() { - parser->populateEventList(rankData[0]); + void testPopulateEventListsPerformance() { + detail::populateEventLists(rankData[0], m_eventListPtrs); } private: @@ -385,5 +381,7 @@ private: boost::shared_ptr<EventParser<int32_t, int64_t, double>> parser; std::vector<std::vector<EventParser<int32_t, int64_t, double>::Event>> rankData; + std::vector<std::vector<TofEvent>> m_eventLists{NUM_BANKS * 1000}; + std::vector<std::vector<TofEvent> *> m_eventListPtrs; }; #endif /* MANTID_PARALLEL_COLLECTIVESTEST_H_ */