diff --git a/CMakeLists.txt b/CMakeLists.txt index 7af8a83f..1f290122 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ option(SHAD_ENABLE_CPPLINT "Enable the linting of source code" ON) option(SHAD_ENABLE_DOXYGEN "Use doxygen to generate the shad API documentation" OFF) option(SHAD_ENABLE_UNIT_TEST "Enable the compilation of Unit Tests" ON) option(SHAD_ENABLE_PERFORMANCE_TEST "Enable the compilation of the Performance Tests" OFF) +option(SHAD_ENABLE_LOGGING "Enable the logging system" OFF) set( SHAD_RUNTIME_SYSTEM "CPP_SIMPLE" CACHE STRING diff --git a/README.md b/README.md index 270cf96b..257e0dd8 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,18 @@ cmake .. -DCMAKE_INSTALL_PREFIX=$GMT_ROOT \ make -j && make install ``` +#### SPDLOG +SHAD uses spdlog which is very fast, header only and C++ library for logging. +It can be installed using the following commands: + +``` +git clone https://github.com/gabime/spdlog.git +cd spdlog +mkdir build && cd build +cmake .. +make -j +``` + ### Build SHAD Before attempting to build SHAD, please take a look at the requirements in [Install Dependencies](#install-dependencies). @@ -82,7 +94,9 @@ cmake .. -DCMAKE_INSTALL_PREFIX=$SHADROOT \ -DGMT_ROOT=$GMTROOT \ # endif \ -DGTEST_ROOT=$GTESTROOT \ - -DGPERFTOOLS_ROOT=$GPERFTOOLSROOT + -DGPERFTOOLS_ROOT=$GPERFTOOLSROOT \ + -DSPDLOG_ROOT=$INCLUDE_DIR_PATH_OF_SPDLOG \ + -DSHAD_ENABLE_LOGGING = 1 make -j && make install ``` If you have multiple compilers (or compiler versions) available on your system, you may want to indicate a specific one using the ```-DCMAKE_CXX_COMPILER=``` option. diff --git a/cmake/FindSPDLOG.cmake b/cmake/FindSPDLOG.cmake new file mode 100644 index 00000000..ff19e174 --- /dev/null +++ b/cmake/FindSPDLOG.cmake @@ -0,0 +1,25 @@ +# Try to find the SPDLOG header only library +# Created by Methun +# Input variables: +# SPDLOG_ROOT - The SPDLOG root folder directory +# Output variables: +# SPDLOG_FOUND - System has SPDLOG +# SPDLOG_INCLUDE_DIRS - The SPDLOG include directories + +include(FindPackageHandleStandardArgs) + +if (NOT DEFINED SPDLOG_FOUND) + + # Set default search paths + if (SPDLOG_ROOT) + set(SPDLOG_INCLUDE_DIR ${SPDLOG_ROOT}/include CACHE PATH "The include directory for SPDLOG") + endif() + + find_path(SPDLOG_INCLUDE_DIRS NAMES spdlog/spdlog.h HINTS ${SPDLOG_INCLUDE_DIR}) + + find_package_handle_standard_args(SPDLOG + FOUND_VAR SPDLOG_FOUND + REQUIRED_VARS SPDLOG_INCLUDE_DIRS + HANDLE_COMPONENTS) + mark_as_advanced(SPDLOG_INCLUDE_DIR SPDLOG_INCLUDE_DIRS) +endif() diff --git a/cmake/config.cmake b/cmake/config.cmake index 06e5e1ee..eb862af2 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -121,6 +121,15 @@ if (GPERFTOOLS_FOUND) endif() endif() +# spdlog: this portion added by methun +if (SHAD_ENABLE_LOGGING) + message(STATUS "Using spdlog library for logging the benchmark.") + find_package(SPDLOG REQUIRED) + message(STATUS ${SPDLOG_INCLUDE_DIRS}) + include_directories(${SPDLOG_INCLUDE_DIRS}) + set(HAVE_LOGGING 1) +endif() + if (SHAD_ENABLE_UNIT_TEST) find_package(GTest REQUIRED) endif() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 75d4c2ba..286f3573 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(array) add_subdirectory(edge_index_graph) +add_subdirectory(Number_add) + diff --git a/examples/Number_add/CMakeLists.txt b/examples/Number_add/CMakeLists.txt new file mode 100644 index 00000000..3a1ca0be --- /dev/null +++ b/examples/Number_add/CMakeLists.txt @@ -0,0 +1,6 @@ +set(program add-number) + +foreach(p ${program}) + add_executable(${p} ${p}.cc) + target_link_libraries(${p} ${SHAD_RUNTIME_LIB} runtime) +endforeach(p) diff --git a/examples/Number_add/add-number.cc b/examples/Number_add/add-number.cc new file mode 100644 index 00000000..f1a31f92 --- /dev/null +++ b/examples/Number_add/add-number.cc @@ -0,0 +1,168 @@ +//===------------------------------------------------------------*- C++ -*-===// +// +// SHAD +// +// The Scalable High-performance Algorithms and Data Structure Library +// +//===----------------------------------------------------------------------===// +// +// Copyright 2018 Battelle Memorial Institute +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +//===----------------------------------------------------------------------===// + +/* + Developer Date Description + ================================================================================ + Methun K 07/11/2018 Simple implementation of adding huge amount of numbers to compare the runtime among traditional forloop, shad sync ForEach and AsyncForEach method. + Methun K 07/26/2018 Replace the console print to log write for testing + -------------------------------------------------------------------------------- + */ + +#include +#include + +#include "shad/data_structures/array.h" +#include "shad/runtime/runtime.h" +#include "shad/util/measure.h" + #include "shad/util/slog.h" + +// Local sum container +std::atomic bigSum(0); +std::atomic offset(0); + +void getRand(size_t index, int& rVal, size_t& range){ + std::default_random_engine generator; + std::uniform_int_distribution distribution(0,range); + + rVal = (offset++) + distribution(generator); + + offset = offset % 999999; +} + +void getAsyncRand(shad::rt::Handle& handle, size_t index, int& rVal, size_t& range){ + std::default_random_engine generator; + std::uniform_int_distribution distribution(0,2*range); + + rVal = (offset++) + distribution(generator); + + offset = offset % 999989; +} + +void accumulateForEach(size_t pos, int& val){ + bigSum += val; +} + +void accumulateAsyncForEach(shad::rt::Handle& handle, size_t pos, int& val){ + bigSum += val; +} + +template +void printArray(T &array, const size_t &size){ + for(size_t i=0;iAt(i)<<","; + } + std::cout<<"\n"; +} + +void syncLoadFor(const size_t& arraySize){ + int a(0); + auto myarray = shad::Array::Create(arraySize,a); + + std::default_random_engine generator; + std::uniform_int_distribution distribution(0,99999); + + #if defined HAVE_LOGGING + auto t1 = shad_clock::now(); + #endif + + for(size_t i=0; iInsertAt(i, rVal); + } + + #if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("For:Load", diff.count(), nullptr, shad::rt::thisLocality(), shad::rt::thisLocality(), sizeof(size_t), sizeof(std::atomic), arraySize); + + t1 = shad_clock::now(); + #endif + + bigSum = 0; + for(size_t i=0; iAt(i); + } + + #if defined HAVE_LOGGING + t2 = shad_clock::now(); + diff = t2-t1; + log_handler->printlf("For:Sum", diff.count(), nullptr, shad::rt::thisLocality(), shad::rt::thisLocality(), sizeof(size_t), sizeof(std::atomic), arraySize); + #endif + + std::cout<<"Sum: "<::Create(arraySize,a); + size_t r = 919199; + + myarray->ForEach(getRand, r); + + bigSum = 0; + myarray->ForEach(accumulateForEach); + + std::cout<<"Sum: "<::Create(arraySize,a); + size_t r = 898989; + shad::rt::Handle handle; + + myarray->AsyncForEach(handle, getAsyncRand, r); + shad::rt::waitForCompletion(handle); + + //printArray(myarray, arraySize); + + bigSum = 0; + myarray->AsyncForEach(handle, accumulateAsyncForEach); + shad::rt::waitForCompletion(handle); + + std::cout<<"Sum: "< -struct AsynchronousInterface { - template - static void asyncExecuteAt(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args) { - using FunctionTy = void (*)(Handle &, const InArgsT &); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - gmt_execute_on_node_with_handle( - getNodeId(loc), execAsyncFunWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), nullptr, - nullptr, GMT_PREEMPTABLE, getGmtHandle(handle)); - } - - template - static void asyncExecuteAt(Handle &handle, const Locality &loc, - FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_node_with_handle( - getNodeId(loc), execAsyncFunWrapper, buffer.get(), newBufferSize, - nullptr, nullptr, GMT_PREEMPTABLE, getGmtHandle(handle)); - } - - template - static void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args, - uint8_t *resultBuffer, - uint32_t *resultSize) { - using FunctionTy = - void (*)(Handle &, const InArgsT &, uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_node_with_handle( - getNodeId(loc), asyncExecFunWithRetBuffWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), - resultBuffer, resultSize, GMT_PREEMPTABLE, getGmtHandle(handle)); - } - - template - static void asyncExecuteAtWithRetBuff( - Handle &handle, const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, const uint32_t bufferSize, - uint8_t *resultBuffer, uint32_t *resultSize) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t, - uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_node_with_handle( - getNodeId(loc), asyncExecFunWithRetBuffWrapper, buffer.get(), - newBufferSize, resultBuffer, resultSize, GMT_PREEMPTABLE, - getGmtHandle(handle)); - } - - template - static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, - FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, ResT *result) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, ResT *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_node_with_handle( - getNodeId(loc), asyncExecFunWithRetWrapper, buffer.get(), - newBufferSize, result, &garbageSize, GMT_PREEMPTABLE, - getGmtHandle(handle)); - } - - template - static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args, - ResT *result) { - using FunctionTy = void (*)(Handle &, const InArgsT &, ResT *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - uint32_t resultSize = 0; - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_node_with_handle( - getNodeId(loc), asyncExecFunWithRetWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), result, - &garbageSize, GMT_PREEMPTABLE, getGmtHandle(handle)); - } - - template - static void asyncExecuteOnAll(Handle &handle, FunT &&function, - const InArgsT &args) { - using FunctionTy = void (*)(Handle &, const InArgsT &); - - FunctionTy fn = std::forward(function); - - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_all_with_handle(execAsyncFunWrapper, - reinterpret_cast(&funArgs), - sizeof(funArgs), GMT_PREEMPTABLE, - getGmtHandle(handle)); - } - - template - static void asyncExecuteOnAll(Handle &handle, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - - checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_execute_on_all_with_handle(execAsyncFunWrapper, buffer.get(), - newBufferSize, GMT_PREEMPTABLE, - getGmtHandle(handle)); - } - - template - static void asyncForEachAt(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args, - const size_t numIters) { - using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - // No need to do anything. - if (!numIters) return; - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - uint32_t workload = - numIters / (gmt_num_workers() * kOverSubscriptionFactor); - workload = std::max(workload, uint32_t(1)); - - ExecFunWrapperArgs funArgs{fn, args}; - - gmt_for_loop_on_node_with_handle( - getNodeId(loc), numIters, workload, - asyncForEachWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), - getGmtHandle(handle)); - } - - template - static void asyncForEachAt(Handle &handle, const Locality &loc, - FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - // No need to do anything. - if (!numIters) return; - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - uint8_t *basePtr = buffer.get(); - *reinterpret_cast(basePtr) = fn; - basePtr += sizeof(fn); - - if (argsBuffer != nullptr && bufferSize) { - memcpy(basePtr, &bufferSize, sizeof(bufferSize)); - basePtr += sizeof(bufferSize); - memcpy(basePtr, argsBuffer.get(), bufferSize); - } - uint32_t workload = - numIters / (gmt_num_workers() * kOverSubscriptionFactor); - workload = std::max(workload, uint32_t(1)); - - gmt_for_loop_on_node_with_handle(getNodeId(loc), numIters, workload, - asyncForEachWrapper, buffer.get(), - newBufferSize, getGmtHandle(handle)); - } - - template - static void asyncForEachOnAll(Handle &handle, FunT &&function, - const InArgsT &args, const size_t numIters) { - using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - checkInputSize(sizeof(InArgsT)); - - // No need to do anything. - if (!numIters) return; - - ExecFunWrapperArgs funArgs{fn, args}; - - uint32_t workload = (numIters / gmt_num_nodes()) / - (gmt_num_workers() * kOverSubscriptionFactor); - workload = std::max(workload, uint32_t(1)); - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_for_loop_with_handle( - numIters, workload, asyncForEachWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), - GMT_SPAWN_SPREAD, getGmtHandle(handle)); - } - - template - static void asyncForEachOnAll(Handle &handle, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, - const size_t numIters) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - checkInputSize(bufferSize); - - // No need to do anything. - if (!numIters) return; - - uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); - - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) { - uint8_t *basePtr = buffer.get() + sizeof(fn); - memcpy(basePtr, &bufferSize, sizeof(bufferSize)); - basePtr += sizeof(bufferSize); - memcpy(basePtr, argsBuffer.get(), bufferSize); - } - - uint32_t workload = (numIters / gmt_num_nodes()) / gmt_num_workers(); - workload = std::max(workload, uint32_t(1)); - - handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) - : handle; - - gmt_for_loop_with_handle(numIters, workload, asyncForEachWrapper, - buffer.get(), newBufferSize, GMT_SPAWN_SPREAD, - getGmtHandle(handle)); - } -}; - -} // namespace impl - -} // namespace rt + namespace rt { + + namespace impl { + + template <> + struct AsynchronousInterface { + template + static void asyncExecuteAt(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + gmt_execute_on_node_with_handle( + getNodeId(loc), execAsyncFunWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), nullptr, + nullptr, GMT_PREEMPTABLE, getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void asyncExecuteAt(Handle &handle, const Locality &loc, + FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_node_with_handle( + getNodeId(loc), execAsyncFunWrapper, buffer.get(), newBufferSize, + nullptr, nullptr, GMT_PREEMPTABLE, getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0); +#endif + } + + template + static void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args, + uint8_t *resultBuffer, + uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const InArgsT &, uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_node_with_handle( + getNodeId(loc), asyncExecFunWithRetBuffWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), + resultBuffer, resultSize, GMT_PREEMPTABLE, getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRetBuff", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void asyncExecuteAtWithRetBuff( + Handle &handle, const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, const uint32_t bufferSize, + uint8_t *resultBuffer, uint32_t *resultSize) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t, + uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_node_with_handle( + getNodeId(loc), asyncExecFunWithRetBuffWrapper, buffer.get(), + newBufferSize, resultBuffer, resultSize, GMT_PREEMPTABLE, + getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRetBuff", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0); +#endif + } + + template + static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, + FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, ResT *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_node_with_handle( + getNodeId(loc), asyncExecFunWithRetWrapper, buffer.get(), + newBufferSize, result, &garbageSize, GMT_PREEMPTABLE, + getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRet", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0); +#endif + } + + template + static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args, + ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, ResT *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + uint32_t resultSize = 0; + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_node_with_handle( + getNodeId(loc), asyncExecFunWithRetWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), result, + &garbageSize, GMT_PREEMPTABLE, getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRet", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void asyncExecuteOnAll(Handle &handle, FunT &&function, + const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &); + + FunctionTy fn = std::forward(function); + + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_all_with_handle(execAsyncFunWrapper, + reinterpret_cast(&funArgs), + sizeof(funArgs), GMT_PREEMPTABLE, + getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT),0); +#endif + } + + template + static void asyncExecuteOnAll(Handle &handle, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + + checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_execute_on_all_with_handle(execAsyncFunWrapper, buffer.get(), + newBufferSize, GMT_PREEMPTABLE, + getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr),0); +#endif + } + + template + static void asyncForEachAt(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args, + const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + // No need to do anything. + if (!numIters) return; + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + uint32_t workload = + numIters / (gmt_num_workers() * kOverSubscriptionFactor); + workload = std::max(workload, uint32_t(1)); + + ExecFunWrapperArgs funArgs{fn, args}; + + gmt_for_loop_on_node_with_handle( + getNodeId(loc), numIters, workload, + asyncForEachWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), + getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0, numIters); +#endif + } + + template + static void asyncForEachAt(Handle &handle, const Locality &loc, + FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + // No need to do anything. + if (!numIters) return; + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + uint8_t *basePtr = buffer.get(); + *reinterpret_cast(basePtr) = fn; + basePtr += sizeof(fn); + + if (argsBuffer != nullptr && bufferSize) { + memcpy(basePtr, &bufferSize, sizeof(bufferSize)); + basePtr += sizeof(bufferSize); + memcpy(basePtr, argsBuffer.get(), bufferSize); + } + uint32_t workload = + numIters / (gmt_num_workers() * kOverSubscriptionFactor); + workload = std::max(workload, uint32_t(1)); + + gmt_for_loop_on_node_with_handle(getNodeId(loc), numIters, workload, + asyncForEachWrapper, buffer.get(), + newBufferSize, getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0, numIters); +#endif + } + + template + static void asyncForEachOnAll(Handle &handle, FunT &&function, + const InArgsT &args, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + checkInputSize(sizeof(InArgsT)); + + // No need to do anything. + if (!numIters) return; + + ExecFunWrapperArgs funArgs{fn, args}; + + uint32_t workload = (numIters / gmt_num_nodes()) / + (gmt_num_workers() * kOverSubscriptionFactor); + workload = std::max(workload, uint32_t(1)); + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_for_loop_with_handle( + numIters, workload, asyncForEachWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), + GMT_SPAWN_SPREAD, getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT),0, numIters); +#endif + } + + template + static void asyncForEachOnAll(Handle &handle, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, + const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + checkInputSize(bufferSize); + + // No need to do anything. + if (!numIters) return; + + uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); + + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) { + uint8_t *basePtr = buffer.get() + sizeof(fn); + memcpy(basePtr, &bufferSize, sizeof(bufferSize)); + basePtr += sizeof(bufferSize); + memcpy(basePtr, argsBuffer.get(), bufferSize); + } + + uint32_t workload = (numIters / gmt_num_nodes()) / gmt_num_workers(); + workload = std::max(workload, uint32_t(1)); + + handle = (handle.IsNull()) ? Handle(HandleTrait::CreateNewHandle()) + : handle; + + gmt_for_loop_with_handle(numIters, workload, asyncForEachWrapper, + buffer.get(), newBufferSize, GMT_SPAWN_SPREAD, + getGmtHandle(handle)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachOnAll-argsBuffer", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr),0, numIters); +#endif + } + }; + + } // namespace impl + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_ASYNCHRONOUS_INTERFACE_H_ + diff --git a/include/shad/runtime/mappings/gmt/gmt_synchronous_interface.h b/include/shad/runtime/mappings/gmt/gmt_synchronous_interface.h index 193c7ec1..1745a046 100644 --- a/include/shad/runtime/mappings/gmt/gmt_synchronous_interface.h +++ b/include/shad/runtime/mappings/gmt/gmt_synchronous_interface.h @@ -22,6 +22,13 @@ // //===----------------------------------------------------------------------===// +/* + Developer Date Description + ================================================================================ + Methun K 08/01/2018 Added logging + -------------------------------------------------------------------------------- + */ + #ifndef INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_SYNCHRONOUS_INTERFACE_H_ #define INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_SYNCHRONOUS_INTERFACE_H_ @@ -34,301 +41,437 @@ #include #include "shad/runtime/locality.h" -#include "shad/runtime/mappings/gmt/gmt_traits_mapping.h" #include "shad/runtime/mappings/gmt/gmt_utility.h" #include "shad/runtime/synchronous_interface.h" +#include "shad/util/slog.h" namespace shad { -namespace rt { - -namespace impl { - -template <> -struct SynchronousInterface { - template - static void executeAt(const Locality &loc, FunT &&function, - const InArgsT &args) { - using FunctionTy = void (*)(const InArgsT &); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - gmt_execute_on_node(getNodeId(loc), execFunWrapper, - reinterpret_cast(&funArgs), - sizeof(funArgs), nullptr, nullptr, GMT_PREEMPTABLE); - } - - template - static void executeAt(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - - impl::checkLocality(loc); - impl::checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - gmt_execute_on_node(impl::getNodeId(loc), execFunWrapper, buffer.get(), - newBufferSize, nullptr, nullptr, GMT_PREEMPTABLE); - } - - template - static void executeAtWithRetBuff(const Locality &loc, FunT &&function, - const InArgsT &args, uint8_t *resultBuffer, - uint32_t *resultSize) { - using FunctionTy = void (*)(const InArgsT &, uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - gmt_execute_on_node( - getNodeId(loc), execFunWithRetBuffWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), - resultBuffer, resultSize, GMT_PREEMPTABLE); - } - - template - static void executeAtWithRetBuff(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, - uint8_t *resultBuffer, - uint32_t *resultSize) { - using FunctionTy = - void (*)(const uint8_t *, const uint32_t, uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - gmt_execute_on_node(getNodeId(loc), execFunWithRetBuffWrapper, buffer.get(), - newBufferSize, resultBuffer, resultSize, - GMT_PREEMPTABLE); - } - - template - static void executeAtWithRet(const Locality &loc, FunT &&function, - const InArgsT &args, ResT *result) { - using FunctionTy = void (*)(const InArgsT &, ResT *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - uint32_t resultSize = 0; - gmt_execute_on_node(getNodeId(loc), - execFunWithRetWrapper, - reinterpret_cast(&funArgs), - sizeof(funArgs), result, &resultSize, GMT_PREEMPTABLE); - } - - template - static void executeAtWithRet(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, ResT *result) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, ResT *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - uint32_t retSize; - gmt_execute_on_node(getNodeId(loc), execFunWithRetWrapper, - buffer.get(), newBufferSize, result, &retSize, - GMT_PREEMPTABLE); - } - - template - static void executeOnAll(FunT &&function, const InArgsT &args) { - using FunctionTy = void (*)(const InArgsT &); - - FunctionTy fn = std::forward(function); - - checkInputSize(sizeof(InArgsT)); - - ExecFunWrapperArgs funArgs{fn, args}; - - gmt_execute_on_all(execFunWrapper, - reinterpret_cast(&funArgs), - sizeof(funArgs), GMT_PREEMPTABLE); - } - - template - static void executeOnAll(FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - - impl::checkInputSize(bufferSize); - - uint32_t newBufferSize = bufferSize + sizeof(fn); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) - memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); - - gmt_execute_on_all(impl::execFunWrapper, buffer.get(), newBufferSize, - GMT_PREEMPTABLE); - } - - template - static void forEachAt(const Locality &loc, FunT &&function, - const InArgsT &args, const size_t numIters) { - using FunctionTy = void (*)(const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(sizeof(InArgsT)); - - // No need to do anything. - if (!numIters) return; - - uint32_t workload = - numIters / (gmt_num_workers() * kOverSubscriptionFactor); - workload = std::max(workload, uint32_t(1)); - - impl::ExecFunWrapperArgs funArgs{fn, args}; - - gmt_for_loop_on_node(impl::getNodeId(loc), numIters, workload, - impl::forEachWrapper, - reinterpret_cast(&funArgs), - sizeof(funArgs)); - } - - template - static void forEachAt(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - checkInputSize(bufferSize); - - // No need to do anything. - if (!numIters) return; - - uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - uint8_t *basePtr = buffer.get(); - *reinterpret_cast(basePtr) = fn; - basePtr += sizeof(fn); - - if (argsBuffer != nullptr && bufferSize) { - memcpy(basePtr, &bufferSize, sizeof(bufferSize)); - basePtr += sizeof(bufferSize); - memcpy(basePtr, argsBuffer.get(), bufferSize); - } - uint32_t workload = - numIters / (gmt_num_workers() * kOverSubscriptionFactor); - workload = std::max(workload, uint32_t(1)); - - gmt_for_loop_on_node(getNodeId(loc), numIters, workload, forEachWrapper, - buffer.get(), newBufferSize); - } - - template - static void forEachOnAll(FunT &&function, const InArgsT &args, - const size_t numIters) { - using FunctionTy = void (*)(const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - impl::checkInputSize(sizeof(InArgsT)); - - // No need to do anything. - if (!numIters) return; - - impl::ExecFunWrapperArgs funArgs{fn, args}; - - uint32_t workload = (numIters / gmt_num_nodes()) / gmt_num_workers(); - workload = std::max(workload, uint32_t(1)); - - gmt_for_loop(numIters, workload, impl::forEachWrapper, - reinterpret_cast(&funArgs), sizeof(funArgs), - GMT_SPAWN_SPREAD); - } - - template - static void forEachOnAll(FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - checkInputSize(bufferSize); - - // No need to do anything. - if (!numIters) return; - - uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); - std::unique_ptr buffer(new uint8_t[newBufferSize]); - - *reinterpret_cast(const_cast(buffer.get())) = fn; - - if (argsBuffer != nullptr && bufferSize) { - uint8_t *basePtr = buffer.get() + sizeof(fn); - memcpy(basePtr, &bufferSize, sizeof(bufferSize)); - basePtr += sizeof(bufferSize); - memcpy(basePtr, argsBuffer.get(), bufferSize); - } - - uint32_t workload = (numIters / gmt_num_nodes()) / gmt_num_workers(); - workload = std::max(workload, uint32_t(1)); - - gmt_for_loop(numIters, workload, forEachWrapper, buffer.get(), - newBufferSize, GMT_SPAWN_SPREAD); - } -}; - -} // namespace impl - -} // namespace rt + namespace rt { + + namespace impl { + + template <> + struct SynchronousInterface { + template + static void executeAt(const Locality &loc, FunT &&function, + const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + gmt_execute_on_node(getNodeId(loc), execFunWrapper, + reinterpret_cast(&funArgs), + sizeof(funArgs), nullptr, nullptr, GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void executeAt(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + + impl::checkLocality(loc); + impl::checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + gmt_execute_on_node(impl::getNodeId(loc), execFunWrapper, buffer.get(), + newBufferSize, nullptr, nullptr, GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0); +#endif + } + + template + static void executeAtWithRetBuff(const Locality &loc, FunT &&function, + const InArgsT &args, uint8_t *resultBuffer, + uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + gmt_execute_on_node( + getNodeId(loc), execFunWithRetBuffWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), + resultBuffer, resultSize, GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRetBuff", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void executeAtWithRetBuff(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, + uint8_t *resultBuffer, + uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(const uint8_t *, const uint32_t, uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + gmt_execute_on_node(getNodeId(loc), execFunWithRetBuffWrapper, buffer.get(), + newBufferSize, resultBuffer, resultSize, + GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRetBuff", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0); +#endif + } + + template + static void executeAtWithRet(const Locality &loc, FunT &&function, + const InArgsT &args, ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, ResT *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + uint32_t resultSize = 0; + gmt_execute_on_node(getNodeId(loc), + execFunWithRetWrapper, + reinterpret_cast(&funArgs), + sizeof(funArgs), result, &resultSize, GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRet", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void executeAtWithRet(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, ResT *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + uint32_t retSize; + gmt_execute_on_node(getNodeId(loc), execFunWithRetWrapper, + buffer.get(), newBufferSize, result, &retSize, + GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRet", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0); +#endif + } + + template + static void executeOnAll(FunT &&function, const InArgsT &args) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &); + + FunctionTy fn = std::forward(function); + + checkInputSize(sizeof(InArgsT)); + + ExecFunWrapperArgs funArgs{fn, args}; + + gmt_execute_on_all(execFunWrapper, + reinterpret_cast(&funArgs), + sizeof(funArgs), GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT),0); +#endif + } + + template + static void executeOnAll(FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + + impl::checkInputSize(bufferSize); + + uint32_t newBufferSize = bufferSize + sizeof(fn); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) + memcpy(buffer.get() + sizeof(fn), argsBuffer.get(), bufferSize); + + gmt_execute_on_all(impl::execFunWrapper, buffer.get(), newBufferSize, + GMT_PREEMPTABLE); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr),0); +#endif + } + + template + static void forEachAt(const Locality &loc, FunT &&function, + const InArgsT &args, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(sizeof(InArgsT)); + + // No need to do anything. + if (!numIters) return; + + uint32_t workload = + numIters / (gmt_num_workers() * kOverSubscriptionFactor); + workload = std::max(workload, uint32_t(1)); + + impl::ExecFunWrapperArgs funArgs{fn, args}; + + gmt_for_loop_on_node(impl::getNodeId(loc), numIters, workload, + impl::forEachWrapper, + reinterpret_cast(&funArgs), + sizeof(funArgs)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0, numIters); +#endif + } + + template + static void forEachAt(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + checkInputSize(bufferSize); + + // No need to do anything. + if (!numIters) return; + + uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + uint8_t *basePtr = buffer.get(); + *reinterpret_cast(basePtr) = fn; + basePtr += sizeof(fn); + + if (argsBuffer != nullptr && bufferSize) { + memcpy(basePtr, &bufferSize, sizeof(bufferSize)); + basePtr += sizeof(bufferSize); + memcpy(basePtr, argsBuffer.get(), bufferSize); + } + uint32_t workload = + numIters / (gmt_num_workers() * kOverSubscriptionFactor); + workload = std::max(workload, uint32_t(1)); + + gmt_for_loop_on_node(getNodeId(loc), numIters, workload, forEachWrapper, + buffer.get(), newBufferSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr),0, numIters); +#endif + } + + template + static void forEachOnAll(FunT &&function, const InArgsT &args, + const size_t numIters) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + impl::checkInputSize(sizeof(InArgsT)); + + // No need to do anything. + if (!numIters) return; + + impl::ExecFunWrapperArgs funArgs{fn, args}; + + uint32_t workload = (numIters / gmt_num_nodes()) / gmt_num_workers(); + workload = std::max(workload, uint32_t(1)); + + gmt_for_loop(numIters, workload, impl::forEachWrapper, + reinterpret_cast(&funArgs), sizeof(funArgs), + GMT_SPAWN_SPREAD); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT),0, numIters); +#endif + } + + template + static void forEachOnAll(FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + checkInputSize(bufferSize); + + // No need to do anything. + if (!numIters) return; + + uint32_t newBufferSize = bufferSize + sizeof(fn) + sizeof(bufferSize); + std::unique_ptr buffer(new uint8_t[newBufferSize]); + + *reinterpret_cast(const_cast(buffer.get())) = fn; + + if (argsBuffer != nullptr && bufferSize) { + uint8_t *basePtr = buffer.get() + sizeof(fn); + memcpy(basePtr, &bufferSize, sizeof(bufferSize)); + basePtr += sizeof(bufferSize); + memcpy(basePtr, argsBuffer.get(), bufferSize); + } + + uint32_t workload = (numIters / gmt_num_nodes()) / gmt_num_workers(); + workload = std::max(workload, uint32_t(1)); + + gmt_for_loop(numIters, workload, forEachWrapper, buffer.get(), + newBufferSize, GMT_SPAWN_SPREAD); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr),0, numIters); +#endif + } + }; + + } // namespace impl + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_GMT_MAPPINGS_GMT_SYNCHRONOUS_INTERFACE_H_ + diff --git a/include/shad/runtime/mappings/gmt/gmt_traits_mapping.h b/include/shad/runtime/mappings/gmt/gmt_traits_mapping.h index ded6c3e2..8c39a537 100644 --- a/include/shad/runtime/mappings/gmt/gmt_traits_mapping.h +++ b/include/shad/runtime/mappings/gmt/gmt_traits_mapping.h @@ -34,70 +34,71 @@ #include "shad/runtime/mapping_traits.h" namespace shad { - -namespace rt { -namespace impl { - -struct gmt_tag {}; - -template <> -struct HandleTrait { - using HandleTy = gmt_handle_t; - using ParameterTy = gmt_handle_t &; - using ConstParameterTy = const gmt_handle_t &; - - static void Init(ParameterTy H, HandleTy V) { H = V; } - - static constexpr HandleTy NullValue() { return GMT_HANDLE_NULL; } - - static bool Equal(ConstParameterTy lhs, ConstParameterTy rhs) { - return lhs == rhs; - } - - static std::string toString(ConstParameterTy H) { return std::to_string(H); } - - static uint64_t toUnsignedInt(ConstParameterTy H) { return H; } - - static HandleTy CreateNewHandle() { return gmt_get_handle(); } - - static void WaitFor(ParameterTy &H) { - if (H == NullValue()) - std::cout << "WARNING: Called wait on a NULL handle" << std::endl; - gmt_wait_handle(H); - H = NullValue(); - } -}; - -template <> -struct LockTrait { - using LockTy = std::mutex; - - static void lock(LockTy &L) { - while (!L.try_lock()) gmt_yield(); - } - - static void unlock(LockTy &L) { L.unlock(); } -}; - -template <> -struct RuntimeInternalsTrait { - static void Initialize(int argc, char *argv[]) {} - - static void Finalize() {} - - static size_t Concurrency() { return gmt_num_workers(); } - static void Yield() { gmt_yield(); } - - static uint32_t ThisLocality() { return gmt_node_id(); } - static uint32_t NullLocality() { return -1; } - static uint32_t NumLocalities() { return gmt_num_nodes(); } -}; - -} // namespace impl - -using TargetSystemTag = impl::gmt_tag; - -} // namespace rt + + namespace rt { + namespace impl { + + struct gmt_tag {}; + + template <> + struct HandleTrait { + using HandleTy = gmt_handle_t; + using ParameterTy = gmt_handle_t &; + using ConstParameterTy = const gmt_handle_t &; + + static void Init(ParameterTy H, HandleTy V) { H = V; } + + static constexpr HandleTy NullValue() { return GMT_HANDLE_NULL; } + + static bool Equal(ConstParameterTy lhs, ConstParameterTy rhs) { + return lhs == rhs; + } + + static std::string toString(ConstParameterTy H) { return std::to_string(H); } + + static uint64_t toUnsignedInt(ConstParameterTy H) { return H; } + + static HandleTy CreateNewHandle() { return gmt_get_handle(); } + + static void WaitFor(ParameterTy &H) { + if (H == NullValue()) + std::cout << "WARNING: Called wait on a NULL handle" << std::endl; + gmt_wait_handle(H); + H = NullValue(); + } + }; + + template <> + struct LockTrait { + using LockTy = std::mutex; + + static void lock(LockTy &L) { + while (!L.try_lock()) gmt_yield(); + } + + static void unlock(LockTy &L) { L.unlock(); } + }; + + template <> + struct RuntimeInternalsTrait { + static void Initialize(int argc, char *argv[]) {} + + static void Finalize() {} + + static size_t Concurrency() { return gmt_num_workers(); } + static void Yield() { gmt_yield(); } + + static uint32_t ThisLocality() { return gmt_node_id(); } + static uint32_t NullLocality() { return -1; } + static uint32_t NumLocalities() { return gmt_num_nodes(); } + }; + + } // namespace impl + + using TargetSystemTag = impl::gmt_tag; + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_TRAITS_MAPPING_H_ + diff --git a/include/shad/runtime/mappings/gmt/gmt_utility.h b/include/shad/runtime/mappings/gmt/gmt_utility.h index 0b09e163..01c043f0 100644 --- a/include/shad/runtime/mappings/gmt/gmt_utility.h +++ b/include/shad/runtime/mappings/gmt/gmt_utility.h @@ -22,6 +22,13 @@ // //===----------------------------------------------------------------------===// +/* + Developer Date Description + ================================================================================ + Methun K 08/01/2018 Added logging + -------------------------------------------------------------------------------- + */ + #ifndef INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_UTILITY_H_ #define INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_UTILITY_H_ @@ -31,285 +38,467 @@ #include #include "shad/runtime/locality.h" +#include "shad/runtime/mappings/gmt/gmt_traits_mapping.h" +#include "shad/util/slog.h" namespace shad { -namespace rt { - -namespace impl { - -static uint32_t kOverSubscriptionFactor = 300; - -inline uint32_t getNodeId(const Locality &loc) { - return static_cast(loc); -} - -inline void checkLocality(const Locality &loc) { - uint32_t nodeID = getNodeId(loc); - if (nodeID >= gmt_num_nodes()) { - std::stringstream ss; - ss << "The system does not include " << loc; - throw std::system_error(0xdeadc0de, std::generic_category(), ss.str()); - } -} - -inline void checkInputSize(size_t size) { - if (size > gmt_max_args_per_task()) { - std::stringstream ss; - ss << "The input size exeeds the hard limit of " << gmt_max_args_per_task() - << "B imposed by GMT. A more general solution is under development."; - throw std::system_error(0xdeadc0de, std::generic_category(), ss.str()); - } -} - -inline void checkOutputSize(size_t size) { - if (size > gmt_max_return_size()) { - std::stringstream ss; - ss << "The output size exeeds the hard limit of " << gmt_max_return_size() - << "B imposed by GMT. A more general solution is under development."; - throw std::system_error(0xdeadc0de, std::generic_category(), ss.str()); - } -} - -/// @brief Structure to build the function closure to be sent. -template -struct ExecFunWrapperArgs { - FunT fun; - InArgsT args; -}; - -template -void execFunWrapper(const void *args, uint32_t args_size, void *, uint32_t *, - gmt_handle_t) { - const ExecFunWrapperArgs &funArgs = - *reinterpret_cast *>(args); - funArgs.fun(funArgs.args); -} - -inline void execFunWrapper(const void *args, uint32_t args_size, void *, - uint32_t *, gmt_handle_t) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - functionPtr(reinterpret_cast(args) + sizeof(functionPtr), - args_size - sizeof(functionPtr)); -} - -template -void execFunWithRetBuffWrapper(const void *args, uint32_t, void *result, - uint32_t *resultSize, gmt_handle_t) { - const impl::ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - funArgs->fun(fnargs, reinterpret_cast(result), resultSize); - - checkOutputSize(*resultSize); -} - -inline void execFunWithRetBuffWrapper(const void *args, uint32_t argsSize, - void *result, uint32_t *resultSize, - gmt_handle_t) { - using FunctionTy = - void (*)(const uint8_t *, const uint32_t, uint8_t *, uint32_t *); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - functionPtr(reinterpret_cast(args) + sizeof(functionPtr), - argsSize - sizeof(functionPtr), - reinterpret_cast(result), resultSize); - - checkOutputSize(*resultSize); -} - -template -void execFunWithRetWrapper(const void *args, uint32_t args_size, void *result, - uint32_t *resSize, gmt_handle_t) { - using FunctionTy = void (*)(const InArgsT &, ResT *); - - const impl::ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - - funArgs->fun(fnargs, reinterpret_cast(result)); - *resSize = sizeof(ResT); -} - -template -void execFunWithRetWrapper(const void *args, uint32_t args_size, void *result, - uint32_t *resSize, gmt_handle_t) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, ResT *); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - - ResT *resultPtr = reinterpret_cast(result); - - functionPtr(reinterpret_cast(args) + sizeof(functionPtr), - args_size - sizeof(functionPtr), resultPtr); - *resSize = sizeof(ResT); -} - -inline void forEachWrapper(uint64_t startIt, uint64_t numIters, - const void *args, gmt_handle_t) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - const uint32_t argSize = *reinterpret_cast( - reinterpret_cast(args) + sizeof(functionPtr)); - - const uint8_t *buffer = reinterpret_cast(args) + - sizeof(functionPtr) + sizeof(argSize); - - for (size_t i = 0; i < numIters; ++i) - functionPtr(buffer, argSize, startIt + i); -} - -template -void forEachWrapper(uint64_t startIt, uint64_t numIters, const void *args, - gmt_handle_t) { - const impl::ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - - for (size_t i = 0; i < numIters; ++i) funArgs->fun(fnargs, startIt + i); -} - -static uint32_t garbageSize; - -inline gmt_handle_t getGmtHandle(Handle &handle) { - return static_cast(handle); -} - -template -void execAsyncFunWrapper(const void *args, uint32_t args_size, void *, - uint32_t *, gmt_handle_t handle) { - const ExecFunWrapperArgs &funArgs = - *reinterpret_cast *>(args); - - Handle H(handle); - funArgs.fun(H, funArgs.args); -} - -inline void execAsyncFunWrapper(const void *args, uint32_t args_size, void *, - uint32_t *, gmt_handle_t handle) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - - Handle H(handle); - functionPtr(H, reinterpret_cast(args) + sizeof(functionPtr), - args_size - sizeof(functionPtr)); -} - -template -void asyncExecFunWithRetWrapper(const void *args, uint32_t args_size, - void *result, uint32_t *resSize, - gmt_handle_t handle) { - using FunctionTy = void (*)(Handle &, const InArgsT &, ResT *); - - const ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - - Handle H(handle); - funArgs->fun(H, fnargs, reinterpret_cast(result)); - *resSize = sizeof(ResT); -} - -template -void asyncExecFunWithRetWrapper(const void *args, uint32_t args_size, - void *result, uint32_t *resSize, - gmt_handle_t handle) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, ResT *); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - - ResT *resultPtr = reinterpret_cast(result); - - Handle H(handle); - functionPtr(H, reinterpret_cast(args) + sizeof(functionPtr), - args_size - sizeof(functionPtr), resultPtr); - *resSize = sizeof(ResT); -} - -template -void asyncExecFunWithRetBuffWrapper(const void *args, uint32_t, void *result, - uint32_t *resultSize, gmt_handle_t handle) { - const ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - - Handle H(handle); - funArgs->fun(H, fnargs, reinterpret_cast(result), resultSize); - - checkOutputSize(*resultSize); -} - -inline void asyncExecFunWithRetBuffWrapper(const void *args, uint32_t argsSize, - void *result, uint32_t *resultSize, - gmt_handle_t handle) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t, - uint8_t *, uint32_t *); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - - Handle H(handle); - functionPtr(H, reinterpret_cast(args) + sizeof(functionPtr), - argsSize - sizeof(functionPtr), - reinterpret_cast(result), resultSize); - - checkOutputSize(*resultSize); -} - -inline void asyncForEachWrapper(uint64_t startIt, uint64_t numIters, - const void *args, gmt_handle_t handle) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, size_t); - - FunctionTy functionPtr = - *reinterpret_cast(const_cast(args)); - const uint32_t argSize = *reinterpret_cast( - reinterpret_cast(args) + sizeof(functionPtr)); - - const uint8_t *buffer = reinterpret_cast(args) + - sizeof(functionPtr) + sizeof(argSize); - Handle H(handle); - for (size_t i = 0; i < numIters; ++i) - functionPtr(H, buffer, argSize, startIt + i); -} - -template -void asyncForEachWrapper(uint64_t startIt, uint64_t numIters, const void *args, - gmt_handle_t handle) { - const ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - - Handle H(handle); - for (size_t i = 0; i < numIters; ++i) funArgs->fun(H, fnargs, startIt + i); -} - -template -void execAsyncFunWithRetBuffWrapper(const void *args, uint32_t args_size, - void *result, uint32_t *resSize, - gmt_handle_t handle) { - const ExecFunWrapperArgs *funArgs = - reinterpret_cast *>(args); - const InArgsT &fnargs = funArgs->args; - funArgs->fun(fnargs, reinterpret_cast(result), resSize, - Handle(handle)); - - checkOutputSize(*resSize); -} - -} // namespace impl - -} // namespace rt + namespace rt { + + namespace impl { + + static uint32_t kOverSubscriptionFactor = 300; + + inline uint32_t getNodeId(const Locality &loc) { + return static_cast(loc); + } + + inline void checkLocality(const Locality &loc) { + uint32_t nodeID = getNodeId(loc); + if (nodeID >= gmt_num_nodes()) { + std::stringstream ss; + ss << "The system does not include " << loc; + throw std::system_error(0xdeadc0de, std::generic_category(), ss.str()); + } + } + + inline void checkInputSize(size_t size) { + if (size > gmt_max_args_per_task()) { + std::stringstream ss; + ss << "The input size exeeds the hard limit of " << gmt_max_args_per_task() + << "B imposed by GMT. A more general solution is under development."; + throw std::system_error(0xdeadc0de, std::generic_category(), ss.str()); + } + } + + inline void checkOutputSize(size_t size) { + if (size > gmt_max_return_size()) { + std::stringstream ss; + ss << "The output size exeeds the hard limit of " << gmt_max_return_size() + << "B imposed by GMT. A more general solution is under development."; + throw std::system_error(0xdeadc0de, std::generic_category(), ss.str()); + } + } + + /// @brief Structure to build the function closure to be sent. + template + struct ExecFunWrapperArgs { + FunT fun; + InArgsT args; + }; + + template + void execFunWrapper(const void *args, uint32_t args_size, void *, uint32_t *, + gmt_handle_t) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const ExecFunWrapperArgs &funArgs = *reinterpret_cast *>(args); + funArgs.fun(funArgs.args); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execFunWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0); +#endif + } + + inline void execFunWrapper(const void *args, uint32_t args_size, void *, + uint32_t *, gmt_handle_t) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t); + + FunctionTy functionPtr = *reinterpret_cast(const_cast(args)); + functionPtr(reinterpret_cast(args) + sizeof(functionPtr), + args_size - sizeof(functionPtr)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execFunWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), args_size - sizeof(functionPtr), 0); +#endif + } + + template + void execFunWithRetBuffWrapper(const void *args, uint32_t, void *result, + uint32_t *resultSize, gmt_handle_t) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const impl::ExecFunWrapperArgs *funArgs = reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + funArgs->fun(fnargs, reinterpret_cast(result), resultSize); + + checkOutputSize(*resultSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execFunWithRetBuffWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), sizeof(uint32_t)); +#endif + } + + inline void execFunWithRetBuffWrapper(const void *args, uint32_t argsSize, + void *result, uint32_t *resultSize, + gmt_handle_t) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(const uint8_t *, const uint32_t, uint8_t *, uint32_t *); + + FunctionTy functionPtr = + *reinterpret_cast(const_cast(args)); + functionPtr(reinterpret_cast(args) + sizeof(functionPtr), + argsSize - sizeof(functionPtr), + reinterpret_cast(result), resultSize); + + checkOutputSize(*resultSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execFunWithRetBuffWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), argsSize - sizeof(functionPtr), sizeof(*resultSize)); +#endif + } + + template + void execFunWithRetWrapper(const void *args, uint32_t args_size, void *result, + uint32_t *resSize, gmt_handle_t) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, ResT *); + + const impl::ExecFunWrapperArgs *funArgs = + reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + + funArgs->fun(fnargs, reinterpret_cast(result)); + *resSize = sizeof(ResT); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execFunWithRetWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), sizeof(ResT)); +#endif + } + + template + void execFunWithRetWrapper(const void *args, uint32_t args_size, void *result, + uint32_t *resSize, gmt_handle_t) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, ResT *); + + FunctionTy functionPtr = + *reinterpret_cast(const_cast(args)); + + ResT *resultPtr = reinterpret_cast(result); + + functionPtr(reinterpret_cast(args) + sizeof(functionPtr), + args_size - sizeof(functionPtr), resultPtr); + *resSize = sizeof(ResT); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execFunWithRetWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), args_size - sizeof(functionPtr), sizeof(ResT)); +#endif + } + + inline void forEachWrapper(uint64_t startIt, uint64_t numIters, + const void *args, gmt_handle_t) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); + + FunctionTy functionPtr = + *reinterpret_cast(const_cast(args)); + const uint32_t argSize = *reinterpret_cast( + reinterpret_cast(args) + sizeof(functionPtr)); + + const uint8_t *buffer = reinterpret_cast(args) + + sizeof(functionPtr) + sizeof(argSize); + + for (size_t i = 0; i < numIters; ++i) + functionPtr(buffer, argSize, startIt + i); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(argSize), 0, numIters); +#endif + } + + template + void forEachWrapper(uint64_t startIt, uint64_t numIters, const void *args, + gmt_handle_t) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const impl::ExecFunWrapperArgs *funArgs = + reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + + for (size_t i = 0; i < numIters; ++i) funArgs->fun(fnargs, startIt + i); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachWrapper", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0, numIters); +#endif + } + + static uint32_t garbageSize; + + inline gmt_handle_t getGmtHandle(Handle &handle) { + return static_cast(handle); + } + + template + void execAsyncFunWrapper(const void *args, uint32_t args_size, void *, + uint32_t *, gmt_handle_t handle) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const ExecFunWrapperArgs &funArgs = *reinterpret_cast *>(args); + + Handle H(handle); + funArgs.fun(H, funArgs.args); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execAsyncFunWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0); +#endif + } + + inline void execAsyncFunWrapper(const void *args, uint32_t args_size, void *, + uint32_t *, gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); + + FunctionTy functionPtr = *reinterpret_cast(const_cast(args)); + + Handle H(handle); + functionPtr(H, reinterpret_cast(args) + sizeof(functionPtr), + args_size - sizeof(functionPtr)); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execAsyncFunWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), args_size - sizeof(functionPtr), 0); +#endif + } + + template + void asyncExecFunWithRetWrapper(const void *args, uint32_t args_size, + void *result, uint32_t *resSize, + gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, ResT *); + + const ExecFunWrapperArgs *funArgs = reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + + Handle H(handle); + funArgs->fun(H, fnargs, reinterpret_cast(result)); + *resSize = sizeof(ResT); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecFunWithRetWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), sizeof(ResT)); +#endif + } + + template + void asyncExecFunWithRetWrapper(const void *args, uint32_t args_size, + void *result, uint32_t *resSize, + gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, ResT *); + + FunctionTy functionPtr = *reinterpret_cast(const_cast(args)); + + ResT *resultPtr = reinterpret_cast(result); + + Handle H(handle); + functionPtr(H, reinterpret_cast(args) + sizeof(functionPtr), + args_size - sizeof(functionPtr), resultPtr); + *resSize = sizeof(ResT); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecFunWithRetWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), args_size - sizeof(functionPtr), sizeof(ResT)); +#endif + } + + template + void asyncExecFunWithRetBuffWrapper(const void *args, uint32_t, void *result, + uint32_t *resultSize, gmt_handle_t handle) { + +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const ExecFunWrapperArgs *funArgs = reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + + Handle H(handle); + funArgs->fun(H, fnargs, reinterpret_cast(result), resultSize); + + checkOutputSize(*resultSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecFunWithRetBuffWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), sizeof(*resultSize)); +#endif + } + + inline void asyncExecFunWithRetBuffWrapper(const void *args, uint32_t argsSize, + void *result, uint32_t *resultSize, + gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t, + uint8_t *, uint32_t *); + + FunctionTy functionPtr = *reinterpret_cast(const_cast(args)); + + Handle H(handle); + functionPtr(H, reinterpret_cast(args) + sizeof(functionPtr), + argsSize - sizeof(functionPtr), + reinterpret_cast(result), resultSize); + + checkOutputSize(*resultSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecFunWithRetBuffWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), argsSize - sizeof(functionPtr), sizeof(*resultSize)); +#endif + } + + inline void asyncForEachWrapper(uint64_t startIt, uint64_t numIters, + const void *args, gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, size_t); + + FunctionTy functionPtr = *reinterpret_cast(const_cast(args)); + const uint32_t argSize = *reinterpret_cast(reinterpret_cast(args) + sizeof(functionPtr)); + + const uint8_t *buffer = reinterpret_cast(args) + sizeof(functionPtr) + sizeof(argSize); + Handle H(handle); + for (size_t i = 0; i < numIters; ++i) + functionPtr(H, buffer, argSize, startIt + i); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(argSize), 0, numIters); +#endif + } + + template + void asyncForEachWrapper(uint64_t startIt, uint64_t numIters, const void *args, + gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const ExecFunWrapperArgs *funArgs = reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + + Handle H(handle); + for (size_t i = 0; i < numIters; ++i) funArgs->fun(H, fnargs, startIt + i); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0, numIters); +#endif + } + + template + void execAsyncFunWithRetBuffWrapper(const void *args, uint32_t args_size, + void *result, uint32_t *resSize, + gmt_handle_t handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + const ExecFunWrapperArgs *funArgs = + reinterpret_cast *>(args); + const InArgsT &fnargs = funArgs->args; + funArgs->fun(fnargs, reinterpret_cast(result), resSize, + Handle(handle)); + + Handle H(handle); + checkOutputSize(*resSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("execAsyncFunWithRetBuffWrapper", diff.count(), &H, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), sizeof(*resSize)); +#endif + } + + } // namespace impl + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_MAPPINGS_GMT_GMT_UTILITY_H_ + diff --git a/include/shad/runtime/mappings/tbb/tbb_asynchronous_interface.h b/include/shad/runtime/mappings/tbb/tbb_asynchronous_interface.h index 7c8a4b3e..8262b424 100644 --- a/include/shad/runtime/mappings/tbb/tbb_asynchronous_interface.h +++ b/include/shad/runtime/mappings/tbb/tbb_asynchronous_interface.h @@ -22,6 +22,15 @@ // //===----------------------------------------------------------------------===// +/* + Developer Date Description + ================================================================================ + Methun K 07/27/2018 Adding logging functionality in asyncExecuteAt method + Methun K 07/31/2018 Adding logging functionality in other methods + Methun K 08/01/2018 Fixing the thisLocality issue + -------------------------------------------------------------------------------- + */ + #ifndef INCLUDE_SHAD_RUNTIME_MAPPINGS_TBB_TBB_ASYNCHRONOUS_INTERFACE_H_ #define INCLUDE_SHAD_RUNTIME_MAPPINGS_TBB_TBB_ASYNCHRONOUS_INTERFACE_H_ @@ -34,240 +43,375 @@ #include "shad/runtime/handle.h" #include "shad/runtime/locality.h" #include "shad/runtime/mapping_traits.h" +#include "shad/runtime/mappings/tbb/tbb_traits_mapping.h" #include "shad/runtime/mappings/tbb/tbb_utility.h" +#include "shad/util/slog.h" namespace shad { -namespace rt { - -namespace impl { - -template <> -struct AsynchronousInterface { - template - static void asyncExecuteAt(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args) { - using FunctionTy = void (*)(Handle &, const InArgsT &); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { fn(handle, args); }); - } - - template - static void asyncExecuteAt(Handle &handle, const Locality &loc, - FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { fn(handle, argsBuffer.get(), bufferSize); }); - } - - template - static void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args, - uint8_t *resultBuffer, - uint32_t *resultSize) { - using FunctionTy = - void (*)(Handle &, const InArgsT &, uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run( - [=, &handle] { fn(handle, args, resultBuffer, resultSize); }); - } - - template - static void asyncExecuteAtWithRetBuff( - Handle &handle, const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, const uint32_t bufferSize, - uint8_t *resultBuffer, uint32_t *resultSize) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t, - uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { - fn(handle, argsBuffer.get(), bufferSize, resultBuffer, resultSize); - }); - } - - template - static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args, - ResT *result) { - using FunctionTy = void (*)(Handle &, const InArgsT &, ResT *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { fn(handle, args, result); }); - } - - template - static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, - FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, ResT *result) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, ResT *); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([&, fn, argsBuffer, bufferSize, result] { - fn(handle, argsBuffer.get(), bufferSize, result); - }); - } - - template - static void asyncExecuteOnAll(Handle &handle, FunT &&function, - const InArgsT &args) { - using FunctionTy = void (*)(Handle &, const InArgsT &); - - FunctionTy fn = std::forward(function); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { fn(handle, args); }); - } - - template - static void asyncExecuteOnAll(Handle &handle, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { fn(handle, argsBuffer.get(), bufferSize); }); - } - - template - static void asyncForEachAt(Handle &handle, const Locality &loc, - FunT &&function, const InArgsT &args, - const size_t numIters) { - using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { - tbb::parallel_for(tbb::blocked_range(0, numIters), - [=, &handle](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(handle, args, i); - }); - }); - } - - template - static void asyncForEachAt(Handle &handle, const Locality &loc, - FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { - tbb::parallel_for(tbb::blocked_range(0, numIters), - [=, &handle](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(handle, argsBuffer.get(), bufferSize, i); - }); - }); - } - - template - static void asyncForEachOnAll(Handle &handle, FunT &&function, - const InArgsT &args, const size_t numIters) { - using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { - tbb::parallel_for(tbb::blocked_range(0, numIters), - [&](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(handle, args, i); - }); - }); - } - - template - static void asyncForEachOnAll(Handle &handle, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, - const size_t numIters) { - using FunctionTy = - void (*)(Handle &, const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - handle.id_ = - handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; - - handle.id_->run([=, &handle] { - tbb::parallel_for(tbb::blocked_range(0, numIters), - [=, &handle](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(handle, argsBuffer.get(), bufferSize, i); - }); - }); - } -}; - -} // namespace impl - -} // namespace rt + namespace rt { + + namespace impl { + + template <> + struct AsynchronousInterface { + template + static void asyncExecuteAt(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { fn(handle, args); }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT),0); +#endif + } + + template + static void asyncExecuteAt(Handle &handle, const Locality &loc, + FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { fn(handle, argsBuffer.get(), bufferSize); }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args, + uint8_t *resultBuffer, + uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const InArgsT &, uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run( + [=, &handle] { fn(handle, args, resultBuffer, resultSize); }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRetBuff", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0); +#endif + } + + template + static void asyncExecuteAtWithRetBuff( + Handle &handle, const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, const uint32_t bufferSize, + uint8_t *resultBuffer, uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t, + uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { + fn(handle, argsBuffer.get(), bufferSize, resultBuffer, resultSize); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRetBuff", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args, + ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, ResT *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { fn(handle, args, result); }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRet", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0); +#endif + } + + template + static void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, + FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, ResT *); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([&, fn, argsBuffer, bufferSize, result] { + fn(handle, argsBuffer.get(), bufferSize, result); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteAtWithRet", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void asyncExecuteOnAll(Handle &handle, FunT &&function, + const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &); + + FunctionTy fn = std::forward(function); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { fn(handle, args); }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0); +#endif + } + + template + static void asyncExecuteOnAll(Handle &handle, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { fn(handle, argsBuffer.get(), bufferSize); }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncExecuteOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr), 0); +#endif + } + + template + static void asyncForEachAt(Handle &handle, const Locality &loc, + FunT &&function, const InArgsT &args, + const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { + tbb::parallel_for(tbb::blocked_range(0, numIters), + [=, &handle](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(handle, args, i); + }); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0, numIters); +#endif + } + + template + static void asyncForEachAt(Handle &handle, const Locality &loc, + FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { + tbb::parallel_for(tbb::blocked_range(0, numIters), + [=, &handle](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(handle, argsBuffer.get(), bufferSize, i); + }); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachAt", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0, numIters); +#endif + } + + template + static void asyncForEachOnAll(Handle &handle, FunT &&function, + const InArgsT &args, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(Handle &, const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { + tbb::parallel_for(tbb::blocked_range(0, numIters), + [&](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(handle, args, i); + }); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0, numIters); +#endif + } + + template + static void asyncForEachOnAll(Handle &handle, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, + const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(Handle &, const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + handle.id_ = + handle.IsNull() ? HandleTrait::CreateNewHandle() : handle.id_; + + handle.id_->run([=, &handle] { + tbb::parallel_for(tbb::blocked_range(0, numIters), + [=, &handle](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(handle, argsBuffer.get(), bufferSize, i); + }); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("asyncForEachOnAll", diff.count(), &handle, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr), 0, numIters); +#endif + } + }; + + } // namespace impl + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_MAPPINGS_TBB_TBB_ASYNCHRONOUS_INTERFACE_H_ + diff --git a/include/shad/runtime/mappings/tbb/tbb_synchronous_interface.h b/include/shad/runtime/mappings/tbb/tbb_synchronous_interface.h index 07b204f2..9d976d28 100644 --- a/include/shad/runtime/mappings/tbb/tbb_synchronous_interface.h +++ b/include/shad/runtime/mappings/tbb/tbb_synchronous_interface.h @@ -22,6 +22,13 @@ // //===----------------------------------------------------------------------===// +/* + Developer Date Description + ================================================================================ + Methun K 08/01/2018 Adding logging + -------------------------------------------------------------------------------- + */ + #ifndef INCLUDE_SHAD_RUNTIME_MAPPINGS_TBB_TBB_SYNCHRONOUS_INTERFACE_H_ #define INCLUDE_SHAD_RUNTIME_MAPPINGS_TBB_TBB_SYNCHRONOUS_INTERFACE_H_ @@ -32,163 +39,297 @@ #include "shad/runtime/mappings/tbb/tbb_traits_mapping.h" #include "shad/runtime/mappings/tbb/tbb_utility.h" #include "shad/runtime/synchronous_interface.h" +#include "shad/util/slog.h" namespace shad { -namespace rt { - -namespace impl { - -template <> -struct SynchronousInterface { - template - static void executeAt(const Locality &loc, FunT &&function, - const InArgsT &args) { - using FunctionTy = void (*)(const InArgsT &); - - checkLocality(loc); - FunctionTy fn = std::forward(function); - fn(args); - } - - template - static void executeAt(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - checkLocality(loc); - fn(argsBuffer.get(), bufferSize); - } - - template - static void executeAtWithRetBuff(const Locality &loc, FunT &&function, - const InArgsT &args, uint8_t *resultBuffer, - uint32_t *resultSize) { - using FunctionTy = void (*)(const InArgsT &, uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - checkLocality(loc); - fn(args, resultBuffer, resultSize); - } - - template - static void executeAtWithRetBuff(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, - uint8_t *resultBuffer, - uint32_t *resultSize) { - using FunctionTy = - void (*)(const uint8_t *, const uint32_t, uint8_t *, uint32_t *); - - FunctionTy fn = std::forward(function); - checkLocality(loc); - fn(argsBuffer.get(), bufferSize, resultBuffer, resultSize); - } - - template - static void executeAtWithRet(const Locality &loc, FunT &&function, - const InArgsT &args, ResT *result) { - using FunctionTy = void (*)(const InArgsT &, ResT *); - - FunctionTy fn = std::forward(function); - checkLocality(loc); - fn(args, result); - } - - template - static void executeAtWithRet(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, ResT *result) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, ResT *); - - FunctionTy fn = std::forward(function); - checkLocality(loc); - fn(argsBuffer.get(), bufferSize, result); - } - - template - static void executeOnAll(FunT &&function, const InArgsT &args) { - using FunctionTy = void (*)(const InArgsT &); - - FunctionTy fn = std::forward(function); - fn(args); - } - - template - static void executeOnAll(FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t); - - FunctionTy fn = std::forward(function); - fn(argsBuffer.get(), bufferSize); - } - - template - static void forEachAt(const Locality &loc, FunT &&function, - const InArgsT &args, const size_t numIters) { - using FunctionTy = void (*)(const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - tbb::parallel_for(tbb::blocked_range(0, numIters), - [&](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(args, i); - }); - } - - template - static void forEachAt(const Locality &loc, FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - checkLocality(loc); - tbb::parallel_for(tbb::blocked_range(0, numIters), - [&](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(argsBuffer.get(), bufferSize, i); - }); - } - - template - static void forEachOnAll(FunT &&function, const InArgsT &args, - const size_t numIters) { - using FunctionTy = void (*)(const InArgsT &, size_t); - - FunctionTy fn = std::forward(function); - - tbb::parallel_for(tbb::blocked_range(0, numIters), - [&](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(args, i); - }); - } - - template - static void forEachOnAll(FunT &&function, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); - - FunctionTy fn = std::forward(function); - - tbb::parallel_for(tbb::blocked_range(0, numIters), - [&](const tbb::blocked_range &range) { - for (auto i = range.begin(); i < range.end(); ++i) - fn(argsBuffer.get(), bufferSize, i); - }); - } -}; - -} // namespace impl - -} // namespace rt + namespace rt { + + namespace impl { + + template <> + struct SynchronousInterface { + template + static void executeAt(const Locality &loc, FunT &&function, + const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &); + + checkLocality(loc); + FunctionTy fn = std::forward(function); + fn(args); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0); +#endif + } + + template + static void executeAt(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + checkLocality(loc); + fn(argsBuffer.get(), bufferSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void executeAtWithRetBuff(const Locality &loc, FunT &&function, + const InArgsT &args, uint8_t *resultBuffer, + uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + checkLocality(loc); + fn(args, resultBuffer, resultSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRetBuff", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0); +#endif + } + + template + static void executeAtWithRetBuff(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, + uint8_t *resultBuffer, + uint32_t *resultSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = + void (*)(const uint8_t *, const uint32_t, uint8_t *, uint32_t *); + + FunctionTy fn = std::forward(function); + checkLocality(loc); + fn(argsBuffer.get(), bufferSize, resultBuffer, resultSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRetBuff", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void executeAtWithRet(const Locality &loc, FunT &&function, + const InArgsT &args, ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, ResT *); + + FunctionTy fn = std::forward(function); + checkLocality(loc); + fn(args, result); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRet", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0); +#endif + } + + template + static void executeAtWithRet(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, ResT *result) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, ResT *); + + FunctionTy fn = std::forward(function); + checkLocality(loc); + fn(argsBuffer.get(), bufferSize, result); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeAtWithRet", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void executeOnAll(FunT &&function, const InArgsT &args) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &); + + FunctionTy fn = std::forward(function); + fn(args); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0); +#endif + } + + template + static void executeOnAll(FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t); + + FunctionTy fn = std::forward(function); + fn(argsBuffer.get(), bufferSize); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("executeOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr), 0); +#endif + } + + template + static void forEachAt(const Locality &loc, FunT &&function, + const InArgsT &args, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + tbb::parallel_for(tbb::blocked_range(0, numIters), + [&](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(args, i); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(InArgsT), 0); +#endif + } + + template + static void forEachAt(const Locality &loc, FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + checkLocality(loc); + tbb::parallel_for(tbb::blocked_range(0, numIters), + [&](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(argsBuffer.get(), bufferSize, i); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachAt", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), loc, sizeof(std::shared_ptr), 0); +#endif + } + + template + static void forEachOnAll(FunT &&function, const InArgsT &args, + const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const InArgsT &, size_t); + + FunctionTy fn = std::forward(function); + + tbb::parallel_for(tbb::blocked_range(0, numIters), + [&](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(args, i); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(InArgsT), 0, numIters); +#endif + } + + template + static void forEachOnAll(FunT &&function, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + using FunctionTy = void (*)(const uint8_t *, const uint32_t, size_t); + + FunctionTy fn = std::forward(function); + + tbb::parallel_for(tbb::blocked_range(0, numIters), + [&](const tbb::blocked_range &range) { + for (auto i = range.begin(); i < range.end(); ++i) + fn(argsBuffer.get(), bufferSize, i); + }); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("forEachOnAll", diff.count(), nullptr, RuntimeInternalsTrait::ThisLocality(), RuntimeInternalsTrait::ThisLocality(), sizeof(std::shared_ptr), 0, numIters); +#endif + } + }; + + } // namespace impl + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_MAPPINGS_TBB_TBB_SYNCHRONOUS_INTERFACE_H_ + diff --git a/include/shad/runtime/runtime.h b/include/shad/runtime/runtime.h index 5341ec3a..b383663d 100644 --- a/include/shad/runtime/runtime.h +++ b/include/shad/runtime/runtime.h @@ -47,1137 +47,1149 @@ /// @namespace shad namespace shad { - -namespace rt { - -/// @brief Lock. -/// -/// The Lock can be used to lock a non-threadsafe objects. -/// Locks are local, and cannot be transfered remote localities. -class Lock { - public: - /// @brief Acquire the lock. - void lock() { impl::LockTrait::lock(lock_); } - /// @brief Release the lock. - void unlock() { impl::LockTrait::unlock(lock_); } - - private: - typename impl::LockTrait::LockTy lock_; -}; - -namespace impl { - -/// @brief yield the runtime -inline void yield() { RuntimeInternalsTrait::Yield(); } - -/// @brief returns number of threads/cores -inline size_t getConcurrency() { - return RuntimeInternalsTrait::Concurrency(); -} - -/// @brief Initialize the runtime environment. -/// @param argc pointer to argument count -/// @param argv pointer to array of char * -inline void initialize(int argc, char *argv[]) { - RuntimeInternalsTrait::Initialize(argc, argv); -} - -/// @brief Finailize the runtime environment prior to program termination. -inline void finalize() { RuntimeInternalsTrait::Finalize(); } - -/// @brief Creates a new Handle. -inline Handle createHandle() { - // auto handle = HandleTrait::CreateNewHandle(); - // Handle newHandle(handle); - return Handle(HandleTrait::CreateNewHandle()); -} - -} // namespace impl - -/// @brief Number of localities on which the runtime is executing. -inline uint32_t numLocalities() { - return impl::RuntimeInternalsTrait::NumLocalities(); -} - -/// @brief Identity of locality on which the call is made. -inline Locality thisLocality() { - return Locality(impl::RuntimeInternalsTrait::ThisLocality()); -} - -inline std::set allLocalities() { - std::set result; - for (uint32_t L = 0; L < numLocalities(); ++L) { - result.insert(Locality(L)); - } - return result; -} - -/// @brief Execute a function on a selected locality synchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const Args & args) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// executeAt(locality, task, args); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const InArgsT &); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -template -void executeAt(const Locality &loc, FunT &&func, const InArgsT &args) { - impl::SynchronousInterface::executeAt(loc, func, args); -} - -/// @brief Execute a function on a selected locality synchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const uint8_t *, const uint32_t) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// executeAt(locality, task, ptr, sizeof(Args)); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const uint8_t *, const uint32_t); -/// @endcode -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -template -void executeAt(const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - impl::SynchronousInterface::executeAt(loc, func, argsBuffer, - bufferSize); -} - -/// @brief Execute a function on a selected locality synchronously and return a -/// buffer. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const Args & args, -/// const uint8_t *dst, uint32_t * outsize) { -/// memcpy(&args, dst, sizeof(Args)); -/// *outsize = sizeof(Args); -/// } -/// -/// Args args { 2, 'a' }; -/// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); -/// uint32_t size(0); -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// // every call will overwrite outbuff -/// executeAtWithRetBuffer(locality, task, args, outbuff.get(), &size); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const InArgsT &, const uint8_t *, uint32_t *); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param resultBuffer The buffer where to store the results. -/// @param resultSize The location where the runtime will store the number of -/// bytes written in the result buffer -template -void executeAtWithRetBuff(const Locality &loc, FunT &&func, const InArgsT &args, - uint8_t *resultBuffer, uint32_t *resultSize) { - impl::SynchronousInterface::executeAtWithRetBuff( - loc, func, args, resultBuffer, resultSize); -} - -/// @brief Execute a function on a selected locality synchronously and -/// return a result buffer. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const uint8_t *src, const uint32_t size, -/// const uint8_t *dst, uint32_t * outsize) { -/// memcpy(src, dst, size); -/// *outsize = size; -/// } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); -/// uint32_t size(0); -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// // every call will overwrite outbuff -/// executeAtWithRetBuff(locality, task, ptr, sizeof(Args), -/// outbuff.get(), &size); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const uint8_t *, const uint32_t, const uint8_t *, uint32_t *); -/// @endcode -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param resultBuffer The buffer where to store the results. -/// @param resultSize The location where the runtime will store the number of -/// bytes written in the result buffer -template -void executeAtWithRetBuff(const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, uint8_t *resultBuffer, - uint32_t *resultSize) { - impl::SynchronousInterface::executeAtWithRetBuff( - loc, func, argsBuffer, bufferSize, resultBuffer, resultSize); -} - -/// @brief Execute a function on a selected locality synchronously and return a -/// result. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const Args & args, Args * outArgs) { -/// *outArgs = args; -/// } -/// -/// Args args { 2, 'a' }; -/// Args out; -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// // every call will overwrite outbuff -/// executeAtWithRet(locality, task, args, out); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const InArgsT &, ResT *); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @tparam ResT The type of the result value. The type can be a structure or a -/// class but with the restriction that must be memcopy-able. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param result The location where to store the result. -template -void executeAtWithRet(const Locality &loc, FunT &&func, const InArgsT &args, - ResT *result) { - impl::SynchronousInterface::executeAtWithRet(loc, func, args, - result); -} - -/// @brief Execute a function on a selected locality synchronously and -/// return a result. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const uint8_t *src, const uint32_t size, -/// Args * res) { -/// memcpy(src, res, sizeof(Args)); -/// } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// Args out; -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// // every call will overwrite out -/// executeAtWithRet(locality, task, ptr, sizeof(Args), &out); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const uint8_t *, const uint32_t, ResT *); -/// @endcode -/// -/// @tparam ResT The type of the result value. The type can be a structure or a -/// class but with the restriction that must be memcopy-able. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param result The location where to store the result. -template -void executeAtWithRet(const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, ResT *result) { - impl::SynchronousInterface::executeAtWithRet( - loc, func, argsBuffer, bufferSize, result); -} - -/// @brief Execute a function on all localities synchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const Args & args) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// executeOnAll(task, args); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const InArgsT &); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -template -void executeOnAll(FunT &&func, const InArgsT &args) { - impl::SynchronousInterface::executeOnAll(func, args); -} - -/// @brief Execute a function on all localities synchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(const uint8_t *, const uint32_t) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// executeOnAll(task, ptr.get(), sizeof(Args)); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const uint8_t *, const uint32_t); -/// @endcode -/// -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -template -void executeOnAll(FunT &&func, const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - impl::SynchronousInterface::executeOnAll(func, argsBuffer, - bufferSize); -} - -/// @brief Execute a parallel loop at a specific locality. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// Args args { 2, 'a' }; -/// -/// shad::rt::forEachAt(locality, -/// [](const Args & input, size_t itrNum) { -/// // Do something. -/// }, -/// args, iterations); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const ArgsT &, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param numIters The total number of iteration of the loop. -template -void forEachAt(const Locality &loc, FunT &&func, const InArgsT &args, - const size_t numIters) { - impl::SynchronousInterface::forEachAt(loc, func, args, - numIters); -} - -/// @brief Execute a parallel loop at a specific locality. -/// -/// Typical Usage: -/// @code -/// std::shared_ptr ptr(new uint8_t[2]{ 5, 5 }, -/// std::default_delete()); -/// -/// shad::rt::forEachAt(locality, -/// [](const uint8_t * input, const uint32_t size, size_t itrNum) { -/// // Do something. -/// }, -/// buffer, sizeof(buffer), -/// iterations); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const uint8_t *, const uint32_t, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param numIters The total number of iteration of the loop. -template -void forEachAt(const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - impl::SynchronousInterface::forEachAt(loc, func, argsBuffer, - bufferSize, numIters); -} - -/// @brief Execute a parallel loop on the whole system. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// Args args { 2, 'a' }; -/// -/// shad::rt::forEachOnAll( -/// [](const Args & args, size_t itrNum) { -/// // Do something -/// }, -/// args, -/// iterations); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const ArgsT &, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param numIters The total number of iteration of the loop. -template -void forEachOnAll(FunT &&func, const InArgsT &args, const size_t numIters) { - impl::SynchronousInterface::forEachOnAll(func, args, - numIters); -} - -/// @brief Execute a parallel loop on the whole system. -/// -/// Typical Usage: -/// @code -/// std::shared_ptr ptr(new uint8_t[2]{ 5, 5 }, -/// std::default_delete()); -/// -/// shad::rt::forEachOnAll( -/// [](const uint8_t * input, const uint32_t size, size_t itrNum) { -/// // Do something -/// }, -/// buffer, sizeof(buffer), -/// iterations); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(const uint8_t *, const uint32_t, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param numIters The total number of iteration of the loop. -template -void forEachOnAll(FunT &&func, const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - impl::SynchronousInterface::forEachOnAll( - func, argsBuffer, bufferSize, numIters); -} - -/// @brief Execute a function on a selected locality asynchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const Args & args) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// Handle handle; -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// asyncExecuteAt(handle, locality, task, args); -/// -/// waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const InArgsT &); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -template -void asyncExecuteAt(Handle &handle, const Locality &loc, FunT &&func, - const InArgsT &args) { - impl::AsynchronousInterface::asyncExecuteAt(handle, loc, - func, args); -} - -/// @brief Execute a function on a selected locality asynchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, -/// const uint8_t * buff, -/// const uint32_t size) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// Handle handle; -/// for (auto & locality : allLocalities) -/// if (static_cast(locality) % 2) -/// executeAt(handle, locality, task, ptr.get(), sizeof(Args)); -/// -/// waitForCompletion(handle) -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const uint8_t *, const uint32_t); -/// @endcode -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -template -void asyncExecuteAt(Handle &handle, const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize) { - impl::AsynchronousInterface::asyncExecuteAt( - handle, loc, func, argsBuffer, bufferSize); -} - -/// @brief Execute a function on a selected locality synchronously and return a -/// buffer. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const Args & args, -/// const uint8_t *dst, uint32_t * outsize) { -/// memcpy(&args, dst, sizeof(Args)); -/// *outsize = sizeof(Args); -/// } -/// -/// Args args { 2, 'a' }; -/// std::vector> outBuffers(numLocalities()); -/// std::vector outSizes(numLocalities(), 0); -/// for (auto & vecPtr : outBuffers) { -/// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); -/// vecPtr = std::move(outbuff); -/// } -/// -/// Handle handle; -/// for (auto & locality : allLocalities()) { -/// uint32_t localityID = static_cast(locality); -/// if (localityID % 2) -/// // every call will overwrite outbuff -/// asyncExecuteAtWithRetBuff( -/// handle, locality, task, args, outBuffers[localityID].get(), -/// &outSizes[localityID]); -/// } -/// -/// waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const InArgsT &, const uint8_t *, uint32_t *); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param resultBuffer The buffer where to store the results. -/// @param resultSize The location where the runtime will store the number of -/// bytes written in the result buffer -template -void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, FunT &&func, - const InArgsT &args, uint8_t *resultBuffer, - uint32_t *resultSize) { - impl::AsynchronousInterface::asyncExecuteAtWithRetBuff( - handle, loc, func, args, resultBuffer, resultSize); -} - -/// @brief Execute a function on a selected locality asynchronously and return a -/// result buffer. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const uint8_t *src, const uint32_t size, -/// const uint8_t *dst, uint32_t * outsize) { -/// memcpy(src, dst, size); -/// *outsize = size; -/// } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// std::vector> outBuffers(numLocalities()); -/// std::vector outSizes(numLocalities(), 0); -/// for (auto & vecPtr : outBuffers) { -/// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); -/// vecPtr = std::move(outbuff); -/// } -/// -/// Handle handle; -/// for (auto & locality : allLocalities) { -/// if (static_cast(locality) % 2) -/// // every call will overwrite outbuff -/// asyncExecuteAtWithRetBuff( -/// handle, locality, task, ptr, sizeof(Args), -/// outBuffers[localityID].get(), &outSizes[localityID]); -/// } -/// -/// waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const uint8_t *, const uint32_t, const uint8_t *, uint32_t *) -/// @endcode -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param resultBuffer The buffer where to store the results. -/// @param resultSize The location where the runtime will store the number of -/// bytes written in the result buffer -template -void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, uint8_t *resultBuffer, - uint32_t *resultSize) { - impl::AsynchronousInterface::asyncExecuteAtWithRetBuff( - handle, loc, func, argsBuffer, bufferSize, resultBuffer, resultSize); -} - -/// @brief Execute a function on a selected locality asynchronously and return a -/// result. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const Args & args, Args * res) { -/// // Do something. -/// } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::vector outBuffers(numLocalities()); -/// -/// Handle handle; -/// for (auto & locality : allLocalities()) { -/// uint32_t localityID = static_cast(locality); -/// asyncExecuteAtWithRet( -/// handle, locality, task, args, &outBuffers[localityID]); -/// } -/// waitForCompletion(handle); -/// @endcode -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const InArgsT &, ResT *); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @tparam ResT The type of the result value. The type can be a structure or a -/// class but with the restriction that must be memcopy-able. -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param result The location where to store the result. -template -void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, FunT &&func, - const InArgsT &args, ResT *result) { - impl::AsynchronousInterface::asyncExecuteAtWithRet( - handle, loc, func, args, result); -} - -/// @brief Execute a function on a selected locality asynchronously and return a -/// result. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const uint8_t *src, const uint32_t size, -/// Args * res) { -/// // Do something -/// } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::vector outBuffers(numLocalities()); -/// std::unique_ptr ptr(new uint8_t[sizeof(Args)]); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// Handle handle; -/// for (auto & locality : allLocalities()) { -/// uint32_t localityID = static_cast(locality); -/// asyncExecuteAtWithRet( -/// handle, locality, task, ptr.get(), sizeof(Args), -/// &outBuffers[localityID]); -/// } -/// waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const uint8_t *, const uint32_t, ResT *); -/// @endcode -/// -/// @tparam ResT The type of the result value. The type can be a structure or a -/// class but with the restriction that must be memcopy-able. -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param result The location where to store the result. -template -void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, ResT *result) { - impl::AsynchronousInterface::asyncExecuteAtWithRet( - handle, loc, func, argsBuffer, bufferSize, result); -} - -/// @brief Execute a function on all localities asynchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const Args & args) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// Handle handle; -/// asyncExecuteOnAll(handle, task, args); -/// /* do something else */ -/// waitForcompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const InArgsT &); -/// @endcode -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param handle An Handle for the associated task-group. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -template -void asyncExecuteOnAll(Handle &handle, FunT &&func, const InArgsT &args) { - impl::AsynchronousInterface::asyncExecuteOnAll(handle, func, - args); -} - -/// @brief Execute a function on all localities synchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// void task(Handle & handle, const uint8_t *, -/// const uint32_t) { /* do something */ } -/// -/// Args args { 2, 'a' }; -/// /* Args doesn't need a dynamic allocated buffer but -/// * more complicated data structure might need it */ -/// std::shared_ptr ptr(new uint8_t[sizeof(Args)], -/// std::default_delete()); -/// memcpy(ptr.get(), &args, sizeof(Args)); -/// -/// Handle handle; -/// asyncExecuteOnAll(handle, task, ptr.get(), sizeof(Args)); -/// /* do something else */ -/// waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle & handle, const uint8_t *, const uint32_t); -/// @endcode -/// -/// @param handle An Handle for the associated task-group. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -template -void asyncExecuteOnAll(Handle &handle, FunT &&func, + + namespace rt { + + /// @brief Lock. + /// + /// The Lock can be used to lock a non-threadsafe objects. + /// Locks are local, and cannot be transfered remote localities. + class Lock { + public: + /// @brief Acquire the lock. + void lock() { impl::LockTrait::lock(lock_); } + /// @brief Release the lock. + void unlock() { impl::LockTrait::unlock(lock_); } + + private: + typename impl::LockTrait::LockTy lock_; + }; + + namespace impl { + + /// @brief yield the runtime + inline void yield() { RuntimeInternalsTrait::Yield(); } + + /// @brief returns number of threads/cores + inline size_t getConcurrency() { + return RuntimeInternalsTrait::Concurrency(); + } + + /// @brief Initialize the runtime environment. + /// @param argc pointer to argument count + /// @param argv pointer to array of char * + inline void initialize(int argc, char *argv[]) { + RuntimeInternalsTrait::Initialize(argc, argv); + } + + /// @brief Finailize the runtime environment prior to program termination. + inline void finalize() { RuntimeInternalsTrait::Finalize(); } + + /// @brief Creates a new Handle. + inline Handle createHandle() { + // auto handle = HandleTrait::CreateNewHandle(); + // Handle newHandle(handle); + return Handle(HandleTrait::CreateNewHandle()); + } + + } // namespace impl + + /// @brief Number of localities on which the runtime is executing. + inline uint32_t numLocalities() { + return impl::RuntimeInternalsTrait::NumLocalities(); + } + + /// @brief Identity of locality on which the call is made. + inline Locality thisLocality() { + return Locality(impl::RuntimeInternalsTrait::ThisLocality()); + } + + inline std::set allLocalities() { + std::set result; + for (uint32_t L = 0; L < numLocalities(); ++L) { + result.insert(Locality(L)); + } + return result; + } + + /// @brief Execute a function on a selected locality synchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const Args & args) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// executeAt(locality, task, args); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const InArgsT &); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + template + void executeAt(const Locality &loc, FunT &&func, const InArgsT &args) { + impl::SynchronousInterface::executeAt(loc, func, args); + } + + /// @brief Execute a function on a selected locality synchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const uint8_t *, const uint32_t) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// executeAt(locality, task, ptr, sizeof(Args)); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const uint8_t *, const uint32_t); + /// @endcode + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + template + void executeAt(const Locality &loc, FunT &&func, const std::shared_ptr &argsBuffer, const uint32_t bufferSize) { - impl::AsynchronousInterface::asyncExecuteOnAll( - handle, func, argsBuffer, bufferSize); -} - -/// @brief Execute a parallel loop at a specific locality asynchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// Args args { 2, 'a' }; -/// Handle handle; -/// shad::rt::asyncForEachAt(locality, -/// [](Handle & handle, const Args & input, size_t itrNum) { -/// // Do something. -/// }, -/// args, iterations, handle); -/// shad::rt::waitForcompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const ArgsT &, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param numIters The total number of iteration of the loop. -/// @param handle An Handle for the associated task-group. -template -void asyncForEachAt(Handle &handle, const Locality &loc, FunT &&func, - const InArgsT &args, const size_t numIters) { - impl::AsynchronousInterface::asyncForEachAt( - handle, loc, func, args, numIters); -} - -/// @brief Execute a parallel loop at a specific locality asynchronously. -/// -/// Typical Usage: -/// @code -/// std::shared_ptr buffer(new uint8_t[2]{ 5, 5 }, -/// std::default_delete()); -/// -/// Handle handle; -/// shad::rt::asyncForEachAt(locality, -/// handle, -/// [](Handle & handle, const uint8_t * input, const uint32_t size, -/// size_t itrNum) { -/// // Do something. -/// }, -/// buffer, 2, -/// iterations); -/// /* do something else */ -/// shad::rt::waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const uint8_t *, const uint32_t, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @param handle An Handle for the associated task-group. -/// @param loc The Locality where the function must be executed. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param numIters The total number of iteration of the loop. -template -void asyncForEachAt(Handle &handle, const Locality &loc, FunT &&func, - const std::shared_ptr &argsBuffer, - const uint32_t bufferSize, const size_t numIters) { - impl::AsynchronousInterface::asyncForEachAt( - handle, loc, func, argsBuffer, bufferSize, numIters); -} - -/// @brief Execute a parallel loop on the whole system asynchronously. -/// -/// Typical Usage: -/// @code -/// struct Args { -/// int a; -/// char b; -/// }; -/// -/// Args args { 2, 'a' }; -/// Handle handle; -/// shad::rt::asyncForEachOnAll( -/// handle, -/// [](Handle &, const Args &, size_t itrNum) { -/// // Do something. -/// }, -/// args, -/// iterations); -/// /* Do something else */ -/// shad::rt::waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const ArgsT &, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @tparam InArgsT The type of the argument accepted by the function. The type -/// can be a structure or a class but with the restriction that must be -/// memcopy-able. -/// -/// @param handle An Handle for the associated task-group. -/// @param func The function to execute. -/// @param args The arguments to be passed to the function. -/// @param numIters The total number of iteration of the loop. -template -void asyncForEachOnAll(Handle &handle, FunT &&func, const InArgsT &args, + impl::SynchronousInterface::executeAt(loc, func, argsBuffer, + bufferSize); + } + + /// @brief Execute a function on a selected locality synchronously and return a + /// buffer. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const Args & args, + /// const uint8_t *dst, uint32_t * outsize) { + /// memcpy(&args, dst, sizeof(Args)); + /// *outsize = sizeof(Args); + /// } + /// + /// Args args { 2, 'a' }; + /// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); + /// uint32_t size(0); + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// // every call will overwrite outbuff + /// executeAtWithRetBuffer(locality, task, args, outbuff.get(), &size); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const InArgsT &, const uint8_t *, uint32_t *); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param resultBuffer The buffer where to store the results. + /// @param resultSize The location where the runtime will store the number of + /// bytes written in the result buffer + template + void executeAtWithRetBuff(const Locality &loc, FunT &&func, const InArgsT &args, + uint8_t *resultBuffer, uint32_t *resultSize) { + impl::SynchronousInterface::executeAtWithRetBuff( + loc, func, args, resultBuffer, resultSize); + } + + /// @brief Execute a function on a selected locality synchronously and + /// return a result buffer. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const uint8_t *src, const uint32_t size, + /// const uint8_t *dst, uint32_t * outsize) { + /// memcpy(src, dst, size); + /// *outsize = size; + /// } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); + /// uint32_t size(0); + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// // every call will overwrite outbuff + /// executeAtWithRetBuff(locality, task, ptr, sizeof(Args), + /// outbuff.get(), &size); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const uint8_t *, const uint32_t, const uint8_t *, uint32_t *); + /// @endcode + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param resultBuffer The buffer where to store the results. + /// @param resultSize The location where the runtime will store the number of + /// bytes written in the result buffer + template + void executeAtWithRetBuff(const Locality &loc, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, uint8_t *resultBuffer, + uint32_t *resultSize) { + impl::SynchronousInterface::executeAtWithRetBuff( + loc, func, argsBuffer, bufferSize, resultBuffer, resultSize); + } + + /// @brief Execute a function on a selected locality synchronously and return a + /// result. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const Args & args, Args * outArgs) { + /// *outArgs = args; + /// } + /// + /// Args args { 2, 'a' }; + /// Args out; + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// // every call will overwrite outbuff + /// executeAtWithRet(locality, task, args, out); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const InArgsT &, ResT *); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @tparam ResT The type of the result value. The type can be a structure or a + /// class but with the restriction that must be memcopy-able. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param result The location where to store the result. + template + void executeAtWithRet(const Locality &loc, FunT &&func, const InArgsT &args, + ResT *result) { + impl::SynchronousInterface::executeAtWithRet(loc, func, args, + result); + } + + /// @brief Execute a function on a selected locality synchronously and + /// return a result. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const uint8_t *src, const uint32_t size, + /// Args * res) { + /// memcpy(src, res, sizeof(Args)); + /// } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// Args out; + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// // every call will overwrite out + /// executeAtWithRet(locality, task, ptr, sizeof(Args), &out); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const uint8_t *, const uint32_t, ResT *); + /// @endcode + /// + /// @tparam ResT The type of the result value. The type can be a structure or a + /// class but with the restriction that must be memcopy-able. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param result The location where to store the result. + template + void executeAtWithRet(const Locality &loc, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, ResT *result) { + impl::SynchronousInterface::executeAtWithRet( + loc, func, argsBuffer, bufferSize, result); + } + + /// @brief Execute a function on all localities synchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const Args & args) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// executeOnAll(task, args); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const InArgsT &); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + template + void executeOnAll(FunT &&func, const InArgsT &args) { + impl::SynchronousInterface::executeOnAll(func, args); + } + + /// @brief Execute a function on all localities synchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(const uint8_t *, const uint32_t) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// executeOnAll(task, ptr.get(), sizeof(Args)); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const uint8_t *, const uint32_t); + /// @endcode + /// + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + template + void executeOnAll(FunT &&func, const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { + impl::SynchronousInterface::executeOnAll(func, argsBuffer, + bufferSize); + } + + /// @brief Execute a parallel loop at a specific locality. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// Args args { 2, 'a' }; + /// + /// shad::rt::forEachAt(locality, + /// [](const Args & input, size_t itrNum) { + /// // Do something. + /// }, + /// args, iterations); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const ArgsT &, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param numIters The total number of iteration of the loop. + template + void forEachAt(const Locality &loc, FunT &&func, const InArgsT &args, const size_t numIters) { - impl::AsynchronousInterface::asyncForEachOnAll( - handle, func, args, numIters); -} - -/// @brief Execute a parallel loop on the whole system asynchronously. -/// -/// Typical Usage: -/// @code -/// std::shared_ptr buffer(new uint8_t[2]{ 5, 5 }, -/// std::default_delete()); -/// -/// Handle handle; -/// shad::rt::asyncForEachOnAll(handle, -/// [](Handle &, const uint8_t * input, const uint32_t size, -/// size_t itrNum) { -/// // Do something -/// }, -/// buffer, 2, -/// iterations); -/// /* do something else */ -/// shad::rt::waitForCompletion(handle); -/// @endcode -/// -/// @tparam FunT The type of the function to be executed. The function -/// prototype must be: -/// @code -/// void(Handle &, const uint8_t *, const uint32_t, size_t itrNum); -/// @endcode -/// where the itrNum is the n-th iteration of the loop. -/// -/// @param handle An Handle for the associated task-group. -/// @param func The function to execute. -/// @param argsBuffer A buffer of bytes to be passed to the function. -/// @param bufferSize The size of the buffer argsBuffer passed. -/// @param numIters The total number of iteration of the loop. -template -void asyncForEachOnAll(Handle &handle, FunT &&func, + impl::SynchronousInterface::forEachAt(loc, func, args, + numIters); + } + + /// @brief Execute a parallel loop at a specific locality. + /// + /// Typical Usage: + /// @code + /// std::shared_ptr ptr(new uint8_t[2]{ 5, 5 }, + /// std::default_delete()); + /// + /// shad::rt::forEachAt(locality, + /// [](const uint8_t * input, const uint32_t size, size_t itrNum) { + /// // Do something. + /// }, + /// buffer, sizeof(buffer), + /// iterations); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const uint8_t *, const uint32_t, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param numIters The total number of iteration of the loop. + template + void forEachAt(const Locality &loc, FunT &&func, const std::shared_ptr &argsBuffer, const uint32_t bufferSize, const size_t numIters) { - impl::AsynchronousInterface::asyncForEachOnAll( - handle, func, argsBuffer, bufferSize, numIters); -} - -/// @brief Wait for completion of a set of tasks -inline void waitForCompletion(Handle &handle) { - impl::HandleTrait::WaitFor(handle.id_); -} -/// @} - -} // namespace rt + impl::SynchronousInterface::forEachAt(loc, func, argsBuffer, + bufferSize, numIters); + } + + /// @brief Execute a parallel loop on the whole system. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// Args args { 2, 'a' }; + /// + /// shad::rt::forEachOnAll( + /// [](const Args & args, size_t itrNum) { + /// // Do something + /// }, + /// args, + /// iterations); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const ArgsT &, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param numIters The total number of iteration of the loop. + template + void forEachOnAll(FunT &&func, const InArgsT &args, const size_t numIters) { + impl::SynchronousInterface::forEachOnAll(func, args, + numIters); + } + + /// @brief Execute a parallel loop on the whole system. + /// + /// Typical Usage: + /// @code + /// std::shared_ptr ptr(new uint8_t[2]{ 5, 5 }, + /// std::default_delete()); + /// + /// shad::rt::forEachOnAll( + /// [](const uint8_t * input, const uint32_t size, size_t itrNum) { + /// // Do something + /// }, + /// buffer, sizeof(buffer), + /// iterations); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(const uint8_t *, const uint32_t, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param numIters The total number of iteration of the loop. + template + void forEachOnAll(FunT &&func, const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { + impl::SynchronousInterface::forEachOnAll( + func, argsBuffer, bufferSize, numIters); + } + + /// @brief Execute a function on a selected locality asynchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const Args & args) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// Handle handle; + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// asyncExecuteAt(handle, locality, task, args); + /// + /// waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const InArgsT &); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + template + void asyncExecuteAt(Handle &handle, const Locality &loc, FunT &&func, + const InArgsT &args) { + impl::AsynchronousInterface::asyncExecuteAt(handle, loc, + func, args); + } + + /// @brief Execute a function on a selected locality asynchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, + /// const uint8_t * buff, + /// const uint32_t size) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// Handle handle; + /// for (auto & locality : allLocalities) + /// if (static_cast(locality) % 2) + /// executeAt(handle, locality, task, ptr.get(), sizeof(Args)); + /// + /// waitForCompletion(handle) + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const uint8_t *, const uint32_t); + /// @endcode + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + template + void asyncExecuteAt(Handle &handle, const Locality &loc, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { + impl::AsynchronousInterface::asyncExecuteAt( + handle, loc, func, argsBuffer, bufferSize); + } + + /// @brief Execute a function on a selected locality synchronously and return a + /// buffer. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const Args & args, + /// const uint8_t *dst, uint32_t * outsize) { + /// memcpy(&args, dst, sizeof(Args)); + /// *outsize = sizeof(Args); + /// } + /// + /// Args args { 2, 'a' }; + /// std::vector> outBuffers(numLocalities()); + /// std::vector outSizes(numLocalities(), 0); + /// for (auto & vecPtr : outBuffers) { + /// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); + /// vecPtr = std::move(outbuff); + /// } + /// + /// Handle handle; + /// for (auto & locality : allLocalities()) { + /// uint32_t localityID = static_cast(locality); + /// if (localityID % 2) + /// // every call will overwrite outbuff + /// asyncExecuteAtWithRetBuff( + /// handle, locality, task, args, outBuffers[localityID].get(), + /// &outSizes[localityID]); + /// } + /// + /// waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const InArgsT &, const uint8_t *, uint32_t *); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param resultBuffer The buffer where to store the results. + /// @param resultSize The location where the runtime will store the number of + /// bytes written in the result buffer + template + void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, FunT &&func, + const InArgsT &args, uint8_t *resultBuffer, + uint32_t *resultSize) { + impl::AsynchronousInterface::asyncExecuteAtWithRetBuff( + handle, loc, func, args, resultBuffer, resultSize); + } + + /// @brief Execute a function on a selected locality asynchronously and return a + /// result buffer. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const uint8_t *src, const uint32_t size, + /// const uint8_t *dst, uint32_t * outsize) { + /// memcpy(src, dst, size); + /// *outsize = size; + /// } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// std::vector> outBuffers(numLocalities()); + /// std::vector outSizes(numLocalities(), 0); + /// for (auto & vecPtr : outBuffers) { + /// std::unique_ptr outbuff(new uint8_t[sizeof(Args)]); + /// vecPtr = std::move(outbuff); + /// } + /// + /// Handle handle; + /// for (auto & locality : allLocalities) { + /// if (static_cast(locality) % 2) + /// // every call will overwrite outbuff + /// asyncExecuteAtWithRetBuff( + /// handle, locality, task, ptr, sizeof(Args), + /// outBuffers[localityID].get(), &outSizes[localityID]); + /// } + /// + /// waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const uint8_t *, const uint32_t, const uint8_t *, uint32_t *) + /// @endcode + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param resultBuffer The buffer where to store the results. + /// @param resultSize The location where the runtime will store the number of + /// bytes written in the result buffer + template + void asyncExecuteAtWithRetBuff(Handle &handle, const Locality &loc, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, uint8_t *resultBuffer, + uint32_t *resultSize) { + impl::AsynchronousInterface::asyncExecuteAtWithRetBuff( + handle, loc, func, argsBuffer, bufferSize, resultBuffer, resultSize); + } + + /// @brief Execute a function on a selected locality asynchronously and return a + /// result. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const Args & args, Args * res) { + /// // Do something. + /// } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::vector outBuffers(numLocalities()); + /// + /// Handle handle; + /// for (auto & locality : allLocalities()) { + /// uint32_t localityID = static_cast(locality); + /// asyncExecuteAtWithRet( + /// handle, locality, task, args, &outBuffers[localityID]); + /// } + /// waitForCompletion(handle); + /// @endcode + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const InArgsT &, ResT *); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @tparam ResT The type of the result value. The type can be a structure or a + /// class but with the restriction that must be memcopy-able. + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param result The location where to store the result. + template + void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, FunT &&func, + const InArgsT &args, ResT *result) { + impl::AsynchronousInterface::asyncExecuteAtWithRet( + handle, loc, func, args, result); + } + + /// @brief Execute a function on a selected locality asynchronously and return a + /// result. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const uint8_t *src, const uint32_t size, + /// Args * res) { + /// // Do something + /// } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::vector outBuffers(numLocalities()); + /// std::unique_ptr ptr(new uint8_t[sizeof(Args)]); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// Handle handle; + /// for (auto & locality : allLocalities()) { + /// uint32_t localityID = static_cast(locality); + /// asyncExecuteAtWithRet( + /// handle, locality, task, ptr.get(), sizeof(Args), + /// &outBuffers[localityID]); + /// } + /// waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const uint8_t *, const uint32_t, ResT *); + /// @endcode + /// + /// @tparam ResT The type of the result value. The type can be a structure or a + /// class but with the restriction that must be memcopy-able. + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param result The location where to store the result. + template + void asyncExecuteAtWithRet(Handle &handle, const Locality &loc, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, ResT *result) { + impl::AsynchronousInterface::asyncExecuteAtWithRet( + handle, loc, func, argsBuffer, bufferSize, result); + } + + /// @brief Execute a function on all localities asynchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const Args & args) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// Handle handle; + /// asyncExecuteOnAll(handle, task, args); + /// /* do something else */ + /// waitForcompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const InArgsT &); + /// @endcode + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param handle An Handle for the associated task-group. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + template + void asyncExecuteOnAll(Handle &handle, FunT &&func, const InArgsT &args) { + impl::AsynchronousInterface::asyncExecuteOnAll(handle, func, + args); + } + + /// @brief Execute a function on all localities synchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// void task(Handle & handle, const uint8_t *, + /// const uint32_t) { /* do something */ } + /// + /// Args args { 2, 'a' }; + /// /* Args doesn't need a dynamic allocated buffer but + /// * more complicated data structure might need it */ + /// std::shared_ptr ptr(new uint8_t[sizeof(Args)], + /// std::default_delete()); + /// memcpy(ptr.get(), &args, sizeof(Args)); + /// + /// Handle handle; + /// asyncExecuteOnAll(handle, task, ptr.get(), sizeof(Args)); + /// /* do something else */ + /// waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle & handle, const uint8_t *, const uint32_t); + /// @endcode + /// + /// @param handle An Handle for the associated task-group. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + template + void asyncExecuteOnAll(Handle &handle, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize) { + impl::AsynchronousInterface::asyncExecuteOnAll( + handle, func, argsBuffer, bufferSize); + } + + /// @brief Execute a parallel loop at a specific locality asynchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// Args args { 2, 'a' }; + /// Handle handle; + /// shad::rt::asyncForEachAt(locality, + /// [](Handle & handle, const Args & input, size_t itrNum) { + /// // Do something. + /// }, + /// args, iterations, handle); + /// shad::rt::waitForcompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const ArgsT &, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param numIters The total number of iteration of the loop. + /// @param handle An Handle for the associated task-group. + template + void asyncForEachAt(Handle &handle, const Locality &loc, FunT &&func, + const InArgsT &args, const size_t numIters) { + impl::AsynchronousInterface::asyncForEachAt( + handle, loc, func, args, numIters); + } + + /// @brief Execute a parallel loop at a specific locality asynchronously. + /// + /// Typical Usage: + /// @code + /// std::shared_ptr buffer(new uint8_t[2]{ 5, 5 }, + /// std::default_delete()); + /// + /// Handle handle; + /// shad::rt::asyncForEachAt(locality, + /// handle, + /// [](Handle & handle, const uint8_t * input, const uint32_t size, + /// size_t itrNum) { + /// // Do something. + /// }, + /// buffer, 2, + /// iterations); + /// /* do something else */ + /// shad::rt::waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const uint8_t *, const uint32_t, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @param handle An Handle for the associated task-group. + /// @param loc The Locality where the function must be executed. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param numIters The total number of iteration of the loop. + template + void asyncForEachAt(Handle &handle, const Locality &loc, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { + impl::AsynchronousInterface::asyncForEachAt( + handle, loc, func, argsBuffer, bufferSize, numIters); + } + + /// @brief Execute a parallel loop on the whole system asynchronously. + /// + /// Typical Usage: + /// @code + /// struct Args { + /// int a; + /// char b; + /// }; + /// + /// Args args { 2, 'a' }; + /// Handle handle; + /// shad::rt::asyncForEachOnAll( + /// handle, + /// [](Handle &, const Args &, size_t itrNum) { + /// // Do something. + /// }, + /// args, + /// iterations); + /// /* Do something else */ + /// shad::rt::waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const ArgsT &, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @tparam InArgsT The type of the argument accepted by the function. The type + /// can be a structure or a class but with the restriction that must be + /// memcopy-able. + /// + /// @param handle An Handle for the associated task-group. + /// @param func The function to execute. + /// @param args The arguments to be passed to the function. + /// @param numIters The total number of iteration of the loop. + template + void asyncForEachOnAll(Handle &handle, FunT &&func, const InArgsT &args, + const size_t numIters) { + impl::AsynchronousInterface::asyncForEachOnAll( + handle, func, args, numIters); + } + + /// @brief Execute a parallel loop on the whole system asynchronously. + /// + /// Typical Usage: + /// @code + /// std::shared_ptr buffer(new uint8_t[2]{ 5, 5 }, + /// std::default_delete()); + /// + /// Handle handle; + /// shad::rt::asyncForEachOnAll(handle, + /// [](Handle &, const uint8_t * input, const uint32_t size, + /// size_t itrNum) { + /// // Do something + /// }, + /// buffer, 2, + /// iterations); + /// /* do something else */ + /// shad::rt::waitForCompletion(handle); + /// @endcode + /// + /// @tparam FunT The type of the function to be executed. The function + /// prototype must be: + /// @code + /// void(Handle &, const uint8_t *, const uint32_t, size_t itrNum); + /// @endcode + /// where the itrNum is the n-th iteration of the loop. + /// + /// @param handle An Handle for the associated task-group. + /// @param func The function to execute. + /// @param argsBuffer A buffer of bytes to be passed to the function. + /// @param bufferSize The size of the buffer argsBuffer passed. + /// @param numIters The total number of iteration of the loop. + template + void asyncForEachOnAll(Handle &handle, FunT &&func, + const std::shared_ptr &argsBuffer, + const uint32_t bufferSize, const size_t numIters) { + impl::AsynchronousInterface::asyncForEachOnAll( + handle, func, argsBuffer, bufferSize, numIters); + } + + /// @brief Wait for completion of a set of tasks + inline void waitForCompletion(Handle &handle) { +#if defined HAVE_LOGGING + auto t1 = shad_clock::now(); +#endif + + impl::HandleTrait::WaitFor(handle.id_); + +#if defined HAVE_LOGGING + auto t2 = shad_clock::now(); + std::chrono::duration diff = t2-t1; + auto log_handler = shad::slog::ShadLog::Instance(); + log_handler->printlf("waitForCompletion", diff.count(), &handle, thisLocality(), thisLocality(), 0, 0); +#endif + } + /// @} + + } // namespace rt } // namespace shad #endif // INCLUDE_SHAD_RUNTIME_RUNTIME_H_ + diff --git a/include/shad/util/slog.h b/include/shad/util/slog.h new file mode 100644 index 00000000..948fb73f --- /dev/null +++ b/include/shad/util/slog.h @@ -0,0 +1,183 @@ +//===------------------------------------------------------------*- C++ -*-===// +// +// SHAD +// +// The Scalable High-performance Algorithms and Data Structure Library +// +//===----------------------------------------------------------------------===// +// +// Copyright 2018 Battelle Memorial Institute +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +//===----------------------------------------------------------------------===// + +/* + Developer Date Description + ================================================================================ + Methun K 07/24/2018 Creating class under shad namespace that encapsulate logging functionalities + Methun K 07/26/2018 Create structure for logging items, Create custom loggin message + Methun K 07/27/2018 Change the logging message format + Methun K 08/01/2018 Create template for locality + Methun K 08/14/2018 Add macro to control the log writing + -------------------------------------------------------------------------------- + */ + +#ifndef INCLUDE_UTIL_SLOG_H_ +#define INCLUDE_UTIL_SLOG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "spdlog/spdlog.h" +#include "spdlog/sinks/daily_file_sink.h" +#include "spdlog/async.h" +#include "spdlog/fmt/ostr.h" + +using shad_clock = std::chrono::system_clock; + +namespace shad{ + namespace slog{ + + struct ShadType + { + std::string rtTagName; // GMT, TBB, etc + std::string eventName; + std::string execTime; + std::string execTimeUnit; + rt::Handle *handle; + uint32_t sloc; // Source locality + uint32_t dloc; // Destination locality + size_t inputSizeInByte; + size_t outputSizeInByte; + size_t loopCounter; + + template + friend OStream &operator<<(OStream &os, const ShadType &c) + { + //#ifdef FORMAT_CSV + // return os << c.rtTagName << "," << c.currentTimeStemp << "," << rt::thisLocality() << "," << c.eventName << "," << c.execTime; + //#elif FORMAT_JSON + return os << "\"TAG\":\"" << c.rtTagName << "\",\"SL\":" << std::to_string(c.sloc) << ",\"EN\":\"" << c.eventName << "\",\"ET\":" << c.execTime << ",\"ETU\":\"" << c.execTimeUnit << "\",\"H\":" << ((c.handle==nullptr)?"null":std::to_string(static_cast(*c.handle))) << ", \"DL\":" << std::to_string(c.dloc) << ",\"IS\":" << std::to_string(c.inputSizeInByte) << ",\"OS\":" << std::to_string(c.outputSizeInByte) << ",\"LI\":" << std::to_string(c.loopCounter); + //#endif + } + }; + + class ShadLog{ + private: + // @brief Get Today's date + std::string getTodayDate(){ + auto now = shad_clock::now(); + auto in_time_t = shad_clock::to_time_t(now); + + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d"); + return ss.str(); + } + + // @brief Get current time + std::string getCurrentTime(){ + auto now = shad_clock::now(); + auto in_time_t = shad_clock::to_time_t(now); + + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%X"); + return ss.str(); + } + + // @brief Get current datetime + std::string getCurrentDateTime(){ + auto now = shad_clock::now(); + auto in_time_t = shad_clock::to_time_t(now); + + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d_%X"); + return ss.str(); + } + + // @brief Compute time and unit and return them separately + // Input is a time difference + template + std::vector getTime(T t){ + if(t<1){ + return {std::to_string(t*1000),"ms"}; + }else if(t>=1 && t<60){ + return {std::to_string(t),"sec"}; + }else if(t>=60 && t<3600){ + return {std::to_string(t/60),"min"}; + }else if(t>=3600 && t<86400){ + return {std::to_string(t/3600),"hr"}; + }else{ + float d = t/86400; + + if(d>1&&d<30) return {std::to_string(d),"days"}; + else if(d>=30&&d<365) return {std::to_string(d/30),"mn"}; + else{ + return {std::to_string(d/365),"yr"}; + } + } + } + + // @brief Printing logging information in a file, the suffix of the file name is today's date + // arg: vector of parameters + void printLogInFile(const ShadType& msg){ + try{ + auto async_logger = spdlog::get("SHAD_LOGGER"); + + if(!async_logger){ + async_logger = spdlog::create_async("SHAD_LOGGER", "logs/" + msg.rtTagName + "_" + std::to_string(static_cast(msg.sloc)) + ".json", 0, 0); + async_logger->set_pattern("{\"T\":%t, \"P\":%P, \"TS\":\"%Y-%m-%dT%X.%eZ\", %v},"); + } + + async_logger->info("{}", msg); + async_logger->flush(); + + }catch (const spdlog::spdlog_ex& ex){ + std::cout << ex.what() << std::endl; + } + } + public: + // @brief Default constructor + ShadLog() = default; + + // @brief Creating singleton object + static ShadLog *Instance() { + static ShadLog instance; + return &instance; + } + + template + void printlf(std::string eventName, double execTimeInSec, rt::Handle* handle, SLoc sloc, DLoc dloc, size_t inputSizeInByte, size_t outputSizeInByte, size_t loopCounter=1){ + //std::vector v = getTime(execTimeInSec); + std::string tag = ""; +#if defined HAVE_TBB + tag = "TBB"; +#elif defined HAVE_GMT + tag = "GMT"; +#endif + + const ShadType param = {tag, eventName, std::to_string(execTimeInSec), "sec", handle, static_cast(sloc), static_cast(dloc), inputSizeInByte, outputSizeInByte, loopCounter}; + + printLogInFile(param); + } + }; + } // namespace slog +} // namespace shad + +#endif + diff --git a/script/slog.py b/script/slog.py new file mode 100755 index 00000000..59e0808c --- /dev/null +++ b/script/slog.py @@ -0,0 +1,905 @@ +#!/usr/bin/python + +#===------------------------------------------------------------*- Python v3 -*-===// +# +# SHAD +# +# The Scalable High-performance Algorithms and Data Structure Library +# Performance analyzer +#===----------------------------------------------------------------------===// +# +# Copyright 2018 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +#===----------------------------------------------------------------------===// + +# Developer Date Description +# ================================================================================ +# Methun K 08/03/2018 Created this file +# Methun K 08/07/2018 Created class to modularize the code +# Methun K 08/09/2018 Created class to manage date related operation +# Methun K 08/10/2018 Created data management class that read log files and prepare pandas dataframe +# Methun K 08/13/2018 Created class to manage different kinds of plotting +# Methun K 08/14/2018 Fix the legend position issue, move it to outside the plotting area +# -------------------------------------------------------------------------------- + +import os, errno +from os import listdir +from os.path import isfile, join +import pandas as pd +import numpy as np +import math +import matplotlib +from matplotlib import pyplot as plt +import datetime as dt +import sys, getopt +import fileinput + +# Class holds datetime functionalities +class SDateTime: + """This class holds the functionalities related to date time.""" + + def __init__(self): + """Empty constructor.""" + pass + + def formatDateTime(self, t="", format="%Y-%m-%dT%H:%M:%S.%fZ"): + """This method converts a datetime string to a datetime object with in a specified format + + Parameters: + t (string): Datetime in string format. If no value is passed then method will return current datetime in the specified format. + format (string): Datetime parsing format. Y for year, m for month, d for day, H for hour, M for minute, S for second, f for milisecond. + + Returns: + datetime: Datetime object + """ + if len(t)==0: + if len(format)==0: + return str(dt.datetime.now()) + return dt.datetime.strptime(str(dt.datetime.now()),format) + + try: + return dt.datetime.strptime(str(t),format) + except: + return dt.datetime.strptime(str(dt.datetime.now()),format) + +# Class holds plotting functionalitites +class SPlot: + """This class handles all plotting functionalities.""" + def __init__(self, _dir="/"): + """Constructor for SPlot + + Parameters: + _dir (string): The absolute path of the directory where the plots will be saved. If the directory does not exists then system will create that directory. + """ + self.dir = _dir + + if not(self.dir == "/"): + if not os.path.exists(self.dir): + try: + os.makedirs(self.dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + def getFileName(self, xlabel, ylabel): + """This method generates file name based on axis label + + Parameters: + xlabel (string): Label along x axis + ylabel (string): Label along y axis + + Return: + string: Generates file name concatenated with datetime + """ + fn = '' + if len(xlabel)>0: + fn = fn + xlabel.replace(" ", "_") + "_" + + if len(ylabel)>0: + fn = fn + ylabel.replace(" ", "_") + "_" + + return fn + str(dt.datetime.now()).replace(" ", "_") + + def barPlot(self, x, y, xlabel="", ylabel="", title="", xRot=0, yRot=0, xFontSize=10, yFontSize=10, save=True, fileName="", scaleX="", scaleY="", fdpi=350): + """Bar chart plot + + Parameters: + x (list): Vector or list of x coordinate data + y (list): Vector or list of y coordinate data + xlabel (string): Text to explain x axis data + ylabel (string): Text to explain y axis data + title (string): Title of the figure + xRot (int): Degree to rotate xlabel text + yRot (int): Degree to rotate ylabel text + xFontSize (float): Font size of xlabel text + yFontSize (float): Font size of ylabel text + save (boolean): True indicates save the plot in a file, False indicates show the plot on run. + fileName (string): The name of the file + scaleX (string): Scale the x axis data. Test 'log' specifies scaling the x axis data in log scale. + scaleY (string): Scale the y axis data. Test 'log' specifies scaling the y axis data in log scale. + fdpi (int): Picture dpi. Default value 350. + """ + plt.figure(dpi=fdpi) + plt.bar(x, y) + plt.xticks(fontsize=xFontSize) + plt.yticks(fontsize=yFontSize) + + if scaleX.upper() == "LOG": + plt.xscale(scaleX) + + if scaleY.upper() == "LOG": + plt.yscale(scaleY) + + if len(xlabel)>0: + plt.xlabel(xlabel) + + if xRot!=0: + plt.xticks(rotation=xRot) + + if len(ylabel)>0: + plt.ylabel(ylabel) + + if yRot!=0: + plt.yticks(rotation=yRot) + + if len(title)>0: + plt.title(title) + + if len(fileName)==0: + fileName = self.getFileName(xlabel, ylabel) + + if save == True: + plt.savefig(join(self.dir, fileName + ".pdf"), bbox_inches='tight') + plt.close('all') + else: + plt.show() + + def __generateGrid(self, fig, x=[], y=[], showXMajorTics=True, showXMinorTics=True, xMajorTics=10, xMinorTics=5, showYMajorTics=True, showYMinorTics=True, yMajorTics=10, yMinorTics=5, alphaMajor=0.5, alphaMinor=0.2): + """Generate grid for a figure + + Parameters: + fig (object): matplotlib.plt.figure object + x (list): Range of x coordinate data. x[0] is minimum data, x[1] is maximum data + y (list): Range of y coordinate data. y[0] is minimum data, y[1] is maximum data + showXMajorTics (boolean): Show major tics along x axis or not. Default value is True + showXMinorTics (boolean): Show minor tics along x axis or not. Default value is True + xMajorTics (int): Number of major tics along x axis. Default value is 10 + xMinorTics (int): Number of minor tics along x axis. Default value is 5 + showYMajorTics (boolean): Show major axis along y axis or not. Default value is True + showYMinorTics (boolean): Show minor tics along y axis or not. Default value is True + yMajorTics (int): Number of major tics along y axis. Default value is 10 + yMinorTics (int): Number of minor tics along y axis. Default value is 5 + alphaMajor (float): Depth of major axis. Range of value from 0 to 1. Default value is 0.5 + alphaMinor (float): Depth of minor axis. Range of value from 0 to 1. Default value is 0.2 + """ + ax = fig.add_subplot(1, 1, 1) + + if len(x) > 0: + if showXMajorTics==True and xMajorTics!=0: + ax.set_xticks(np.arange(x[0], x[1], xMajorTics)) + if showXMinorTics==True and xMinorTics!=0: + ax.set_xticks(np.arange(x[0], x[1], xMinorTics), minor=True) + + if len(y) > 0: + if showYMajorTics==True and yMajorTics!=0: + ax.set_yticks(np.arange(y[0], y[1], yMajorTics)) + if showYMinorTics==True and yMinorTics!=0: + ax.set_yticks(np.arange(y[0], y[1], yMinorTics), minor=True) + + # And a corresponding grid + ax.grid(which='both') + + # Or if you want different settings for the grids: + ax.grid(which='minor', alpha=alphaMinor) + ax.grid(which='major', alpha=alphaMajor) + + ''' + matplotlib.colors + b : blue. + g : green. + r : red. + c : cyan. + m : magenta. + y : yellow. + k : black. + w : white. + ''' + def lineChartPlot(self, x, y, xRange=[], yRange=[], xlabel="", ylabel="", title="", xRot=0, yRot=0, xFontSize=10, yFontSize=10, + save=True, fileName="", scaleX="", scaleY="", _showXMajorTics=True, _showXMinorTics=False, _xMajorTics=10, _xMinorTics=5, + _showYMajorTics=True, _showYMinorTics=False, _yMajorTics=10, _yMinorTics=5, _alphaMajor=0.5, _alphaMinor=0.2, color=['k'], + lineType='-', lineWidth=2, fdpi=350, showGrid=False, showLegends=False, legends=[], legendPos='center left', boxToAnchor=(1, 0.5)): + """Line chart plot + + Parameters: + x (list): Vector or list of x coordinate data + y (list): Vector or list of y coordinate data + xRange (list): Range of x coordinate data. x[0] is minimum data, x[1] is maximum data + yRange (list): Range of y coordinate data. y[0] is minimum data, y[1] is maximum data + xlabel (string): Text to explain x axis data + ylabel (string): Text to explain y axis data + title (string): Title of the figure + xRot (int): Degree to rotate xlabel text + yRot (int): Degree to rotate ylabel text + xFontSize (float): Font size of xlabel text + yFontSize (float): Font size of ylabel text + save (boolean): True indicates save the plot in a file, False indicates show the plot on run. + fileName (string): The name of the file + scaleX (string): Scale the x axis data. Test 'log' specifies scaling the x axis data in log scale. + scaleY (string): Scale the y axis data. Test 'log' specifies scaling the y axis data in log scale. + _showXMajorTics (boolean): Show major tics along x axis or not. Default value is True + _showXMinorTics (boolean): Show minor tics along x axis or not. Default value is True + _xMajorTics (int): Number of major tics along x axis. Default value is 10 + _xMinorTics (int): Number of minor tics along x axis. Default value is 5 + _showYMajorTics (boolean): Show major axis along y axis or not. Default value is True + _showYMinorTics (boolean): Show minor tics along y axis or not. Default value is True + _yMajorTics (int): Number of major tics along y axis. Default value is 10 + _yMinorTics (int): Number of minor tics along y axis. Default value is 5 + _alphaMajor (float): Depth of major axis. Range of value from 0 to 1. Default value is 0.5 + _alphaMinor (float): Depth of minor axis. Range of value from 0 to 1. Default value is 0.2 + color (list): List of matplotlib.colors + lineType (string): Line type. Default value '-' + lineWidth (int): Line width, default value is 2 + fdpi (int): Picture dpi. Default value 350. + showGrid (boolean): Show grid or not. Default value is False + showLegends (boolean): Show legends or not. Default value is False + legends (list): List of legends. Default value is [] + legendPos (string): Legend position. Default value is 'center left' + boxToAnchor (array): Position of legend box. Default value is (1, 0.5) + """ + fig = plt.figure(dpi=fdpi) + + if showGrid==True: + if len(xRange)==0: + xRange = [min(x), max(x)] + if len(yRange)==0: + yRange = [min(y), max(y)] + + self.__generateGrid(fig, xRange, yRange, showXMajorTics=_showXMajorTics, showXMinorTics=_showXMinorTics, xMajorTics=_xMajorTics, xMinorTics=_xMinorTics, showYMajorTics=_showYMajorTics, showYMinorTics=_showYMinorTics, yMajorTics=_yMajorTics, yMinorTics=_yMinorTics, alphaMajor=_alphaMajor, alphaMinor=_alphaMinor) + + for i in range(0, len(x), 1): + plt.plot(x[i], y[i], color=color[i], linewidth=lineWidth) + + if showLegends==True: + plt.legend(legends, loc=legendPos, bbox_to_anchor=boxToAnchor) + + plt.xticks(fontsize=xFontSize) + plt.yticks(fontsize=yFontSize) + + if scaleX.upper() == "LOG": + plt.xscale(scaleX) + + if scaleY.upper() == "LOG": + plt.yscale(scaleY) + + if len(xlabel)>0: + plt.xlabel(xlabel) + + if xRot!=0: + plt.xticks(rotation=xRot) + + if len(ylabel)>0: + plt.ylabel(ylabel) + + if yRot!=0: + plt.yticks(rotation=yRot) + + if len(title)>0: + plt.title(title) + + if len(fileName)==0: + fileName = self.getFileName(xlabel, ylabel) + + if save == True: + plt.savefig(join(self.dir, fileName + ".pdf"), bbox_inches='tight') + plt.close('all') + else: + plt.show() + + +# Data management layer +class SLogAnalysis: + """ This is a data management class for logging. It reads the log files, process to make it Pandas data frame""" + def __init__(self, _dir="/", _fdir="/"): + """ Constructor for SLogAnalysis class + + Parameters: + _dir (string): The absolute path of the directory where the log files are saved. If the directory does not exists then system will create that directory. + _fdir (string): The absolute path of the directory where the plots will be saved. If the directory does not exists then system will create that directory. + """ + self.dir = _dir + self.fileList = [] + self.df = None + self.dateObj = SDateTime() + self.plot = SPlot(_fdir) + self.__checkDir(self.dir) + _tDir = join(self.dir, 'tmp') + self.__checkDir(_tDir) + self.tJSON = join(_tDir,'temp.json') + + #def fileChooser(self): + # root = tk.Tk() + # root.withdraw() + # file_path = filedialog.askopenfilenames(initialdir = self.dir, title = "Select file", filetypes = (("JSON files","*.json"),("all files","*.*"))) + # self.fileList = [i for i in root.tk.splitlist(file_path)] + + def __checkDir(self, _dir): + """ This method is used to check whether the given directory is already exists or not. If directory does not exists that it will create a new one + + Parameters: + _dir (string): Absolute path. If directory is not a root directory (e.g. /) then it will create a new directory it it does ot exists + + """ + if not(_dir == "/"): + if not os.path.exists(_dir): + try: + os.makedirs(_dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + def getLogFiles(self, runtime="", locality=-1, startDate=None, endDate=None): + """The method is used to filter logging files based on following filters. + + Parameters: + runtime (string): Runtime of the system. E.g. GMT, TBB, etc + locality (int): Locality id + startDate (datetime): Search start date + endDate (datetime): Search end date + + Return: + list: List of logging files name with absolute path + """ + _fileList = [f for f in listdir(self.dir) if isfile(join(self.dir, f))] + self.fileList = [] + + if len(runtime) >0 or locality>=0 or (startDate is not None and endDate is None): + # filter based on criteria + fs = '' + if len(runtime)>0: + fs = runtime.upper() + "_" + + if locality >=0: + fs = fs + str(locality) + "_" + + if startDate is not None and endDate is None: + fs = fs + str(startDate) + + #print(fs) + + [self.fileList.append(join(self.dir, f)) for f in _fileList if fs in f] + + #print(self.fileList) + + elif startDate is not None and endDate is not None: + date_range = [startDate + dt.timedelta(days=x) for x in range(0, (endDate-startDate).days)] + + fs = '' + if len(runtime)>0: + fs = runtime.upper() + "_" + + if locality >=0: + fs = fs + str(locality) + "_" + + for _date in date_range: + [self.fileList.append(join(self.dir, f)) for f in _fileList if (fs + str(_date)) in f] + + def __printFiles(self): + """This is a private method to print the filtered logging file list.""" + print(self.fileList) + + def readFiles(self): + """This method is used to read logging files and convert it to a Pandas data object.""" + if len(self.fileList) > 0: + print("Starts processing JSON object...") + if isfile(self.tJSON): + os.remove(self.tJSON) + + with open(self.tJSON, 'w') as outfile: + outfile.write("[") + input_lines = fileinput.input(files=self.fileList) + a = 0 + for line in input_lines: + a += 1 + input_lines = fileinput.input(files=self.fileList) + b=0 + for line in input_lines: + b +=1 + + if (line[-1:]!=','): + line = line[:-1] + if b==a: + line = line[:-1]+"]" + + outfile.write(line) + + print("Converting JSON to dataframe...") + self.df = pd.DataFrame(pd.read_json(self.tJSON, "record")) + print("Conversion completed...") + + + def eventFrequencyPlot(self, xlab="", ylab="", xRotation = 0, yRotation = 0, fullTitle="", fontSizeX=7, fontSizeY=7, xScale="", yScale=""): + """This method is used to plot event name vs frequency of an event + + Parameters: + xlab (string): Label text for x axis values + ylab (string): Label text for y axis values + xRotation (float): Rotation angle for x axis values + yRotation (float): Rotation angle for y axis values + fullTitle (string): Title of the image + fontSizeX (float): Font size of x axis texts + fontSizeY (float): Font size of y axis texts + xScale (float): Scale the x axis values (e.g. log) + yScale (float): Scale the y axis values (e.g. log) + """ + if self.df is None: + self.readFiles(); + + if self.df is not None: + df_ENC = self.df.groupby('EN').size().reset_index(name='Counts') + # plotting histogram + self.plot.barPlot(df_ENC['EN'], df_ENC['Counts'], xlabel=xlab, ylabel=ylab, xRot = xRotation, yRot = yRotation, title=fullTitle, xFontSize=fontSizeX, yFontSize=fontSizeY, scaleX=xScale, scaleY=yScale) + + def eventMatricPlot(self, matricColName='ET', matricName='Execution time', matricUnit="s", xlab="", ylab="", xRotation = 0, yRotation = 0, fullTitle="", fontSizeX=7, fontSizeY=7, xScale="", yScale=""): + """This method is used to plot event name vs frequency of an event + + Parameters: + matricColName (string): Which matric we want to use (default: ET. Other values: IS, OS, LI) + matricName (string): Name of the matric that you choose (default:Execution time. Other values: Input size, Output size, Loop counter) + matricUnit (string): The unit of the selected matric (default: s. Other values: byte or b) + xlab (string): Label text for x axis values + ylab (string): Label text for y axis values + xRotation (float): Rotation angle for x axis values + yRotation (float): Rotation angle for y axis values + fullTitle (string): Title of the image + fontSizeX (float): Font size of x axis texts. Default value: 7 + fontSizeY (float): Font size of y axis texts. Default value: 7 + xScale (float): Scale the x axis values (e.g. log) + yScale (float): Scale the y axis values (e.g. log) + """ + if self.df is None: + self.readFiles(); + + cn = matricName + if len(cn)==0: + cn = 'abc' + + if self.df is not None: + df_ENT = self.df.groupby('EN')[matricColName].sum().reset_index(name=cn) + # plotting histogram + self.plot.barPlot(df_ENT['EN'], df_ENT[cn], xlabel=xlab, ylabel=ylab, xRot = xRotation, yRot=yRotation, title=fullTitle, xFontSize=fontSizeX, yFontSize=fontSizeY, scaleX=xScale, scaleY=yScale) + + def __timeDistanceofAnEvent(self, st=None, unit="s"): + """This method is used to create time difference based on unit value. For instance, if any event occurs at time t1 and the starting time is st then the time difference of this event is: (t2-st). + + Parameters: + st (datetime): Starting datetime in the time column values + unit (string): Unit of time. (default: s for second. Other values are: m/min for minutes, h/hr/hour for hours, d/day for days, mn/month for months) + """ + if (st is None): + ats = sorted(self.df['TS']) + st = self.dateObj.formatDateTime(ats[0]) + + t = self.dateObj.formatDateTime(st) + self.df['TIS'] = [(self.dateObj.formatDateTime(i)-t).total_seconds() for i in self.df['TS']] + + unit = unit.lower() + # minutes + if(unit == "m" or unit == "min"): + self.df['TIS'] = [i/60 for i in self.df['TIS']] + # hours + elif(unit == "h" or unit == "hr" or unit == "hour"): + self.df['TIS'] = [i/(60*60) for i in self.df['TIS']] + # day + elif(unit == "d" or unit == "day"): + self.df['TIS'] = [i/(60*60*24) for i in self.df['TIS']] + # month (assuming each month is 30 days long) + elif(unit == "mn" or unit == "month"): + self.df['TIS'] = [i/(60*60*24*30) for i in self.df['TIS']] + + + ''' + Location string Location code boxToAnchor (to place the legend outside the plotting area) + =============== ============= ============ + 'best' 0 + 'upper right' 1 + 'upper left' 2 + 'lower left' 3 (1.04,0) + 'lower right' 4 (1,0) + 'right' 5 + 'center left' 6 (1.04,0.5) + 'center right' 7 + 'lower center' 8 + 'upper center' 9 + 'center' 10 + ''' + def analyzeEventMatric(self, en="", matr="", ts=10, unit="s", _xlabel="", _ylabel="", _title="", _xRot=0, _yRot=0, _xFontSize=10, _yFontSize=10, _save=True, _fileName="", + _scaleX="", _scaleY="", showXMajorTics=True, showXMinorTics=False, xMajorTics=10, xMinorTics=5, showYMajorTics=True, + showYMinorTics=False, yMajorTics=10, yMinorTics=5, alphaMajor=0.5, alphaMinor=0.2, _color='k', _lineType='-', + _lineWidth=2, _fdpi=350, _showGrid=False, multiLine=False): + """This method is designed to analyze any matric for any specific event. I can also generate results for all matrics for an event or a specific matric for all events. It also has capability to generate seperate results for all events and all possible matrics. Beside that it can generate combined result. For instance, it can generate result for all matrics of an event in a simgle plot. + + Parameters: + en (string): Event name. + matr (string): Matric name. + ts (float): Time difference duing plotting time along x axis. + unit (string): Time unit. (default: s for second. Other values are: m/min for minutes, h/hr/hour for hours, d/day for days, mn/month for months) + _xlabel (string): Label text for x axis values + _ylabel (string): Label text for y axis values + _title (string): Title of the image + _xRot(float): Rotation angle for x axis values + _yRot (float): Rotation angle for y axis values + _xFontSize (float): Font size of x axis texts. Default value: 10 + _yFontSize (float): Font size of y axis texts. Default value: 10 + _save (boolean): True means want to save as image file and False means want to show image + _fileName (string): Name of the saved file name, + _scaleX (string): Scale the x axis values (e.g. log) + _scaleY (string): Scale the x] axis values (e.g. log) + showXMajorTics (boolean): True indicates that allow the grid to show major tics + showXMinorTics (boolean): True indicates that allow the grid to show minor tics + xMajorTics (int): Number of major tics + xMinorTics (int): Number of minor tics + showYMajorTics (boolean): True indicates that allow the grid to show major ticsz + showYMinorTics (boolean): True indicates that allow the grid to show minor tics + yMajorTics (int): Number of major tics. Default value: 10 + yMinorTics (int): Number of major tics. Default value: 5 + alphaMajor (float): The depth of major axis. Default:0.5. Values ranges from 0 to 1. + alphaMinor (float): The depth of major axis. Default:0.2. Values ranges from 0 to 1. + _color (string): matplot color code. Default: k for black + _lineType (string): The appearance of the line. Default:'-', + _lineWidth (int): Width of a line. Default: 2 + _fdpi (int): Frame DPI. Defailt value: 350 + _showGrid (boolean): True means shows the picture in a grid fashion + multiLine (boolean): True indicates to show multiple plots in same frame. + """ + + if self.df is None: + self.readFiles(); + + if len(matr)==0: + matr = ['ET', 'IS', 'OS', 'LI'] + else: + matr = [matr] + + if self.df is not None: + if len(en)==0: + en = [i for i in self.df.EN.unique()] + else: + en = [en] + + ats = sorted(self.df['TS']) + st = self.dateObj.formatDateTime(ats[0]) + et = self.dateObj.formatDateTime(ats[len(ats)-1]) + + dur = (et-st).total_seconds() + + unit = unit.lower() + tunit = "seconds" + # minutes + if(unit == "m" or unit == "min"): + dur = dur/60 + tunit = "minutes" + # hours + elif(unit == "h" or unit == "hr" or unit == "hour"): + dur = dur/(60*60) + tunit = "hours" + # day + elif(unit == "d" or unit == "day"): + dur = dur/(60*60*24) + tunit = "days" + # month (assuming each month is 30 days long) + elif(unit == "mn" or unit == "month"): + dur = dur/(60*60*24*30) + tunit = "months" + + if(dur%ts!=0): + dur = dur + ts + + tl = list(np.arange(0, dur, ts)) + + self.__timeDistanceofAnEvent(ats[0], unit) + + cv = [i for i in range(1, len(en)+1, 1)] + cmap = matplotlib.cm.viridis + norm = matplotlib.colors.Normalize(vmin=min(cv), vmax=max(cv)) + + _xRange = [min(self.df['TIS']), max(self.df['TIS'])] + + # For each matric (execution time/input size/output size/loop counter) + for _tmn in matr: + _yRange = [min(self.df[_tmn]), max(self.df[_tmn])] + yMajorTics = (max(self.df[_tmn]) - min(self.df[_tmn]))/ts + + j=0 + col = [] + x=[] + y=[] + + mn = '' + yl = '' + _title = '' + if _tmn == "ET": + mn = "Execution time" + yl = "Execution time (" + tunit + ")" + _title = "Event execution time plot" + elif _tmn == "IS": + mn = "Input size" + yl = "Input size (byte)" + _title = "Event input size plot" + elif _tmn == "OS": + mn = "Output size" + yl = "Output size (byte)" + _title = "Event output size plot" + elif _tmn == "LI": + mn = "Loop counter" + yl = "Loop counter" + _title = "Event loop counter plot" + + for _ten in en: + if len(en)>1: + col.append(cmap(norm(cv[j]))) + j = j + 1 + else: + col.append(_color) + + tdf = self.df[self.df['EN'] == _ten] + + if multiLine==True: + x.append(tdf['TIS']) + y.append(tdf[_tmn]) + _fileName = yl + " for all events and " + mn + "_" + str(dt.datetime.now()) + else: + _fileName = yl + " for event (" + _ten + ")_" + str(dt.datetime.now()) + + if multiLine==False: + _yRange = [min(tdf[_tmn]), max(tdf[_tmn])] + yMajorTics = (max(tdf[_tmn]) - min(tdf[_tmn]))/ts + + self.plot.lineChartPlot([tdf['TIS']], [tdf[_tmn]], xRange=_xRange, yRange=_yRange, xlabel=_xlabel, ylabel=yl, title=_title + " for " + _ten, xRot=_xRot, yRot=_yRot, xFontSize=_xFontSize, yFontSize=_yFontSize, save=_save, fileName=_fileName, + scaleX=_scaleX, scaleY=_scaleY, _showXMajorTics=showXMajorTics, _showXMinorTics=showXMinorTics, _xMajorTics=xMajorTics, _xMinorTics=xMinorTics, _showYMajorTics=showYMajorTics, + _showYMinorTics=showYMinorTics, _yMajorTics=yMajorTics, _yMinorTics=yMinorTics, _alphaMajor=alphaMajor, _alphaMinor=alphaMinor, color=col, lineType=_lineType, + lineWidth=_lineWidth, fdpi=_fdpi, showGrid=_showGrid, showLegends=False) + + + if multiLine==True: + self.plot.lineChartPlot(x, y, xRange=_xRange, yRange=_yRange, xlabel=_xlabel, ylabel=yl, title=_title, xRot=_xRot, yRot=_yRot, xFontSize=_xFontSize, yFontSize=_yFontSize, save=_save, fileName=_fileName, + scaleX=_scaleX, scaleY=_scaleY, _showXMajorTics=showXMajorTics, _showXMinorTics=showXMinorTics, _xMajorTics=xMajorTics, _xMinorTics=xMinorTics, _showYMajorTics=showYMajorTics, + _showYMinorTics=showYMinorTics, _yMajorTics=yMajorTics, _yMinorTics=yMinorTics, _alphaMajor=alphaMajor, _alphaMinor=alphaMinor, color=col, lineType=_lineType, + lineWidth=_lineWidth, fdpi=_fdpi, showGrid=_showGrid, showLegends=True, legends=en, legendPos='center left') + + +# Class handles user request from command prompt +class SLogMenu: + """This class parse command line arguments and call specific methods to generate results. + """ + def __init__(self, argv): + """Default constructor for SLogMenu class + """ + self.ldir = '' + self.fdir = '' + self.runtime = '' + self.locality=-1 + self.date=None + self.startDT = None + self.endDT = None + self.eventCount = False + self.eventCountScaleY = '' + self.eventMatricCount = False + self.eventMatricCountScaleY = '' + self.eventMatricName = 'ET' + self.EventMatricUnit = "s" + self.eventMatric = False + self.eventMatricScaleY='' + self.eventName = '' + self.matricName = '' + self.timeInterval = 10 + self.timeUnit = 's' + self.multiLine = False + + self.dateObj = SDateTime() + self.__parseArgs(argv) + + def __helpMessage(self): + """This method shows the list of arguments that the system accepts""" + print('-h or --help: help message' + + '\n-d: Directory of logging file [Required field]' + + '\n-f: Directory of saved image [If not provided then it will use the location provided in -d. Directory must have write permission.]' + + '\n-r: Runtime [Optional]' + + '\n-l:Locality [Optional]' + + '\n--dt: Date in a format of mm-dd-yyyy [Optional]' + + '\n--dtr: Date range. Eg. 07-12-2016T09-03-2017 [Optional]' + + '\n--ec: Plot the number of times an event is called' + + '\n--ecy: Scale y axis values [optional, default value ''], eg. log' + + '\n--emc: Plot aggregate matric count vs event. You have to pass the matric name using --emn parameter.' + + '\n--emcy: Scale y axis values [optional, default value ''], eg. log' + + '\n--emn: Event matric name, eg. execution time (ET), input size (IS), output size (OS), loop counter (LI)' + + '\n--emu: Event matric unit: for execution time: Milisecond (ms), Minute (m or min), Hour (h or hr or hour), Day (d or day), Month (mn or month), and default unit is second; For IS or OS: kilo (kb), mega (mb), giga (gb), tera (tb), default is byte (b)' + + '\n--em: Flag to enable functionality to plot event vs matric [By default it will plot event vs matric for ]' + + '\n--en: Event name' + + '\n--emy: Scale y axis values [optional, default value ''], eg. log' + + '\n--mn: Matric name, eg. execution time (ET), input size (IS), output size (OS), loop counter (LI)' + + '\n--ti: Time interval in the time line' + + '\n--tu: Time interval unit, eg. Milisecond (ms), Minute (m or min), Hour (h or hr or hour), Day (d or day), Month (mn or month), and default unit is second (s)' + + '\n--ml: Show all event time lines in a single chart [optional, default: False]' + + '\n') + + def __parseDateRange(self, dt): + """This method is used to parse the datetime string and convert it into start and end datetime + + Parameters: + dt (string): Two datetime string concatenated by character T. For instance:07-12-2016T09-03-2017. + """ + dtl = dt.split("T") + self.startDT = self.dateObj.formatDateTime(dtl[0], "%m-%d-%Y").date() + self.endDT = self.dateObj.formatDateTime(dtl[1], "%m-%d-%Y").date() + + + def __parseArgs(self, argv): + """This method parses the supplied arguments from the terminal""" + try: + opts, args = getopt.getopt(argv, 'hd:f:r:l:', ["help","dt=","dtr=","ec","ecy=","emc","emcy=","emn=","emu=","em","emy=","en=","mn=","ti=","tu=","ml"]) + except getopt.GetoptError as err: + print(err) + self.__helpMessage() + sys.exit(2) + + for opt, arg in opts: + if opt in ("-h", "--help"): + helpMessage() + sys.exit() + elif opt == "-d": + self.ldir = arg + elif opt == "-f": + self.fdir = arg + elif opt == "-r": + self.runtime = arg + elif opt == "-l": + self.locality = int(arg) + elif opt == "--dt": + self.date = self.dateObj.formatDateTime(arg, format="%m-%d-%Y").date() + elif opt == "--dtr": + self.__parseDateRange(arg) + elif opt == "--ec": + self.eventCount = True + elif opt == "--ecy": + self.eventCountScaleY = arg + elif opt == "--emc": + self.eventMatricCount = True + elif opt == "--emcy": + self.eventMatricCountScaleY = arg + elif opt == "--emn": + self.eventMatricName = arg + elif opt == "--emu": + self.EventMatricUnit = arg + elif opt == "--em": + self.eventMatric = True + elif opt == "--emy": + self.eventMatricScaleY = arg + elif opt == "--en": + self.eventName = arg + elif opt == "--mn": + self.matricName = arg + elif opt == "--ti": + self.timeInterval = float(arg) + elif opt == "--tu": + self.timeUnit = arg + elif opt == "--ml": + self.multiLine = True + + if len(self.ldir)==0: + self.__helpMessage() + sys.exit() + + if len(self.fdir)==0: + self.fdir = self.ldir + + def __test(self): + """This method shows the argument values""" + print("log dir=",self.ldir) + print("img dir=", self.fdir) + print("runtime=",self.runtime) + print("locality=",self.locality) + print("Date=",self.date) + print("Start date=", self.startDT) + print("End date=", self.endDT) + print("Event count=", self.eventCount) + print("Event count scale Y=", self.eventCountScaleY) + print("Event Matric count=", self.eventMatricCount) + print("Event Matric count scale Y=", self.eventMatricCountScaleY) + print("Event Matric Name=", self.eventMatricName) + print("Event matric=", self.eventMatric) + print("Event matric Scale Y=", self.eventMatricScaleY) + print("Event name=", self.eventName) + print("Matric name=", self.matricName) + print("Time interval=", self.timeInterval) + print("Time unit=", self.timeUnit) + + def generateReport(self): + """This method does following operations: + + 1. It creates pandas dataframe after reading the log files + 2. It calls specidic report generating methods to generate report + """ + self.__test() + logObj = SLogAnalysis(self.ldir, self.fdir) + + _date = None + if self.startDT is not None: + _date = self.startDT + elif self.date is not None: + _date = self.date + + logObj.getLogFiles(runtime=self.runtime, locality=self.locality, startDate=_date, endDate=self.endDT) + + if self.eventCount==True: + logObj.eventFrequencyPlot(xlab = "Event name", ylab="Frequency", xRotation=30, fullTitle="Event frequency plot", yScale=self.eventCountScaleY) + + if self.eventMatricCount == True: + mn = '' + yl = '' + title = '' + if self.eventMatricName == "ET": + mn = "Execution time" + yl = "Aggregated execution time (sec)" + title = "Event execution time plot" + elif self.eventMatricName == "IS": + mn = "Input size" + yl = "Aggregated input size (byte)" + title = "Event input size plot" + elif self.eventMatricName == "OS": + mn = "Output size" + yl = "Aggregated output size (byte)" + title = "Event output size plot" + elif self.eventMatricName == "LI": + mn = "Loop counter" + yl = "Aggregated loop counter" + title = "Event loop counter plot" + + if self.eventMatricCountScaleY.upper() == "LOG": + yl += " in logarithmic scale" + + logObj.eventMatricPlot(matricColName=self.eventMatricName, matricName=mn, xlab = "Event name", ylab=yl, xRotation=30, fullTitle=title, yScale=self.eventMatricCountScaleY) + + if self.eventMatric==True: + + tunit = 'seconds' + # miliseconds + if(self.timeUnit.upper() == "MS"): + tunit = "miliseconds" + # minutes + if(self.timeUnit.upper() == "M" or self.timeUnit.upper() == "MIN"): + tunit = "minutes" + # hours + elif(self.timeUnit.upper() == "H" or self.timeUnit.upper() == "HR" or self.timeUnit.upper() == "HOUR"): + tunit = "hours" + # day + elif(self.timeUnit.upper() == "D" or self.timeUnit.upper() == "DAY"): + tunit = "days" + # month (assuming each month is 30 days long) + elif(self.timeUnit.upper() == "MN" or self.timeUnit.upper() == "MONTH"): + tunit = "months" + + logObj.analyzeEventMatric(en=self.eventName, matr=self.matricName, ts=self.timeInterval, unit=self.timeUnit, + _xlabel="Time in " + tunit , _xFontSize=7, _yFontSize=7, _scaleY=self.eventMatricScaleY, + _showGrid=True, xMajorTics=self.timeInterval, multiLine=self.multiLine) + +# Main function +if __name__ == "__main__": + """This is the main entry point of the system""" + menu = SLogMenu(sys.argv[1:]) + menu.generateReport() + +# test command: +# python3 ./slog.py -d "/Users/methun/self/PNNL/Work/Shad_log/log_2018-08-15" -f "/Users/methun/self/PNNL/Work/Shad_log/logfig" --dt "08-15-2018" --ec --em --ti 5 --ml +