-
-
Notifications
You must be signed in to change notification settings - Fork 172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CPP] Invented a parallel algorithm based on seidel implementation. #163
base: develop
Are you sure you want to change the base?
Changes from 5 commits
b1000a1
344b166
4b1d84d
64e5c56
b002cdf
09ebd7d
8fd1f61
4365e5a
3a402b9
5c42ee2
f3e98b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,4 +111,5 @@ venv.bak/ | |
cpp/.clangd | ||
build* | ||
cpp/doc/CMakeFiles/* | ||
cpp/doc/doc/* | ||
cpp/doc/doc/* | ||
temp/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,7 @@ option(TOPPRA_DEBUG_ON "Set logging mode to on." OFF) | |
option(TOPPRA_WARN_ON "Enable warning messages." ON) | ||
option(OPT_MSGPACK "Serialization using msgpack " OFF) | ||
# Bindings | ||
option(PYTHON_BINDINGS "Build bindings for Python" ON) | ||
option(PYTHON_BINDINGS "Build bindings for Python" OFF) | ||
set(PYTHON_VERSION 3.7 CACHE STRING "Build bindings for Python version") | ||
set(BUILD_WITH_PINOCCHIO_PYTHON false CACHE BOOL "Force compile with Pinocchio bindings") | ||
# This option is needed because sometime the flag | ||
|
@@ -47,6 +47,13 @@ if(BUILD_WITH_GLPK) | |
message(STATUS "Found glpk ${GLPK_LIBRARY} ${GLPK_INCLUDE_DIR}") | ||
endif(BUILD_WITH_GLPK) | ||
|
||
find_package(OpenMP REQUIRED) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to have a BUILD_WITH_OPENMP flag and find OpenMP only if it is switched on. Otherwise this breaks compilation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. |
||
if (OPENMP_FOUND) | ||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") | ||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") | ||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") | ||
endif() | ||
|
||
add_subdirectory(src) | ||
add_subdirectory(doc) | ||
add_subdirectory(bindings) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,16 @@ | |
#include <iostream> | ||
#include "toppra/toppra.hpp" | ||
|
||
#include <ctime> | ||
#include <sys/time.h> | ||
|
||
unsigned long long GetCurrentTimeUsec() | ||
{ | ||
struct timeval tv; | ||
gettimeofday(&tv,NULL); | ||
return ((unsigned long long)tv.tv_sec * 1000000 + (unsigned long long)tv.tv_usec); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a C-style way of measuring time. Although valid, I would be in favor of a more C++ style (e.g. https://www.techiedelight.com/measure-elapsed-time-program-chrono-library). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, It's a good suggestion. |
||
|
||
namespace toppra { | ||
|
||
PathParametrizationAlgorithm::PathParametrizationAlgorithm( | ||
|
@@ -13,15 +23,24 @@ PathParametrizationAlgorithm::PathParametrizationAlgorithm( | |
|
||
ReturnCode PathParametrizationAlgorithm::computePathParametrization(value_type vel_start, | ||
value_type vel_end) { | ||
size_t be = GetCurrentTimeUsec(); | ||
initialize(); | ||
size_t en = GetCurrentTimeUsec(); | ||
printf("time of init: %fms\n", (en - be)/1000.0); | ||
be = en; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. |
||
m_solver->setupSolver(); | ||
Bound vel_ends; | ||
vel_ends.setConstant(vel_end); | ||
m_data.ret_code = computeControllableSets(vel_ends); | ||
en = GetCurrentTimeUsec(); | ||
printf("time of computeControllableSets: %fms\n", (en - be)/1000.0); | ||
be = en; | ||
if ((int)m_data.ret_code > 0) { | ||
return m_data.ret_code; | ||
} | ||
m_data.ret_code = computeForwardPass(vel_start); | ||
en = GetCurrentTimeUsec(); | ||
printf("time of computeForwardPass: %fms\n", (en - be)/1000.0); | ||
return m_data.ret_code; | ||
}; | ||
|
||
|
@@ -67,6 +86,100 @@ ReturnCode PathParametrizationAlgorithm::computeControllableSets( | |
return ret; | ||
} | ||
|
||
ReturnCode PathParametrizationAlgorithm::computePathParametrizationParallel(value_type vel_start, | ||
value_type vel_end) { | ||
|
||
size_t be = GetCurrentTimeUsec(); | ||
initialize(); | ||
size_t en = GetCurrentTimeUsec(); | ||
printf("time of init: %fms\n", (en - be)/1000.0); | ||
be = en; | ||
|
||
m_solver->setupSolver(); | ||
Bound vel_ends; | ||
vel_ends.setConstant(vel_end); | ||
m_data.ret_code = computeControllableSetsParallel(vel_ends); | ||
en = GetCurrentTimeUsec(); | ||
printf("time of computeControllableSetsParallel: %fms\n", (en - be)/1000.0); | ||
be = en; | ||
if ((int)m_data.ret_code > 0) { | ||
return m_data.ret_code; | ||
} | ||
|
||
m_data.ret_code = computeForwardPass(vel_start); | ||
en = GetCurrentTimeUsec(); | ||
printf("time of computeForwardPass: %fms\n", (en - be)/1000.0); | ||
return m_data.ret_code; | ||
}; | ||
|
||
ReturnCode PathParametrizationAlgorithm::computeControllableSetsParallel( | ||
const Bound &vel_ends) { | ||
ReturnCode ret = ReturnCode::OK; | ||
bool solver_ret; | ||
Vector g_upper{2}, g_lower{2}, solution; | ||
// Vectors solution_upper, solution_lower; | ||
// solution_upper.assign(m_N, Vector::Zero(2, 1)); | ||
// solution_lower.assign(m_N, Vector::Zero(2, 1)); | ||
|
||
g_upper << 1e-9, -1; | ||
g_lower << -1e-9, 1; | ||
m_data.controllable_sets.row(m_N) = vel_ends.cwiseAbs2(); | ||
|
||
size_t be = GetCurrentTimeUsec(); | ||
|
||
bool batch_ok = true; | ||
printf("omp omp_get_max_threads %d\n", omp_get_max_threads()); | ||
#pragma omp parallel for schedule(dynamic) | ||
for (int i = 0; i < m_N; i++) { | ||
// solver_ret = m_solver->solveStagewiseBatch(i, g_upper, solution_upper[i]); | ||
solver_ret = m_solver->solveStagewiseBatch(i, g_upper); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't look right to me. Are you sure that this routine returns the correct controllable sets? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it just store the half-finished solution in solver. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here is actually the implementation of parallelism. |
||
if (!solver_ret) { | ||
ret = ReturnCode::ERR_FAIL_CONTROLLABLE; | ||
printf("Fail: solveStagewiseBatch, upper problem, idx: %d\n", i); | ||
batch_ok = false; | ||
} | ||
|
||
// solver_ret = m_solver->solveStagewiseBatch(i, g_lower, solution_lower[i]); | ||
solver_ret = m_solver->solveStagewiseBatch(i, g_lower); | ||
if (!solver_ret) { | ||
ret = ReturnCode::ERR_FAIL_CONTROLLABLE; | ||
printf("Fail: solveStagewiseBatch, lower problem, idx: %d\n", i); | ||
batch_ok = false; | ||
} | ||
} | ||
if (!batch_ok) return ret; | ||
|
||
size_t en = GetCurrentTimeUsec(); | ||
printf("time of Batch: %fms\n", (en - be)/1000.0); | ||
be = en; | ||
|
||
Bound x_next; | ||
for (int i = m_N - 1; i != -1; i--) { | ||
x_next = m_data.controllable_sets.row(i + 1); | ||
solver_ret = m_solver->solveStagewiseBack(i, g_upper, x_next, solution); | ||
if (!solver_ret) { | ||
ret = ReturnCode::ERR_FAIL_CONTROLLABLE; | ||
printf("Fail: solveStagewiseBack, upper problem, idx: %d\n", i); | ||
break; | ||
} | ||
m_data.controllable_sets(i, 1) = solution[1]; | ||
|
||
solver_ret = m_solver->solveStagewiseBack(i, g_lower, x_next, solution); | ||
if (!solver_ret) { | ||
ret = ReturnCode::ERR_FAIL_CONTROLLABLE; | ||
printf("Fail: solveStagewiseBack, lower problem, idx: %d\n", i); | ||
break; | ||
} | ||
// For whatever reason, sometimes the solver return negative | ||
// solution despite having a set of positve bounds. This readjust | ||
// if the solution is negative. | ||
m_data.controllable_sets(i, 0) = std::max(0.0, solution[1]); | ||
} | ||
en = GetCurrentTimeUsec(); | ||
printf("time of Back: %fms\n", (en - be)/1000.0); | ||
return ret; | ||
} | ||
|
||
ReturnCode PathParametrizationAlgorithm::computeFeasibleSets() { | ||
initialize(); | ||
ReturnCode ret = ReturnCode::OK; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't change the default flag needlessly. You can always use
-DPython_BINDINGS=OFF
during compilation.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.